Skip to content

Commit 44b7973

Browse files
bobrowadamdnouri
andauthored
Add configurable extension status faces (#210)
* Add extension status faces * Make extension status faces discoverable Extension status face customization is keyed by the statusKey that an extension sends, not necessarily by the extension package name. Say that in the user option and README so users do not have to guess.\n\nPut the status key on header-line status text as local help, and give that text a mouse highlight so the hover target is visible. Tighten the Customize type to accept face symbols or face attribute plists.\n\nTest the full header-line path with a pi-sub-shaped key. --------- Co-authored-by: Daniel Nouri <daniel.nouri@gmail.com>
1 parent ebf239d commit 44b7973

3 files changed

Lines changed: 59 additions & 2 deletions

File tree

README.org

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ Several features match the TUI experience:
259259
pi-coding-agent has basic support for pi extensions. Extension commands
260260
show up in slash completion and the transient menu, extension tools run
261261
normally, and extensions can use notifications, confirm/select/input
262-
prompts, prefill the input buffer, and show status text.
262+
prompts, prefill the input buffer, and show status text. Hover status text
263+
to see the exact =statusKey= used for =pi-coding-agent-extension-status-faces=.
263264

264265
Rich TUI-specific extension UI is not supported in Emacs yet: custom
265266
widgets, custom editor components, custom headers/footers, and other

pi-coding-agent-ui.el

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,23 @@ When nil (the default), only the visible text is copied."
172172
:type 'boolean
173173
:group 'pi-coding-agent)
174174

175+
(defcustom pi-coding-agent-extension-status-faces nil
176+
"Alist mapping extension status keys to faces in the header line.
177+
Keys are exact `statusKey' strings sent by extension `setStatus' requests,
178+
not necessarily extension package names. Hovering header status text shows
179+
the key to use here. Values are face symbols or face attribute plists
180+
accepted by `propertize'.
181+
182+
For example:
183+
\='((\"sub-status:usage\" . (:foreground \"#c6a0f6\"))
184+
(\"solveit-mode\" . warning))"
185+
:type '(alist :key-type string
186+
:value-type (choice (face :tag "Face")
187+
(plist :tag "Face attributes"
188+
:key-type symbol
189+
:value-type sexp)))
190+
:group 'pi-coding-agent)
191+
175192
(defcustom pi-coding-agent-quit-without-confirmation nil
176193
"Whether `pi-coding-agent-quit' skips confirmation for a live process.
177194
When non-nil, quitting a session never asks whether a running pi process
@@ -1775,7 +1792,17 @@ Returns extension statuses joined with \" · \", or empty string."
17751792
(if (null ext-status)
17761793
""
17771794
(mapconcat (lambda (pair)
1778-
(pi-coding-agent--header-escape-text (cdr pair)))
1795+
(let* ((key (car pair))
1796+
(text (pi-coding-agent--header-escape-text (cdr pair)))
1797+
(face (cdr (assoc key pi-coding-agent-extension-status-faces)))
1798+
(properties (and (stringp key)
1799+
(list 'help-echo key
1800+
'mouse-face 'highlight))))
1801+
(when face
1802+
(setq properties (append properties (list 'face face))))
1803+
(if properties
1804+
(apply #'propertize text properties)
1805+
text)))
17791806
ext-status
17801807
" · ")))
17811808

test/pi-coding-agent-ui-test.el

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,35 @@ Buffer is read-only with `inhibit-read-only' used for insertion.
692692
"Hot-tail turn count defaults to 3 headed turns."
693693
(should (= 3 pi-coding-agent-hot-tail-turn-count)))
694694

695+
(ert-deftest pi-coding-agent-test-extension-status-properties-apply-in-header-line ()
696+
"Extension status properties are applied by status key in the header line."
697+
(let ((pi-coding-agent-extension-status-faces
698+
'(("sub-status:usage" . (:foreground "#c6a0f6")))))
699+
(with-temp-buffer
700+
(pi-coding-agent-chat-mode)
701+
(setq pi-coding-agent--state '(:model "claude-sonnet-4")
702+
pi-coding-agent--extension-status
703+
'(("solveit-mode" . "⚡ concise")
704+
("sub-status:usage" . "4h51m 1% · 9h9m 41%")))
705+
(let ((header (pi-coding-agent--header-line-string)))
706+
(should (string-match-p "⚡ concise · 4h51m 1%% · 9h9m 41%%"
707+
(substring-no-properties header)))
708+
(should-not (get-text-property (string-match-p "" header) 'face header))
709+
(should (equal (get-text-property (string-match-p "" header)
710+
'help-echo header)
711+
"solveit-mode"))
712+
(should (eq (get-text-property (string-match-p "" header)
713+
'mouse-face header)
714+
'highlight))
715+
(should (equal (get-text-property (string-match-p "4h" header) 'face header)
716+
'(:foreground "#c6a0f6")))
717+
(should (equal (get-text-property (string-match-p "4h" header)
718+
'help-echo header)
719+
"sub-status:usage"))
720+
(should (eq (get-text-property (string-match-p "4h" header)
721+
'mouse-face header)
722+
'highlight))))))
723+
695724
(ert-deftest pi-coding-agent-test-kill-ring-save-strips-by-default ()
696725
"kill-ring-save strips hidden markup by default."
697726
(pi-coding-agent-test--with-chat-markup "Hello **bold** world"

0 commit comments

Comments
 (0)