<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/vterm-config.el, branch load-graph-classify-start</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-19T00:28:27+00:00</updated>
<entry>
<title>fix(vterm): stop wheel/escape forwarders from blocking Emacs</title>
<updated>2026-05-19T00:28:27+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-19T00:28:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=016068349e0ebbd470e337440a1ef378248e0edb'/>
<id>urn:sha1:016068349e0ebbd470e337440a1ef378248e0edb</id>
<content type='text'>
vterm-send-string ends with (accept-process-output ... vterm-timer-delay
...). The global vterm-timer-delay is nil in this config, so the call
blocks forever when the pty's program consumes the event without producing
output -- a common pattern for TUIs like Claude Code reacting to mouse
wheel or Escape. The symptom is a spinning cursor until C-g.

cj/vterm--send-mouse-wheel and cj/vterm-send-escape now wrap the send in a
let-binding that pins vterm-timer-delay to 0, so accept-process-output
returns immediately. A top-level (defvar vterm-timer-delay) declaration
goes alongside so the let is dynamic. Without it, lexical-binding-t in
this file makes the binding lexical, invisible to vterm-send-string across
files. The backtrace from the failing case confirmed the lookup was still
receiving nil before the declaration.
</content>
</entry>
<entry>
<title>feat(vterm): forward &lt;escape&gt; to the pty in vterm-mode</title>
<updated>2026-05-18T21:00:08+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-18T21:00:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=55fb9102c70dc272d4267aec30eed4860f3abdf5'/>
<id>urn:sha1:55fb9102c70dc272d4267aec30eed4860f3abdf5</id>
<content type='text'>
`&lt;escape&gt;' is bound globally to `keyboard-escape-quit' in
modules/keybindings.el, so Emacs swallows the key before it can reach the
pty. Bind it in vterm-mode-map to cj/vterm-send-escape, which writes a
literal ESC byte via vterm-send-string. tmux's copy-mode `cancel' binding
then fires; vi-mode exits, fzf cancel, etc., also work as expected.
</content>
</entry>
<entry>
<title>feat(vterm): forward wheel events and route C-; x c into tmux copy-mode</title>
<updated>2026-05-18T20:49:29+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-18T20:49:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=0202a65825441562eb9903ccc28939367e29c274'/>
<id>urn:sha1:0202a65825441562eb9903ccc28939367e29c274</id>
<content type='text'>
vterm-mode-map binds only mouse-1 and mouse-yank-primary, so wheel events
fall through to Emacs scrolling and never reach the pty. tmux's `set -g
mouse on' never sees them. Bind wheel-up / wheel-down (and X11 mouse-4 /
mouse-5) to send SGR mouse-wheel escapes via vterm-send-string. tmux's
existing WheelUpPane / WheelDownPane bindings route into copy-mode from
there.

For keyboard parity, route C-; x c through cj/vterm-copy-mode-dwim, which
sends C-b [ when a tmux client is attached and falls back to vterm-copy-mode
otherwise. tmux's history-limit is now reachable from either entry point.
The matching copy-mode keys (M-w stays, C-g / q / Escape exit, Enter
unbound) land in the dotfiles repo alongside.
</content>
</entry>
<entry>
<title>feat(vterm): show tmux scrollback history in place</title>
<updated>2026-05-13T20:39:40+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-13T20:39:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c3ec8508a8ff414d099d9e567eb5ffd43a9c93f2'/>
<id>urn:sha1:c3ec8508a8ff414d099d9e567eb5ffd43a9c93f2</id>
<content type='text'>
`cj/vterm-tmux-history' previously used `pop-to-buffer', which routed the history view through display-buffer-alist -- in an agent window that often meant a split or a hand-off to another window, costing the agent its frame slot. `switch-to-buffer' instead drops the history into the selected window directly; the existing quit handler already restores the origin in that same window via `set-window-buffer'.

New test asserts the in-place behavior: starting single-window with a vterm origin, invoking the command leaves `(one-window-p)` t with the history buffer in the original slot. The existing render test no longer needs its `pop-to-buffer' stub since `switch-to-buffer' works in batch.
</content>
</entry>
<entry>
<title>feat(vterm): unify the keys in vterm copy-mode and tmux history</title>
<updated>2026-05-11T15:02:17+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-11T15:02:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=949bdeb3ac4d7b027cdd88efd54cc8c121f8c5d3'/>
<id>urn:sha1:949bdeb3ac4d7b027cdd88efd54cc8c121f8c5d3</id>
<content type='text'>
`vterm-copy-mode' and the `C-; x h' tmux-history buffer now share one key story. `M-w' copies the active region and stays put, so I can copy several things in a row. `C-g', `&lt;escape&gt;', or `q' leaves (resuming the live terminal, or closing the history buffer) without copying. `RET' is unbound (no special "copy and exit"). In copy-mode that meant removing vterm's default `RET' -&gt; `vterm-copy-mode-done' binding.

Before, `M-w' exited and copied as it went, which made grabbing more than one selection awkward. The history buffer's `cj/vterm-tmux-history-copy-and-quit' was the copy-and-exit one-shot. It's gone. `M-w' then `q' is the equivalent.

I also moved `cj/vterm-tmux-history' from `C-; x C' to `C-; x h' (unshifted, and it frees `C') and refreshed the file's stale commentary header, which still referenced the old `C-; V' prefix and `&lt;pause&gt;'.
</content>
</entry>
<entry>
<title>refactor(ai-vterm): rename Claude-specific names to a generic "agent"</title>
<updated>2026-05-11T12:18:20+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-11T12:18:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=59b0854464ef29511a0d09f1e76fd1140e675833'/>
<id>urn:sha1:59b0854464ef29511a0d09f1e76fd1140e675833</id>
<content type='text'>
I may add other terminal agents to this launcher (aider, an open-source LLM TUI), so the buffer prefix, the user knob, and the internal helpers shouldn't say "Claude". The module name (ai-vterm) and the `cj/ai-vterm-*` customs were already generic. This finishes the job:

- buffer prefix `claude [&lt;basename&gt;]` -&gt; `agent [&lt;basename&gt;]` (the `defconst` and the matching display-buffer-alist regex move together)
- `cj/ai-vterm-claude-command` -&gt; `cj/ai-vterm-agent-command` (the default still runs the `claude` CLI, with a docstring note on swapping it)
- `cj/--ai-vterm-claude-buffers` / `-displayed-claude-window` / `-reuse-existing-claude` -&gt; `-agent-*`, and their test files renamed to match
- prose in the module commentary and docstrings, plus the matching test docstrings and buffer-name literals

`vterm-config.el` hardcodes the same buffer prefix in `cj/--vterm-toggle-buffer-p` (F12 excludes agent buffers from its candidate set), so that literal moved too. Collapsing it into the shared `cj/--ai-vterm-name-prefix` is a cleanup for another day.

After a reload, a project's buffer opens as `agent [foo]` instead of `claude [foo]`. Old buffers keep their names until killed. I also corrected two stale `eshell-vterm-config.el` references in ai-vterm.el docstrings (that module was split into `vterm-config.el`).

Two things keep saying "Claude": the `cj/ai-vterm-agent-command` default value (the actual CLI), and the "Claude Code" example in `vterm-config.el`'s cursor-restore docstring (a concrete TUI example, not branding).

90 tests pass. `make validate-modules` clean.
</content>
</entry>
<entry>
<title>refactor(cj-window-geometry): rename to cj-window-geometry-lib</title>
<updated>2026-05-10T20:31:27+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T20:31:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=8c12629f8c4c8726b7b74ad3912abd9cd1cade9c'/>
<id>urn:sha1:8c12629f8c4c8726b7b74ad3912abd9cd1cade9c</id>
<content type='text'>
Same naming-convention fix as the other library renames in this series.

Rename modules/cj-window-geometry.el -&gt; modules/cj-window-geometry-lib.el
and tests/test-cj-window-geometry.el -&gt; tests/test-cj-window-geometry-lib.el.
Update provide forms, file headers, and the (require 'cj-window-geometry)
call sites in cj-window-toggle-lib.el, ai-vterm.el, vterm-config.el,
and the test file.

No behavior change.
</content>
</entry>
<entry>
<title>refactor(cj-window-toggle): rename to cj-window-toggle-lib for naming consistency</title>
<updated>2026-05-10T20:28:31+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T20:28:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a2e41803d7d29a43ed37a5cf9fd7fe53ca5c15b5'/>
<id>urn:sha1:a2e41803d7d29a43ed37a5cf9fd7fe53ca5c15b5</id>
<content type='text'>
Rename modules/cj-window-toggle.el -&gt; modules/cj-window-toggle-lib.el
and tests/test-cj-window-toggle.el -&gt; tests/test-cj-window-toggle-lib.el.
Update provide forms, file headers, and the (require 'cj-window-toggle)
call sites in ai-vterm.el, vterm-config.el, and the test file.

Same rationale as the cj-cache and cj-org-text renames -- library files
in this codebase are suffixed `-lib'.  No behavior change.
</content>
</entry>
<entry>
<title>refactor(vterm): move vterm prefix to C-; x and add prompt nav</title>
<updated>2026-05-10T17:39:44+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T17:39:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=5eccbf7bd3c9780eee6170839dbf3224a32e9ef3'/>
<id>urn:sha1:5eccbf7bd3c9780eee6170839dbf3224a32e9ef3</id>
<content type='text'>
The personal vterm map was on `C-; V'. The capital V costs a Shift on every keystroke into the menu, which adds up for the daily `C-; V c' / `C-; V C' bindings. Move the prefix to lowercase `C-; x' -- free, no Shift, faintly mnemonic (xterm/execute). The lowercase `C-; v' stays the version-control menu.

Wire `vterm-next-prompt' and `vterm-previous-prompt' into the menu so they're reachable everywhere, not only inside vterm-copy-mode-map. Lowercase `n' and `p' match Emacs's idiom for next/previous; bump "new vterm" up to capital `N' for the rare new-buffer case.

Drop the `&lt;pause&gt;' binding for `vterm-copy-mode' from `vterm-mode-map'. Modern keyboards rarely have a Pause key and `C-; x c' is the canonical entry now.

Update which-key labels and tests; `test-vterm-keymap-includes-history-and-copy-bindings' now asserts the new prefix, and two new tests cover prompt-nav bindings and the dropped `&lt;pause&gt;' binding.
</content>
</entry>
<entry>
<title>fix(vterm): use a block cursor in vterm-copy-mode</title>
<updated>2026-05-10T17:23:14+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T17:23:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=c56a638192f3b6aff13c26e34ce78db0d26de6fc'/>
<id>urn:sha1:c56a638192f3b6aff13c26e34ce78db0d26de6fc</id>
<content type='text'>
The 3-pixel bar was visible but a block matches the rest of my Emacs cursor and lets the standard cursor color and `blink-cursor-mode' behavior carry through unchanged. Same enter/exit semantics: forced visible on entry, buffer-local override killed on exit so the live terminal goes back to the TUI's chosen state.

Update the test expectations and rename the "prior-was-box" boundary test to "prior-was-hbar" so it still proves the override does something (the prior and the override would otherwise both be `box').
</content>
</entry>
</feed>
