From 7e5aac2e2b50cd5015c140928f20b3c7aac937d8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 27 Mar 2026 20:50:28 +0530 Subject: [PATCH] Allow setting color table value to none via OSC 21 --- kitty/colors.c | 5 +++++ kitty/window.py | 11 ++++++++--- kitty_tests/screen.py | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/kitty/colors.c b/kitty/colors.c index c0e0ac6f1..a901bed34 100644 --- a/kitty/colors.c +++ b/kitty/colors.c @@ -586,6 +586,11 @@ set_color(ColorProfile *self, PyObject *args) { if (!PyArg_ParseTuple(args, "Bk", &i, &val)) return NULL; self->color_table[i] = val; self->dirty = true; + if (val == NULL_COLOR_VALUE) { + bool semantic, dynamic = palette_generation_is_dynamic(global_state.options_object, &semantic); + if (dynamic) generate_256_palette(self, self->color_table, semantic); + else self->color_table[i] = FG_BG_256[i]; + } Py_RETURN_NONE; } diff --git a/kitty/window.py b/kitty/window.py index 4ff0ac395..7b6b7156c 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -49,6 +49,7 @@ from .fast_data_types import ( GLFW_RELEASE, GLFW_REPEAT, NO_CURSOR_SHAPE, + NULL_COLOR_VALUE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, @@ -577,9 +578,13 @@ def color_control(cp: ColorProfile, code: int, value: str | bytes | memoryview = else: if 0 <= colnum <= 255: val = val.partition('@')[0] - col = to_color(val) - if col is not None: - cp.set_color(colnum, color_as_int(col)) + if val: + if (col := to_color(val)) is not None: + cp.set_color(colnum, color_as_int(col)) + elif colnum > 15: + cp.set_color(colnum, NULL_COLOR_VALUE) + else: + cp.set_color(colnum, get_options().color_table[colnum]) else: if attr: delattr(cp, attr) diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 4fec4185b..06bbb82e7 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -1616,6 +1616,9 @@ class TestScreen(BaseTest): q({'selection_background': ''}) self.assertIsNone(s.color_profile.highlight_bg) q({'selection_background': '?'}, {'selection_background': ''}) + opts = self.set_options({'palette_generate': 'semantic'}) + q({'213': ''}) + q({'213': '?'}, {'213': Color(216, 125, 215)}) s.color_profile.reload_from_opts(opts) q({'transparent_background_color9': '?'}, {'transparent_background_color9': '?'}) q({'transparent_background_color2': '?'}, {'transparent_background_color2': ''})