Skip to content

Commit 4cd74f7

Browse files
committed
fix: skip pixel model-line alignment on Emacs <29
`string-pixel-width' and `buffer-text-pixel-size' are both Emacs 29+. Remove dead `buffer-text-pixel-size' branch and skip pixel right-alignment on 28.x, where `string-width' fallback would push right segments past the window edge. Guard pixel-specific tests.
1 parent b12e409 commit 4cd74f7

3 files changed

Lines changed: 11 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Unreleased
44

5-
- Bugfix: keep the `:usage` and `:trust` mode-line segments visible after adding the context-usage bar. The right-alignment reserved space from `(length right)`, which counts the bar's pixel-width `display` spaces (and wide glyphs) as ~1 char each, so the segments overflowed off the right edge. It now measures the real rendered width via `string-pixel-width` (with a `buffer-text-pixel-size` fallback on Emacs < 29) and aligns flush to the right edge in pixels.
5+
- Bugfix: keep the `:usage` and `:trust` mode-line segments visible after adding the context-usage bar. The right-alignment reserved space from `(length right)`, which counts the bar's pixel-width `display` spaces (and wide glyphs) as ~1 char each, so the segments overflowed off the right edge. It now measures the real rendered width via `string-pixel-width` and aligns flush to the right edge in pixels (Emacs 29+ only; on Emacs 28 right segments follow left without alignment).
66
- Bugfix: closing a chat (`kill-buffer`, `C-c C-k`, or the tab close button) now switches the chat window to a sibling chat (the previous tab, or the only one left) instead of falling back to an unrelated buffer like the settings buffer, and drops the dead chat from the session registry. `C-c C-k` (`eca-chat-reset`) only starts a fresh chat when the closed chat was the last one.
7-
- Replace chat copy buttons with `eca-chat-copy-at-point`, bound to `C-c C-w`. It copies the fenced code block at point, the assistant response at point, or the latest response as a fallback, without inserting any visible copy controls into the chat buffer.
7+
- Add `eca-chat-copy-at-point`, bound to `C-c C-w`. It copies the fenced code block at point, the assistant response at point, or the latest response as a fallback.
88
- Bugfix: guard `chat/askQuestion` against a non-sequence `:options` (e.g. a malformed string from a misbehaving server). `append` was splitting such a string into character integers that rendered as a list of random numbers; non-sequence options are now treated as empty.
99
- Add a context-usage bar in the chat mode-line, left of the token usage, showing how full the model context window is, colored by category (system prompt, rules, skills, AGENTS.md, tool definitions, tool calls, conversation, free space), each a distinct color. In graphical frames it renders pixel-width thin segments for high granularity (small percentages stay visible); terminals fall back to block characters. Same footprint either way (`eca-chat-context-bar-width`). Colors come from the server (canonical `color`/`freeColor`) so they are consistent; hover the bar for a legend that maps each category to its server emoji swatch (`emoji`/`freeEmoji`, matching the `/context` command output), or click to run the new `/context` command. Configurable via `eca-chat-context-bar-width` and the `:context-bar` module in `eca-chat-mode-line-format`. Needs an eca server that sends `contextBreakdown` in `usage` content.
1010
- Auto-dismiss a pending `ask_user` question when another client (e.g. an SSE/web client in remote mode, see eca 0.139.0) answers it first. The server resolves the `ask_user` tool out from under us and sends a `toolCalled`/`toolCallRejected` for that tool-call id but no longer expects our answer (it cancels our request); we now correlate that id with `eca-chat--pending-question` and clear the stale answer-mode prompt state instead of staying stuck waiting for input.

eca-chat.el

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,15 +2595,10 @@ are in progress."
25952595
"Return the rendered pixel width of STRING for mode-line alignment.
25962596
Honors `display' specs (e.g. the context bar's pixel-width spaces) and
25972597
wide glyphs, unlike `length'. Uses `string-pixel-width' when
2598-
available, otherwise `buffer-text-pixel-size', falling back to
2599-
`string-width' on Emacsen without either."
2598+
available, falling back to `string-width' on Emacsen without it."
26002599
(cond
26012600
((string-empty-p string) 0)
26022601
((fboundp 'string-pixel-width) (string-pixel-width string))
2603-
((fboundp 'buffer-text-pixel-size)
2604-
(with-temp-buffer
2605-
(insert string)
2606-
(car (buffer-text-pixel-size nil nil t))))
26072602
(t (string-width string))))
26082603

26092604
(defun eca-chat--mode-line-string (session)
@@ -2629,7 +2624,8 @@ available, otherwise `buffer-text-pixel-size', falling back to
26292624
(eca-chat--mode-line-module session m))
26302625
right-modules))
26312626
"")))
2632-
(fill (if (string-empty-p right)
2627+
(fill (if (or (string-empty-p right)
2628+
(not (fboundp 'string-pixel-width)))
26332629
""
26342630
(let ((px (eca-chat--string-pixel-width right)))
26352631
(propertize

test/eca-chat-test.el

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,8 @@ does not treat the first line as metadata. Returns FN's value."
988988
(expect (eca-chat--string-pixel-width "") :to-equal 0))
989989

990990
(it "honors pixel-width display specs instead of counting chars"
991+
(unless (fboundp 'string-pixel-width)
992+
(buttercup-skip "string-pixel-width not available"))
991993
;; A single space carrying a 40px display width must measure ~40, not
992994
;; 1 (its `length'). Counting it as 1 char is what pushed the :usage
993995
;; and :trust mode-line segments off the right edge once the context
@@ -997,6 +999,8 @@ does not treat the first line as metadata. Returns FN's value."
997999
(expect (eca-chat--string-pixel-width s) :to-equal 40)))
9981000

9991001
(it "measures a pixel context-bar wider than its char length"
1002+
(unless (fboundp 'string-pixel-width)
1003+
(buttercup-skip "string-pixel-width not available"))
10001004
(let ((bar (eca-chat--context-bar-pixels
10011005
(list (list :name "System prompt" :tokens 100 :color "#ff0000"))
10021006
(list :freeColor "#222222")
@@ -1005,6 +1009,8 @@ does not treat the first line as metadata. Returns FN's value."
10051009

10061010
(describe "eca-chat context-bar compaction marker"
10071011
(it "keeps the pixel-bar total width when the marker is overlaid"
1012+
(unless (fboundp 'string-pixel-width)
1013+
(buttercup-skip "string-pixel-width not available"))
10081014
(let* ((cats (list (list :name "System prompt" :tokens 100 :color "#ff0000")))
10091015
(bd (list :freeColor "#222222"))
10101016
(plain (eca-chat--context-bar-pixels cats bd 16 0.5))

0 commit comments

Comments
 (0)