- 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
101 lines
3.4 KiB
AutoHotkey
101 lines
3.4 KiB
AutoHotkey
; Util.ahk — Fonctions utilitaires de PromptKey (dates, GUID, normalisation, journal).
|
|
; Aucune dépendance. Voir le document d'architecture, section 19.
|
|
|
|
class Util {
|
|
; Journal local : horodatage + message. JAMAIS de contenu de prompt (architecture §11.6 / §18).
|
|
static LogFile := ""
|
|
static Log(msg) {
|
|
if (Util.LogFile = "")
|
|
return
|
|
try {
|
|
line := FormatTime(, "yyyy-MM-dd HH:mm:ss") " " msg "`r`n"
|
|
FileAppend(line, Util.LogFile, "UTF-8")
|
|
; Rotation grossière : au-delà d'environ 1 Mo, on repart de zéro.
|
|
if (FileGetSize(Util.LogFile) > 1048576)
|
|
FileMove(Util.LogFile, Util.LogFile ".bak", true)
|
|
}
|
|
}
|
|
|
|
static NewGuid() {
|
|
; GUID via l'API Windows (CoCreateGuid), formaté en minuscules avec tirets.
|
|
buf := Buffer(16, 0)
|
|
DllCall("ole32\CoCreateGuid", "Ptr", buf.Ptr)
|
|
g := ""
|
|
fmt := [4, 2, 2, 2, 6] ; tailles en octets des groupes 8-4-4-4-12 (hex)
|
|
off := 0
|
|
parts := []
|
|
for i, sz in fmt {
|
|
hex := ""
|
|
; Le premier groupe est un entier little-endian : on lit les octets dans l'ordre inverse pour les groupes 1 à 3.
|
|
if (i <= 3) {
|
|
loop sz {
|
|
hex := Format("{:02x}", NumGet(buf, off + A_Index - 1, "UChar")) hex
|
|
}
|
|
} else {
|
|
loop sz {
|
|
hex .= Format("{:02x}", NumGet(buf, off + A_Index - 1, "UChar"))
|
|
}
|
|
}
|
|
parts.Push(hex)
|
|
off += sz
|
|
}
|
|
return parts[1] "-" parts[2] "-" parts[3] "-" parts[4] "-" parts[5]
|
|
}
|
|
|
|
static NowIso() {
|
|
return FormatTime(, "yyyy-MM-ddTHH:mm:ss")
|
|
}
|
|
|
|
static Today() {
|
|
return FormatTime(, "yyyy-MM-dd")
|
|
}
|
|
|
|
; Normalisation pour la recherche : minuscules + suppression des accents (architecture §14.1).
|
|
static Normalize(s) {
|
|
s := StrLower(s)
|
|
static accents := Map(
|
|
"à", "a", "á", "a", "â", "a", "ä", "a", "ã", "a",
|
|
"è", "e", "é", "e", "ê", "e", "ë", "e",
|
|
"ì", "i", "í", "i", "î", "i", "ï", "i",
|
|
"ò", "o", "ó", "o", "ô", "o", "ö", "o", "õ", "o",
|
|
"ù", "u", "ú", "u", "û", "u", "ü", "u",
|
|
"ç", "c", "ñ", "n", "ÿ", "y")
|
|
out := ""
|
|
loop parse s {
|
|
out .= accents.Has(A_LoopField) ? accents[A_LoopField] : A_LoopField
|
|
}
|
|
return out
|
|
}
|
|
|
|
; Tronque proprement pour les aperçus.
|
|
static Truncate(s, n) {
|
|
if (StrLen(s) <= n)
|
|
return s
|
|
return SubStr(s, 1, n) "…"
|
|
}
|
|
|
|
; Nom de fichier sûr à partir d'un titre (minuscules, tirets, sans accents).
|
|
static Slugify(title) {
|
|
s := Util.Normalize(Trim(title))
|
|
s := RegExReplace(s, "[^a-z0-9]+", "-")
|
|
s := Trim(s, "-")
|
|
return (s = "") ? "sans-titre" : s
|
|
}
|
|
|
|
; Échappe une valeur pour l'en-tête : guillemets si la valeur contient un caractère spécial du format.
|
|
static QuoteIfNeeded(s) {
|
|
if (s = "")
|
|
return s
|
|
if RegExMatch(s, "[,\[\]#:]") || (Trim(s) != s)
|
|
return '"' StrReplace(s, '"', '\"') '"'
|
|
return s
|
|
}
|
|
|
|
static Unquote(s) {
|
|
s := Trim(s)
|
|
if (StrLen(s) >= 2 && SubStr(s, 1, 1) = '"' && SubStr(s, -1) = '"')
|
|
s := StrReplace(SubStr(s, 2, StrLen(s) - 2), '\"', '"')
|
|
return s
|
|
}
|
|
}
|