More work on multicell URL detection
This commit is contained in:
parent
cf89dba5af
commit
6a19918687
4 changed files with 65 additions and 46 deletions
64
kitty/line.c
64
kitty/line.c
|
|
@ -296,29 +296,60 @@ is_pos_ok_for_url(Line *self, index_type x, bool in_hostname, index_type last_ho
|
|||
}
|
||||
|
||||
index_type
|
||||
line_url_end_at(Line *self, index_type x, bool check_short, char_type sentinel, bool next_line_starts_with_url_chars, bool in_hostname, index_type last_hostname_char_pos) {
|
||||
line_url_end_at(Line *self, index_type x, bool check_short, char_type sentinel, bool next_line_starts_with_url_chars, bool in_hostname, index_type last_hostname_char_pos, ListOfChars *lc) {
|
||||
index_type ans = x;
|
||||
if (x >= self->xnum || (check_short && self->xnum <= MIN_URL_LEN + 3)) return 0;
|
||||
RAII_ListOfChars(lc);
|
||||
#define pos_ok(x) is_pos_ok_for_url(self, x, in_hostname, last_hostname_char_pos, &lc)
|
||||
if (sentinel) { while (ans < self->xnum && !cell_is_char(self->cpu_cells + ans, sentinel) && pos_ok(ans)) ans++; }
|
||||
else { while (ans < self->xnum && pos_ok(ans)) ans++; }
|
||||
if (ans) ans--;
|
||||
if (ans < self->xnum - 1 || !next_line_starts_with_url_chars) {
|
||||
while (ans > x && !self->cpu_cells[ans].ch_is_idx && can_strip_from_end_of_url(self->cpu_cells[ans].ch_or_idx)) ans--;
|
||||
#define is_not_ok(n) ((sentinel && cell_is_char(self->cpu_cells + n, sentinel)) || !is_pos_ok_for_url(self, n, in_hostname, last_hostname_char_pos, lc))
|
||||
if (x >= self->xnum || (check_short && self->xnum <= MIN_URL_LEN + 3) || is_not_ok(x)) return 0;
|
||||
index_type n = ans;
|
||||
while ((n = next_char_pos(self, ans, 1)) < self->xnum) {
|
||||
if (is_not_ok(n)) break;
|
||||
ans = n;
|
||||
}
|
||||
#undef is_not_ok
|
||||
if (ans < self->xnum - 1 || !next_line_starts_with_url_chars) {
|
||||
while (ans > x && !self->cpu_cells[ans].ch_is_idx && can_strip_from_end_of_url(self->cpu_cells[ans].ch_or_idx)) {
|
||||
n = prev_char_pos(self, ans, 1);
|
||||
if (n >= self->xnum || n < x) break;
|
||||
ans = n;
|
||||
}
|
||||
}
|
||||
#undef pos_ok
|
||||
return ans;
|
||||
}
|
||||
|
||||
bool
|
||||
line_startswith_url_chars(Line *self, bool in_hostname) {
|
||||
RAII_ListOfChars(lc);
|
||||
text_in_cell(self->cpu_cells, self->text_cache, &lc);
|
||||
if (in_hostname) return is_hostname_lc(&lc);
|
||||
return is_url_lc(&lc);
|
||||
line_startswith_url_chars(Line *self, bool in_hostname, ListOfChars *lc) {
|
||||
text_in_cell(self->cpu_cells, self->text_cache, lc);
|
||||
if (in_hostname) return is_hostname_lc(lc);
|
||||
return is_url_lc(lc);
|
||||
}
|
||||
|
||||
char_type
|
||||
get_url_sentinel(Line *line, index_type url_start) {
|
||||
char_type before = 0, sentinel;
|
||||
if (url_start > 0 && url_start < line->xnum) {
|
||||
index_type n = prev_char_pos(line, url_start, 1);
|
||||
if (n < line->xnum) before = cell_first_char(line->cpu_cells + n, line->text_cache);
|
||||
}
|
||||
switch(before) {
|
||||
case '"':
|
||||
case '\'':
|
||||
case '*':
|
||||
sentinel = before; break;
|
||||
case '(':
|
||||
sentinel = ')'; break;
|
||||
case '[':
|
||||
sentinel = ']'; break;
|
||||
case '{':
|
||||
sentinel = '}'; break;
|
||||
case '<':
|
||||
sentinel = '>'; break;
|
||||
default:
|
||||
sentinel = 0; break;
|
||||
}
|
||||
return sentinel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PyObject*
|
||||
url_start_at(Line *self, PyObject *x) {
|
||||
|
|
@ -333,7 +364,8 @@ url_end_at(Line *self, PyObject *args) {
|
|||
unsigned int x, sentinel = 0;
|
||||
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, false, self->xnum));
|
||||
RAII_ListOfChars(lc);
|
||||
return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, x, true, sentinel, next_line_starts_with_url_chars, false, self->xnum, &lc));
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
|
|
|||
|
|
@ -70,8 +70,9 @@ void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch
|
|||
void line_apply_cursor(Line *self, const Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
|
||||
char_type line_get_char(Line *self, index_type at);
|
||||
index_type line_url_start_at(Line *self, index_type x, ListOfChars *lc);
|
||||
index_type line_url_end_at(Line *self, index_type x, bool, char_type, bool, bool, index_type);
|
||||
bool line_startswith_url_chars(Line*, bool);
|
||||
index_type line_url_end_at(Line *self, index_type x, bool, char_type, bool, bool, index_type, ListOfChars*);
|
||||
bool line_startswith_url_chars(Line*, bool, ListOfChars*);
|
||||
char_type get_url_sentinel(Line *line, index_type url_start);
|
||||
bool line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_before, char_type prefix_char, bool skip_multiline_non_zero_lines) __attribute__((nonnull));
|
||||
unsigned int line_length(Line *self);
|
||||
size_t cell_as_unicode_for_fallback(const ListOfChars *lc, Py_UCS4 *buf);
|
||||
|
|
|
|||
|
|
@ -3706,7 +3706,7 @@ extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type s
|
|||
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, in_hostname);
|
||||
next_line_starts_with_url_chars = line_startswith_url_chars(line, in_hostname, screen->lc);
|
||||
has_newline = !line->attrs.is_continued;
|
||||
if (next_line_starts_with_url_chars && has_newline && !newlines_allowed) next_line_starts_with_url_chars = false;
|
||||
if (sentinel && next_line_starts_with_url_chars && cell_is_char(line->cpu_cells, sentinel)) next_line_starts_with_url_chars = false;
|
||||
|
|
@ -3722,8 +3722,8 @@ extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type s
|
|||
}
|
||||
}
|
||||
}
|
||||
index_type new_x = line_url_end_at(line, 0, false, sentinel, next_line_starts_with_url_chars, in_hostname, last_hostname_char_pos);
|
||||
if (!new_x && !line_startswith_url_chars(line, in_hostname)) break;
|
||||
index_type new_x = line_url_end_at(line, 0, false, sentinel, next_line_starts_with_url_chars, in_hostname, last_hostname_char_pos, screen->lc);
|
||||
if (!new_x && !line_startswith_url_chars(line, in_hostname, screen->lc)) break;
|
||||
*y += 1; *x = new_x;
|
||||
}
|
||||
if (sentinel && *x == 0 && *y > orig_y) {
|
||||
|
|
@ -3734,29 +3734,6 @@ extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type s
|
|||
}
|
||||
}
|
||||
|
||||
static char_type
|
||||
get_url_sentinel(Line *line, index_type url_start) {
|
||||
char_type before = 0, sentinel;
|
||||
if (url_start > 0 && url_start < line->xnum) before = cell_first_char(line->cpu_cells + url_start - 1, line->text_cache);
|
||||
switch(before) {
|
||||
case '"':
|
||||
case '\'':
|
||||
case '*':
|
||||
sentinel = before; break;
|
||||
case '(':
|
||||
sentinel = ')'; break;
|
||||
case '[':
|
||||
sentinel = ']'; break;
|
||||
case '{':
|
||||
sentinel = '}'; break;
|
||||
case '<':
|
||||
sentinel = '>'; break;
|
||||
default:
|
||||
sentinel = 0; break;
|
||||
}
|
||||
return sentinel;
|
||||
}
|
||||
|
||||
int
|
||||
screen_detect_url(Screen *screen, unsigned int x, unsigned int y) {
|
||||
bool has_url = false;
|
||||
|
|
@ -3783,7 +3760,7 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) {
|
|||
bool next_line_starts_with_url_chars = false;
|
||||
if (y < screen->lines - 1) {
|
||||
visual_line(screen, y + 1, &scratch);
|
||||
next_line_starts_with_url_chars = line_startswith_url_chars(&scratch, last_hostname_char_pos >= line->xnum);
|
||||
next_line_starts_with_url_chars = line_startswith_url_chars(&scratch, last_hostname_char_pos >= line->xnum, screen->lc);
|
||||
if (next_line_starts_with_url_chars && !newlines_allowed && !scratch.attrs.is_continued) next_line_starts_with_url_chars = false;
|
||||
}
|
||||
sentinel = get_url_sentinel(line, url_start);
|
||||
|
|
@ -3791,7 +3768,7 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) {
|
|||
for (index_type i = url_start; i < line->xnum; i++) {
|
||||
if (cell_is_char(line->cpu_cells + i, '/') && ++slash_count > 2) { last_hostname_char_pos = i - 1; break; }
|
||||
}
|
||||
url_end = line_url_end_at(line, x, true, sentinel, next_line_starts_with_url_chars, x <= last_hostname_char_pos, last_hostname_char_pos);
|
||||
url_end = line_url_end_at(line, x, true, sentinel, next_line_starts_with_url_chars, x <= last_hostname_char_pos, last_hostname_char_pos, screen->lc);
|
||||
}
|
||||
has_url = url_end > url_start;
|
||||
if (has_url) {
|
||||
|
|
|
|||
|
|
@ -679,3 +679,12 @@ def set_link(url=None, id=None):
|
|||
self.ae('url-a', s.hyperlink_at(x, y))
|
||||
asu((0, 0, 3), (1, 0, 3))
|
||||
self.ae(s.current_url_text(), 'ab')
|
||||
|
||||
# URL detection
|
||||
s = self.create_screen(cols=40)
|
||||
|
||||
s.reset()
|
||||
url = 'http://moo.com'
|
||||
multicell(s, url, scale=2)
|
||||
s.detect_url(0, 0)
|
||||
asl((0, 0, len(url)*2), (1, 0, len(url)*2))
|
||||
|
|
|
|||
Loading…
Reference in a new issue