Dont allow CUB to move cursor onto previous line

Reserve this behavior for actual backspace. Fixes #8900
This commit is contained in:
Kovid Goyal 2025-08-14 21:48:22 +05:30
parent c8c0201cbb
commit a0b58ef205
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 13 additions and 7 deletions

View file

@ -1892,7 +1892,7 @@ screen_is_cursor_visible(const Screen *self) {
void
screen_backspace(Screen *self) {
screen_cursor_move(self, 1, -1);
screen_cursor_move(self, 1, -1, true);
}
void
@ -1963,7 +1963,7 @@ screen_set_tab_stop(Screen *self) {
}
void
screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/) {
screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/, bool allow_move_to_previous_line) {
if (count == 0) count = 1;
bool in_margins = cursor_within_margins(self);
if (move_direction > 0) {
@ -1980,7 +1980,7 @@ screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=
count -= self->cursor->x;
self->cursor->x = 0;
} else {
if (self->cursor->y == top) count = 0;
if (self->cursor->y == top || !allow_move_to_previous_line) count = 0;
else {
count--; self->cursor->y--;
self->cursor->x = self->columns-1;
@ -1993,7 +1993,7 @@ screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=
void
screen_cursor_forward(Screen *self, unsigned int count/*=1*/) {
screen_cursor_move(self, count, 1);
screen_cursor_move(self, count, 1, false);
}
void
@ -4492,7 +4492,7 @@ is_using_alternate_linebuf(Screen *self, PyObject *a UNUSED) {
Py_RETURN_FALSE;
}
WRAP1E(cursor_move, 1, -1)
WRAP1E(cursor_move, 1, -1, true)
WRAP1B(erase_in_line, 0)
WRAP1B(erase_in_display, 0)
static PyObject* scroll_until_cursor_prompt(Screen *self, PyObject *args) { int b=false; if(!PyArg_ParseTuple(args, "|p", &b)) return NULL; screen_scroll_until_cursor_prompt(self, b); Py_RETURN_NONE; }

View file

@ -187,7 +187,7 @@ void screen_save_modes(Screen *);
void screen_save_mode(Screen *, unsigned int);
bool write_escape_code_to_child(Screen *self, unsigned char which, const char *data);
void screen_cursor_position(Screen*, unsigned int, unsigned int);
void screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/);
void screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/, bool allow_move_to_previous_line);
void screen_erase_in_line(Screen *, unsigned int, bool);
void screen_erase_in_display(Screen *, unsigned int, bool);
void screen_draw_text(Screen *self, const uint32_t *chars, size_t num_chars);

View file

@ -1009,7 +1009,7 @@ parse_sgr(Screen *screen, const uint8_t *buf, unsigned int num, const char *repo
static void
screen_cursor_up2(Screen *s, unsigned int count) { screen_cursor_up(s, count, false, -1); }
static void
screen_cursor_back1(Screen *s, unsigned int count) { screen_cursor_move(s, count, -1); }
screen_cursor_back1(Screen *s, unsigned int count) { screen_cursor_move(s, count, -1, false); }
static void
screen_tabn(Screen *s, unsigned int count) { for (index_type i=0; i < MAX(1u, count); i++) screen_tab(s); }

View file

@ -555,6 +555,12 @@ def backspace(use_bs=True):
backspace(use_bs)
self.ae(str(s.line(0)), q[:-1] + ' ')
self.ae(str(s.line(1)), ' ')
# Test that CUB does not move cursor onto previous line
s.reset()
s.draw('a'*s.columns + 'b')
self.ae((s.cursor.x, s.cursor.y), (1, 1))
parse_bytes(s, b'\x1b[100D')
self.ae((s.cursor.x, s.cursor.y), (0, 1))
def test_margins(self):
# Taken from vttest/main.c