From f046884f23ead19a0d8be24a3790977ae4a7af12 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 21 Mar 2023 08:04:42 +0530 Subject: [PATCH] Allow stopping of URL detection at newlines via url_excluded_characters Fixes #6122 --- docs/changelog.rst | 2 ++ kitty/options/definition.py | 7 ++++++- kitty/options/parse.py | 6 +++--- kitty/screen.c | 18 ++++++++++++------ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 18dee8177..c280443a6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -82,6 +82,8 @@ Detailed list of changes - X11: Fix a crash if the X server requests clipboard data after we have relinquished the clipboard (:iss:`5650`) +- Allow stopping of URL detection at newlines via :opt:`url_excluded_characters` (:iss:`6122`) + 0.27.1 [2023-02-07] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/options/definition.py b/kitty/options/definition.py index c3df2242d..fcb4adb0e 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -469,10 +469,15 @@ are still clickable. ) opt('url_excluded_characters', '', - ctype='!url_excluded_characters', + option_type='python_string', ctype='!url_excluded_characters', long_text=''' Additional characters to be disallowed from URLs, when detecting URLs under the mouse cursor. By default, all characters that are legal in URLs are allowed. +Additionally, newlines are allowed (but stripped). This is to accommodate +programs such as mutt that add hard line breaks even for continued lines. +:code:`\\\\n` can be added to this option to disable this behavior. Special +characters can be specified using backslash escapes, to specify a backslash use +a double backslash. ''' ) diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 1c10b1f86..d4a607f15 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -3,8 +3,8 @@ # isort: skip_file import typing from kitty.conf.utils import ( - merge_dicts, positive_float, positive_int, to_bool, to_cmdline, to_color, to_color_or_none, - unit_float + merge_dicts, positive_float, positive_int, python_string, to_bool, to_cmdline, to_color, + to_color_or_none, unit_float ) from kitty.options.utils import ( action_alias, active_tab_title_template, allow_hyperlinks, bell_on_tab, box_drawing_scale, @@ -1302,7 +1302,7 @@ class Parser: ans['url_color'] = to_color(val) def url_excluded_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: - ans['url_excluded_characters'] = str(val) + ans['url_excluded_characters'] = python_string(val) def url_prefixes(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['url_prefixes'] = url_prefixes(val) diff --git a/kitty/screen.c b/kitty/screen.c index 490b334ef..09f50ec94 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -2793,17 +2793,21 @@ screen_open_url(Screen *self) { // URLs {{{ static void -extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type sentinel) { +extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type sentinel, bool newlines_allowed) { unsigned int count = 0; + bool has_newline = false; while(count++ < 10) { - if (*x != line->xnum - 1) break; + has_newline = !line->gpu_cells[line->xnum-1].attrs.next_char_was_wrapped; + if (*x != line->xnum - 1 || (!newlines_allowed && has_newline)) break; bool next_line_starts_with_url_chars = false; line = screen_visual_line(screen, *y + 2); - if (line) next_line_starts_with_url_chars = line_startswith_url_chars(line); + if (line) { + next_line_starts_with_url_chars = line_startswith_url_chars(line); + has_newline = !line->attrs.is_continued; + if (next_line_starts_with_url_chars && has_newline && !newlines_allowed) next_line_starts_with_url_chars = false; + } line = screen_visual_line(screen, *y + 1); if (!line) break; - // we deliberately allow non-continued lines as some programs, like - // mutt split URLs with newlines at line boundaries index_type new_x = line_url_end_at(line, 0, false, sentinel, next_line_starts_with_url_chars); if (!new_x && !line_startswith_url_chars(line)) break; *y += 1; *x = new_x; @@ -2845,6 +2849,7 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) { return hid; } char_type sentinel = 0; + bool newlines_allowed = !is_excluded_from_url('\n'); if (line) { url_start = line_url_start_at(line, x); if (url_start < line->xnum) { @@ -2852,6 +2857,7 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) { if (y < screen->lines - 1) { line = screen_visual_line(screen, y+1); next_line_starts_with_url_chars = line_startswith_url_chars(line); + if (next_line_starts_with_url_chars && !newlines_allowed && !line->attrs.is_continued) next_line_starts_with_url_chars = false; line = screen_visual_line(screen, y); } sentinel = get_url_sentinel(line, url_start); @@ -2861,7 +2867,7 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) { } if (has_url) { index_type y_extended = y; - extend_url(screen, line, &url_end, &y_extended, sentinel); + extend_url(screen, line, &url_end, &y_extended, sentinel, newlines_allowed); screen_mark_url(screen, url_start, y, url_end, y_extended); } else { screen_mark_url(screen, 0, 0, 0, 0);