Add eat-style input modes (char, emacs, copy, line, semi-char)#78
Add eat-style input modes (char, emacs, copy, line, semi-char)#78
Conversation
b1e771f to
6d81a44
Compare
95cacee to
1a31d37
Compare
f31dab1 to
9b6240f
Compare
|
FYI I'm trying out this branch and calling Not sure if this is due to this branch or is generally a bug on main (don't have time to debug or check right now). |
|
@dakra First impressions: It would be nice to have a mode line indicator for which input mode you're in, like EAT does. (EAT appends an indicator to the mode line lighter.) I appreciate the echo area info on how to leave the input mode once you enter it; very useful for newcomers + those without good muscle memory for the package (yet). Why would one enter copy mode vs emacs mode? Is copy mode meant to be a specialized emacs mode? If so, what benefit does it have over regular emacs mode? (In EAT, I would enter their emacs mode if I wanted to copy anything.) It isn't immediately obvious what the benefit of line mode is: when should I enter it? (This one is more because I'm ignorant, not because it shouldn't exist.) Bug in line mode?: Say I am in char mode and type some command without sending it, |
There should be a mode line indicator. (for semi-char I left it blank as a default)
copy mode is basically emacs mode, but copy-mode freezes the terminal while emacs-mode is live.. so e.g. if you
I'm not an eat user, so I'm good with only semi-char+copy-mode, but many asked for eat line-mode.
|
Calling module-load on a path whose shared library is already mapped into the running Emacs makes dyld/ld.so return the existing handle and resolve emacs_module_init via dlsym on the stale image, which segfaults (reported in #78). Skip the second module-load when ghostel-module is already featurep'd and tell the user to restart Emacs to pick up the new version.
Thanks for reporting. This is fixed on latest main (by just not letting the user re-load a native module which is not supported by Emacs) |
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
46aea4d to
c17de90
Compare
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
When entering line mode at a prompt where input was typed via the PTY in a previous mode (e.g. `ls -la` in char/semi-char), the renderer's ghostel-input span gets adopted into the editable buffer — but the shell's readline still holds those bytes. On RET the line was sent verbatim, so the shell concatenated and echoed a duplicated prefix: `ls -lals -la`. Capture the adopted character count on entry and erase it via N backspaces before any path that writes the buffer back to the PTY (RET, mode teardown forward). Backspace works under any cooked-mode line discipline (bash, fish, zsh, vi-mode readline, python REPL) where a readline-only kill like C-u would not. Reported on PR #78.
Inspired by eat.el. The user can switch between a terminal-focused default (semi-char), a send-everything mode (char), a live-but- read-only mode (emacs), a frozen copy mode, and a shell-like mode (line) that buffers input locally and sends whole lines. `ghostel--input-mode' is the single source of truth; `ghostel--copy-mode-active' is gone. Predicates `ghostel--buffer-editable-p', `--terminal-live-p', `--terminal-frozen-p' replace the old boolean check. `evil-ghostel' gates on semi-char specifically. The keymap splits into a slim base (C-c prefix, mouse, drag-n-drop, clipboard, xterm-paste) and one keymap per mode. Mode switches live in the base map so they work from every live mode: C-c C-j semi-char C-c M-d char C-c C-e emacs C-c C-t copy (toggle) C-c C-l line M-RET char-mode escape hatch `C-c C-l' (was clear-scrollback) becomes line mode; clear-scrollback moves to `C-c M-l'. Prompt navigation (`C-c M-n' / `C-c M-p') auto-enters Emacs mode so the terminal keeps running while the user jumps between prompts. Emacs mode unfreezes the terminal: output streams while the buffer is read-only, so `isearch', `occur', `M-x', `C-SPC' + `M-w', and the rest of Emacs's vocabulary work over a live log. Typed keys do *not* reach the shell — self-insert / RET / TAB / DEL fall through to the buffer's `text-read-only' signal, so reading scrollback can't accidentally fire commands at the prompt. Pasting via `ghostel-yank' is preserved as a deliberate, explicit action and snaps the window back to the live cursor before sending. Char mode routes through `emulation-mode-map-alists' so a global minor-mode prefix on `C-c' can't steal the key first. `M-RET' / `<M-return>' / `C-M-m' all switch back to semi-char to cover GUI and TTY Emacs. Copy mode and Emacs mode share a unified read-only framework (`ghostel-readonly-mode-map', `ghostel-readonly-*' commands, `ghostel-readonly-fast-exit' defcustom). Copy mode freezes the redraw timer; Emacs mode keeps it live. Both remember the previous mode in `ghostel--pre-readonly-mode' so exit returns the user to wherever they came from rather than always semi-char. Line mode is live — output keeps streaming, but each redraw snapshots the in-progress input (text + point/mark offsets), clears the prompt row, and re-inserts the input at the new prompt-end after the renderer rewrites the viewport. `ghostel-full-redraw' is forced buffer-locally so the dirty-row diff path always rebuilds the prompt. The input region is bounded by `ghostel--line-input-start' and `--line-input-end' so status bars or any non-blank content drawn below the prompt survive entry and per-redraw snapshot/restore; the trailing-blank trim is gated to only delete pure whitespace. Pre-existing `ghostel-input' cells are adopted as the initial input on entry, so typing in semi-char and switching mid-edit keeps the typed chars — and the adopted character count is erased from the shell's readline buffer with N backspaces before any send path so RET doesn't duplicate the prefix. Prompt discovery uses the terminal cursor as the source of truth (via the new `ghostel--cursor-row-char-offset' Zig binding, which walks the cursor row's cells so wide/box-drawing glyphs map correctly across platforms). OSC 133 markers refine the location when the cursor's own row carries `ghostel-prompt' chars. This makes line mode work in REPLs without shell integration (python3, irb, sqlite3 launched under bash) — it no longer lands on the outer bash prompt. History ring (`M-p' / `M-n'), `C-c C-c' interrupt, `C-d' EOF on empty input. Send and interrupt stay in line mode — the next redraw moves the marker to the next prompt and the user keeps editing. If the prompt cannot be located after a redraw (shell integration dropped out and the cursor is unavailable), the captured input forwards raw rather than being lost. Refuses to enter on the alt screen. Scrollback is protected with a `read-only' text property, with `rear-nonsticky' on the boundary char covering all properties so text typed after a colored prompt (e.g. python's purple-bold `>>> ') doesn't inherit the prompt's face. Restored input is tagged `ghostel-input' so URL detection leaves it alone. Self-inserting a key while point sits in the read-only scrollback snaps to `ghostel--line-input-end' first and inserts there, mirroring the "type to dismiss" feel of copy/Emacs mode without leaving line mode. `C-a' is smart in both line and Emacs modes: `ghostel-beginning-of-input-or-line' jumps to the start of input on a prompt row and falls through to `move-beginning-of-line' otherwise, so it works correctly from scrollback too. RET follows links in copy, Emacs, and line modes. In line mode, `ghostel-line-mode-send-or-open-link' opens the link at point if there is one and otherwise falls through to send. The text-property `ghostel-link-map' still owns mouse-1/mouse-2. TAB runs `completion-at-point' against the input region (filenames, env vars, executables on PATH, pcomplete extensions). When the `bash-completion' package is installed, `bash-completion-capf-nonexclusive' is layered on by default (`ghostel-line-mode-use-bash-completion'), so `complete -F _git git' and friends work — TAB after `git checkout ' lists branch names. Optional `ghostel-line-mode-bash-completion-prespawn' amortises the first-call cost at mode-entry time. README gains an "Input modes" section. Tests cover state, predicates, keymap definitions, transitions, prompt-navigation auto-Emacs, line-mode prompt discovery (cursor and OSC 133), cell-walking offset, send, history, interrupt, EOF, snapshot/ restore across realistic post-RET sequences, end-marker bounding, existing-input adoption, readline-prefix erase, status-bar preservation, snap-on-type, snap-on-self-insert from scrollback, smart-C-a, RET-follows-link in all read-only modes, and bash- completion integration. Closes #40.
Summary
Adds five eat.el-inspired input modes for ghostel. Closes #40.
C-cprefix reservedC-c M-d): all keys to terminal,M-RETexits — for TUI apps that wantC-x,M-x,C-hC-c C-e): unfrozen — terminal keeps running, buffer is read-only, standard Emacs keys (isearch,occur,M-x,C-SPC+M-w) fall through to the global map. Lets you search across a live logC-c C-t): frozen + read-only + aggressive copy keymap (M-wcopies and exits)C-c C-l): buffers input locally in Emacs;RETsends the whole line to the shell in one write. Full Emacs editing (yank, transpose, kill-word…) works. Requires OSC 133 shell integrationMechanics
ghostel--input-mode;ghostel--copy-mode-activeremovedghostel-mode-map(C-c prefix + drag-n-drop) with per-mode child mapsghostel--buffer-editable-p,ghostel--terminal-live-p,ghostel--terminal-frozen-p— all five check sites that usedcopy-mode-activemigratedinhibit-read-only/inhibit-redisplaybindings aroundghostel--redraw, so nothing in the Zig layer changes; the delayed-redraw path now preserves point unconditionally in Emacs modeC-c C-n/C-c C-p) now auto-enters Emacs mode instead of copy mode so the terminal keeps running during navigationBase
This PR targets
scrollback-in-buffer(PR #73) since it depends on the always-materialized-scrollback model. Once #73 merges to main, this can be rebased onto main.Test plan
make build— native module compiles (no Zig changes, sanity check)make test-all— 120 ghostel tests pass (93 existing + 27 new mode tests)make test-evil— 30 evil-integration tests still passmake lint— package-lint + checkdoc cleanC-c M-dchar mode,C-c C-eEmacs mode + isearch across streaming output,C-c C-tcopy mode,C-c C-lline mode with bash +ls -la+ RET