Skip to content

fix(erase_last_command): erase the most recent command even empty output - #10201

Merged
kovidgoyal merged 1 commit into
kovidgoyal:masterfrom
slayerlab:fix-erase-last-command-multiline-prompt
Jun 29, 2026
Merged

kovidgoyal merged 1 commit into
kovidgoyal:masterfrom
slayerlab:fix-erase-last-command-multiline-prompt

Conversation

@slayerlab

@slayerlab slayerlab commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

erase_last_command (the clear_terminal last_command action) located the region to erase with find_cmd_output(..., -1), which anchors on OUTPUT_START (OSC 133;C). A prompt block with no command output -- a command that prints nothing (cd, export, a comment) or no command at all (a bare Enter) -- has no OUTPUT_START, so the search does have output. It therefore erases an older block instead of the most recent one.

This PR selects the region by prompt marks instead: it erases the prompt block immediately above the live prompt, newest-first, one block per keypress. If no block sits above the live prompt, it does nothing. It also fixes two pre-existing problems on the same path:

  • The on-screen deletion anchored at cursor->y - count, which assumes the region ends one row above the cursor. Multi-line prompts (and rows above the region) break that, leaving residual lines; it now anchors at the top of the region.
  • When part of the region sat in the scrollback, erase removed the lines but signaled no redraw, so off-screen deletions only appeared after the next scroll. It now clamps scrolled_by and calls dirty_scroll(), as screen_clear_scrollback does.

include_prompt remains for API compatibility but now does nothing (the unit is the whole prompt block; no in-tree caller passes it).

erase_last_command selected the region to erase via find_cmd_output(..., -1),
which anchors on OUTPUT_START (OSC, 133;C). Commands that produce no output
(an empty Enter, a comment, cd, export, etc. -- never emit 133;C, so they were
skipped and an older command-with-output was erased instead. "Erase the last
command" therefore did not erase the last command whenever the most recent ones
has no output.

Select the region by prompt marks instead: erase the prompt block immediately
above the current (live) prompt, whatever it contains. Every submittd command
is now one unit, removed newest-first, one prompt block per invocation.

This also fixes two latent defects in the previous implementation:

* The on-screen deletion was anchored at `cursor->y - count`, which
  assumes the region ends exactly one row above the cursor.
  Multi-line prompts and skipped rows broke that assumption and left
  residual lines. Anchor at the top of the region instead.

* When part of the erased region was in the scrollback, the lines
  were removed from the history buffer but no redraw was signalled,
  so the deletion of the off-screen lines only became visible after
  the next scroll event recomputed the history viewport. Clamp
  scrolled_by to the new history length and call dirty_scroll()
  after shrinking the buffer.

include_prompt is retained for API compatibility but is now a no-op: the
unit erased is always the whole prompt block.
@kovidgoyal
kovidgoyal merged commit 4e0f7fa into kovidgoyal:master Jun 29, 2026
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