; Picker.ahk — Le Quick Picker : surface principale de PromptKey (architecture §8). ; Fenêtre pré-créée, recherche instantanée, navigation clavier, aperçu, retour de focus propre. class PromptPicker { GuiObj := "" SearchEdit := "" LV := "" Preview := "" Status := "" Items := [] ; prompts correspondant aux lignes affichées Ctx := Map() OnUse := "" ; Func(prompt, useDefaults) OnEdit := "" ; Func(prompt) ProfileLabel := "" HotkeysArmed := false Build(onUse, onEdit) { this.OnUse := onUse this.OnEdit := onEdit g := Gui("-MaximizeBox +Resize", "PromptKey") g.SetFont("s10", "Segoe UI") this.GuiObj := g g.Add("Text", "xm", "Rechercher :") this.SearchEdit := g.Add("Edit", "x+10 w470", "") this.SearchEdit.OnEvent("Change", (*) => this.RefreshList()) this.ProfileLabel := g.Add("Text", "x+10 w180", "") this.LV := g.Add("ListView", "xm w500 r14", ["Titre", "Catégorie", "Étiquettes"]) this.LV.ModifyCol(1, 240) this.LV.ModifyCol(2, 110) this.LV.ModifyCol(3, 140) this.LV.OnEvent("ItemSelect", (lv, row, selected) => selected ? this.UpdatePreview(row) : "") this.LV.OnEvent("DoubleClick", (lv, row) => row > 0 ? this.UseSelected(false) : "") this.Preview := g.Add("Edit", "x+15 w330 r14 ReadOnly -Wrap", "") this.Status := g.Add("Text", "xm w850", "") g.OnEvent("Escape", (*) => this.Hide()) g.OnEvent("Close", (*) => this.Hide()) } Show(ctx) { this.Ctx := ctx this.SearchEdit.Value := "" this.RefreshList() this.GuiObj.Show("Center w880") this.SearchEdit.Focus() this.ArmHotkeys() if (ctx.Has("profileName")) this.ProfileLabel.Text := "Profil : " ctx["profileName"] } Hide() { this.DisarmHotkeys() this.GuiObj.Hide() } ; Raccourcis propres au Picker, actifs seulement quand sa fenêtre est active (§8.2). ArmHotkeys() { if this.HotkeysArmed return HotIfWinActive("ahk_id " this.GuiObj.Hwnd) Hotkey("Enter", (*) => this.UseSelected(false), "On") Hotkey("^Enter", (*) => this.UseSelected(true), "On") Hotkey("^e", (*) => this.EditSelected(), "On") Hotkey("Down", (*) => this.MoveSelection(1), "On") Hotkey("Up", (*) => this.MoveSelection(-1), "On") Hotkey("^c", (*) => this.CopySelected(), "On") HotIfWinActive() this.HotkeysArmed := true } DisarmHotkeys() { if !this.HotkeysArmed return HotIfWinActive("ahk_id " this.GuiObj.Hwnd) for hk in ["Enter", "^Enter", "^e", "Down", "Up", "^c"] { try Hotkey(hk, "Off") } HotIfWinActive() this.HotkeysArmed := false } MoveSelection(delta) { row := this.LV.GetNext() if (row = 0) row := delta > 0 ? 1 : this.Items.Length else row := Max(1, Min(this.Items.Length, row + delta)) if (row >= 1 && row <= this.Items.Length) { this.LV.Modify(0, "-Select") this.LV.Modify(row, "Select Focus Vis") this.UpdatePreview(row) } } RefreshList() { q := this.SearchEdit.Value usageData := App.Usage ? App.Usage.Data : Map() this.Items := Search.Filter(App.Store.Prompts, q, usageData) this.LV.Delete() for p in this.Items { marker := "" if p.Pinned marker .= "📌 " if p.Favorite marker .= "★ " this.LV.Add("", marker p.Title, p.Category, Join(p.Tags, ", ")) } if (this.Items.Length > 0) { this.LV.Modify(1, "Select Focus") this.UpdatePreview(1) } else { this.Preview.Value := "(aucun prompt ne correspond)" } this.Status.Text := this.Items.Length " résultat(s) · Entrée Utiliser · Ctrl+Entrée Valeurs par défaut · Ctrl+E Modifier · Échap Fermer" } UpdatePreview(row) { if (row < 1 || row > this.Items.Length) return p := this.Items[row] txt := p.Body sel := this.Ctx.Has("selection") ? this.Ctx["selection"] : "" if (sel != "") txt .= "`r`n`r`n— Sélection capturée (" StrLen(sel) " caractères) : « " Util.Truncate(sel, 120) " »" if (p.ParseError != "") txt := "⚠ Erreur de fichier : " p.ParseError "`r`n`r`n" txt this.Preview.Value := txt } SelectedPrompt() { row := this.LV.GetNext() if (row >= 1 && row <= this.Items.Length) return this.Items[row] return "" } UseSelected(useDefaults) { p := this.SelectedPrompt() if (p = "") return this.Hide() this.OnUse(p, useDefaults) } EditSelected() { p := this.SelectedPrompt() if (p = "") return this.Hide() this.OnEdit(p) } ; Ctrl+C : copie le corps brut (sans résolution) — la résolution complète passe par l'injection. CopySelected() { p := this.SelectedPrompt() if (p = "") return A_Clipboard := p.Body TrayTip("Corps du prompt « " p.Title " » copié.", "PromptKey") this.Hide() } }