- 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
202 lines
5.2 KiB
AutoHotkey
202 lines
5.2 KiB
AutoHotkey
; 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)
|
|
}
|
|
}
|