Skip to content

Fix evil-ghostel multi-line dd targeting the wrong line (#218)#222

Merged
dakra merged 1 commit intomainfrom
fix/issue-218-multiline-dd
May 9, 2026
Merged

Fix evil-ghostel multi-line dd targeting the wrong line (#218)#222
dakra merged 1 commit intomainfrom
fix/issue-218-multiline-dd

Conversation

@dakra
Copy link
Copy Markdown
Owner

@dakra dakra commented May 2, 2026

Summary

Fixes #218 — in multi-line TUI input (pi, ipython, ptpython), ESC k dd deleted the wrong line. Investigation surfaced four other latent bugs in the same code paths; bundled together since the user-visible fix doesn't work without them.

  • Same-row dispatch for line-type dd / cc: keep the readline-aware Ctrl-e/Ctrl-u shortcut for the single-line shell case (where the buffer line includes the prompt prefix); use cursor-sync + backspaces only when point is on a different viewport row from the terminal cursor (the actual Evil multi-line issues in pi #218 case).
  • Snap point on next redraw after the Ctrl-u path so point lands at the start of the input area, not at column 0 on the prompt.
  • Scrollback-aware evil-ghostel--cursor-to-point — previously off by exactly the scrollback line count.
  • Padding-aware backspace count — TUIs that draw fixed-width input boxes write spaces past the user's input; those are not characters in the TUI's input model and shouldn't become PTY backspaces.
  • evil-replace count consistency — paste and delete now both go through evil-ghostel--meaningful-length so trailing whitespace stripped from one side isn't re-added by the other.

Test plan

  • make test-evil — 56/56 pass, including 7 new tests covering each fix.
  • Live verified shell dd / cc: input cleared via Ctrl-u, prompt preserved, point lands at start of input area.
  • Live verified pi AAA\nBBB\nCCC + ESC kk dd: AAA gone, BBB and CCC remain.
  • CI green on Emacs 28.2 / 29.4 / snapshot.

@dakra dakra force-pushed the fix/issue-218-multiline-dd branch from ff4f984 to 85b1bd4 Compare May 2, 2026 21:08
@dakra dakra force-pushed the fix/issue-218-multiline-dd branch 8 times, most recently from e08e132 to 4be599d Compare May 9, 2026 14:07
In multi-line TUI input (pi, ipython, prompt_toolkit), ESC k dd
deleted the last line instead of the line at point.  In a normal
single-line shell, several operator and motion edge cases were
also broken — flagged by noctuid in the #218 follow-up.

User-visible fixes:

- dd / cc on a non-cursor row in multi-line input deletes the
  right line.  Line-type evil-delete / evil-change dispatches by
  viewport row: same-row keeps the readline Ctrl-e/Ctrl-u
  shortcut; off-row syncs the terminal cursor to end-of-region
  and backspaces through it.  A one-shot
  sync-point-on-next-redraw lands point at the start of the input
  area after the Ctrl-u path, not at column 0 on the prompt.

- cw on a word lands at the start of the deleted range, not at
  column 0.  around-change no longer runs a redundant post-delete
  cursor-to-point that would emit extra left arrows against the
  stale live libghostty cursor — sync only when count = 0 (the
  C-at-EOL path); delete-region already syncs in count > 0.

- dw on 'word ' deletes 5 chars, not 4 ('word word word' + ESC
  bbdw → 'word word', not 'word wword').  meaningful-length
  strips trailing whitespace only in multi-line ranges, where TUI
  input boxes paint padding past the user's input; single-line
  ranges treat trailing whitespace as real content.

- 0 and ^ skip the shell prompt prefix.  evil-beginning-of-line
  and evil-first-non-blank route through
  ghostel-beginning-of-input-or-line on rows carrying the
  ghostel-prompt property, so 0i lands typing at the input start
  and d0 / c0 don't try to delete the prompt characters.  Falls
  through to the original motion on scrollback / output rows.

- ^ / \$ / 0 followed by i lands insertion at the navigated
  column even when the buffer has scrollback.
  insert-state-entry compared point's *buffer* line to the
  cursor's *viewport* row, so any scrollback failed the same-row
  check and dropped into reset-cursor-point — silently undoing
  the user's navigation.  Subtract scrollback before comparing.

- Column navigation in normal state (^, \$, 0, h, l, …) survives
  idle redraws on the cursor's line.  The on-prompt-line override
  let the renderer's cursor placement win whenever point shared
  the cursor's buffer line — true for every redraw in a
  single-line shell.  Replace with a prompt-moved check: only
  override saved-point when the cursor actually scrolled to a new
  line.

- evil-replace's paste count matches its delete count when
  meaningful-length strips trailing whitespace in multi-line
  ranges, so trailing whitespace stripped from one side isn't
  re-added by the other.

Architectural fixes underneath:

- cursor-to-point subtracts scrollback when computing buffer→
  viewport row deltas — was sending arrows off into space in any
  session with scrollback.

- evil-ghostel--shadow-cursor models the pending terminal cursor
  between PTY-bound key emits and their echo back through the
  redraw.  Within a single advice call we may emit several key
  sequences before any are echoed; ghostel--cursor-position
  reflects the live libghostty state, which lags our queued keys,
  so a follow-up cursor-to-point would compute deltas from a
  stale baseline and over-correct.  cursor-to-point and
  delete-region advance the shadow as keys are emitted;
  around-redraw and unmodelable operations (Ctrl-a/e/u/w/r/n/p,
  paste) reset it.

Verified live: shell dd / cc clears input via Ctrl-u with point
at start of input; pi 'AAA\\nBBB\\nCCC' + ESC kk dd leaves BBB and
CCC with AAA gone; word word word + ESC bbdw leaves word word; 0i
on a shell prompt lands typing at the input start.

Tests: 78 evil-ghostel, all passing — covers each user-visible
fix and the shadow cursor lifecycle.

Fixes #218
@dakra dakra force-pushed the fix/issue-218-multiline-dd branch from 4be599d to 7e5e9e5 Compare May 9, 2026 14:10
@dakra dakra merged commit 7e5e9e5 into main May 9, 2026
22 checks passed
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.

Evil multi-line issues in pi

1 participant