diff --git a/commands.c b/commands.c index a3e48458..0b8329b7 100644 --- a/commands.c +++ b/commands.c @@ -8,6 +8,7 @@ #include "selection.h" #include "terminal.h" #include "url-mode.h" +#include "vimode.h" #include "util.h" void @@ -47,6 +48,7 @@ cmd_scrollback_up(struct terminal *term, int rows) selection_view_up(term, new_view); term->grid->view = new_view; + vimode_view_up(term, 0); if (rows < term->rows) { term_damage_scroll( @@ -101,6 +103,7 @@ cmd_scrollback_down(struct terminal *term, int rows) selection_view_down(term, new_view); term->grid->view = new_view; + vimode_view_down(term, 0); if (rows < term->rows) { term_damage_scroll( diff --git a/input.c b/input.c index d2d19e17..a63ddf06 100644 --- a/input.c +++ b/input.c @@ -501,11 +501,17 @@ execute_binding(struct seat *seat, struct terminal *term, term_theme_toggle(term); return true; - case BIND_ACTION_SELECT_BEGIN: - selection_start( - term, (struct coord){.row = seat->mouse.row, .col = seat->mouse.col}, SELECTION_CHAR_WISE, false); + case BIND_ACTION_SELECT_BEGIN: { + struct coord const point = {.row = seat->mouse.row, .col = seat->mouse.col}; + selection_start(term, point, SELECTION_CHAR_WISE, false); + // TODO (kociap): Single click causes selection to start + // instead of just repositioning the cursor. + vimode_mouse_selection_begin(term, point, VI_MODE_VISUAL); return true; + } + // TODO (kociap): Add vimode selection to the remaining selection + // bindings. case BIND_ACTION_SELECT_BEGIN_BLOCK: selection_start( term, (struct coord){.row = seat->mouse.row, .col = seat->mouse.col}, SELECTION_BLOCK, false); @@ -2566,6 +2572,8 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, break; case TERM_SURF_GRID: + // TODO (kociap): unsure what this does and when it + // triggers. selection_finalize(seat, old_moused, seat->pointer.serial); break; @@ -2721,7 +2729,7 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, xassert(seat->mouse.row >= 0 && seat->mouse.row < term->rows); /* Cursor has moved to a different cell since last time */ - bool cursor_is_on_new_cell + const bool cursor_is_on_new_cell = old_col != seat->mouse.col || old_row != seat->mouse.row; if (cursor_is_on_new_cell) { @@ -2746,47 +2754,49 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, if (auto_scroll_direction == SELECTION_SCROLL_NOT) selection_stop_scroll_timer(term); - /* Update selection */ - if (!term->vimode.active) { - if (auto_scroll_direction != SELECTION_SCROLL_NOT) { - /* - * Start 'selection auto-scrolling' - * - * The speed of the scrolling is proportional to the - * distance between the mouse and the grid; the - * further away the mouse is, the faster we scroll. - * - * Note that the speed is measured in 'intervals (in - * ns) between each timed scroll of a single line'. - * - * Thus, the further away the mouse is, the smaller - * interval value we use. - */ + if (auto_scroll_direction != SELECTION_SCROLL_NOT) { + /* + * Start 'selection auto-scrolling' + * + * The speed of the scrolling is proportional to the + * distance between the mouse and the grid; the + * further away the mouse is, the faster we scroll. + * + * Note that the speed is measured in 'intervals (in + * ns) between each timed scroll of a single line'. + * + * Thus, the further away the mouse is, the smaller + * interval value we use. + */ - int distance = auto_scroll_direction == SELECTION_SCROLL_UP - ? term->margins.top - y - : y - (term->height - term->margins.bottom); + int distance = auto_scroll_direction == SELECTION_SCROLL_UP + ? term->margins.top - y + : y - (term->height - term->margins.bottom); - xassert(distance > 0); - int divisor - = distance * term->conf->scrollback.multiplier / term->scale; + xassert(distance > 0); + int divisor + = distance * term->conf->scrollback.multiplier / term->scale; - selection_start_scroll_timer( - term, 400000000 / (divisor > 0 ? divisor : 1), - auto_scroll_direction, seat->mouse.col); - } - - if (term->selection.ongoing && - (cursor_is_on_new_cell || - (term->selection.coords.end.row < 0 && - seat->mouse.x >= term->margins.left && - seat->mouse.x < term->width - term->margins.right && - seat->mouse.y >= term->margins.top && - seat->mouse.y < term->height - term->margins.bottom))) - { - selection_update(term, (struct coord){.row = seat->mouse.row, .col = seat->mouse.col}); - } + selection_start_scroll_timer( + term, 400000000 / (divisor > 0 ? divisor : 1), + auto_scroll_direction, seat->mouse.col); } + const bool mouse_in_bounds = + seat->mouse.x >= term->margins.left && + seat->mouse.x < term->width - term->margins.right && + seat->mouse.y >= term->margins.top && + seat->mouse.y < term->height - term->margins.bottom; + const bool selection_ongoing = + (!term->vimode.active && term->selection.ongoing) || + term->vimode.selection.mouse_button_pressed; + if (selection_ongoing && (cursor_is_on_new_cell || + (term->selection.coords.end.row < 0 && mouse_in_bounds))) { + struct coord point = {.row = seat->mouse.row, + .col = seat->mouse.col}; + selection_update(term, point); + vimode_mouse_move(term, point); + } + /* Send mouse event to client application */ if (!term_mouse_grabbed(term, seat) && @@ -3210,9 +3220,6 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, break; case TERM_SURF_GRID: { - // TODO (kociap): unsure whether mouse should cancel vimode - // or work in tandem. - vimode_cancel(term); urls_reset(term); bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0; @@ -3248,7 +3255,11 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, } case WL_POINTER_BUTTON_STATE_RELEASED: - selection_finalize(seat, term, serial); + if (!term->vimode.active) { + selection_finalize(seat, term, serial); + } else { + vimode_mouse_selection_end(term); + } if (send_to_client && !term_mouse_grabbed(term, seat)) { term_mouse_up( diff --git a/selection.c b/selection.c index b8dec4d7..101ee969 100644 --- a/selection.c +++ b/selection.c @@ -741,7 +741,7 @@ selection_start(struct terminal *term, struct coord const start, kind == SELECTION_WORD_WISE ? "word-wise" : kind == SELECTION_LINE_WISE ? "line-wise" : kind == SELECTION_BLOCK ? "block" : "", - row, col); + start.row, start.col); term->selection.kind = kind; term->selection.ongoing = true; diff --git a/terminal.c b/terminal.c index 1c651a37..080e0854 100644 --- a/terminal.c +++ b/terminal.c @@ -3094,6 +3094,7 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows /* Cancel selections that cannot be scrolled */ if (unlikely(term->selection.coords.end.row >= 0)) { + // TODO (kociap): selection cancelled on scroll. /* * Selection is (partly) inside either the top or bottom * scrolling regions, or on (at least one) of the lines diff --git a/terminal.h b/terminal.h index e583717a..2f3dcae0 100644 --- a/terminal.h +++ b/terminal.h @@ -634,6 +634,7 @@ struct terminal { struct coord cursor; struct { + bool mouse_button_pressed; struct coord start; } selection; diff --git a/vimode.c b/vimode.c index 5e8018fc..62041351 100644 --- a/vimode.c +++ b/vimode.c @@ -460,6 +460,32 @@ void vimode_cancel(struct terminal *term) render_refresh(term); } +void vimode_view_up(struct terminal *term, int const delta) +{ + if (!term->vimode.active) { + return; + } + + damage_cursor_cell(term); + term->vimode.cursor.row += delta; + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); +} + +void vimode_view_down(struct terminal *const term, int const delta) +{ + if (!term->vimode.active) { + return; + } + + damage_cursor_cell(term); + term->vimode.cursor.row -= delta; + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); +} + static ssize_t matches_cell(const struct terminal *term, const struct cell *cell, char32_t const *const buf, size_t const len, size_t search_ofs) @@ -819,19 +845,6 @@ void vimode_search_add_chars(struct terminal *term, const char *src, on_search_string_updated(term); } -void vimode_view_down(struct terminal *const term, int const delta) -{ - if (!term->vimode.active) { - return; - } - - LOG_DBG("VIMODE VIEW DOWN [delta=%d]", delta); - damage_cursor_cell(term); - term->vimode.cursor.row -= delta; - clip_cursor_to_view(term); - update_highlights(term); -} - enum c32_class { CLASS_BLANK, CLASS_PUNCTUATION, @@ -1738,3 +1751,36 @@ void vimode_input(struct seat *seat, struct terminal *term, } } } + +void vimode_mouse_selection_begin(struct terminal *const term, + struct coord const point, + enum vi_mode const vmode) +{ + if (term->vimode.active == false) { + return; + } + + if (!is_mode_visual(vmode)) { + return; + } + + term->vimode.selection.mouse_button_pressed = true; + term->vimode.selection.start = point; + term->vimode.mode = vmode; + damage_cursor_cell(term); + term->vimode.cursor = cursor_from_view_relative(term, point); + damage_cursor_cell(term); +} + +void vimode_mouse_selection_end(struct terminal *const term) +{ + term->vimode.selection.mouse_button_pressed = false; +} + +void vimode_mouse_move(struct terminal *const term, struct coord const point) +{ + damage_cursor_cell(term); + term->vimode.cursor = cursor_from_view_relative(term, point); + damage_cursor_cell(term); + update_selection(term); +} diff --git a/vimode.h b/vimode.h index 696d75dd..a3b7ea68 100644 --- a/vimode.h +++ b/vimode.h @@ -7,11 +7,11 @@ void vimode_begin(struct terminal *term); -/* vimode_search_begin - * - * Enter search mode directly without needing to interact with the - * vimode first. Enters vimode as well. - */ +// vimode_search_begin +// +// Enter search mode directly without needing to interact with the +// vimode first. Enters vimode as well. +// void vimode_search_begin(struct terminal *term); void vimode_cancel(struct terminal *term); @@ -20,6 +20,27 @@ void vimode_input(struct seat *seat, struct terminal *term, xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed, const xkb_keysym_t *raw_syms, size_t raw_count, uint32_t serial); + +// vimode_mouse_selection_begin +// +// Enter visual selection mode guided by a mouse. The position of the +// vimode cursor is updated to match the position of the mouse. +// +// Does nothing if vimode is not active. +// +// Parameters: +// point - view-relative position of the mouse. +// vmode - the visual mode to be started. If a non-visual mode is +// passed, the function does nothing. +// +void vimode_mouse_selection_begin(struct terminal *term, struct coord point, + enum vi_mode vmode); +void vimode_mouse_selection_end(struct terminal *term); +void vimode_mouse_move(struct terminal *term, struct coord point); + +void vimode_view_up(struct terminal *term, int new_view); +void vimode_view_down(struct terminal *term, int new_view); + void vimode_search_add_chars(struct terminal *term, const char *text, size_t len); @@ -34,5 +55,3 @@ struct search_match_iterator search_matches_new_iter(struct terminal *term, char32_t const *const buf, size_t const len); struct range search_matches_next(struct search_match_iterator *iter); - -void vimode_view_down(struct terminal *term, int delta);