From 9d304ccbc6895a8615ad9bec6f17a3eab283e2dc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 20 Dec 2024 15:06:22 +0530 Subject: [PATCH] Nicer fix for #8124 Now colors from the auto themes are first merged onto the default colors to ensure that themes that dont specify all colors still have correct values for all colors. --- docs/changelog.rst | 4 +++- kitty/colors.py | 32 ++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 8384ae558..73624b253 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -90,7 +90,9 @@ Detailed list of changes - macOS: Fix a regression in the previous release that broke rendering of Emoji using the VS16 variation selector (:iss:`8130`) -- themes kitten: When using the *Default* theme as an auto switch theme include all the actual settings values (:iss:`8124`) +- When automatically changing colors based on OS color preference, first reset + all colors to default before applying the new theme so that even colors not + specified in the theme are correct (:iss:`8124`) - Graphics: Fix deleted but not freed images without any references being incorrectly freed on a subsequent delete command (:disc:`8129`) diff --git a/kitty/colors.py b/kitty/colors.py index 931b05a35..0816ca0a9 100644 --- a/kitty/colors.py +++ b/kitty/colors.py @@ -16,6 +16,7 @@ from .typing import WindowType ColorsSpec = dict[str, Optional[int]] TransparentBackgroundColors = tuple[tuple[Color, float], ...] ColorSchemes = Literal['light', 'dark', 'no_preference'] +Colors = tuple[ColorsSpec, TransparentBackgroundColors] class ThemeFile(Enum): @@ -30,6 +31,29 @@ class ThemeColors: light_mtime: int = -1 no_preference_mtime: int = -1 applied_theme: Literal['light', 'dark', 'no_preference', ''] = '' + default_colors: Optional[ColorsSpec] = None + + def get_default_colors(self) -> ColorsSpec: + if self.default_colors is None: + from kitty.options.types import defaults, option_names + ans: ColorsSpec = dict.fromkeys(nullable_colors) + + for name in option_names: + defval = getattr(defaults, name) + if isinstance(defval, Color): + ans[name] = int(defval) + self.default_colors = ans + return self.default_colors + + def parse_colors(self, f: Iterable[str]) -> Colors: + # When parsing the theme file we first apply the default theme so that + # all colors are reset to default values first. This is needed for themes + # that don't specify all colors. + spec, tbc = parse_colors((f,)) + dc_spec = self.get_default_colors() + ans = dc_spec.copy() + ans.update(spec) + return ans, tbc def refresh(self) -> bool: found = False @@ -39,21 +63,21 @@ class ThemeColors: mtime = x.stat().st_mtime_ns if mtime > self.dark_mtime: with open(x.path) as f: - self.dark_spec, self.dark_tbc = parse_colors((f,)) + self.dark_spec, self.dark_tbc = self.parse_colors(f) self.dark_mtime = mtime found = True elif x.name == ThemeFile.light.value: mtime = x.stat().st_mtime_ns if mtime > self.light_mtime: with open(x.path) as f: - self.light_spec, self.light_tbc = parse_colors((f,)) + self.light_spec, self.light_tbc = self.parse_colors(f) self.light_mtime = mtime found = True elif x.name == ThemeFile.no_preference.value: mtime = x.stat().st_mtime_ns if mtime > self.no_preference_mtime: with open(x.path) as f: - self.no_preference_spec, self.no_preference_tbc = parse_colors((f,)) + self.no_preference_spec, self.no_preference_tbc = self.parse_colors(f) self.no_preference_mtime = mtime found = True return found @@ -123,7 +147,7 @@ class ThemeColors: theme_colors = ThemeColors() -def parse_colors(args: Iterable[Union[str, Iterable[str]]]) -> tuple[ColorsSpec, TransparentBackgroundColors]: +def parse_colors(args: Iterable[Union[str, Iterable[str]]]) -> Colors: colors: dict[str, Optional[Color]] = {} nullable_color_map: dict[str, Optional[int]] = {} transparent_background_colors = ()