diff --git a/docs/changelog.rst b/docs/changelog.rst index 1cdef279a..504a1458a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -94,6 +94,14 @@ consumption to do the same tasks. Detailed list of changes ------------------------------------- +0.41.0 [future] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- A new mode of operation for :opt:`text_fg_override_threshold` to override + foreground colors so as to maintain a minimum contrast between foreground and + background text colors. Works in a perceptual color for best color accuracy + (:pull:`8420`) + 0.40.1 [2025-03-18] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/conf/utils.py b/kitty/conf/utils.py index ab9018808..344f3865c 100644 --- a/kitty/conf/utils.py +++ b/kitty/conf/utils.py @@ -67,17 +67,17 @@ def unit_float(x: ConvertibleToNumbers) -> float: return max(0, min(float(x), 1)) -def number_with_unit(x: str, default_unit: str = '') -> tuple[float, str]: - mat = number_unit_pat.match(x) - exception = None - if mat is not None: +def number_with_unit(x: str, default_unit: str, *extra_units: str) -> tuple[float, str]: + if (mat := number_unit_pat.match(x)) is not None: try: - value, unit = float(mat.group(1)), mat.group(2) - unit = default_unit if not unit else unit - return value, unit + value = float(mat.group(1)) except Exception as e: - exception = e - raise ValueError(f'Invalid number with unit config option provided: {x if exception is None else exception}') + raise ValueError(f'Not a number: {x} with error: {e}') + unit = mat.group(2) or default_unit + if unit != default_unit and unit not in extra_units: + raise ValueError(f'Not a valid unit: {x}. Allowed units are: {default_unit}, {", ".join(extra_units)}') + return value, unit + raise ValueError(f'Invalid number with unit: {x}') def to_bool(x: str) -> bool: diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 0f37f051e..34e39fc3f 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -265,31 +265,32 @@ Then adjust the second parameter until it looks good. Then switch to a light the and adjust the first parameter until the perceived thickness matches the dark theme. ''') -opt('text_fg_override_threshold', '0 %', option_type='text_fg_override_threshold', long_text=''' -A setting to prevent low contrast scenarios, configurable in two different modes (suffix :code:` %` and suffix :code:` ratio`). -The default value is :code:`0`, which means no overriding is performed. Useful when working with applications -that use colors that do not contrast well with your preferred color scheme. - -A value with the suffix :code:` %` represents the minimum accepted difference in luminance between the foreground and background -color, below which kitty will override the foreground color. It is percentage -ranging from :code:`0 %` to :code:`100 %`. If the difference in luminance of the -foreground and background is below this threshold, the foreground color will be set -to white if the background is dark or black if the background is light. +opt('text_fg_override_threshold', '0', option_type='text_fg_override_threshold', long_text=''' +A setting to prevent low contrast between foreground and background colors. +Useful when working with applications that use colors that do not contrast +well with your preferred color scheme. The default value is :code:`0`, which means no color overriding is performed. +There are two modes of operation: A value with the suffix :code:` ratio` represents the minimum accepted contrast ratio between the foreground and background color. Possible values range from :code:`0.0 ratio` to :code:`21.0 ratio`. -To for example meet :link:`WCAG level AA ` +For example, to meet :link:`WCAG level AA ` a value of :code:`4.5 ratio` can be provided. The algorithm is implemented using :link:`HSLuv ` which enables it to change the perceived lightness of a color just as much as needed without really changing its hue and saturation. +A value with the suffix :code:` %` represents the minimum accepted difference in luminance +between the foreground and background color, below which kitty will override the foreground color. +It is percentage ranging from :code:`0 %` to :code:`100 %`. If the difference in luminance of the +foreground and background is below this threshold, the foreground color will be set +to white if the background is dark or black if the background is light. + WARNING: Some programs use characters (such as block characters) for graphics display and may expect to be able to set the foreground and background to the -same color (or similar colors). If you see unexpected stripes, dots, lines, +same color (or similar colors). If you see unexpected stripes, dots, lines, incorrect color, no color where you expect color, or any kind of graphic display problem try setting :opt:`text_fg_override_threshold` to :code:`0` to -see if this is the cause of the problem or consider the minimum contrast ratio (negative value) -over the minimum difference as it implements a basic workaround for this scenario. +see if this is the cause of the problem or consider using the :code:`ratio` mode of operation +described above instead of the :code:`%` mode of operation. ''') egr() # }}} diff --git a/kitty/options/utils.py b/kitty/options/utils.py index a4972a7fd..f468c54fa 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -754,10 +754,7 @@ def active_tab_title_template(x: str) -> str | None: def text_fg_override_threshold(x: str) -> tuple[float, str]: - value, unit = number_with_unit(x, default_unit='%') - if unit not in ['%', 'ratio']: - raise ValueError(f'The unit {unit} is not a valid choice for text_fg_override_threshold') - return value, unit + return number_with_unit(x, '%', 'ratio') ClearOn = Literal['next', 'focus']