From 63e23d7fe3c1e17c62d8b876849ae5ac0eb574a1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 25 Oct 2021 10:01:32 +0530 Subject: [PATCH] Fix set-colors unable to set tab_bar_background to none --- kitty/boss.py | 12 ++++++------ kitty/colors.c | 15 ++++++++------- kitty/fast_data_types.pyi | 5 ++--- kitty/launch.py | 4 ++-- kitty/rc/set_colors.py | 40 +++++++++++++++++++-------------------- kitty/state.c | 9 +++++---- kitty/tab_bar.py | 35 ++++++++++++++++++++-------------- 7 files changed, 63 insertions(+), 57 deletions(-) diff --git a/kitty/boss.py b/kitty/boss.py index da30260f5..ff5430d1f 100755 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -1687,16 +1687,16 @@ class Boss: window.screen.disable_ligatures = strategy window.refresh() - def patch_colors(self, spec: Dict[str, int], cursor_text_color: Union[bool, int, Color], configured: bool = False) -> None: + def patch_colors(self, spec: Dict[str, Optional[int]], configured: bool = False) -> None: opts = get_options() if configured: for k, v in spec.items(): if hasattr(opts, k): - setattr(opts, k, color_from_int(v)) - if cursor_text_color is not False: - if isinstance(cursor_text_color, int): - cursor_text_color = color_from_int(cursor_text_color) - opts.cursor_text_color = cursor_text_color + if v is None: + if k in ('cursor_text_color', 'tab_bar_background'): + setattr(opts, k, None) + else: + setattr(opts, k, color_from_int(v)) for tm in self.all_tab_managers: tm.tab_bar.patch_colors(spec) patch_global_colors(spec, configured) diff --git a/kitty/colors.c b/kitty/colors.c index 0cb28a9ba..2d2f4b14b 100644 --- a/kitty/colors.c +++ b/kitty/colors.c @@ -114,7 +114,7 @@ copy_color_profile(ColorProfile *dest, ColorProfile *src) { static void patch_color_table(const char *key, PyObject *profiles, PyObject *spec, size_t which, int change_configured) { PyObject *v = PyDict_GetItemString(spec, key); - if (v) { + if (v && PyLong_Check(v)) { color_type color = PyLong_AsUnsignedLong(v); for (Py_ssize_t j = 0; j < PyTuple_GET_SIZE(profiles); j++) { ColorProfile *self = (ColorProfile*)PyTuple_GET_ITEM(profiles, j); @@ -128,7 +128,7 @@ patch_color_table(const char *key, PyObject *profiles, PyObject *spec, size_t wh #define patch_mark_color(key, profiles, spec, array, i) { \ PyObject *v = PyDict_GetItemString(spec, key); \ - if (v) { \ + if (v && PyLong_Check(v)) { \ color_type color = PyLong_AsUnsignedLong(v); \ for (Py_ssize_t j = 0; j < PyTuple_GET_SIZE(profiles); j++) { \ ColorProfile *self = (ColorProfile*)PyTuple_GET_ITEM(profiles, j); \ @@ -139,8 +139,8 @@ patch_color_table(const char *key, PyObject *profiles, PyObject *spec, size_t wh static PyObject* patch_color_profiles(PyObject *module UNUSED, PyObject *args) { - PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color; - if (!PyArg_ParseTuple(args, "O!OO!p", &PyDict_Type, &spec, &cursor_text_color, &PyTuple_Type, &profiles, &change_configured)) return NULL; + PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; + if (!PyArg_ParseTuple(args, "O!O!p", &PyDict_Type, &spec, &PyTuple_Type, &profiles, &change_configured)) return NULL; char key[32] = {0}; for (size_t i = 0; i < arraysz(FG_BG_256); i++) { snprintf(key, sizeof(key) - 1, "color%zu", i); @@ -153,7 +153,7 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) { } #define S(config_name, profile_name) { \ v = PyDict_GetItemString(spec, #config_name); \ - if (v) { \ + if (v && PyLong_Check(v)) { \ color_type color = PyLong_AsUnsignedLong(v); \ for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) { \ self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i); \ @@ -166,12 +166,13 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) { S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color); S(selection_foreground, highlight_fg); S(selection_background, highlight_bg); #undef S - if (cursor_text_color != Py_False) { + PyObject *cursor_text_color = PyDict_GetItemString(spec, "cursor_text_color"); + if (cursor_text_color) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) { self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i); self->overridden.cursor_text_color = 0x111111; self->overridden.cursor_text_uses_bg = 3; - if (cursor_text_color != Py_None) { + if (PyLong_Check(cursor_text_color)) { self->overridden.cursor_text_color = (PyLong_AsUnsignedLong(cursor_text_color) << 8) | 2; self->overridden.cursor_text_uses_bg = 1; } diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index cfe9ce8d2..8564fafa4 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -614,7 +614,7 @@ def safe_pipe(nonblock: bool = True) -> Tuple[int, int]: pass -def patch_global_colors(spec: Dict[str, int], configured: bool) -> None: +def patch_global_colors(spec: Dict[str, Optional[int]], configured: bool) -> None: pass @@ -647,8 +647,7 @@ class ColorProfile: def patch_color_profiles( - spec: Dict[str, int], cursor_text_color: Optional[Union[bool, int]], - profiles: Tuple[ColorProfile, ...], change_configured: bool + spec: Dict[str, Optional[int]], profiles: Tuple[ColorProfile, ...], change_configured: bool ) -> None: pass diff --git a/kitty/launch.py b/kitty/launch.py index 0fc4f299d..494331b6f 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -281,9 +281,9 @@ class LaunchKwds(TypedDict): def apply_colors(window: Window, spec: Sequence[str]) -> None: from kitty.rc.set_colors import parse_colors - colors, cursor_text_color = parse_colors(spec) + colors = parse_colors(spec) profiles = window.screen.color_profile, - patch_color_profiles(colors, cursor_text_color, profiles, True) + patch_color_profiles(colors, profiles, True) def launch( diff --git a/kitty/rc/set_colors.py b/kitty/rc/set_colors.py index b3043850b..92f9750b4 100644 --- a/kitty/rc/set_colors.py +++ b/kitty/rc/set_colors.py @@ -3,7 +3,7 @@ import os -from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Union +from typing import TYPE_CHECKING, Dict, Iterable, Optional from kitty.config import parse_config from kitty.fast_data_types import patch_color_profiles @@ -18,24 +18,29 @@ if TYPE_CHECKING: from kitty.cli_stub import SetColorsRCOptions as CLIOptions -def parse_colors(args: Iterable[str]) -> Tuple[Dict[str, int], Optional[Union[int, bool]]]: +def parse_colors(args: Iterable[str]) -> Dict[str, Optional[int]]: colors: Dict[str, Optional[Color]] = {} + nullable_colors: Dict[str, Optional[int]] = {} for spec in args: if '=' in spec: colors.update(parse_config((spec.replace('=', ' '),))) else: with open(os.path.expanduser(spec), encoding='utf-8', errors='replace') as f: colors.update(parse_config(f)) - q = colors.pop('cursor_text_color', False) - ctc = int(q) if isinstance(q, Color) else (False if q is False else None) - return {k: int(v) for k, v in colors.items() if isinstance(v, Color)}, ctc + for k in ('cursor_text_color', 'tab_bar_background'): + q = colors.pop(k, False) + if q is not False: + val = int(q) if isinstance(q, Color) else None + nullable_colors[k] = val + ans: Dict[str, Optional[int]] = {k: int(v) for k, v in colors.items() if isinstance(v, Color)} + ans.update(nullable_colors) + return ans class SetColors(RemoteCommand): ''' - colors+: An object mapping names to colors as 24-bit RGB integers - cursor_text_color: A 24-bit color for text under the cursor, or null to use background. + colors+: An object mapping names to colors as 24-bit RGB integers or null for nullable colors match_window: Window to change colors in match_tab: Tab to change colors in all: Boolean indicating change colors everywhere or not @@ -72,35 +77,28 @@ this option, any color arguments are ignored and --configured and --all are impl args_completion = {'files': ('CONF files', ('*.conf',))} def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: - final_colors: Dict[str, int] = {} - cursor_text_color: Optional[Union[int, bool]] = False + final_colors: Dict[str, Optional[int]] = {} if not opts.reset: try: - final_colors, cursor_text_color = parse_colors(args) + final_colors = parse_colors(args) except Exception as err: raise ParsingOfArgsFailed(str(err)) from err ans = { 'match_window': opts.match, 'match_tab': opts.match_tab, 'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset, - 'colors': final_colors, 'reset': opts.reset, 'dummy': 0 + 'colors': final_colors, 'reset': opts.reset, } - if cursor_text_color is not False: - ans['cursor_text_color'] = cursor_text_color - del ans['dummy'] return ans def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType: windows = self.windows_for_payload(boss, window, payload_get) - colors = payload_get('colors') - cursor_text_color = payload_get('cursor_text_color', missing=False) + colors: Dict[str, Optional[int]] = payload_get('colors') if payload_get('reset'): colors = {k: int(v) for k, v in boss.startup_colors.items()} - cursor_text_color = boss.startup_cursor_text_color + colors['cursor_text_color'] = None if boss.startup_cursor_text_color is None else int(boss.startup_cursor_text_color) profiles = tuple(w.screen.color_profile for w in windows) - if isinstance(cursor_text_color, (tuple, list, Color)): - cursor_text_color = int(Color(*cursor_text_color)) - patch_color_profiles(colors, cursor_text_color, profiles, payload_get('configured')) - boss.patch_colors(colors, cursor_text_color, payload_get('configured')) + patch_color_profiles(colors, profiles, payload_get('configured')) + boss.patch_colors(colors, payload_get('configured')) default_bg_changed = 'background' in colors for w in windows: if default_bg_changed: diff --git a/kitty/state.c b/kitty/state.c index 86fc4e672..ca2be609a 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -942,13 +942,14 @@ PYWRAP1(patch_global_colors) { if (!PyArg_ParseTuple(args, "Op", &spec, &configured)) return NULL; #define P(name) { \ PyObject *val = PyDict_GetItemString(spec, #name); \ - if (val && PyLong_Check(val)) { \ - OPT(name) = PyLong_AsLong(val); \ + if (val) { \ + if (val == Py_None) OPT(name) = 0; \ + else if (PyLong_Check(val)) OPT(name) = PyLong_AsLong(val); \ } \ } - P(active_border_color); P(inactive_border_color); P(bell_border_color); + P(active_border_color); P(inactive_border_color); P(bell_border_color); P(tab_bar_background); if (configured) { - P(background); P(url_color); P(tab_bar_background); + P(background); P(url_color); P(mark1_background); P(mark1_foreground); P(mark2_background); P(mark2_foreground); P(mark3_background); P(mark3_foreground); } diff --git a/kitty/tab_bar.py b/kitty/tab_bar.py index 8a7ec98ca..df6a0db5a 100644 --- a/kitty/tab_bar.py +++ b/kitty/tab_bar.py @@ -457,32 +457,40 @@ class TabBar: else: self.align = lambda: None - def patch_colors(self, spec: Dict[str, Any]) -> None: - if 'active_tab_foreground' in spec: - self.active_fg = (spec['active_tab_foreground'] << 8) | 2 - self.draw_data = self.draw_data._replace(active_fg=color_from_int(spec['active_tab_foreground'])) - if 'active_tab_background' in spec: - self.active_bg = (spec['active_tab_background'] << 8) | 2 - self.draw_data = self.draw_data._replace(active_bg=color_from_int(spec['active_tab_background'])) - if 'inactive_tab_background' in spec: - self.draw_data = self.draw_data._replace(inactive_bg=color_from_int(spec['inactive_tab_background'])) - if 'tab_bar_background' in spec: - self.draw_data = self.draw_data._replace(default_bg=color_from_int(spec['tab_bar_background'])) + def patch_colors(self, spec: Dict[str, Optional[int]]) -> None: opts = get_options() - fg = spec.get('inactive_tab_foreground', color_as_int(opts.inactive_tab_foreground)) + atf = spec.get('active_tab_foreground') + if isinstance(atf, int): + self.active_fg = (atf << 8) | 2 + self.draw_data = self.draw_data._replace(active_fg=color_from_int(atf)) + atb = spec.get('active_tab_background') + if isinstance(atb, int): + self.active_bg = (atb << 8) | 2 + self.draw_data = self.draw_data._replace(active_bg=color_from_int(atb)) + itb = spec.get('inactive_tab_background') + if isinstance(itb, int): + self.draw_data = self.draw_data._replace(inactive_bg=color_from_int(itb)) + if 'tab_bar_background' in spec: + val = spec['tab_bar_background'] + if val is None: + val = color_as_int(opts.background) + self.draw_data = self.draw_data._replace(default_bg=color_from_int(val)) bg = spec.get('tab_bar_background', False) if bg is None: bg = color_as_int(opts.background) elif bg is False: bg = color_as_int(opts.tab_bar_background or opts.background) + fg = spec.get('inactive_tab_foreground') + if fg is None: + fg = color_as_int(opts.inactive_tab_foreground) self.screen.color_profile.set_configured_colors(fg, bg) def update_blank_rects(self) -> None: opts = get_options() central, tab_bar, vw, vh, cell_width, cell_height = viewport_for_window(self.os_window_id) blank_rects: List[Border] = [] + bg = BorderColor.default_bg if opts.tab_bar_margin_height: - bg = BorderColor.default_bg if opts.tab_bar_edge == 3: # bottom if opts.tab_bar_margin_height.outer: blank_rects.append(Border(0, tab_bar.bottom + 1, vw, vh, bg)) @@ -496,7 +504,6 @@ class TabBar: g = self.window_geometry if g.left > 0: viewport_width = max(4 * cell_width, tab_bar.width - 2 * self.margin_width) - bg = BorderColor.default_bg blank_rects.append(Border(0, g.top, g.left, g.bottom + 1, bg)) blank_rects.append(Border(g.right - 1, g.top, viewport_width, g.bottom + 1, bg))