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.

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.  Adds a public
input-region API in ghostel core that integrations can build on.

ghostel.el (new public API):
- ghostel-input-start-point, ghostel-cursor-point,
  ghostel-cursor-row-end-point (strips trailing whitespace so
  renderer padding doesn't count as input)
- ghostel-point-on-cursor-row-p, ghostel-point-in-input-p
- 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
- 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
- ghostel-delete-input-region, ghostel-replace-input-region

evil-ghostel.el:
- New commands: evil-ghostel-delete, -delete-line, -delete-char,
  -delete-backward-char, -change, -change-line, -substitute,
  -substitute-line, -replace, -paste-after, -paste-before,
  -insert, -insert-line, -append, -append-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)
- Lifts evil-ghostel--cursor-to-point / --delete-region / --meaningful-length
  into ghostel core as the public API

Tests:
- 16 new ghostel-core API tests
- 4 new evil-ghostel regression tests covering the dw-overshoot
  bug and the w-stays-on-input-row behavior
- Existing tests updated to call evil-ghostel-* directly and mock
  ghostel-goto-input-position instead of the removed internals

Net: 370 elisp + 173 native + 76 evil-ghostel tests pass.
@dakra dakra force-pushed the evil-ghostel-rewrite branch from 4228dc0 to 22ae308 Compare May 13, 2026 10:27
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