Skip to content

Rewrite evil-ghostel from advice to command-remap architecture#264

Open
dakra wants to merge 1 commit into
mainfrom
evil-ghostel-rewrite
Open

Rewrite evil-ghostel from advice to command-remap architecture#264
dakra wants to merge 1 commit into
mainfrom
evil-ghostel-rewrite

Conversation

@dakra
Copy link
Copy Markdown
Owner

@dakra dakra commented May 11, 2026

Summary

  • Replaces ~13 advice-add hooks on evil-* commands with evil-define-operator / evil-define-motion definitions bound via evil-ghostel-mode-map for normal and visual states (vterm-collection-style).
  • Adds a public input-region API in ghostel.el (ghostel-input-start-point, ghostel-cursor-point, ghostel-cursor-row-end-point, ghostel-point-on-cursor-row-p, ghostel-point-in-input-p, ghostel-clamp-to-input, ghostel-goto-input-position, ghostel-delete-input-region, ghostel-replace-input-region) that integrations can build on. Lifts what was internal evil-ghostel--cursor-to-point / --delete-region / --meaningful-length into ghostel core.
  • Drops the shadow-cursor model (and its two tests); the new operators read ghostel--cursor-pos directly each call and the existing sync-inhibit flag already covers the double-call scenarios the shadow was defending against.
  • Operator-level clamp on forward overshoot — dw on the last input word no longer over-deletes into the blank renderer rows below the prompt. End-of-typed-input is detected by stripping trailing whitespace on the cursor row; works for shells without OSC 133.
  • Forward word motions (w, W, e, E) clamped in normal state only so w from the last input word stays on the cursor row. Operator-pending state uses vanilla motions so dw / cw ranges can overshoot and get trimmed by the operator clamp.
  • ghostel-goto-input-position includes vterm-style recovery for literal ^[[C echo (inner program doesn't interpret arrow keys) and for bash-autosuggest accept-on-right-arrow.

Test plan

  • make -j4 all test-evil clean: 370 elisp + 173 native + 76 evil-ghostel tests, 0 unexpected, 2 unrelated skips, lint clean.
  • New regression tests cover: dw-overshoot clamping (evil-ghostel-test-delete-word-on-last-word-clamps-overshoot), w-stays-on-input-row (evil-ghostel-test-forward-word-stops-at-input-end), w-falls-through-in-scrollback (evil-ghostel-test-forward-word-falls-through-off-cursor-row).
  • Live-verified in a clean Emacs -Q against zsh -fi (no OSC 133): word word word<esc>bbcw → correct, w stays on cursor row, dw on last word deletes it, 0/^/$ work.
  • @noctuid scenarios from Issues with evil single line movement/editing #246: please retest bbcw 3× consecutively in zsh and pi to confirm no regressions.

Notes for reviewers

  • evil-ghostel.el ends up at 852 LOC vs evil-collection-vterm's 308. The delta is dominated by evil-ghostel--around-redraw (79 LOC — ghostel's renderer wipes the viewport region, vterm doesn't need this), the cursor↔point sync helpers (~50 LOC — viewport-row math), the insert-state-entry hook (45 LOC — vterm's cursor is the buffer cursor), and the three-way ESC routing (auto / terminal / evil).
  • API stability: once exposed, the ghostel-* input-region functions become public contract.

@dakra dakra mentioned this pull request May 11, 2026
@noctuid
Copy link
Copy Markdown

noctuid commented May 12, 2026

@dakra Thanks a lot. I didn't have time to test thoroughly. I'll test tomorrow but couldn't find any major problems with basic use. Here are two things:

  • it should use remaps only, not bind any specific keys
  • minor: word<esc>a (evil-ghostel-append) will add a visual space that isn't there (point will be after a space but backspace in insert would delete the "d"); test with evil-move-cursor-back nil and zsh (not sure if this is specific to my config, couldn't reproduce in bash)

@dakra dakra force-pushed the evil-ghostel-rewrite branch from 872b853 to fc7f17f Compare May 12, 2026 11:15
@dakra
Copy link
Copy Markdown
Owner Author

dakra commented May 12, 2026

@noctuid Thanks. I fixed the 2 bugs you mentioned.
I'll still have to have a closer look at it and test it more. but if you want to give it another test ride that's obviously helpful as well.

@dakra dakra force-pushed the evil-ghostel-rewrite branch from fc7f17f to 4228dc0 Compare May 12, 2026 15:38
@noctuid
Copy link
Copy Markdown

noctuid commented May 13, 2026

I still haven't seen any more issues with editing/operators, though I'm seeing similar issues to the appending one. Sometimes the cursor will jump to the right side of the window when appending.

evil-forward-char can sometimes go many characters beyond the end of the text in the prompt line in normal state (e.g. in pi always and in zsh I can go right as far as I had previously typed text even if it was deleted). Same applies to e.g. 0/$.

I saw weird point warping a couple of times but can't reliably reproduce.

@dakra dakra force-pushed the evil-ghostel-rewrite branch 3 times, most recently from 99e37b1 to 4ee9cd4 Compare May 13, 2026 15:31
Replaces ~13 advice-add hooks on evil-* commands with proper
evil-define-operator / evil-define-motion definitions bound via
evil-ghostel-mode-map for normal and visual states.

New evil-ghostel commands: -delete (and -line/-char/-backward-char),
-change (and -line), -substitute (and -line), -replace,
-paste-after, -paste-before, -insert (and -line),
-append (and -line), -beginning-of-line, -first-non-blank,
-forward-word-begin/-WORD-begin/-word-end/-WORD-end, -undo, -redo.
Bound in evil-ghostel-mode-map; forward-word motions are
normal-only so operator-pending (dw, cw) uses vanilla motion +
operator clamp.

Drops the shadow-cursor model and all advice on evil-* commands.
Keeps advice on `ghostel--redraw' / `ghostel--set-cursor-style'
and the insert-state-entry hook (essential plumbing).

PTY-driven input editing helpers (new, live here because they all
depend on a cooperative line editor — readline / zle /
prompt_toolkit accepting arrow keys, backspace, bracketed paste):

- evil-ghostel-goto-input-position — moves the terminal cursor via
  arrow keys, with vterm-style recovery for literal `^[[C' echo
  and bash-autosuggest accept-on-right-arrow.
- evil-ghostel-delete-input-region, -replace-input-region.
- evil-ghostel-point-in-input-p — predicate for the editable
  input region.
- evil-ghostel--clamp-to-input — trims an operator's range to the
  live input region.  Clamps END to row-end on forward overshoot
  so `dw' on the last input word no longer over-deletes into blank
  renderer rows below the prompt.
- evil-ghostel--cursor-row-end-point — strips renderer-emitted
  trailing whitespace.
- evil-ghostel--input-start-from-prop, --meaningful-input-length,
  --sync-render — internal helpers.

Tests: 88 evil-ghostel tests covering operators, motions, paste,
undo/redo, escape handling, plus unit tests for the new
input-region helpers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants