A new option to control when hyperlinks are underlined

While kitty is never going to underline detected URLs as the performance
of that is absurd, underlining hyperlinks specifically is acceptable,
since they dont require detection.

See #6766
This commit is contained in:
Kovid Goyal
2023-11-03 08:51:58 +05:30
parent 954b7f87a5
commit b4f88b4f81
10 changed files with 65 additions and 7 deletions

View File

@@ -486,7 +486,8 @@ opt('detect_urls', 'yes',
long_text='''
Detect URLs under the mouse. Detected URLs are highlighted with an underline and
the mouse cursor becomes a hand over them. Even if this option is disabled, URLs
are still clickable.
are still clickable. See also the :opt:`underline_hyperlinks` option to control
how hyperlinks (as opposed to plain text URLs) are displayed.
'''
)
@@ -510,6 +511,16 @@ When the mouse hovers over a terminal hyperlink, show the actual URL that will
be activated when the hyperlink is clicked.
''')
opt('underline_hyperlinks', 'hover', choices=('hover', 'always', 'never'),
ctype='underline_hyperlinks', long_text='''
Control how hyperlinks are underlined. They can either be underlined on mouse
``hover``, ``always`` (i.e. permanently underlined) or ``never`` which means
that kitty will not apply any underline styling to hyperlinks.
Uses the :opt:`url_style` and :opt:`url_color` settings for the underline style.
''')
opt('copy_on_select', 'no',
option_type='copy_on_select',
long_text='''

View File

@@ -1308,6 +1308,14 @@ class Parser:
choices_for_undercurl_style = frozenset(('thin-sparse', 'thin-dense', 'thick-sparse', 'thick-dense'))
def underline_hyperlinks(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_underline_hyperlinks:
raise ValueError(f"The value {val} is not a valid choice for underline_hyperlinks")
ans["underline_hyperlinks"] = val
choices_for_underline_hyperlinks = frozenset(('hover', 'always', 'never'))
def update_check_interval(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['update_check_interval'] = float(val)

View File

@@ -291,6 +291,19 @@ convert_from_opts_show_hyperlink_targets(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_underline_hyperlinks(PyObject *val, Options *opts) {
opts->underline_hyperlinks = underline_hyperlinks(val);
}
static void
convert_from_opts_underline_hyperlinks(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "underline_hyperlinks");
if (ret == NULL) return;
convert_from_python_underline_hyperlinks(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_select_by_word_characters(PyObject *val, Options *opts) {
select_by_word_characters(val, opts);
@@ -1143,6 +1156,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_show_hyperlink_targets(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_underline_hyperlinks(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_select_by_word_characters(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_select_by_word_characters_forward(py_opts, opts);

View File

@@ -57,6 +57,16 @@ window_title_in(PyObject *title_in) {
return ALL;
}
static UnderlineHyperlinks
underline_hyperlinks(PyObject *x) {
const char *in = PyUnicode_AsUTF8(x);
switch(in[0]) {
case 'a': return UNDERLINE_ALWAYS;
case 'n': return UNDERLINE_NEVER;
default : return UNDERLINE_ON_HOVER;
}
}
static BackgroundImageLayout
bglayout(PyObject *layout_name) {
const char *name = PyUnicode_AsUTF8(layout_name);

View File

@@ -29,6 +29,7 @@ choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separ
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_underline_hyperlinks = typing.Literal['hover', 'always', 'never']
choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right']
option_names = ( # {{{
@@ -432,6 +433,7 @@ option_names = ( # {{{
'text_fg_override_threshold',
'touch_scroll_multiplier',
'undercurl_style',
'underline_hyperlinks',
'update_check_interval',
'url_color',
'url_excluded_characters',
@@ -588,6 +590,7 @@ class Options:
text_fg_override_threshold: float = 0.0
touch_scroll_multiplier: float = 1.0
undercurl_style: choices_for_undercurl_style = 'thin-sparse'
underline_hyperlinks: choices_for_underline_hyperlinks = 'hover'
update_check_interval: float = 24.0
url_color: Color = Color(0, 135, 189)
url_excluded_characters: str = ''