Skip to content

Commit

Permalink
Fix multicell marking of hyperlinks
Browse files Browse the repository at this point in the history
  • Loading branch information
kovidgoyal committed Jan 11, 2025
1 parent 6602be5 commit a96b5ba
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 20 deletions.
41 changes: 21 additions & 20 deletions kitty/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -3622,30 +3622,24 @@ extend_tuple(PyObject *a, PyObject *b) {

static PyObject*
current_url_text(Screen *self, PyObject *args UNUSED) {
PyObject *empty_string = PyUnicode_FromString(""), *ans = NULL;
RAII_PyObject(empty_string, PyUnicode_FromString(""));
if (!empty_string) return NULL;
RAII_PyObject(ans, NULL);
for (size_t i = 0; i < self->url_ranges.count; i++) {
Selection *s = self->url_ranges.items + i;
if (!is_selection_empty(s)) {
PyObject *temp = text_for_range(self, s, false, false);
if (!temp) goto error;
PyObject *text = PyUnicode_Join(empty_string, temp);
Py_CLEAR(temp);
if (!text) goto error;
RAII_PyObject(temp, text_for_range(self, s, false, false));
if (!temp) return NULL;
RAII_PyObject(text, PyUnicode_Join(empty_string, temp));
if (!text) return NULL;
if (ans) {
PyObject *t = ans;
ans = PyUnicode_Concat(ans, text);
Py_CLEAR(text); Py_CLEAR(t);
if (!ans) goto error;
} else ans = text;
PyObject *t = PyUnicode_Concat(ans, text);
if (!t) return NULL;
Py_CLEAR(ans); ans = t;
} else ans = Py_NewRef(text);
}
}
Py_CLEAR(empty_string);
if (!ans) Py_RETURN_NONE;
return ans;
error:
Py_CLEAR(empty_string); Py_CLEAR(ans);
return NULL;
return Py_NewRef(ans ? ans : Py_None);
}


Expand Down Expand Up @@ -4692,12 +4686,18 @@ screen_mark_url(Screen *self, index_type start_x, index_type start_y, index_type
}

static bool
mark_hyperlinks_in_line(Screen *self, Line *line, hyperlink_id_type id, index_type y) {
mark_hyperlinks_in_line(Screen *self, Line *line, hyperlink_id_type id, index_type y, bool *found_nonzero_multiline) {
index_type start = 0;
bool found = false;
bool in_range = false;
*found_nonzero_multiline = false;
for (index_type x = 0; x < line->xnum; x++) {
bool has_hyperlink = line->cpu_cells[x].hyperlink_id == id;
bool is_nonzero_multiline = line->cpu_cells[x].is_multicell && line->cpu_cells[x].y > 0;
if (has_hyperlink && is_nonzero_multiline) {
has_hyperlink = false;
*found_nonzero_multiline = true;
}
if (in_range) {
if (!has_hyperlink) {
add_url_range(self, start, y, x - 1, y, true);
Expand Down Expand Up @@ -4735,16 +4735,17 @@ screen_mark_hyperlink(Screen *self, index_type x, index_type y) {
hyperlink_id_type id = line->cpu_cells[x].hyperlink_id;
if (!id) return 0;
index_type ypos = y, last_marked_line = y;
bool found_nonzero_multiline;
do {
if (mark_hyperlinks_in_line(self, line, id, ypos)) last_marked_line = ypos;
if (mark_hyperlinks_in_line(self, line, id, ypos, &found_nonzero_multiline) || found_nonzero_multiline) last_marked_line = ypos;
if (ypos == 0) break;
ypos--;
line = screen_visual_line(self, ypos);
} while (last_marked_line - ypos < 5);
ypos = y + 1; last_marked_line = y;
while (ypos < self->lines - 1 && ypos - last_marked_line < 5) {
line = screen_visual_line(self, ypos);
if (mark_hyperlinks_in_line(self, line, id, ypos)) last_marked_line = ypos;
if (mark_hyperlinks_in_line(self, line, id, ypos, &found_nonzero_multiline)) last_marked_line = ypos;
ypos++;
}
if (self->url_ranges.count > 1) sort_ranges(self, &self->url_ranges);
Expand Down
17 changes: 17 additions & 0 deletions kitty_tests/multicell.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2024, Kovid Goyal <kovid at kovidgoyal.net>

from functools import partial

from kitty.fast_data_types import EXTEND_CELL, TEXT_SIZE_CODE, test_ch_and_idx, wcswidth

Expand Down Expand Up @@ -662,3 +663,19 @@ def asa(*expected, strip_trailing_whitespace=False):
asl((0, 0, 1), (1, 0, 3))
ast('Xab')
asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;X\x07ab', '\x1b[m')

# Hyperlinks
asu = partial(asl, bp=2)
def set_link(url=None, id=None):
parse_bytes(s, '\x1b]8;id={};{}\x1b\\'.format(id or '', url or '').encode('utf-8'))

s.reset()
set_link('url-a', 'a')
multicell(s, 'ab', scale=2)
for y in (0, 1):
self.ae(s.line(y).hyperlink_ids(), (1, 1, 1, 1, 0, 0, 0, 0))
for y in (0, 1):
for x in (0, 3):
self.ae('url-a', s.hyperlink_at(x, y))
asu((0, 0, 3), (1, 0, 3))
self.ae(s.current_url_text(), 'ab')

0 comments on commit a96b5ba

Please sign in to comment.