Merge branch 'decst8c' of https://github.com/aymanbagabas/kitty
Some checks failed
CI / Linux (python=3.13 cc=clang sanitize=1) (push) Has been cancelled
CI / Linux (python=3.11 cc=gcc sanitize=0) (push) Has been cancelled
CI / Linux (python=3.12 cc=gcc sanitize=1) (push) Has been cancelled
CI / Linux package (push) Has been cancelled
CI / Bundle test (macos-latest) (push) Has been cancelled
CI / Bundle test (ubuntu-latest) (push) Has been cancelled
CI / macOS Brew (push) Has been cancelled
CI / Test ./dev.sh and benchmark (push) Has been cancelled
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (c, macos-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Has been cancelled
Depscan / Scan dependencies for vulnerabilities (push) Has been cancelled

This commit is contained in:
Kovid Goyal 2026-05-27 08:38:45 +05:30
commit 3fc5bed364
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 34 additions and 0 deletions

View file

@ -188,6 +188,8 @@ Detailed list of changes
- Preserve user-set tab stops across window resizes instead of resetting to 8 column default
- Add support for the DECST8C escape sequence (``CSI ? 5 W``) to reset tab stops to every 8 columns
0.47.0 [2026-05-19]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -2075,6 +2075,11 @@ screen_set_tab_stop(Screen *self) {
self->tabstops[self->cursor->x] = true;
}
void
screen_reset_tab_stops(Screen *self) {
init_tabstops(self->tabstops, self->columns);
}
void
screen_cursor_move(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/, bool allow_move_to_previous_line) {
if (count == 0) count = 1;
@ -4978,6 +4983,7 @@ WRAP0(reverse_index)
WRAP0(reset)
WRAP0(set_tab_stop)
WRAP1(clear_tab_stop, 0)
WRAP0(reset_tab_stops)
WRAP0(backspace)
WRAP0(tab)
WRAP0(linefeed)
@ -6260,6 +6266,7 @@ static PyMethodDef methods[] = {
MND(carriage_return, METH_NOARGS)
MND(set_tab_stop, METH_NOARGS)
MND(clear_tab_stop, METH_VARARGS)
MND(reset_tab_stops, METH_NOARGS)
MND(start_selection, METH_VARARGS)
MND(update_selection, METH_VARARGS)
{"clear_selection", (PyCFunction)clear_selection_, METH_NOARGS, ""},

View file

@ -245,6 +245,7 @@ void screen_set_tab_stop(Screen *self);
void screen_tab(Screen *self);
void screen_backtab(Screen *self, unsigned int);
void screen_clear_tab_stop(Screen *self, unsigned int how);
void screen_reset_tab_stops(Screen *self);
void screen_set_mode(Screen *self, unsigned int mode);
void screen_reset_mode(Screen *self, unsigned int mode);
void screen_decsace(Screen *self, unsigned int);

View file

@ -1246,6 +1246,14 @@ dispatch_csi(PS *self) {
}
REPORT_ERROR("Unknown CSI R sequence with start and end modifiers: '%c' '%c' and %u parameters", start_modifier, end_modifier, num_params);
break;
case 'W':
if (start_modifier == '?' && !end_modifier && num_params == 1 && params[0] == 5) {
REPORT_COMMAND(screen_reset_tab_stops);
screen_reset_tab_stops(self->screen);
break;
}
REPORT_ERROR("Unknown CSI W sequence with start and end modifiers: '%c' '%c' and %u parameters", start_modifier, end_modifier, num_params);
break;
case ECH:
CALL_CSI_HANDLER1(screen_erase_characters, 1);
case DA:

View file

@ -530,6 +530,22 @@ class TestScreen(BaseTest):
s = self.create_screen(cols=4, lines=2)
s.draw('aaaX\tbbbb')
self.ae(str(s.line(0)) + str(s.line(1)), 'aaaXbbbb')
# DECST8C: reset tab stops to every 8 columns
s = self.create_screen(cols=20, lines=2)
s.clear_tab_stop(3)
s.reset_tab_stops()
s.cursor_position(1, 1)
s.tab()
self.ae(s.cursor.x, 8)
s.tab()
self.ae(s.cursor.x, 16)
# Verify the DECST8C escape sequence
s = self.create_screen(cols=20, lines=2)
s.clear_tab_stop(3)
parse_bytes(s, b'\x1b[?5W')
s.cursor_position(1, 1)
s.tab()
self.ae(s.cursor.x, 8)
# Custom tab stops survive a window resize
s = self.create_screen(cols=20, lines=2)