diff --git a/kitty/line.c b/kitty/line.c index 9cd3fc756..b58caa4a6 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -133,16 +133,24 @@ line_url_start_at(Line *self, index_type x) { } index_type -line_url_end_at(Line *self, index_type x, bool check_short, char_type sentinel) { +line_url_end_at(Line *self, index_type x, bool check_short, char_type sentinel, bool next_line_starts_with_url_chars) { index_type ans = x; if (x >= self->xnum || (check_short && self->xnum <= MIN_URL_LEN + 3)) return 0; if (sentinel) { while (ans < self->xnum && self->cpu_cells[ans].ch != sentinel && is_url_char(self->cpu_cells[ans].ch)) ans++; } else { while (ans < self->xnum && is_url_char(self->cpu_cells[ans].ch)) ans++; } if (ans) ans--; - while (ans > x && can_strip_from_end_of_url(self->cpu_cells[ans].ch)) ans--; + if (ans < self->xnum - 1 || !next_line_starts_with_url_chars) { + while (ans > x && can_strip_from_end_of_url(self->cpu_cells[ans].ch)) ans--; + } return ans; } +bool +line_startswith_url_chars(Line *self) { + return is_url_char(self->cpu_cells[0].ch); +} + + static PyObject* url_start_at(Line *self, PyObject *x) { #define url_start_at_doc "url_start_at(x) -> Return the start cell number for a URL containing x or self->xnum if not found" @@ -153,8 +161,9 @@ static PyObject* url_end_at(Line *self, PyObject *args) { #define url_end_at_doc "url_end_at(x) -> Return the end cell number for a URL containing x or 0 if not found" unsigned int x, sentinel = 0; - if (!PyArg_ParseTuple(args, "I|I", &x, &sentinel)) return NULL; - return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, x, true, sentinel)); + int next_line_starts_with_url_chars = 0; + if (!PyArg_ParseTuple(args, "I|Ip", &x, &sentinel, &next_line_starts_with_url_chars)) return NULL; + return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, x, true, sentinel, next_line_starts_with_url_chars)); } // }}} diff --git a/kitty/lineops.h b/kitty/lineops.h index b67b6642a..81fc554dd 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -61,7 +61,8 @@ void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bo void line_right_shift(Line *, unsigned int , unsigned int ); void line_add_combining_char(Line *, uint32_t , unsigned int ); index_type line_url_start_at(Line *self, index_type x); -index_type line_url_end_at(Line *self, index_type x, bool, char_type); +index_type line_url_end_at(Line *self, index_type x, bool, char_type, bool); +bool line_startswith_url_chars(Line*); index_type line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen, bool*, const GPUCell**) __attribute__((nonnull)); unsigned int line_length(Line *self); size_t cell_as_unicode(CPUCell *cell, bool include_cc, Py_UCS4 *buf, char_type); diff --git a/kitty/mouse.c b/kitty/mouse.c index 3e7b0ecbd..a39abb7c1 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -227,11 +227,14 @@ extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type s unsigned int count = 0; while(count++ < 10) { if (*x != line->xnum - 1) 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); 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); + index_type new_x = line_url_end_at(line, 0, false, sentinel, next_line_starts_with_url_chars); if (!new_x) break; *y += 1; *x = new_x; } @@ -274,7 +277,15 @@ detect_url(Screen *screen, unsigned int x, unsigned int y) { if (line) { url_start = line_url_start_at(line, x); sentinel = get_url_sentinel(line, url_start); - if (url_start < line->xnum) url_end = line_url_end_at(line, x, true, sentinel); + if (url_start < line->xnum) { + bool next_line_starts_with_url_chars = false; + if (y < screen->lines - 1) { + line = screen_visual_line(screen, y+1); + next_line_starts_with_url_chars = line_startswith_url_chars(line); + line = screen_visual_line(screen, y); + } + url_end = line_url_end_at(line, x, true, sentinel, next_line_starts_with_url_chars); + } has_url = url_end > url_start; } if (has_url) { diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 755760d1a..2654bce39 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -285,6 +285,10 @@ class TestDataTypes(BaseTest): l4 = create('http://a.b?q=1' + trail) self.ae(l4.url_end_at(1), len(l4) - 1) + l4 = create('http://a.b.') + self.ae(l4.url_end_at(0), len(l4) - 2) + self.ae(l4.url_end_at(0, 0, True), len(l4) - 1) + def rewrap(self, lb, lb2): hb = HistoryBuf(lb2.ynum, lb2.xnum) cy = lb.rewrap(lb2, hb)