diff --git a/docs/changelog.rst b/docs/changelog.rst index bb98a9a29..5db3e3f38 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -196,6 +196,8 @@ Detailed list of changes - ``edit-in-kitty``: Return exit code from underlying editor process on exit (:iss:`10198`) +- Make erasing last command robust against commands with no output and commands in the scrollback (:pull:`10201`) + 0.47.4 [2026-06-15] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 1e2c0cb6b..a0e9c8f3e 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1261,7 +1261,7 @@ class Screen: def test_commit_write_buffer(self, inp: memoryview, output: memoryview) -> int: ... def test_parse_written_data(self, dump_callback: None = None) -> None: ... def hyperlink_for_id(self, hyperlink_id: int) -> str: ... - def erase_last_command(self, include_prompt: bool = True) -> bool: ... + def erase_last_command(self) -> bool: ... def set_progress(self, state: int, percent: int) -> None: ... def mark_potential_url_drag(self) -> bool: ... diff --git a/kitty/screen.c b/kitty/screen.c index 25efce52a..e13a52573 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -4599,10 +4599,7 @@ find_cmd_output(Screen *self, OutputOffset *oo, index_type start_screen_y, unsig } static PyObject* -erase_last_command(Screen *self, PyObject *args) { - int include_prompt = 1; // retained for API compatibility; the prompt block is the unit erased - if (!PyArg_ParseTuple(args, "|p", &include_prompt)) return NULL; - (void)include_prompt; +erase_last_command(Screen *self, PyObject *args UNUSED) { if (self->linebuf != self->main_linebuf) Py_RETURN_FALSE; Line *line; // Erase the most recent command: the prompt block immediately above the @@ -6244,7 +6241,7 @@ static PyMethodDef methods[] = { MND(draw, METH_O) MND(apply_sgr, METH_O) MND(cursor_position, METH_VARARGS) - MND(erase_last_command, METH_VARARGS) + MND(erase_last_command, METH_NOARGS) MND(set_window_char, METH_VARARGS) MND(set_progress, METH_VARARGS) MND(set_mode, METH_VARARGS) diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 4d8fbc339..25d94e3f1 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -1627,7 +1627,7 @@ class TestScreen(BaseTest): s.draw('before\r\n') draw_prompt('p1'), draw_output(2), mark_prompt(), s.draw('partial') x = s.cursor.x - s.erase_last_command(False) # include_prompt is now a no-op: the prompt block is the unit erased + s.erase_last_command() self.ae('before\npartial', at().rstrip()) for scroll in (8, 9, 10): s.reset() @@ -1655,9 +1655,12 @@ class TestScreen(BaseTest): s.reset() s.draw('before\r\n') draw_prompt('p1'), draw_output(1), draw_prompt('e1'), draw_prompt('e2'), mark_prompt(), s.draw('partial') - s.erase_last_command(); self.ae('before\n$ p1\n0\n$ e1\npartial', at().rstrip()) - s.erase_last_command(); self.ae('before\n$ p1\n0\npartial', at().rstrip()) - s.erase_last_command(); self.ae('before\npartial', at().rstrip()) + s.erase_last_command() + self.ae('before\n$ p1\n0\n$ e1\npartial', at().rstrip()) + s.erase_last_command() + self.ae('before\n$ p1\n0\npartial', at().rstrip()) + s.erase_last_command() + self.ae('before\npartial', at().rstrip()) # multi-line live prompt: the command region is erased with no residual s.reset() s.draw('before\r\n')