Fix double-click word selection not extending beyond viewport edges
Add continue_word_upwards_scrollback() and continue_word_downwards_offscreen() to extend word selection beyond viewport boundaries, mirroring the line selection fix. Add tests for word selection wrapping into scrollback and below viewport. Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/58191e45-d925-4996-b0d5-8b1bd4baa8d5 Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
This commit is contained in:
parent
82bf8923cc
commit
18fb31b416
3 changed files with 69 additions and 1 deletions
|
|
@ -217,7 +217,7 @@ Detailed list of changes
|
|||
|
||||
- Fix dragging of splits layout borders sometimes moving in the wrong direction or having no effect (:pull:`9447`)
|
||||
|
||||
- Fix triple-click line selection not extending wrapped lines beyond the bottom edge of the viewport
|
||||
- Fix triple-click line selection and double-click word selection not extending wrapped lines beyond the edges of the viewport
|
||||
|
||||
- Password input in kittens: hide the cursor and display a blinking 🔒 at the end of typed characters to make it visually clear the user is entering a password
|
||||
|
||||
|
|
|
|||
|
|
@ -5406,6 +5406,36 @@ continue_line_downwards_offscreen(Screen *self, int bottom_line, SelectionBounda
|
|||
return num_offscreen;
|
||||
}
|
||||
|
||||
static index_type
|
||||
continue_word_upwards_scrollback(Screen *self, int range_y, index_type *start_x) {
|
||||
index_type num_in_scrollback = 0;
|
||||
Line *line = NULL;
|
||||
while (*start_x == 0 && range_line_is_continued(self, range_y) && (line = checked_range_line(self, range_y - 1))) {
|
||||
if (!is_char_ok_for_word_extension(line, self->columns - 1, false)) break;
|
||||
range_y--;
|
||||
num_in_scrollback++;
|
||||
index_type s = self->columns - 1;
|
||||
while (s > 0 && is_char_ok_for_word_extension(line, s - 1, false)) s--;
|
||||
*start_x = s;
|
||||
}
|
||||
return num_in_scrollback;
|
||||
}
|
||||
|
||||
static index_type
|
||||
continue_word_downwards_offscreen(Screen *self, int range_y, index_type *end_x) {
|
||||
index_type num_offscreen = 0;
|
||||
Line *line = NULL;
|
||||
while (*end_x >= self->columns - 1 && (line = checked_range_line(self, range_y + 1)) && range_line_is_continued(self, range_y + 1)) {
|
||||
if (!is_char_ok_for_word_extension(line, 0, true)) break;
|
||||
range_y++;
|
||||
num_offscreen++;
|
||||
index_type e = 0;
|
||||
while (e < self->columns - 1 && is_char_ok_for_word_extension(line, e + 1, true)) e++;
|
||||
*end_x = e;
|
||||
}
|
||||
return num_offscreen;
|
||||
}
|
||||
|
||||
static int
|
||||
clamp_selection_input_to_multicell(Screen *self, const Selection *s, index_type x, index_type y, bool in_left_half_of_cell) {
|
||||
int delta = 0;
|
||||
|
|
@ -5498,6 +5528,25 @@ do_update_selection(Screen *self, Selection *s, index_type x, index_type y, bool
|
|||
}
|
||||
if (s->adjusting_start || adjust_both_ends) s->start_scrolled_by = self->scrolled_by;
|
||||
if (!s->adjusting_start || adjust_both_ends) s->end_scrolled_by = self->scrolled_by;
|
||||
// extend word into scrollback if needed
|
||||
if (start.y == 0 && self->linebuf == self->main_linebuf &&
|
||||
(adjust_both_ends || adjusted_boundary_is_before)) {
|
||||
index_type num_in_scrollback = continue_word_upwards_scrollback(self, 0, &start.x);
|
||||
if (num_in_scrollback) {
|
||||
s->start_scrolled_by += num_in_scrollback;
|
||||
s->start.x = start.x;
|
||||
}
|
||||
}
|
||||
// extend word below viewport if needed
|
||||
if (end.y >= self->lines - 1 && self->scrolled_by > 0 && self->linebuf == self->main_linebuf &&
|
||||
(adjust_both_ends || !adjusted_boundary_is_before)) {
|
||||
int range_bottom = (int)end.y - (int)self->scrolled_by;
|
||||
index_type num_below_viewport = continue_word_downwards_offscreen(self, range_bottom, &end.x);
|
||||
if (num_below_viewport) {
|
||||
s->end_scrolled_by -= num_below_viewport;
|
||||
s->end.x = end.x;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*a = s->input_current;
|
||||
if (s->adjusting_start) s->start_scrolled_by = self->scrolled_by; else s->end_scrolled_by = self->scrolled_by;
|
||||
|
|
|
|||
|
|
@ -282,6 +282,25 @@ def scroll(x=0, y=0, up=True):
|
|||
self.ae(sel(), '678\nABCDE12345')
|
||||
s.scroll(100, False)
|
||||
|
||||
# word select for wrapped words in scrollback
|
||||
s.reset()
|
||||
s.draw('abcde12345')
|
||||
s.linefeed(), s.carriage_return()
|
||||
s.draw(('X' * s.columns) * (s.lines-1))
|
||||
multi_click(x=1)
|
||||
self.ae(sel(), 'abcde12345')
|
||||
|
||||
# word select for wrapped words below viewport
|
||||
s.reset()
|
||||
s.scroll(100, False)
|
||||
s.draw(('X' * s.columns) * (s.lines - 1))
|
||||
s.linefeed(), s.carriage_return()
|
||||
s.draw('abcde12345')
|
||||
s.scroll(1, True)
|
||||
multi_click(x=1, y=s.lines - 1)
|
||||
self.ae(sel(), 'abcde12345')
|
||||
s.scroll(100, False)
|
||||
|
||||
# Rectangle select
|
||||
init()
|
||||
press(x=1, y=1, modifiers=GLFW_MOD_ALT | GLFW_MOD_CONTROL)
|
||||
|
|
|
|||
Loading…
Reference in a new issue