When hovering over a URL, highlight the URL fully even if it continues over multiple lines. Note that URL detection has not changed. A URL will be detected only if the mouse hovers over the line containing the start of the URL.
This commit is contained in:
parent
d25c0d42bc
commit
95683c658b
@ -291,6 +291,9 @@ class Boss:
|
||||
if url:
|
||||
open_url(url, self.opts.open_url_with)
|
||||
|
||||
def open_url_lines(self, lines):
|
||||
self.open_url(''.join(lines))
|
||||
|
||||
def destroy(self):
|
||||
self.shutting_down = True
|
||||
self.child_monitor.shutdown_monitor()
|
||||
|
||||
@ -10,7 +10,7 @@ layout(std140) uniform CellRenderData {
|
||||
|
||||
int color1, color2;
|
||||
|
||||
uint xnum, ynum, cursor_x, cursor_y, cursor_w, url_xl, url_yl, url_xr, url_yr;
|
||||
uint xnum, ynum, cursor_x, cursor_y, cursor_w;
|
||||
|
||||
uint color_table[256];
|
||||
};
|
||||
@ -18,7 +18,7 @@ layout(std140) uniform CellRenderData {
|
||||
// Have to use fixed locations here as all variants of the cell program share the same VAO
|
||||
layout(location=0) in uvec3 colors;
|
||||
layout(location=1) in uvec4 sprite_coords;
|
||||
layout(location=2) in float is_selected;
|
||||
layout(location=2) in uint is_selected;
|
||||
|
||||
|
||||
|
||||
@ -108,11 +108,6 @@ vec3 choose_color(float q, vec3 a, vec3 b) {
|
||||
return mix(b, a, q);
|
||||
}
|
||||
|
||||
float in_range(uint x, uint y) {
|
||||
if (url_yl == y && url_xl <= x && x <= url_xr) return 1.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float is_cursor(uint x, uint y) {
|
||||
if (y == cursor_y && (x == cursor_x || x == cursor_w)) return 1.0;
|
||||
return 0.0;
|
||||
@ -159,9 +154,9 @@ void main() {
|
||||
uint resolved_fg = resolve_color(colors[fg_index], default_colors[fg_index]);
|
||||
foreground = color_to_vec(resolved_fg);
|
||||
// Selection
|
||||
foreground = choose_color(is_selected, color_to_vec(highlight_fg), foreground);
|
||||
foreground = choose_color(float(is_selected & ONE), color_to_vec(highlight_fg), foreground);
|
||||
// Underline and strike through (rendered via sprites)
|
||||
float in_url = in_range(c, r);
|
||||
float in_url = float((is_selected & TWO) >> 1);
|
||||
decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
|
||||
underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 2) & DECORATION_MASK, ZERO, ZERO));
|
||||
strike_pos = to_sprite_pos(pos, ((text_attrs >> 7) & STRIKE_MASK) * FOUR, ZERO, ZERO);
|
||||
@ -189,11 +184,11 @@ void main() {
|
||||
|
||||
#if defined(SPECIAL) || defined(SIMPLE)
|
||||
// Selection and cursor
|
||||
bg = choose_color(is_selected, color_to_vec(highlight_bg), bg);
|
||||
bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg);
|
||||
background = choose_color(cursor, color_to_vec(cursor_color), bg);
|
||||
#ifdef SPECIAL
|
||||
// bg_alpha should be 1 if cursor/selection otherwise 0
|
||||
bg_alpha = mix(0.0, 1.0, step(0.5, is_selected + cursor));
|
||||
bg_alpha = mix(0.0, 1.0, step(0.5, float(is_selected & ONE) + cursor));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -135,9 +135,9 @@ line_url_start_at(Line *self, index_type x) {
|
||||
}
|
||||
|
||||
index_type
|
||||
line_url_end_at(Line *self, index_type x) {
|
||||
line_url_end_at(Line *self, index_type x, bool check_short) {
|
||||
index_type ans = x;
|
||||
if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0;
|
||||
if (x >= self->xnum || (check_short && self->xnum <= MIN_URL_LEN + 3)) return 0;
|
||||
while (ans < self->xnum && is_url_char(self->cells[ans].ch)) ans++;
|
||||
ans--;
|
||||
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch)) ans--;
|
||||
@ -153,7 +153,7 @@ url_start_at(Line *self, PyObject *x) {
|
||||
static PyObject*
|
||||
url_end_at(Line *self, PyObject *x) {
|
||||
#define url_end_at_doc "url_end_at(x) -> Return the end cell number for a URL containing x or 0 if not found"
|
||||
return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, PyLong_AsUnsignedLong(x)));
|
||||
return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, PyLong_AsUnsignedLong(x), true));
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
@ -51,7 +51,7 @@ 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);
|
||||
index_type line_url_end_at(Line *self, index_type x, bool);
|
||||
index_type line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen);
|
||||
unsigned int line_length(Line *self);
|
||||
size_t cell_as_unicode(Cell *cell, bool include_cc, Py_UCS4 *buf, char_type);
|
||||
|
||||
@ -142,20 +142,33 @@ drag_scroll(Window *w, OSWindow *frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
extend_url(Screen *screen, Line *line, index_type *x, index_type *y) {
|
||||
while(true) {
|
||||
if (*x != line->xnum - 1) break;
|
||||
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);
|
||||
if (!new_x) break;
|
||||
*y += 1; *x = new_x;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
detect_url(Window *w, Screen *screen, unsigned int x, unsigned int y) {
|
||||
detect_url(Screen *screen, unsigned int x, unsigned int y) {
|
||||
bool has_url = false;
|
||||
index_type url_start, url_end = 0;
|
||||
Line *line = screen_visual_line(screen, y);
|
||||
if (line) {
|
||||
url_start = line_url_start_at(line, x);
|
||||
if (url_start < line->xnum) url_end = line_url_end_at(line, x);
|
||||
if (url_start < line->xnum) url_end = line_url_end_at(line, x, true);
|
||||
has_url = url_end > url_start;
|
||||
}
|
||||
if (has_url) {
|
||||
mouse_cursor_shape = HAND;
|
||||
screen_mark_url(screen, url_start, w->mouse_cell_y, url_end, w->mouse_cell_y);
|
||||
index_type y_extended = y;
|
||||
extend_url(screen, line, &url_end, &y_extended);
|
||||
screen_mark_url(screen, url_start, y, url_end, y_extended);
|
||||
} else {
|
||||
mouse_cursor_shape = BEAM;
|
||||
screen_mark_url(screen, 0, 0, 0, 0);
|
||||
@ -173,7 +186,7 @@ HANDLER(handle_move_event) {
|
||||
}
|
||||
if (!cell_for_pos(w, &x, &y)) return;
|
||||
Screen *screen = w->render_data.screen;
|
||||
detect_url(w, screen, x, y);
|
||||
detect_url(screen, x, y);
|
||||
bool mouse_cell_changed = x != w->mouse_cell_x || y != w->mouse_cell_y;
|
||||
w->mouse_cell_x = x; w->mouse_cell_y = y;
|
||||
bool handle_in_kitty = (
|
||||
@ -237,16 +250,8 @@ HANDLER(add_click) {
|
||||
|
||||
static inline void
|
||||
open_url(Window *w) {
|
||||
Line *line = screen_visual_line(w->render_data.screen, w->mouse_cell_y);
|
||||
if (line) {
|
||||
index_type start = line_url_start_at(line, w->mouse_cell_x);
|
||||
if (start < line->xnum) {
|
||||
index_type end = line_url_end_at(line, w->mouse_cell_x);
|
||||
if (end > start) {
|
||||
call_boss(open_url, "N", unicode_in_range(line, start, end + 1, true, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
Screen *screen = w->render_data.screen;
|
||||
screen_open_url(screen);
|
||||
}
|
||||
|
||||
HANDLER(handle_button_event) {
|
||||
|
||||
@ -180,6 +180,7 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
||||
self->is_dirty = true;
|
||||
self->selection = EMPTY_SELECTION;
|
||||
self->url_range = EMPTY_SELECTION;
|
||||
self->selection_updated_once = false;
|
||||
|
||||
// Ensure cursor is on the correct line
|
||||
self->cursor->x = 0;
|
||||
@ -1225,33 +1226,57 @@ visual_line_(Screen *self, index_type y) {
|
||||
return self->linebuf->line;
|
||||
}
|
||||
|
||||
void
|
||||
screen_apply_selection(Screen *self, void *address, size_t size) {
|
||||
#define start (self->last_rendered_selection_start)
|
||||
#define end (self->last_rendered_selection_end)
|
||||
float *data = address;
|
||||
memset(data, 0, size);
|
||||
selection_limits_(selection, &start, &end);
|
||||
self->last_selection_scrolled_by = self->scrolled_by;
|
||||
self->selection_updated_once = true;
|
||||
if (is_selection_empty(self, start.x, start.y, end.x, end.y)) { return; }
|
||||
for (index_type y = start.y; y <= end.y; y++) {
|
||||
static inline void
|
||||
apply_selection(Screen *self, uint8_t *data, SelectionBoundary *start, SelectionBoundary *end, uint8_t set_mask) {
|
||||
if (is_selection_empty(self, start->x, start->y, end->x, end->y)) return;
|
||||
for (index_type y = start->y; y <= end->y; y++) {
|
||||
Line *line = visual_line_(self, y);
|
||||
index_type xlimit = xlimit_for_line(line);
|
||||
if (y == end.y) xlimit = MIN(end.x + 1, xlimit);
|
||||
float *line_start = data + self->columns * y;
|
||||
for (index_type x = (y == start.y ? start.x : 0); x < xlimit; x++) line_start[x] = 1.0;
|
||||
if (y == end->y) xlimit = MIN(end->x + 1, xlimit);
|
||||
uint8_t *line_start = data + self->columns * y;
|
||||
for (index_type x = (y == start->y ? start->x : 0); x < xlimit; x++) line_start[x] |= set_mask;
|
||||
}
|
||||
#undef start
|
||||
#undef end
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
screen_url_range(Screen *self, uint32_t *data) {
|
||||
screen_apply_selection(Screen *self, void *address, size_t size) {
|
||||
memset(address, 0, size);
|
||||
self->last_selection_scrolled_by = self->scrolled_by;
|
||||
self->selection_updated_once = true;
|
||||
selection_limits_(selection, &self->last_rendered_selection_start, &self->last_rendered_selection_end);
|
||||
apply_selection(self, address, &self->last_rendered_selection_start, &self->last_rendered_selection_end, 1);
|
||||
selection_limits_(url_range, &self->last_rendered_url_start, &self->last_rendered_url_end);
|
||||
apply_selection(self, address, &self->last_rendered_url_start, &self->last_rendered_url_end, 2);
|
||||
}
|
||||
|
||||
static inline PyObject*
|
||||
text_for_range(Screen *self, SelectionBoundary start, SelectionBoundary end) {
|
||||
Py_ssize_t i = 0, num_of_lines = end.y - start.y + 1;
|
||||
PyObject *ans = PyTuple_New(num_of_lines);
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
for (index_type y = start.y; y <= end.y; y++, i++) {
|
||||
Line *line = visual_line_(self, y);
|
||||
index_type xlimit = xlimit_for_line(line);
|
||||
if (y == end.y) xlimit = MIN(end.x + 1, xlimit);
|
||||
index_type xstart = (y == start.y ? start.x : 0);
|
||||
char leading_char = i > 0 && !line->continued ? '\n' : 0;
|
||||
PyObject *text = unicode_in_range(line, xstart, xlimit, true, leading_char);
|
||||
if (text == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); }
|
||||
PyTuple_SET_ITEM(ans, i, text);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
bool
|
||||
screen_open_url(Screen *self) {
|
||||
SelectionBoundary start, end;
|
||||
selection_limits_(url_range, &start, &end);
|
||||
if (is_selection_empty(self, start.x, start.y, end.x, end.y)) { *(data + 1) = self->lines; *(data + 3) = self->lines; *data = self->columns; *(data + 2) = self->columns; }
|
||||
else { *data = start.x; *(data+1) = start.y; *(data + 2) = end.x; *(data + 3) = end.y; }
|
||||
if (is_selection_empty(self, start.x, start.y, end.x, end.y)) return false;
|
||||
PyObject *text = text_for_range(self, start, end);
|
||||
if (text) { call_boss(open_url_lines, "(O)", text); Py_CLEAR(text); }
|
||||
else PyErr_Print();
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
@ -1410,20 +1435,7 @@ text_for_selection(Screen *self) {
|
||||
SelectionBoundary start, end;
|
||||
selection_limits_(selection, &start, &end);
|
||||
if (is_selection_empty(self, start.x, start.y, end.x, end.y)) return PyTuple_New(0);
|
||||
Py_ssize_t i = 0, num_of_lines = end.y - start.y + 1;
|
||||
PyObject *ans = PyTuple_New(num_of_lines);
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
for (index_type y = start.y; y <= end.y; y++, i++) {
|
||||
Line *line = visual_line_(self, y);
|
||||
index_type xlimit = xlimit_for_line(line);
|
||||
if (y == end.y) xlimit = MIN(end.x + 1, xlimit);
|
||||
index_type xstart = (y == start.y ? start.x : 0);
|
||||
char leading_char = i > 0 && !line->continued ? '\n' : 0;
|
||||
PyObject *text = unicode_in_range(line, xstart, xlimit, true, leading_char);
|
||||
if (text == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); }
|
||||
PyTuple_SET_ITEM(ans, i, text);
|
||||
}
|
||||
return ans;
|
||||
return text_for_range(self, start, end);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1506,6 +1518,8 @@ screen_is_selection_dirty(Screen *self) {
|
||||
SelectionBoundary start, end;
|
||||
selection_limits_(selection, &start, &end);
|
||||
if (self->last_selection_scrolled_by != self->scrolled_by || start.x != self->last_rendered_selection_start.x || start.y != self->last_rendered_selection_start.y || end.x != self->last_rendered_selection_end.x || end.y != self->last_rendered_selection_end.y || !self->selection_updated_once) return true;
|
||||
selection_limits_(url_range, &start, &end);
|
||||
if (start.x != self->last_rendered_url_start.x || start.y != self->last_rendered_url_start.y || end.x != self->last_rendered_url_end.x || end.y != self->last_rendered_url_end.y) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ typedef struct {
|
||||
id_type window_id;
|
||||
uint32_t utf8_state, utf8_codepoint, *g0_charset, *g1_charset, *g_charset;
|
||||
Selection selection;
|
||||
SelectionBoundary last_rendered_selection_start, last_rendered_selection_end;
|
||||
SelectionBoundary last_rendered_selection_start, last_rendered_selection_end, last_rendered_url_start, last_rendered_url_end;
|
||||
Selection url_range;
|
||||
bool use_latin1, selection_updated_once, is_dirty, scroll_changed;
|
||||
Cursor *cursor;
|
||||
@ -130,9 +130,9 @@ void screen_update_selection(Screen *self, index_type x, index_type y, bool ende
|
||||
bool screen_history_scroll(Screen *self, int amt, bool upwards);
|
||||
Line* screen_visual_line(Screen *self, index_type y);
|
||||
unsigned long screen_current_char_width(Screen *self);
|
||||
void screen_url_range(Screen *self, uint32_t *);
|
||||
void screen_mark_url(Screen *self, index_type start_x, index_type start_y, index_type end_x, index_type end_y);
|
||||
void screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const uint8_t *payload);
|
||||
bool screen_open_url(Screen*);
|
||||
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
|
||||
DECLARE_CH_SCREEN_HANDLER(bell)
|
||||
DECLARE_CH_SCREEN_HANDLER(backspace)
|
||||
|
||||
@ -177,7 +177,7 @@ create_cell_vao() {
|
||||
A1(colors, 3, GL_UNSIGNED_INT, fg);
|
||||
|
||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||
A(is_selected, 1, GL_FLOAT, NULL, 0);
|
||||
A(is_selected, 1, GL_UNSIGNED_BYTE, NULL, 0);
|
||||
|
||||
size_t bufnum = add_buffer_to_vao(vao_idx, GL_UNIFORM_BUFFER);
|
||||
alloc_vao_buffer(vao_idx, cell_program_layouts[CELL_PROGRAM].render_data.size, bufnum, GL_STREAM_DRAW);
|
||||
@ -204,7 +204,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
|
||||
|
||||
GLint color1, color2;
|
||||
|
||||
GLuint xnum, ynum, cursor_x, cursor_y, cursor_w, url_xl, url_yl, url_xr, url_yr;
|
||||
GLuint xnum, ynum, cursor_x, cursor_y, cursor_w;
|
||||
};
|
||||
static struct CellRenderData *rd;
|
||||
|
||||
@ -222,7 +222,6 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
|
||||
rd->cursor_w = rd->cursor_x + MAX(1, screen_current_char_width(screen)) - 1;
|
||||
|
||||
rd->xnum = screen->columns; rd->ynum = screen->lines;
|
||||
screen_url_range(screen, &rd->url_xl);
|
||||
|
||||
rd->xstart = xstart; rd->ystart = ystart; rd->dx = dx; rd->dy = dy;
|
||||
unsigned int x, y, z;
|
||||
@ -255,7 +254,7 @@ cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloa
|
||||
}
|
||||
|
||||
if (screen_is_selection_dirty(screen)) {
|
||||
sz = sizeof(GLfloat) * screen->lines * screen->columns;
|
||||
sz = screen->lines * screen->columns;
|
||||
address = alloc_and_map_vao_buffer(vao_idx, sz, selection_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY);
|
||||
screen_apply_selection(screen, address, sz);
|
||||
unmap_vao_buffer(vao_idx, selection_buffer); address = NULL;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user