diff --git a/docs/changelog.rst b/docs/changelog.rst index 84b15ac2c..3509e0659 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,9 @@ To update |kitty|, :doc:`follow the instructions `. - Support infinite length ligatures (:iss:`3504`) +- Add a configurable mouse action to select from the clicked point to the end of the line. + (:iss:`3585`) + - Unicode input kitten: Fix a regression in 0.20.0 that broke keyboard handling when the num lock or caps lock modifiers were engaged. (:iss:`3587`) @@ -708,7 +711,7 @@ To update |kitty|, :doc:`follow the instructions `. beam and underline cursors (:iss:`2337` and :pull:`2342`) - When the application running in the terminal grabs the mouse, pass middle - clicks to the application unless :opt:`terminal_select_modifiers` are + clicks to the application unless `terminal_select_modifiers` are pressed (:iss:`2368`) - A new ``copy_and_clear_or_interrupt`` function (:iss:`2403`) @@ -988,7 +991,7 @@ To update |kitty|, :doc:`follow the instructions `. the mouse pointer shape when the terminal programs grabs the pointer (:iss:`1808`) -- Add an option :opt:`terminal_select_modifiers` to control which modifiers +- Add an option `terminal_select_modifiers` to control which modifiers are used to override mouse selection even when a terminal application has grabbed the mouse (:iss:`1774`) diff --git a/kitty/config.py b/kitty/config.py index 51667cd11..aef545fa9 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -336,6 +336,7 @@ def mouse_selection(func: str, rest: str) -> FuncArgsType: 'rectangle': defines.MOUSE_SELECTION_RECTANGLE, 'word': defines.MOUSE_SELECTION_WORD, 'line': defines.MOUSE_SELECTION_LINE, + 'line_from_point': defines.MOUSE_SELECTION_LINE_FROM_POINT, } setattr(mouse_selection, 'code_map', cmap) return func, [cmap[rest]] diff --git a/kitty/config_data.py b/kitty/config_data.py index 8dc5ddab1..0f1630a9f 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -670,7 +670,11 @@ for grabbed in (False, True): m('start_rectangle_selection' + name_s, mods_p + 'ctrl+alt+left', 'press', modes, 'mouse_selection rectangle', _('Start selecting text in a rectangle') + ts) m('select_word' + name_s, mods_p + 'left', 'doublepress', modes, 'mouse_selection word', _('Select a word') + ts) - m('select_line' + name_s, mods_p + 'left', 'triplepress', modes, 'mouse_selection line', _('Select a line') + ts) + line_desc = '' + if not grabbed: + line_desc = _('Select the entire line. If you would rather select from the clicked' + ' point to the end of the line, use ``line_at_point`` instead of ``line`` above') + m('select_line' + name_s, mods_p + 'left', 'triplepress', modes, 'mouse_selection line', _('Select a line') + ts, line_desc) # }}} # }}} diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 835dacd44..537a48688 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -15,6 +15,7 @@ MOUSE_SELECTION_EXTEND: int MOUSE_SELECTION_NORMAL: int MOUSE_SELECTION_WORD: int MOUSE_SELECTION_RECTANGLE: int +MOUSE_SELECTION_LINE_FROM_POINT: int KITTY_VCS_REV: str NO_CLOSE_REQUESTED: int IMPERATIVE_CLOSE_REQUESTED: int diff --git a/kitty/mouse.c b/kitty/mouse.c index 7c20c3df9..271a688d9 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -580,6 +580,7 @@ typedef enum MouseSelectionType { MOUSE_SELECTION_RECTANGLE, MOUSE_SELECTION_WORD, MOUSE_SELECTION_LINE, + MOUSE_SELECTION_LINE_FROM_POINT, } MouseSelectionType; @@ -607,6 +608,9 @@ mouse_selection(Window *w, int code, int button) { case MOUSE_SELECTION_LINE: if (screen_selection_range_for_line(screen, w->mouse_pos.cell_y, &start, &end)) S(EXTEND_LINE); break; + case MOUSE_SELECTION_LINE_FROM_POINT: + if (screen_selection_range_for_line(screen, w->mouse_pos.cell_y, &start, &end) && end > w->mouse_pos.cell_x) S(EXTEND_LINE_FROM_POINT); + break; case MOUSE_SELECTION_EXTEND: extend_selection(w, false); break; @@ -821,6 +825,7 @@ init_mouse(PyObject *module) { PyModule_AddIntMacro(module, MOUSE_SELECTION_RECTANGLE); PyModule_AddIntMacro(module, MOUSE_SELECTION_WORD); PyModule_AddIntMacro(module, MOUSE_SELECTION_LINE); + PyModule_AddIntMacro(module, MOUSE_SELECTION_LINE_FROM_POINT); if (PyModule_AddFunctions(module, module_methods) != 0) return false; return true; } diff --git a/kitty/screen.c b/kitty/screen.c index 6a2dd0d80..87c15ae6d 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -2671,6 +2671,7 @@ screen_update_selection(Screen *self, index_type x, index_type y, bool in_left_h if (found_at_end) { b->x = end.x; b->y = end.y; b->in_left_half_of_cell = false; } break; } + case EXTEND_LINE_FROM_POINT: case EXTEND_LINE: { index_type top_line, bottom_line; if (start_extended_selection || y == s->start.y) { @@ -2691,7 +2692,11 @@ screen_update_selection(Screen *self, index_type x, index_type y, bool in_left_h } if (screen_selection_range_for_line(self, top_line, &start.x, &start.y) && screen_selection_range_for_line(self, bottom_line, &end.x, &end.y)) { bool multiline = top_line != bottom_line; - a->x = multiline ? 0 : start.x; a->y = top_line; a->in_left_half_of_cell = true; + if (!multiline && self->selections.extend_mode == EXTEND_LINE_FROM_POINT) { + if (x > end.y) break; + a->x = x; + } else a->x = multiline ? 0 : start.x; + a->y = top_line; a->in_left_half_of_cell = true; b->x = end.y; b->y = bottom_line; b->in_left_half_of_cell = false; } break; diff --git a/kitty/screen.h b/kitty/screen.h index a865cab81..25a836301 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -25,7 +25,7 @@ typedef struct { bool in_left_half_of_cell; } SelectionBoundary; -typedef enum SelectionExtendModes { EXTEND_CELL, EXTEND_WORD, EXTEND_LINE } SelectionExtendMode; +typedef enum SelectionExtendModes { EXTEND_CELL, EXTEND_WORD, EXTEND_LINE, EXTEND_LINE_FROM_POINT } SelectionExtendMode; typedef struct { index_type x, x_limit;