diff --git a/kitty/mouse.c b/kitty/mouse.c index 0d2c35fd7..d4949617a 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -174,14 +174,14 @@ update_drag(bool from_button, Window *w, bool is_release, int modifiers) { global_state.active_drag_in_window = 0; w->last_drag_scroll_at = 0; if (screen->selection.in_progress) - screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, true); + screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, w->mouse_pos.in_left_half_of_cell, true); } else { global_state.active_drag_in_window = w->id; - screen_start_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, modifiers == (int)OPT(rectangle_select_modifiers) || modifiers == ((int)OPT(rectangle_select_modifiers) | (int)OPT(terminal_select_modifiers)), EXTEND_CELL); + screen_start_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, w->mouse_pos.in_left_half_of_cell, modifiers == (int)OPT(rectangle_select_modifiers) || modifiers == ((int)OPT(rectangle_select_modifiers) | (int)OPT(terminal_select_modifiers)), EXTEND_CELL); } } else if (screen->selection.in_progress) { - screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, false); + screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, w->mouse_pos.in_left_half_of_cell, false); } } @@ -218,7 +218,7 @@ static inline void extend_selection(Window *w) { Screen *screen = w->render_data.screen; if (screen_has_selection(screen)) { - screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, true); + screen_update_selection(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y, w->mouse_pos.in_left_half_of_cell, true); } } @@ -335,21 +335,22 @@ multi_click(Window *w, unsigned int count) { bool found_selection = false; SelectionExtendMode mode = EXTEND_CELL; unsigned int y1 = w->mouse_pos.cell_y, y2 = w->mouse_pos.cell_y; + bool start_in_left_half = w->mouse_pos.in_left_half_of_cell, end_in_left_half = w->mouse_pos.in_left_half_of_cell; switch(count) { case 2: - found_selection = screen_selection_range_for_word(screen, w->mouse_pos.cell_x, &y1, &y2, &start, &end, true); + found_selection = screen_selection_range_for_word(screen, w->mouse_pos.cell_x, &y1, &y2, &start, &end, &start_in_left_half, &end_in_left_half, true); mode = EXTEND_WORD; break; case 3: - found_selection = screen_selection_range_for_line(screen, w->mouse_pos.cell_y, &start, &end); + found_selection = screen_selection_range_for_line(screen, w->mouse_pos.cell_y, &start, &end, &start_in_left_half, &end_in_left_half); mode = EXTEND_LINE; break; default: break; } if (found_selection) { - screen_start_selection(screen, start, y1, false, mode); - screen_update_selection(screen, end, y2, false); + screen_start_selection(screen, start, y1, start_in_left_half, false, mode); + screen_update_selection(screen, end, y2, end_in_left_half, false); } } diff --git a/kitty/screen.c b/kitty/screen.c index d25542c86..134efcf00 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1996,6 +1996,15 @@ cursor_up(Screen *self, PyObject *args) { Py_RETURN_NONE; } +static PyObject* +update_selection(Screen *self, PyObject *args) { + unsigned int x, y; + int in_left_half_of_cell = 0, ended = 1; + if (!PyArg_ParseTuple(args, "II|pp", &x, &y, &in_left_half_of_cell, &ended)) return NULL; + screen_update_selection(self, x, y, in_left_half_of_cell, ended); + Py_RETURN_NONE; +} + WRAP0x(index) WRAP0(reverse_index) WRAP0(reset) @@ -2008,14 +2017,13 @@ WRAP0(carriage_return) WRAP2(resize, 1, 1) WRAP2(set_margins, 1, 1) WRAP0(rescale_images) -WRAP2B(update_selection) static PyObject* start_selection(Screen *self, PyObject *args) { unsigned int x, y; int rectangle_select = 0, extend_mode = EXTEND_CELL; if (!PyArg_ParseTuple(args, "II|pi", &x, &y, &rectangle_select, &extend_mode)) return NULL; - screen_start_selection(self, x, y, rectangle_select, extend_mode); + screen_start_selection(self, x, y, false, rectangle_select, extend_mode); Py_RETURN_NONE; } @@ -2045,13 +2053,15 @@ text_for_selection(Screen *self, PyObject *a UNUSED) { } bool -screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end) { +screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end, bool* start_in_left_half, bool* end_in_left_half) { if (y >= self->lines) { return false; } Line *line = visual_line_(self, y); index_type xlimit = line->xnum, xstart = 0; while (xlimit > 0 && CHAR_IS_BLANK(line->cpu_cells[xlimit - 1].ch)) xlimit--; while (xstart < xlimit && CHAR_IS_BLANK(line->cpu_cells[xstart].ch)) xstart++; *start = xstart; *end = xlimit > 0 ? xlimit - 1 : 0; + *start_in_left_half = true; + *end_in_left_half = false; return true; } @@ -2064,8 +2074,9 @@ is_opt_word_char(char_type ch) { } bool -screen_selection_range_for_word(Screen *self, index_type x, index_type *y1, index_type *y2, index_type *s, index_type *e, bool initial_selection) { +screen_selection_range_for_word(Screen *self, index_type x, index_type *y1, index_type *y2, index_type *s, index_type *e, bool *start_in_left_half, bool *end_in_left_half, bool initial_selection) { if (*y1 >= self->lines || x >= self->columns) return false; + *start_in_left_half = true; *end_in_left_half = false; index_type start, end; Line *line = visual_line_(self, *y1); *y2 = *y1; @@ -2145,10 +2156,10 @@ screen_is_selection_dirty(Screen *self) { } void -screen_start_selection(Screen *self, index_type x, index_type y, bool rectangle_select, SelectionExtendMode extend_mode) { +screen_start_selection(Screen *self, index_type x, index_type y, bool in_left_half_of_cell, bool rectangle_select, SelectionExtendMode extend_mode) { #define A(attr, val) self->selection.attr = val; A(start_x, x); A(end_x, x); A(start_y, y); A(end_y, y); A(start_scrolled_by, self->scrolled_by); A(end_scrolled_by, self->scrolled_by); - A(in_progress, true); A(rectangle_select, rectangle_select); A(extend_mode, extend_mode); + A(in_progress, true); A(rectangle_select, rectangle_select); A(extend_mode, extend_mode); A(start_in_left_half, in_left_half_of_cell); A(end_in_left_half, in_left_half_of_cell); #undef A } @@ -2156,13 +2167,15 @@ void screen_mark_url(Screen *self, index_type start_x, index_type start_y, index_type end_x, index_type end_y) { #define A(attr, val) self->url_range.attr = val; A(start_x, start_x); A(end_x, end_x); A(start_y, start_y); A(end_y, end_y); A(start_scrolled_by, self->scrolled_by); A(end_scrolled_by, self->scrolled_by); + A(start_in_left_half, true); A(end_in_left_half, false); #undef A } void -screen_update_selection(Screen *self, index_type x, index_type y, bool ended) { +screen_update_selection(Screen *self, index_type x, index_type y, bool in_left_half_of_cell, bool ended) { index_type orig_x = self->selection.end_x, orig_y = self->selection.end_y, orig_scrolled_by = self->selection.end_scrolled_by; self->selection.end_x = x; self->selection.end_y = y; self->selection.end_scrolled_by = self->scrolled_by; + self->selection.end_in_left_half = in_left_half_of_cell; if (ended) self->selection.in_progress = false; index_type start, end; bool found = false; @@ -2170,19 +2183,19 @@ screen_update_selection(Screen *self, index_type x, index_type y, bool ended) { switch(self->selection.extend_mode) { case EXTEND_WORD: { index_type y1 = y, y2; - found = screen_selection_range_for_word(self, x, &y1, &y2, &start, &end, false); + found = screen_selection_range_for_word(self, x, &y1, &y2, &start, &end, &self->selection.start_in_left_half, &self->selection.end_in_left_half, false); if (found) { if (extending_leftwards) { self->selection.end_x = start; self->selection.end_y = y1; y1 = self->selection.start_y; - found = screen_selection_range_for_word(self, self->selection.start_x, &y1, &y2, &start, &end, false); + found = screen_selection_range_for_word(self, self->selection.start_x, &y1, &y2, &start, &end, &self->selection.start_in_left_half, &self->selection.end_in_left_half, false); if (found) { self->selection.start_x = end; self->selection.start_y = y2; } } else { self->selection.end_x = end; self->selection.end_y = y2; y1 = self->selection.start_y; - found = screen_selection_range_for_word(self, self->selection.start_x, &y1, &y2, &start, &end, false); + found = screen_selection_range_for_word(self, self->selection.start_x, &y1, &y2, &start, &end, &self->selection.start_in_left_half, &self->selection.end_in_left_half, false); if (found) { self->selection.start_x = start; self->selection.start_y = y1; } @@ -2199,7 +2212,7 @@ screen_update_selection(Screen *self, index_type x, index_type y, bool ended) { while(top_line > 0 && visual_line_(self, top_line)->continued) top_line--; while(bottom_line < self->lines - 1 && visual_line_(self, bottom_line + 1)->continued) bottom_line++; bool multiline = self->selection.end_y != self->selection.start_y; - found = screen_selection_range_for_line(self, top_line, &start, &end); + found = screen_selection_range_for_line(self, top_line, &start, &end, &self->selection.start_in_left_half, &self->selection.end_in_left_half); if (found) { if (extending_leftwards) { self->selection.end_x = multiline ? 0 : start; self->selection.end_y = top_line; @@ -2207,7 +2220,7 @@ screen_update_selection(Screen *self, index_type x, index_type y, bool ended) { self->selection.start_x = multiline ? 0 : start; self->selection.start_y = top_line; } } - found = screen_selection_range_for_line(self, bottom_line, &start, &end); + found = screen_selection_range_for_line(self, bottom_line, &start, &end, &self->selection.start_in_left_half, &self->selection.end_in_left_half); if (found) { if (extending_leftwards) { self->selection.start_x = end; self->selection.start_y = bottom_line; diff --git a/kitty/screen.h b/kitty/screen.h index 307eb47b8..1ce56647d 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -29,6 +29,7 @@ typedef struct { unsigned int start_x, start_y, start_scrolled_by, end_x, end_y, end_scrolled_by; bool in_progress, rectangle_select; SelectionExtendMode extend_mode; + bool start_in_left_half, end_in_left_half; } Selection; #define SAVEPOINTS_SZ 256 @@ -181,10 +182,10 @@ bool screen_has_selection(Screen*); bool screen_invert_colors(Screen *self); void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE, bool cursor_has_moved); bool screen_is_cursor_visible(Screen *self); -bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end); -bool screen_selection_range_for_word(Screen *self, index_type x, index_type *, index_type *, index_type *start, index_type *end, bool); -void screen_start_selection(Screen *self, index_type x, index_type y, bool, SelectionExtendMode); -void screen_update_selection(Screen *self, index_type x, index_type y, bool ended); +bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end, bool*, bool*); +bool screen_selection_range_for_word(Screen *self, index_type x, index_type *, index_type *, index_type *start, index_type *end, bool*, bool*, bool); +void screen_start_selection(Screen *self, index_type x, index_type y, bool, bool, SelectionExtendMode); +void screen_update_selection(Screen *self, index_type x, index_type y, bool in_left_half, bool ended); 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); diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 38c81a53a..7c92146e0 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -421,7 +421,7 @@ class TestScreen(BaseTest): s.carriage_return(), s.linefeed() s.draw(str(i) * s.columns) s.start_selection(0, 0, False) - s.update_selection(4, 4, True) + s.update_selection(4, 4) expected = ('55555', '\n66666', '\n77777', '\n88888', '\n99999') self.ae(s.text_for_selection(), expected) s.scroll(2, True)