Files
Spark b102a4a206 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
2026-10-11 10:17:30 -04:00

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)
}
}