You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ship xterm-ghostty terminfo, advertise full capability set
Default TERM=xterm-256color hides ghostel's actual capabilities from
TUI apps that consult terminfo. Most visibly, Claude Code only emits
DEC 2026 (synchronized output) when terminfo advertises `Sync`, so
without it M-x with large scrollback exhibits a choppy cascading
redraw — every small write triggers an unsynchronized partial repaint.
Ship the compiled `xterm-ghostty` entry under terminfo/ (both Linux
x/g/ and macOS 78/67/ hashed-dir layouts; identical bytes), set
TERM=xterm-ghostty + TERMINFO=<bundled> + TERM_PROGRAM=ghostty for
both `ghostel--start-process' and `ghostel-compile' via a shared
helper. The bundled entry intentionally omits `Ms' so apps don't
silently dispatch to OSC 52 when `ghostel-enable-osc52' is off.
`defcustom ghostel-term' (default \"xterm-ghostty\") opts out by
flipping back to xterm-256color and dropping all related env.
Remote-host coverage via `defcustom ghostel-ssh-install-terminfo'
(default `auto', follows `ghostel-tramp-shell-integration'):
- TRAMP-launched ghostel: push compiled terminfo to a remote temp
dir over the existing TRAMP connection (no extra round-trip);
set TERMINFO=<remote dir> in the spawned shell's env; clean up on
exit.
- Outbound `ssh' from a local buffer: bundled bash/zsh/fish
integration shadows `ssh' with a function that resolves the
target via `ssh -G', looks up
${XDG_CACHE_HOME:-~/.cache}/ghostel/ssh-terminfo-cache (key
includes hash of local terminfo for auto-invalidation on
libghostty bumps), and on miss runs one combined probe-and-install
ssh (`infocmp | ssh ... 'tic -x -''), then exec's the user's
real ssh with the resolved TERM. Mkdir-as-lock serializes
concurrent first-time calls to the same target.
Skips install when the user passed a remote command (would clash
with the pipe), when ssh -G can't resolve a host, or when local
`infocmp' is missing. Per-call escape: GHOSTEL_SSH_KEEP_TERM=1.
`M-x ghostel-ssh-clear-terminfo-cache' forces re-probe when a
remote's terminfo changes out of band.
Maintainer-only `make regen-terminfo' regenerates the compiled files
from terminfo/xterm-ghostty.terminfo and verifies cross-layout
parsing via `infocmp'.
Alternatively, download a **pre-built binary** via `M-x ghostel-download-module`
125
125
(or `C-u M-x ghostel-download-module` to pick a specific release).
126
126
127
+
The compiled `xterm-ghostty` terminfo entry ships pre-built in
128
+
`terminfo/` and is identical to what `tic` would produce locally —
129
+
no build step needed, and the file format is portable across BSD
130
+
and ncurses systems. Maintainers regenerate it via `make
131
+
regen-terminfo` after bumping libghostty.
132
+
127
133
## Shell Integration
128
134
129
135
Shell integration (directory tracking via OSC 7, prompt navigation via OSC 133,
@@ -211,6 +217,7 @@ history — even outside copy mode.
211
217
### Terminal Emulation
212
218
- Full VT terminal emulation via libghostty-vt
213
219
- 256-color and RGB (24-bit true color) support
220
+
-**`TERM=xterm-ghostty` with bundled terminfo** — apps that consult terminfo for capabilities (Claude Code, neovim, tmux, modern TUIs) discover synchronized output (DEC 2026), Kitty keyboard protocol, true color, colored underlines, focus reporting, etc., and use their fast paths. Synchronized output in particular eliminates the choppy partial-redraw effect when Claude Code repaints over a large scrollback. OSC 52 (clipboard) is supported but intentionally not advertised in the bundled terminfo — see Clipboard below. Override via `ghostel-term`.
214
221
-**OSC 4 / 10 / 11 color queries** — TUI programs can query the current palette, foreground, and background colors, so tools like `duf`, `btop`, `delta`, and anything else using `termenv` auto-detect the right light/dark theme from the Emacs face colors
215
222
-**OSC 9 / OSC 777** — desktop notifications and ConEmu progress reports (percentage shown in the mode line; see [Notifications and Progress](#notifications-and-progress))
216
223
- Text attributes: bold, italic, faint, underline (single/double/curly/dotted/dashed with color), strikethrough, inverse
@@ -224,7 +231,7 @@ history — even outside copy mode.
224
231
-**File path detection** — patterns like `/path/to/file.el:42` become clickable, opening the file at the given line (toggle with `ghostel-enable-file-detection`)
225
232
226
233
### Clipboard
227
-
-**OSC 52 clipboard** — terminal programs can set the Emacs kill ring and system clipboard (opt-in via `ghostel-enable-osc52`, useful for remote SSH sessions)
234
+
-**OSC 52 clipboard** — terminal programs can set the Emacs kill ring and system clipboard (opt-in via `ghostel-enable-osc52`, useful for remote SSH sessions). Note: the bundled `xterm-ghostty` terminfo intentionally **does not** advertise the `Ms` capability, so apps don't auto-discover it. This avoids silent clipboard drops when `ghostel-enable-osc52` is at its default `nil`. If you enable OSC 52 and want apps (neovim, tmux) to auto-detect, install upstream Ghostty's terminfo on the same path or override `TERMINFO`.
228
235
-**Bracketed paste** — yank from kill ring sends text as a bracketed paste so shells handle it correctly
229
236
230
237
### Input
@@ -313,6 +320,116 @@ test "$INSIDE_EMACS" = 'ghostel'; and source ~/.local/share/ghostel/ghostel.fish
313
320
The integration scripts provide directory tracking (OSC 7), prompt
314
321
navigation (OSC 133), and `ghostel_cmd` for calling Elisp from the shell.
315
322
323
+
#### Remote `xterm-ghostty` terminfo
324
+
325
+
Ghostel sets `TERM=xterm-ghostty` so apps inside the buffer get the
326
+
full capability set (synchronized output, Kitty keyboard, etc.).
327
+
That same `TERM` value gets inherited by anything spawned inside
328
+
the buffer — including `ssh REMOTE` and `M-x ghostel` from a TRAMP
329
+
`default-directory`. Remote hosts without the `xterm-ghostty`
330
+
entry will then print `Error opening terminal: xterm-ghostty`.
331
+
332
+
`ghostel-ssh-install-terminfo` (default `auto`) handles both cases.
333
+
`auto` is enabled when `ghostel-tramp-shell-integration` is on, so
334
+
turning on remote integration also turns on terminfo install — one
335
+
switch.
336
+
337
+
##### TRAMP-launched ghostel
338
+
339
+
`M-x ghostel` from a TRAMP path (`/ssh:host:/path/`) spawns the
340
+
shell on the remote. Ghostel pushes the bundled compiled terminfo
341
+
to a remote temp dir over the existing TRAMP connection (no extra
342
+
ssh round-trip), sets `TERMINFO=<that dir>` in the remote shell's
343
+
env, and cleans up on exit. Both Linux (`x/`, `g/`) and macOS
344
+
(`78/`, `67/`) layouts are written so any ncurses or BSD libcurses
345
+
finds it. Nothing persists on the remote.
346
+
347
+
##### Outbound `ssh` from a local ghostel buffer
348
+
349
+
The bundled bash/zsh/fish integration shadows `ssh` with a function
350
+
that:
351
+
352
+
1. Resolves the canonical target via `ssh -G` (normalises ssh_config
353
+
aliases).
354
+
2. Looks up the target in `~/.cache/ghostel/ssh-terminfo-cache`.
355
+
The cache key includes a hash of the local terminfo, so libghostty
356
+
bumps automatically invalidate it. Cache hit → connect with the
357
+
remembered `TERM`.
358
+
3. On miss, runs a single setup ssh that probes whether the entry
359
+
already exists on the remote, and if not, installs it via
360
+
`tic -x -` into `~/.terminfo/`. Records `ok` (use
361
+
`xterm-ghostty`) or `skip` (use `xterm-256color`) in the cache.
362
+
4. Runs the user's actual ssh with the resolved `TERM`.
363
+
364
+
The setup ssh is one extra connection per new host. Without
365
+
ControlMaster you'll see two auth prompts the first time. Strongly
366
+
recommended:
367
+
368
+
```ssh-config
369
+
# ~/.ssh/config
370
+
Host *
371
+
ControlMaster auto
372
+
ControlPath ~/.ssh/cm-%r@%h:%p
373
+
ControlPersist 60s
374
+
```
375
+
376
+
With this, the setup connection and the real connection share a
377
+
single auth. Subsequent connections within `ControlPersist` are
378
+
free.
379
+
380
+
The cache key includes a hash of the **local** terminfo, so
381
+
libghostty bumps automatically invalidate the cache. It does NOT
382
+
notice when a remote's terminfo changes out-of-band (system update,
383
+
manual `tic`). Run `M-x ghostel-ssh-clear-terminfo-cache` to force
384
+
re-probe.
385
+
386
+
Verified working from macOS to Linux remotes. Mixed macOS-to-macOS
387
+
or BSD targets inherit `tic`'s native hashed-dir layout
388
+
(`~/.terminfo/<hex>/`); `infocmp` reads the same path so they pair
389
+
correctly.
390
+
391
+
Skip-install heuristics:
392
+
-`ssh HOST cmd` (user passes a remote command): wrapper skips
393
+
install for that call to avoid clashing with the user's command.
394
+
Connects with cached `TERM` if known, otherwise `xterm-256color`.
395
+
The next interactive `ssh HOST` triggers install.
396
+
-`ssh -V`, `ssh -h`, etc. (no host resolved): pass through.
397
+
- No `infocmp` locally: pass through.
398
+
399
+
Per-call escape: prefix with `GHOSTEL_SSH_KEEP_TERM=1` to bypass
400
+
the wrapper entirely.
401
+
402
+
##### Manual install (no auto-machinery)
403
+
404
+
If you'd rather not have ghostel touch remote hosts (and don't want
405
+
the auto-cache), set `(setq ghostel-ssh-install-terminfo nil)` and
|`ghostel-module-auto-install`|`ask`| What to do when native module is missing (`ask`, `download`, `compile`, `nil`) |
443
560
|`ghostel-shell`|`$SHELL`| Shell program to run |
561
+
|`ghostel-term`|`"xterm-ghostty"`| Value of `TERM` for spawned processes. Default uses the bundled terminfo so apps can detect ghostel's full capability set. Set to `"xterm-256color"` to fall back (drops `TERMINFO` and `TERM_PROGRAM=ghostty` too) |
562
+
|`ghostel-ssh-install-terminfo`|`auto`| Install `xterm-ghostty` terminfo on remote hosts as needed. `auto` follows `ghostel-tramp-shell-integration`. Affects both TRAMP-launched ghostel (push terminfo over the existing TRAMP connection) and outbound `ssh` from a local buffer (install via `tic` on first connection, cache in `~/.cache/ghostel/ssh-terminfo-cache`). Per-call ssh override: `GHOSTEL_SSH_KEEP_TERM=1`|
444
563
|`ghostel-tramp-shells`|`(see below)`| Shell to use per TRAMP method (with login-shell detection) |
0 commit comments