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