feat(core): moteur PromptKey — bibliothèque .md, variables, injection, raccourcis
- PromptStore/Frontmatter : un prompt = un fichier Markdown, en-tête au sous-ensemble strict du document d'architecture (§7), écriture UTF-8 - VariableEngine : variables typées + automatiques (selection, clipboard, date, app, cursor), résolution et profils de destination - Injector/ClipboardGuard : focus capturé/rendu, presse-papiers sauvegardé puis restauré conditionnellement, aucun envoi automatique par défaut - Search : classement flou insensible aux accents, pondéré par l'usage - UsageStats (usage.json), HotkeyManager (conflits signalés, jamais muets) - Settings : config.ini + profils par IA (claude, chatgpt, qwen, terminal…) - PromptKey.ahk : tray, instance unique, capture du contexte, surveillance de la bibliothèque, installation du pack au premier lancement
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
; Json.ahk — Petit parseur / sérialiseur JSON autonome pour PromptKey.
|
||||
; Utilisé pour usage.json, index-cache.json et l'import/export (architecture §15, §16.1).
|
||||
; Types : Map -> objet, Array -> tableau, String, Integer/Float, 1/0 (les booléens
|
||||
; AHK sont des entiers ; à la sérialisation, true/false sont émis comme true/false
|
||||
; uniquement pour les valeurs stockées via Json.True / Json.False — sinon nombres).
|
||||
|
||||
class Json {
|
||||
static Parse(text) {
|
||||
p := _JsonParser(text)
|
||||
v := p.ParseValue()
|
||||
p.SkipWs()
|
||||
return v
|
||||
}
|
||||
|
||||
static Stringify(value, indent := 0) {
|
||||
pad := indent > 0 ? StrRepeat(" ", indent) : ""
|
||||
padIn := indent > 0 ? StrRepeat(" ", indent * 2) : ""
|
||||
nl := indent > 0 ? "`n" : ""
|
||||
if (value is Map) {
|
||||
if (value.Count = 0)
|
||||
return "{}"
|
||||
parts := []
|
||||
for k, v in value {
|
||||
parts.Push(padIn Json.EscapeString(String(k)) ": " Json.Stringify(v, indent))
|
||||
}
|
||||
return "{" nl Join(parts, "," nl) nl pad "}"
|
||||
}
|
||||
if (value is Array) {
|
||||
if (value.Length = 0)
|
||||
return "[]"
|
||||
parts := []
|
||||
for v in value
|
||||
parts.Push(Json.Stringify(v, indent))
|
||||
return "[" Join(parts, ", ") "]"
|
||||
}
|
||||
if (value is String)
|
||||
return Json.EscapeString(value)
|
||||
if (value is Integer || value is Float)
|
||||
return String(value)
|
||||
if (value = "")
|
||||
return '""'
|
||||
return Json.EscapeString(String(value))
|
||||
}
|
||||
|
||||
static EscapeString(s) {
|
||||
s := StrReplace(s, "\", "\\")
|
||||
s := StrReplace(s, '"', '\"')
|
||||
s := StrReplace(s, "`n", "\n")
|
||||
s := StrReplace(s, "`r", "\r")
|
||||
s := StrReplace(s, "`t", "\t")
|
||||
return '"' s '"'
|
||||
}
|
||||
}
|
||||
|
||||
StrRepeat(ch, n) {
|
||||
out := ""
|
||||
loop n
|
||||
out .= ch
|
||||
return out
|
||||
}
|
||||
|
||||
Join(arr, sep) {
|
||||
out := ""
|
||||
for i, v in arr {
|
||||
if (i > 1)
|
||||
out .= sep
|
||||
out .= v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
class _JsonParser {
|
||||
__New(text) {
|
||||
this.Text := text
|
||||
this.Pos := 1
|
||||
this.Len := StrLen(text)
|
||||
}
|
||||
|
||||
SkipWs() {
|
||||
while (this.Pos <= this.Len) {
|
||||
c := SubStr(this.Text, this.Pos, 1)
|
||||
if (c = " " || c = "`t" || c = "`n" || c = "`r")
|
||||
this.Pos++
|
||||
else
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Peek() {
|
||||
return this.Pos <= this.Len ? SubStr(this.Text, this.Pos, 1) : ""
|
||||
}
|
||||
|
||||
ParseValue() {
|
||||
this.SkipWs()
|
||||
c := this.Peek()
|
||||
if (c = "{")
|
||||
return this.ParseObject()
|
||||
if (c = "[")
|
||||
return this.ParseArray()
|
||||
if (c = '"')
|
||||
return this.ParseString()
|
||||
if (c = "t") {
|
||||
this.Pos += 4 ; true
|
||||
return 1
|
||||
}
|
||||
if (c = "f") {
|
||||
this.Pos += 5 ; false
|
||||
return 0
|
||||
}
|
||||
if (c = "n") {
|
||||
this.Pos += 4 ; null
|
||||
return ""
|
||||
}
|
||||
return this.ParseNumber()
|
||||
}
|
||||
|
||||
ParseObject() {
|
||||
obj := Map()
|
||||
this.Pos++ ; {
|
||||
this.SkipWs()
|
||||
if (this.Peek() = "}") {
|
||||
this.Pos++
|
||||
return obj
|
||||
}
|
||||
loop {
|
||||
this.SkipWs()
|
||||
key := this.ParseString()
|
||||
this.SkipWs()
|
||||
this.Pos++ ; :
|
||||
obj[key] := this.ParseValue()
|
||||
this.SkipWs()
|
||||
c := this.Peek()
|
||||
this.Pos++
|
||||
if (c = "}")
|
||||
break
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
ParseArray() {
|
||||
arr := []
|
||||
this.Pos++ ; [
|
||||
this.SkipWs()
|
||||
if (this.Peek() = "]") {
|
||||
this.Pos++
|
||||
return arr
|
||||
}
|
||||
loop {
|
||||
arr.Push(this.ParseValue())
|
||||
this.SkipWs()
|
||||
c := this.Peek()
|
||||
this.Pos++
|
||||
if (c = "]")
|
||||
break
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
ParseString() {
|
||||
out := ""
|
||||
this.Pos++ ; guillemet ouvrant
|
||||
while (this.Pos <= this.Len) {
|
||||
c := SubStr(this.Text, this.Pos, 1)
|
||||
this.Pos++
|
||||
if (c = '"')
|
||||
break
|
||||
if (c = "\") {
|
||||
e := SubStr(this.Text, this.Pos, 1)
|
||||
this.Pos++
|
||||
switch e {
|
||||
case "n": out .= "`n"
|
||||
case "r": out .= "`r"
|
||||
case "t": out .= "`t"
|
||||
case "b": out .= Chr(8)
|
||||
case "f": out .= Chr(12)
|
||||
case "/": out .= "/"
|
||||
case "\": out .= "\"
|
||||
case '"': out .= '"'
|
||||
case "u":
|
||||
hex := SubStr(this.Text, this.Pos, 4)
|
||||
this.Pos += 4
|
||||
out .= Chr("0x" hex)
|
||||
default: out .= e
|
||||
}
|
||||
} else {
|
||||
out .= c
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
ParseNumber() {
|
||||
start := this.Pos
|
||||
while (this.Pos <= this.Len && RegExMatch(SubStr(this.Text, this.Pos, 1), "[0-9eE+\-.]"))
|
||||
this.Pos++
|
||||
raw := SubStr(this.Text, start, this.Pos - start)
|
||||
if (InStr(raw, ".") || InStr(raw, "e") || InStr(raw, "E"))
|
||||
return Float(raw)
|
||||
return Integer(raw)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user