diff --git a/docs/changelog.rst b/docs/changelog.rst index 1539602cd..dbf73161c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -63,6 +63,8 @@ Detailed list of changes - Add an option :opt:`background_tint_gaps` to control background image tinting for window gaps (:iss:`5596`) +- A new option :opt:`undercurl_style` to control the rendering of undercurls (:pull:`5883`) + - Bash integration: Fix ``clone-in-kitty`` not working on bash >= 5.2 if an environment variable values contain newlines or other special characters (:iss:`5629`) - A new :ac:`sleep` action useful in combine based mappings to make kitty sleep before executing the next action diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index fa8c5b78c..5e6304163 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -13,6 +13,7 @@ from kitty.fast_data_types import ( Screen, create_test_font_group, get_fallback_font, + get_options, set_font_data, set_options, set_send_sprite_to_gpu, @@ -249,16 +250,15 @@ def add_dline(buf: CBufType, cell_width: int, position: int, thickness: int, cel def add_curl(buf: CBufType, cell_width: int, position: int, thickness: int, cell_height: int) -> None: max_x, max_y = cell_width - 1, cell_height - 1 - xfactor = 2.0 * pi / max_x - thickness = max(1, thickness) - if thickness < 3: - half_height = thickness - thickness -= 1 - elif thickness == 3: - half_height = thickness = 2 + opts = get_options() + xfactor = (4.0 if 'dense' in opts.undercurl_style else 2.0) * pi / max_x + + max_height = cell_height - (position - thickness // 2) # descender from the font + half_height = max(1, max_height // 4) + if 'thick' in opts.undercurl_style: + thickness = max(half_height, thickness) else: - half_height = thickness // 2 - thickness -= 2 + thickness = max(1, thickness) - (1 if thickness < 3 else 2) def add_intensity(x: int, y: int, val: int) -> None: y += position diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 257566d87..d5ea2c803 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -220,6 +220,16 @@ The sizes of the lines used for the box drawing Unicode characters. These values are in pts. They will be scaled by the monitor DPI to arrive at a pixel value. There must be four values corresponding to thin, normal, thick, and very thick lines. +''' + ) + +opt('undercurl_style', 'thin-sparse', + choices=('thin-sparse', 'thin-dense', 'thick-sparse', 'thick-dense'), + long_text=''' +The style with which undercurls are rendered. This option takes the form +:code:`(thin|thick)-(sparse|dense)`. Thin and thick control the thickness of the +undercurl. Sparse and dense control how often the curl oscillates. With sparse +the curl will peak once per character, with dense twice. ''' ) egr() # }}} diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 25a883c49..bb3180f19 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -1281,6 +1281,14 @@ class Parser: def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['touch_scroll_multiplier'] = float(val) + def undercurl_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_undercurl_style: + raise ValueError(f"The value {val} is not a valid choice for undercurl_style") + ans["undercurl_style"] = val + + choices_for_undercurl_style = frozenset(('thin-sparse', 'thin-dense', 'thick-sparse', 'thick-dense')) + def update_check_interval(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['update_check_interval'] = float(val) diff --git a/kitty/options/types.py b/kitty/options/types.py index 20299f127..b37808287 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -29,6 +29,7 @@ if typing.TYPE_CHECKING: choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator', 'slant', 'custom'] choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted'] choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right'] + choices_for_undercurl_style = typing.Literal['thin-sparse', 'thin-dense', 'thick-sparse', 'thick-dense'] choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'] else: choices_for_allow_cloning = str @@ -46,6 +47,7 @@ else: choices_for_tab_bar_style = str choices_for_tab_powerline_style = str choices_for_tab_switch_strategy = str + choices_for_undercurl_style = str choices_for_window_logo_position = str option_names = ( # {{{ @@ -442,6 +444,7 @@ option_names = ( # {{{ 'tab_title_template', 'term', 'touch_scroll_multiplier', + 'undercurl_style', 'update_check_interval', 'url_color', 'url_excluded_characters', @@ -592,6 +595,7 @@ class Options: tab_title_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title}' term: str = 'xterm-kitty' touch_scroll_multiplier: float = 1.0 + undercurl_style: choices_for_undercurl_style = 'thin-sparse' update_check_interval: float = 24.0 url_color: Color = Color(0, 135, 189) url_excluded_characters: str = ''