From 210325d8aa841d464ef230875f35362e3f3155a8 Mon Sep 17 00:00:00 2001 From: Piotr Kocia Date: Mon, 31 Mar 2025 23:31:44 +0200 Subject: [PATCH] reformat --- vimode.c | 2458 ++++++++++++++++++++++++++++-------------------------- vimode.h | 8 +- 2 files changed, 1269 insertions(+), 1197 deletions(-) diff --git a/vimode.c b/vimode.c index 4c6f4ff7..aa2778ee 100644 --- a/vimode.c +++ b/vimode.c @@ -21,151 +21,166 @@ // TODO (kociap): jump list? // TODO (kociap): WORD motions. -static bool is_mode_visual(enum vi_mode const mode) { - return mode == VI_MODE_VISUAL || mode == VI_MODE_VLINE || - mode == VI_MODE_VBLOCK; +static bool is_mode_visual(enum vi_mode const mode) +{ + return mode == VI_MODE_VISUAL || mode == VI_MODE_VLINE || + mode == VI_MODE_VBLOCK; } -static enum selection_kind -selection_kind_from_vi_mode(enum vi_mode const mode) { - switch (mode) { - case VI_MODE_VISUAL: - return SELECTION_CHAR_WISE; - case VI_MODE_VLINE: - return SELECTION_LINE_WISE; - case VI_MODE_VBLOCK: - return SELECTION_BLOCK; - default: - BUG("invalid vi mode"); - return SELECTION_NONE; - } +static enum selection_kind selection_kind_from_vi_mode(enum vi_mode const mode) +{ + switch (mode) { + case VI_MODE_VISUAL: + return SELECTION_CHAR_WISE; + case VI_MODE_VLINE: + return SELECTION_LINE_WISE; + case VI_MODE_VBLOCK: + return SELECTION_BLOCK; + default: + BUG("invalid vi mode"); + return SELECTION_NONE; + } } -static enum search_direction invert_direction(enum search_direction direction) { - return direction == SEARCH_FORWARD ? SEARCH_BACKWARD : SEARCH_FORWARD; +static enum search_direction invert_direction(enum search_direction direction) +{ + return direction == SEARCH_FORWARD ? SEARCH_BACKWARD : SEARCH_FORWARD; } static struct coord cursor_to_view_relative(struct terminal *const term, - struct coord cursor) { - cursor.row += term->grid->offset; - cursor.row -= term->grid->view; - return cursor; + struct coord cursor) +{ + cursor.row += term->grid->offset; + cursor.row -= term->grid->view; + return cursor; } static struct coord cursor_from_view_relative(struct terminal *const term, - struct coord coord) { - coord.row += term->grid->view; - coord.row -= term->grid->offset; - return coord; + struct coord coord) +{ + coord.row += term->grid->view; + coord.row -= term->grid->offset; + return coord; } -static int cursor_to_scrollback_relative(struct terminal *const term, int row) { - row = grid_row_abs_to_sb(term->grid, term->rows, - grid_row_absolute(term->grid, row)); - return row; +static int cursor_to_scrollback_relative(struct terminal *const term, int row) +{ + row = grid_row_abs_to_sb(term->grid, term->rows, + grid_row_absolute(term->grid, row)); + return row; } -static int cursor_from_scrollback_relative(struct terminal *const term, - int row) { - row = grid_row_sb_to_abs(term->grid, term->rows, row); - row -= term->grid->offset; - return row; +static int cursor_from_scrollback_relative(struct terminal *const term, int row) +{ + row = grid_row_sb_to_abs(term->grid, term->rows, row); + row -= term->grid->offset; + return row; } -static int view_to_scrollback_relative(struct terminal *const term) { - return grid_row_abs_to_sb(term->grid, term->rows, term->grid->view); +static int view_to_scrollback_relative(struct terminal *const term) +{ + return grid_row_abs_to_sb(term->grid, term->rows, term->grid->view); } static struct coord delta_cursor_in_abs_coord(struct terminal *const term, - struct coord const coord) { - int const location = grid_row_abs_to_sb(term->grid, term->rows, coord.row); - int const cursor = - cursor_to_scrollback_relative(term, term->vimode.cursor.row); - return (struct coord){ - .row = location - cursor, - .col = coord.col - term->vimode.cursor.col, - }; + struct coord const coord) +{ + int const location = grid_row_abs_to_sb(term->grid, term->rows, coord.row); + int const cursor = + cursor_to_scrollback_relative(term, term->vimode.cursor.row); + return (struct coord){ + .row = location - cursor, + .col = coord.col - term->vimode.cursor.col, + }; } -static void damage_cursor_cell(struct terminal *const term) { - struct coord const cursor = - cursor_to_view_relative(term, term->vimode.cursor); - term_damage_cell_in_view(term, cursor.row, cursor.col); - render_refresh(term); -} - -static void clip_cursor_to_view(struct terminal *const term) { - damage_cursor_cell(term); - int cursor_row = cursor_to_scrollback_relative(term, term->vimode.cursor.row); - int const view_row = view_to_scrollback_relative(term); - if (cursor_row < view_row) { - // Cursor is located above the current view. Move it to the top of - // the view. - cursor_row = view_row; - } else if (cursor_row - view_row >= term->rows) { - // Cursor is below the current view. Move it to the bottom of the - // view. - cursor_row = view_row + term->rows - 1; - } - term->vimode.cursor.row = cursor_from_scrollback_relative(term, cursor_row); - LOG_DBG("CLIP CURSOR (%d, %d)\n", term->vimode.cursor.row, - term->vimode.cursor.col); - damage_cursor_cell(term); - render_refresh(term); -} - -static void center_view_on_cursor(struct terminal *const term) { - int const cursor = - cursor_to_scrollback_relative(term, term->vimode.cursor.row); - int const current_view = view_to_scrollback_relative(term); - int const half_viewport = term->rows / 2; - int const delta = (cursor - half_viewport) - current_view; - LOG_DBG("CENTER VIEW [cursor=(%d, %d); current_view=%d; half_viewport=%d; " - "delta=%d]", - cursor, term->vimode.cursor.col, current_view, half_viewport, delta); - if (delta < 0) { - cmd_scrollback_up(term, -delta); - } else if (delta > 0) { - cmd_scrollback_down(term, delta); - } -} - -static void update_selection(struct terminal *const term) { - enum vi_mode const mode = term->vimode.mode; - if (is_mode_visual(mode)) { +static void damage_cursor_cell(struct terminal *const term) +{ struct coord const cursor = cursor_to_view_relative(term, term->vimode.cursor); - selection_update(term, cursor); - LOG_DBG( - "UPDATE SELECTION [view=%d; cursor=(%d, %d); selection.end=(%d,%d)]", - term->grid->view, cursor.row, cursor.col, - term->selection.coords.end.row, term->selection.coords.end.col); - } + term_damage_cell_in_view(term, cursor.row, cursor.col); + render_refresh(term); } -static void damage_highlights(struct terminal *const term) { - struct highlight_location const *location = term->vimode.highlights; - int const offset = term->grid->offset; - while (location != NULL) { - struct coord const start = location->range.start; - struct coord const end = location->range.end; - for (int col = start.col; col <= end.col; col += 1) { - term_damage_cell(term, start.row - offset, col); +static void clip_cursor_to_view(struct terminal *const term) +{ + damage_cursor_cell(term); + int cursor_row = + cursor_to_scrollback_relative(term, term->vimode.cursor.row); + int const view_row = view_to_scrollback_relative(term); + if (cursor_row < view_row) { + // Cursor is located above the current view. Move it to the top of + // the view. + cursor_row = view_row; + } else if (cursor_row - view_row >= term->rows) { + // Cursor is below the current view. Move it to the bottom of the + // view. + cursor_row = view_row + term->rows - 1; } - location = location->next; - } - render_refresh(term); + term->vimode.cursor.row = cursor_from_scrollback_relative(term, cursor_row); + LOG_DBG("CLIP CURSOR (%d, %d)\n", term->vimode.cursor.row, + term->vimode.cursor.col); + damage_cursor_cell(term); + render_refresh(term); } -static void clear_highlights(struct terminal *const term) { - damage_highlights(term); - struct highlight_location const *location = term->vimode.highlights; - while (location != NULL) { - struct highlight_location const *next = location->next; - free((void *)location); - location = next; - } - term->vimode.highlights = NULL; +static void center_view_on_cursor(struct terminal *const term) +{ + int const cursor = + cursor_to_scrollback_relative(term, term->vimode.cursor.row); + int const current_view = view_to_scrollback_relative(term); + int const half_viewport = term->rows / 2; + int const delta = (cursor - half_viewport) - current_view; + LOG_DBG("CENTER VIEW [cursor=(%d, %d); current_view=%d; half_viewport=%d; " + "delta=%d]", + cursor, term->vimode.cursor.col, current_view, half_viewport, + delta); + if (delta < 0) { + cmd_scrollback_up(term, -delta); + } else if (delta > 0) { + cmd_scrollback_down(term, delta); + } +} + +static void update_selection(struct terminal *const term) +{ + enum vi_mode const mode = term->vimode.mode; + if (is_mode_visual(mode)) { + struct coord const cursor = + cursor_to_view_relative(term, term->vimode.cursor); + selection_update(term, cursor); + LOG_DBG("UPDATE SELECTION [view=%d; cursor=(%d, %d); " + "selection.end=(%d,%d)]", + term->grid->view, cursor.row, cursor.col, + term->selection.coords.end.row, term->selection.coords.end.col); + } +} + +static void damage_highlights(struct terminal *const term) +{ + struct highlight_location const *location = term->vimode.highlights; + int const offset = term->grid->offset; + while (location != NULL) { + struct coord const start = location->range.start; + struct coord const end = location->range.end; + for (int col = start.col; col <= end.col; col += 1) { + term_damage_cell(term, start.row - offset, col); + } + location = location->next; + } + render_refresh(term); +} + +static void clear_highlights(struct terminal *const term) +{ + damage_highlights(term); + struct highlight_location const *location = term->vimode.highlights; + while (location != NULL) { + struct highlight_location const *next = location->next; + free((void *)location); + location = next; + } + term->vimode.highlights = NULL; } // calculate_highlight_regions @@ -177,56 +192,58 @@ static void clear_highlights(struct terminal *const term) { // The regions are split so that each one spans at most // a single line. The regions are in absolute row coordinates. // -static void calculate_highlight_regions(struct terminal *const term) { - char32_t const *search_buf = term->vimode.search.buf; - size_t search_len = term->vimode.search.len; - if (search_buf == NULL) { - search_buf = term->vimode.confirmed_search.buf; - search_len = term->vimode.confirmed_search.len; - } - - struct highlight_location *start = NULL; - struct highlight_location *current = NULL; - struct search_match_iterator iter = - search_matches_new_iter(term, search_buf, search_len); - for (struct range match = search_matches_next(&iter); match.start.row >= 0; - match = search_matches_next(&iter)) { - int r = match.start.row; - int start_col = match.start.col; - int const end_row = match.end.row; - - while (true) { - const int end_col = r == end_row ? match.end.col : term->cols - 1; - struct highlight_location *location = - xmalloc(sizeof(struct highlight_location)); - location->next = NULL; - location->range = (struct range){ - .start.row = r, - .start.col = start_col, - .end.row = end_row, - .end.col = end_col, - }; - r += 1; - start_col = 0; - if (start != NULL) { - current->next = location; - current = location; - } else { - start = location; - current = location; - } - if (r > end_row) { - break; - } +static void calculate_highlight_regions(struct terminal *const term) +{ + char32_t const *search_buf = term->vimode.search.buf; + size_t search_len = term->vimode.search.len; + if (search_buf == NULL) { + search_buf = term->vimode.confirmed_search.buf; + search_len = term->vimode.confirmed_search.len; } - } - term->vimode.highlights = start; + + struct highlight_location *start = NULL; + struct highlight_location *current = NULL; + struct search_match_iterator iter = + search_matches_new_iter(term, search_buf, search_len); + for (struct range match = search_matches_next(&iter); match.start.row >= 0; + match = search_matches_next(&iter)) { + int r = match.start.row; + int start_col = match.start.col; + int const end_row = match.end.row; + + while (true) { + const int end_col = r == end_row ? match.end.col : term->cols - 1; + struct highlight_location *location = + xmalloc(sizeof(struct highlight_location)); + location->next = NULL; + location->range = (struct range){ + .start.row = r, + .start.col = start_col, + .end.row = end_row, + .end.col = end_col, + }; + r += 1; + start_col = 0; + if (start != NULL) { + current->next = location; + current = location; + } else { + start = location; + current = location; + } + if (r > end_row) { + break; + } + } + } + term->vimode.highlights = start; } -static void update_highlights(struct terminal *const term) { - clear_highlights(term); - calculate_highlight_regions(term); - damage_highlights(term); +static void update_highlights(struct terminal *const term) +{ + clear_highlights(term); + calculate_highlight_regions(term); + damage_highlights(term); } /* @@ -240,186 +257,197 @@ static void update_highlights(struct terminal *const term) { * row, and if it is NULL, we move the viewport *backward* until the * last row is non-NULL. */ -static int ensure_view_is_allocated(struct terminal *term, int new_view) { - struct grid *grid = term->grid; - int view_end = (new_view + term->rows - 1) & (grid->num_rows - 1); +static int ensure_view_is_allocated(struct terminal *term, int new_view) +{ + struct grid *grid = term->grid; + int view_end = (new_view + term->rows - 1) & (grid->num_rows - 1); - if (grid->rows[new_view] == NULL) { - while (grid->rows[new_view] == NULL) - new_view = (new_view + 1) & (grid->num_rows - 1); - } - - else if (grid->rows[view_end] == NULL) { - while (grid->rows[view_end] == NULL) { - new_view--; - if (new_view < 0) - new_view += grid->num_rows; - view_end = (new_view + term->rows - 1) & (grid->num_rows - 1); + if (grid->rows[new_view] == NULL) { + while (grid->rows[new_view] == NULL) + new_view = (new_view + 1) & (grid->num_rows - 1); + } + + else if (grid->rows[view_end] == NULL) { + while (grid->rows[view_end] == NULL) { + new_view--; + if (new_view < 0) + new_view += grid->num_rows; + view_end = (new_view + term->rows - 1) & (grid->num_rows - 1); + } } - } #if defined(_DEBUG) - for (size_t r = 0; r < term->rows; r++) - xassert(grid->rows[(new_view + r) & (grid->num_rows - 1)] != NULL); + for (size_t r = 0; r < term->rows; r++) + xassert(grid->rows[(new_view + r) & (grid->num_rows - 1)] != NULL); #endif - return new_view; + return new_view; } -static bool search_ensure_size(struct terminal *term, size_t wanted_size) { - struct vimode_search *const search = &term->vimode.search; - while (wanted_size >= search->sz) { - size_t new_sz = search->sz == 0 ? 64 : search->sz * 2; - char32_t *new_buf = realloc(search->buf, new_sz * sizeof(search->buf[0])); +static bool search_ensure_size(struct terminal *term, size_t wanted_size) +{ + struct vimode_search *const search = &term->vimode.search; + while (wanted_size >= search->sz) { + size_t new_sz = search->sz == 0 ? 64 : search->sz * 2; + char32_t *new_buf = + realloc(search->buf, new_sz * sizeof(search->buf[0])); - if (new_buf == NULL) { - LOG_ERRNO("failed to resize search buffer"); - return false; + if (new_buf == NULL) { + LOG_ERRNO("failed to resize search buffer"); + return false; + } + + search->buf = new_buf; + search->sz = new_sz; } - search->buf = new_buf; - search->sz = new_sz; - } - - return true; + return true; } static void start_search(struct terminal *term, - enum search_direction const direction) { - if (term->vimode.searching) { - return; - } + enum search_direction const direction) +{ + if (term->vimode.searching) { + return; + } - LOG_DBG("VIMODE-SEARCH BEGIN"); + LOG_DBG("VIMODE-SEARCH BEGIN"); - const struct grid *grid = term->grid; - term->vimode.search.original_view = grid->view; - term->vimode.search.original_cursor = term->vimode.cursor; - term->vimode.search.len = 0; - term->vimode.search.sz = 64; - term->vimode.search.buf = - xmalloc(term->vimode.search.sz * sizeof(term->vimode.search.buf[0])); - term->vimode.search.buf[0] = U'\0'; - term->vimode.search.direction = direction; - term->vimode.search.match = (struct coord){-1, -1}; - term->vimode.search.match_len = 0; - term->vimode.searching = true; + const struct grid *grid = term->grid; + term->vimode.search.original_view = grid->view; + term->vimode.search.original_cursor = term->vimode.cursor; + term->vimode.search.len = 0; + term->vimode.search.sz = 64; + term->vimode.search.buf = + xmalloc(term->vimode.search.sz * sizeof(term->vimode.search.buf[0])); + term->vimode.search.buf[0] = U'\0'; + term->vimode.search.direction = direction; + term->vimode.search.match = (struct coord){-1, -1}; + term->vimode.search.match_len = 0; + term->vimode.searching = true; - /* On-demand instantiate wayland surface */ - bool ret = - wayl_win_subsurface_new(term->window, &term->window->search, false); - xassert(ret); + /* On-demand instantiate wayland surface */ + bool ret = + wayl_win_subsurface_new(term->window, &term->window->search, false); + xassert(ret); - render_refresh_vimode_search_box(term); + render_refresh_vimode_search_box(term); } -static void restore_pre_search_state(struct terminal *const term) { - damage_cursor_cell(term); - term->vimode.cursor = term->vimode.search.original_cursor; - damage_cursor_cell(term); - term->grid->view = - ensure_view_is_allocated(term, term->vimode.search.original_view); - term_damage_view(term); - render_refresh(term); - update_selection(term); +static void restore_pre_search_state(struct terminal *const term) +{ + damage_cursor_cell(term); + term->vimode.cursor = term->vimode.search.original_cursor; + damage_cursor_cell(term); + term->grid->view = + ensure_view_is_allocated(term, term->vimode.search.original_view); + term_damage_view(term); + render_refresh(term); + update_selection(term); } static void cancel_search(struct terminal *const term, - bool const restore_original) { - if (!term->vimode.searching) { - return; - } + bool const restore_original) +{ + if (!term->vimode.searching) { + return; + } - wayl_win_subsurface_destroy(&term->window->search); - clear_highlights(term); - term->vimode.searching = false; - struct vimode_search *const search = &term->vimode.search; - if (restore_original) { - restore_pre_search_state(term); - } + wayl_win_subsurface_destroy(&term->window->search); + clear_highlights(term); + term->vimode.searching = false; + struct vimode_search *const search = &term->vimode.search; + if (restore_original) { + restore_pre_search_state(term); + } - free(search->buf); - search->buf = NULL; - search->len = search->sz = 0; - search->cursor = 0; - search->original_view = 0; - search->match = (struct coord){-1, -1}; - search->match_len = 0; - term->render.search_glyph_offset = 0; + free(search->buf); + search->buf = NULL; + search->len = search->sz = 0; + search->cursor = 0; + search->original_view = 0; + search->match = (struct coord){-1, -1}; + search->match_len = 0; + term->render.search_glyph_offset = 0; } -static void confirm_search(struct terminal *const term) { - if (term->vimode.confirmed_search.buf != NULL) { +static void confirm_search(struct terminal *const term) +{ + if (term->vimode.confirmed_search.buf != NULL) { + free(term->vimode.confirmed_search.buf); + } + term->vimode.confirmed_search.buf = term->vimode.search.buf; + term->vimode.confirmed_search.len = term->vimode.search.len; + term->vimode.confirmed_search.direction = term->vimode.search.direction; + term->vimode.search.buf = NULL; + cancel_search(term, false); +} + +void vimode_search_begin(struct terminal *term) +{ + vimode_begin(term); + start_search(term, SEARCH_FORWARD); + term_xcursor_update(term); +} + +void vimode_begin(struct terminal *term) +{ + LOG_DBG("VIMODE BEGIN"); + + vimode_cancel(term); + + term->vimode.cursor = term->grid->cursor.point; + // From a user's perspective, it is reasonable to expect that the + // mode will launch at the exact position in the scrollback they are + // currently viewing, thus we move the cursor into the view. + clip_cursor_to_view(term); + + /* Reset IME state */ + if (term_ime_is_enabled(term)) { + term_ime_disable(term); + term_ime_enable(term); + } + + term->vimode.active = true; + + term_xcursor_update(term); +} + +void vimode_cancel(struct terminal *term) +{ + if (!term->vimode.active) { + return; + } + + LOG_DBG("VIMODE CANCEL"); + + cancel_search(term, false); free(term->vimode.confirmed_search.buf); - } - term->vimode.confirmed_search.buf = term->vimode.search.buf; - term->vimode.confirmed_search.len = term->vimode.search.len; - term->vimode.confirmed_search.direction = term->vimode.search.direction; - term->vimode.search.buf = NULL; - cancel_search(term, false); -} + term->vimode.confirmed_search.buf = NULL; + term->vimode.confirmed_search.len = 0; + term->vimode.confirmed_search.direction = SEARCH_FORWARD; + clear_highlights(term); + selection_cancel(term); -void vimode_search_begin(struct terminal *term) { - vimode_begin(term); - start_search(term, SEARCH_FORWARD); - term_xcursor_update(term); -} + term->vimode.active = false; -void vimode_begin(struct terminal *term) { - LOG_DBG("VIMODE BEGIN"); + /* Reset IME state */ + if (term_ime_is_enabled(term)) { + term_ime_disable(term); + term_ime_enable(term); + } - vimode_cancel(term); - - term->vimode.cursor = term->grid->cursor.point; - // From a user's perspective, it is reasonable to expect that the - // mode will launch at the exact position in the scrollback they are - // currently viewing, thus we move the cursor into the view. - clip_cursor_to_view(term); - - /* Reset IME state */ - if (term_ime_is_enabled(term)) { - term_ime_disable(term); - term_ime_enable(term); - } - - term->vimode.active = true; - - term_xcursor_update(term); -} - -void vimode_cancel(struct terminal *term) { - if (!term->vimode.active) { - return; - } - - LOG_DBG("VIMODE CANCEL"); - - cancel_search(term, false); - free(term->vimode.confirmed_search.buf); - term->vimode.confirmed_search.buf = NULL; - term->vimode.confirmed_search.len = 0; - term->vimode.confirmed_search.direction = SEARCH_FORWARD; - clear_highlights(term); - selection_cancel(term); - - term->vimode.active = false; - - /* Reset IME state */ - if (term_ime_is_enabled(term)) { - term_ime_disable(term); - term_ime_enable(term); - } - - struct grid *const grid = term->grid; - grid->view = grid->offset; - term_damage_view(term); - term_xcursor_update(term); - render_refresh(term); + struct grid *const grid = term->grid; + grid->view = grid->offset; + term_damage_view(term); + term_xcursor_update(term); + render_refresh(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) { + size_t const len, size_t search_ofs) +{ assert(search_ofs < len); char32_t base = cell->wc; @@ -446,308 +474,318 @@ static ssize_t matches_cell(const struct terminal *term, } } - return composed != NULL ? composed->count : 1; + return composed != NULL ? composed->count : 1; } static bool find_next(struct terminal *term, char32_t const *const buf, size_t const len, enum search_direction direction, struct coord abs_start, struct coord abs_end, - struct range *match) { + struct range *match) +{ #define ROW_DEC(_r) ((_r) = ((_r) - 1 + grid->num_rows) & (grid->num_rows - 1)) #define ROW_INC(_r) ((_r) = ((_r) + 1) & (grid->num_rows - 1)) - struct grid *grid = term->grid; - const bool backward = direction != SEARCH_FORWARD; + struct grid *grid = term->grid; + const bool backward = direction != SEARCH_FORWARD; - LOG_DBG("%s: start: %dx%d, end: %dx%d", backward ? "backward" : "forward", - abs_start.row, abs_start.col, abs_end.row, abs_end.col); + LOG_DBG("%s: start: %dx%d, end: %dx%d", backward ? "backward" : "forward", + abs_start.row, abs_start.col, abs_end.row, abs_end.col); - xassert(abs_start.row >= 0); - xassert(abs_start.row < grid->num_rows); - xassert(abs_start.col >= 0); - xassert(abs_start.col < term->cols); + xassert(abs_start.row >= 0); + xassert(abs_start.row < grid->num_rows); + xassert(abs_start.col >= 0); + xassert(abs_start.col < term->cols); - xassert(abs_end.row >= 0); - xassert(abs_end.row < grid->num_rows); - xassert(abs_end.col >= 0); - xassert(abs_end.col < term->cols); + xassert(abs_end.row >= 0); + xassert(abs_end.row < grid->num_rows); + xassert(abs_end.col >= 0); + xassert(abs_end.col < term->cols); - for (int match_start_row = abs_start.row, match_start_col = abs_start.col;; - backward ? ROW_DEC(match_start_row) : ROW_INC(match_start_row)) { + for (int match_start_row = abs_start.row, match_start_col = abs_start.col;; + backward ? ROW_DEC(match_start_row) : ROW_INC(match_start_row)) { - const struct row *row = grid->rows[match_start_row]; - if (row == NULL) { - if (match_start_row == abs_end.row) - break; - continue; - } - - for (; backward ? match_start_col >= 0 : match_start_col < term->cols; - backward ? match_start_col-- : match_start_col++) { - if (matches_cell(term, &row->cells[match_start_col], buf, len, 0) < 0) { - if (match_start_row == abs_end.row && match_start_col == abs_end.col) { - break; + const struct row *row = grid->rows[match_start_row]; + if (row == NULL) { + if (match_start_row == abs_end.row) + break; + continue; } - continue; - } - /* - * Got a match on the first letter. Now we'll see if the - * rest of the search buffer matches. - */ + for (; backward ? match_start_col >= 0 : match_start_col < term->cols; + backward ? match_start_col-- : match_start_col++) { + if (matches_cell(term, &row->cells[match_start_col], buf, len, 0) < + 0) { + if (match_start_row == abs_end.row && + match_start_col == abs_end.col) { + break; + } + continue; + } - LOG_DBG("search: initial match at row=%d, col=%d", match_start_row, - match_start_col); + /* + * Got a match on the first letter. Now we'll see if the + * rest of the search buffer matches. + */ - int match_end_row = match_start_row; - int match_end_col = match_start_col; - const struct row *match_row = row; - size_t match_len = 0; + LOG_DBG("search: initial match at row=%d, col=%d", match_start_row, + match_start_col); - for (size_t i = 0; i < len;) { - if (match_end_col >= term->cols) { - ROW_INC(match_end_row); - match_end_col = 0; + int match_end_row = match_start_row; + int match_end_col = match_start_col; + const struct row *match_row = row; + size_t match_len = 0; - match_row = grid->rows[match_end_row]; - if (match_row == NULL) + for (size_t i = 0; i < len;) { + if (match_end_col >= term->cols) { + ROW_INC(match_end_row); + match_end_col = 0; + + match_row = grid->rows[match_end_row]; + if (match_row == NULL) + break; + } + + if (match_row->cells[match_end_col].wc >= CELL_SPACER) { + match_end_col++; + continue; + } + + ssize_t additional_chars = matches_cell( + term, &match_row->cells[match_end_col], buf, len, i); + if (additional_chars < 0) + break; + + i += additional_chars; + match_len += additional_chars; + match_end_col++; + + while (match_end_col < term->cols && + match_row->cells[match_end_col].wc > CELL_SPACER) { + match_end_col++; + } + } + + if (match_len != len) { + /* Didn't match (completely) */ + + if (match_start_row == abs_end.row && + match_start_col == abs_end.col) { + break; + } + + continue; + } + + *match = (struct range){ + .start = {match_start_col, match_start_row}, + .end = {match_end_col - 1, match_end_row}, + }; + + return true; + } + + if (match_start_row == abs_end.row && match_start_col == abs_end.col) break; - } - if (match_row->cells[match_end_col].wc >= CELL_SPACER) { - match_end_col++; - continue; - } - - ssize_t additional_chars = - matches_cell(term, &match_row->cells[match_end_col], buf, len, i); - if (additional_chars < 0) - break; - - i += additional_chars; - match_len += additional_chars; - match_end_col++; - - while (match_end_col < term->cols && - match_row->cells[match_end_col].wc > CELL_SPACER) { - match_end_col++; - } - } - - if (match_len != len) { - /* Didn't match (completely) */ - - if (match_start_row == abs_end.row && match_start_col == abs_end.col) { - break; - } - - continue; - } - - *match = (struct range){ - .start = {match_start_col, match_start_row}, - .end = {match_end_col - 1, match_end_row}, - }; - - return true; + match_start_col = backward ? term->cols - 1 : 0; } - if (match_start_row == abs_end.row && match_start_col == abs_end.col) - break; - - match_start_col = backward ? term->cols - 1 : 0; - } - - return false; + return false; #undef ROW_DEC } static bool find_next_from_cursor(struct terminal *const term, char32_t *const buf, size_t const len, enum search_direction const direction, - struct range *const match) { - if (len == 0 || buf == NULL) { - return false; - } - - struct grid *grid = term->grid; - - struct coord start = { - .row = grid_row_absolute(grid, term->vimode.cursor.row), - .col = term->vimode.cursor.col, - }; - - // Step 1 character in the direction we are searching so that we do - // not repeatedly match the same location. - switch (direction) { - case SEARCH_FORWARD: - start.col += 1; - if (start.col >= term->cols) { - start.col = 0; - start.row++; - start.row &= grid->num_rows - 1; + struct range *const match) +{ + if (len == 0 || buf == NULL) { + return false; } - break; - case SEARCH_BACKWARD: - start.col -= 1; - if (start.col < 0) { - start.col = term->cols - 1; - start.row += grid->num_rows - 1; - start.row &= grid->num_rows - 1; + struct grid *grid = term->grid; + + struct coord start = { + .row = grid_row_absolute(grid, term->vimode.cursor.row), + .col = term->vimode.cursor.col, + }; + + // Step 1 character in the direction we are searching so that we do + // not repeatedly match the same location. + switch (direction) { + case SEARCH_FORWARD: + start.col += 1; + if (start.col >= term->cols) { + start.col = 0; + start.row++; + start.row &= grid->num_rows - 1; + } + break; + + case SEARCH_BACKWARD: + start.col -= 1; + if (start.col < 0) { + start.col = term->cols - 1; + start.row += grid->num_rows - 1; + start.row &= grid->num_rows - 1; + } + break; } - break; - } - xassert(start.row >= 0 && start.col >= 0); + xassert(start.row >= 0 && start.col >= 0); - struct coord end = start; - switch (direction) { - case SEARCH_FORWARD: - /* Search forward, until we reach the cell *before* current start */ - end.col -= 1; - if (end.col < 0) { - end.col = term->cols - 1; - end.row += grid->num_rows - 1; - end.row &= grid->num_rows - 1; + struct coord end = start; + switch (direction) { + case SEARCH_FORWARD: + /* Search forward, until we reach the cell *before* current start */ + end.col -= 1; + if (end.col < 0) { + end.col = term->cols - 1; + end.row += grid->num_rows - 1; + end.row &= grid->num_rows - 1; + } + break; + + case SEARCH_BACKWARD: + /* Search backwards, until we reach the cell *after* current start */ + end.col += 1; + if (end.col >= term->cols) { + end.col = 0; + end.row += 1; + end.row &= grid->num_rows - 1; + } + break; } - break; - case SEARCH_BACKWARD: - /* Search backwards, until we reach the cell *after* current start */ - end.col += 1; - if (end.col >= term->cols) { - end.col = 0; - end.row += 1; - end.row &= grid->num_rows - 1; - } - break; - } - - return find_next(term, buf, len, direction, start, end, match); + return find_next(term, buf, len, direction, start, end, match); } struct search_match_iterator search_matches_new_iter(struct terminal *const term, char32_t const *const buf, - size_t const len) { - return (struct search_match_iterator){ - .term = term, - .start = {0, 0}, - .buf = buf, - .len = len, - }; + size_t const len) +{ + return (struct search_match_iterator){ + .term = term, + .start = {0, 0}, + .buf = buf, + .len = len, + }; } -struct range search_matches_next(struct search_match_iterator *iter) { - struct terminal *term = iter->term; - struct grid *grid = term->grid; - if (iter->buf == NULL || iter->len == 0 || iter->start.row >= term->rows) { - iter->start.row = -1; - iter->start.col = -1; - return (struct range){{-1, -1}, {-1, -1}}; - } +struct range search_matches_next(struct search_match_iterator *iter) +{ + struct terminal *term = iter->term; + struct grid *grid = term->grid; + if (iter->buf == NULL || iter->len == 0 || iter->start.row >= term->rows) { + iter->start.row = -1; + iter->start.col = -1; + return (struct range){{-1, -1}, {-1, -1}}; + } - xassert(iter->start.row >= 0); - xassert(iter->start.row < term->rows); - xassert(iter->start.col >= 0); - xassert(iter->start.col < term->cols); + xassert(iter->start.row >= 0); + xassert(iter->start.row < term->rows); + xassert(iter->start.col >= 0); + xassert(iter->start.col < term->cols); - struct coord abs_start = iter->start; - abs_start.row = grid_row_absolute_in_view(grid, abs_start.row); + struct coord abs_start = iter->start; + abs_start.row = grid_row_absolute_in_view(grid, abs_start.row); - struct coord abs_end = {term->cols - 1, - grid_row_absolute_in_view(grid, term->rows - 1)}; + struct coord abs_end = {term->cols - 1, + grid_row_absolute_in_view(grid, term->rows - 1)}; - /* BUG: matches *starting* outside the view, but ending *inside*, aren't - * matched */ - struct range match; - bool found = find_next(term, iter->buf, iter->len, SEARCH_FORWARD, abs_start, - abs_end, &match); - if (!found) { - iter->start.row = -1; - iter->start.col = -1; - return (struct range){{-1, -1}, {-1, -1}}; - } + /* BUG: matches *starting* outside the view, but ending *inside*, aren't + * matched */ + struct range match; + bool found = find_next(term, iter->buf, iter->len, SEARCH_FORWARD, + abs_start, abs_end, &match); + if (!found) { + iter->start.row = -1; + iter->start.col = -1; + return (struct range){{-1, -1}, {-1, -1}}; + } - LOG_DBG("match at (absolute coordinates) %dx%d-%dx%d", match.start.row, - match.start.col, match.end.row, match.end.col); + LOG_DBG("match at (absolute coordinates) %dx%d-%dx%d", match.start.row, + match.start.col, match.end.row, match.end.col); - /* Assert match end comes *after* the match start */ - xassert( - match.end.row > match.start.row || - (match.end.row == match.start.row && match.end.col >= match.start.col)); + /* Assert match end comes *after* the match start */ + xassert( + match.end.row > match.start.row || + (match.end.row == match.start.row && match.end.col >= match.start.col)); - /* Assert the match starts at, or after, the iterator position */ - xassert( - match.start.row > abs_start.row || - (match.start.row == abs_start.row && match.start.col >= abs_start.col)); + /* Assert the match starts at, or after, the iterator position */ + xassert( + match.start.row > abs_start.row || + (match.start.row == abs_start.row && match.start.col >= abs_start.col)); - /* Continue at next column, next time */ - iter->start.row += match.start.row - abs_start.row; - iter->start.col = match.start.col + 1; + /* Continue at next column, next time */ + iter->start.row += match.start.row - abs_start.row; + iter->start.col = match.start.col + 1; - if (iter->start.col >= term->cols) { - iter->start.col = 0; - iter->start.row += 1; /* Overflow is caught in next iteration */ - } + if (iter->start.col >= term->cols) { + iter->start.col = 0; + iter->start.row += 1; /* Overflow is caught in next iteration */ + } - xassert(iter->start.row >= 0); - xassert(iter->start.row <= term->rows); - xassert(iter->start.col >= 0); - xassert(iter->start.col < term->cols); - return match; + xassert(iter->start.row >= 0); + xassert(iter->start.row <= term->rows); + xassert(iter->start.col >= 0); + xassert(iter->start.col < term->cols); + return match; } -static void add_wchars(struct terminal *term, char32_t *src, size_t count) { - /* Strip non-printable characters */ - for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) { - if (isc32print(src[i])) - src[j++] = src[i]; - else - count--; - } +static void add_wchars(struct terminal *term, char32_t *src, size_t count) +{ + /* Strip non-printable characters */ + for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) { + if (isc32print(src[i])) + src[j++] = src[i]; + else + count--; + } - if (!search_ensure_size(term, term->vimode.search.len + count)) - return; + if (!search_ensure_size(term, term->vimode.search.len + count)) + return; - xassert(term->vimode.search.len + count < term->vimode.search.sz); + xassert(term->vimode.search.len + count < term->vimode.search.sz); - memmove(&term->vimode.search.buf[term->vimode.search.cursor + count], - &term->vimode.search.buf[term->vimode.search.cursor], - (term->vimode.search.len - term->vimode.search.cursor) * - sizeof(char32_t)); + memmove(&term->vimode.search.buf[term->vimode.search.cursor + count], + &term->vimode.search.buf[term->vimode.search.cursor], + (term->vimode.search.len - term->vimode.search.cursor) * + sizeof(char32_t)); - memcpy(&term->vimode.search.buf[term->vimode.search.cursor], src, - count * sizeof(char32_t)); + memcpy(&term->vimode.search.buf[term->vimode.search.cursor], src, + count * sizeof(char32_t)); - term->vimode.search.len += count; - term->vimode.search.cursor += count; - term->vimode.search.buf[term->vimode.search.len] = U'\0'; + term->vimode.search.len += count; + term->vimode.search.cursor += count; + term->vimode.search.buf[term->vimode.search.len] = U'\0'; } void vimode_search_add_chars(struct terminal *term, const char *src, - size_t count) { - size_t chars = mbsntoc32(NULL, src, count, 0); - if (chars == (size_t)-1) { - LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src); - return; - } + size_t count) +{ + size_t chars = mbsntoc32(NULL, src, count, 0); + if (chars == (size_t)-1) { + LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src); + return; + } - char32_t c32s[chars + 1]; - mbsntoc32(c32s, src, count, chars); - add_wchars(term, c32s, chars); + char32_t c32s[chars + 1]; + mbsntoc32(c32s, src, count, chars); + add_wchars(term, c32s, chars); } -void vimode_view_down(struct terminal *const term, int const delta) { - if (!term->vimode.active) { - return; - } +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); + 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); } // move_cursor_delta @@ -760,97 +798,103 @@ void vimode_view_down(struct terminal *const term, int const delta) { // up/left, positive down/right. // static void move_cursor_delta(struct terminal *const term, - struct coord const delta) { - damage_cursor_cell(term); - struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); - cursor.row += delta.row; - cursor.col += delta.col; + struct coord const delta) +{ + damage_cursor_cell(term); + struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); + cursor.row += delta.row; + cursor.col += delta.col; - if (cursor.row < 0) { - int const overflow = -cursor.row; - cmd_scrollback_up(term, overflow); - cursor.row = 0; - } else if (cursor.row >= term->rows) { - int const overflow = cursor.row - term->rows + 1; - cmd_scrollback_down(term, overflow); - cursor.row = term->rows - 1; - } + if (cursor.row < 0) { + int const overflow = -cursor.row; + cmd_scrollback_up(term, overflow); + cursor.row = 0; + } else if (cursor.row >= term->rows) { + int const overflow = cursor.row - term->rows + 1; + cmd_scrollback_down(term, overflow); + cursor.row = term->rows - 1; + } - if (cursor.col < 0) { - cursor.col = 0; - } else if (cursor.col >= term->cols) { - cursor.col = term->cols - 1; - } + if (cursor.col < 0) { + cursor.col = 0; + } else if (cursor.col >= term->cols) { + cursor.col = term->cols - 1; + } - term->vimode.cursor = cursor_from_view_relative(term, cursor); - LOG_DBG("CURSOR MOVED (%d, %d) [delta=(%d, %d)]", term->vimode.cursor.row, - term->vimode.cursor.col, delta.row, delta.col); - damage_cursor_cell(term); - render_refresh(term); + term->vimode.cursor = cursor_from_view_relative(term, cursor); + LOG_DBG("CURSOR MOVED (%d, %d) [delta=(%d, %d)]", term->vimode.cursor.row, + term->vimode.cursor.col, delta.row, delta.col); + damage_cursor_cell(term); + render_refresh(term); } -static void move_cursor_vertical(struct terminal *const term, int const count) { - move_cursor_delta(term, (struct coord){.row = count, .col = 0}); +static void move_cursor_vertical(struct terminal *const term, int const count) +{ + move_cursor_delta(term, (struct coord){.row = count, .col = 0}); } -static void move_cursor_horizontal(struct terminal *const term, - int const count) { - move_cursor_delta(term, (struct coord){.row = 0, .col = count}); +static void move_cursor_horizontal(struct terminal *const term, int const count) +{ + move_cursor_delta(term, (struct coord){.row = 0, .col = count}); } enum c32_class { - CLASS_BLANK, - CLASS_PUNCTUATION, - CLASS_WORD, + CLASS_BLANK, + CLASS_PUNCTUATION, + CLASS_WORD, }; -enum c32_class get_class(char32_t const c) { - if (c == '\0') { - return CLASS_BLANK; - } - - // We consider an underscore to be a word character instead of - // punctuation. - if (c == '_') { - return CLASS_WORD; - } - - bool const whitespace = isc32space(c); - if (whitespace) { - return CLASS_BLANK; - } - - // TODO (kociap): unsure whether this handles all possible - // punctuation, a subset of it or just the latin characters. - bool const punctuation = isc32punct(c); - if (punctuation) { - return CLASS_PUNCTUATION; - } - - // Most other characters may be considered "word" characters. - return CLASS_WORD; -} - -char32_t cursor_char(struct terminal *const term) { - struct row *const row = grid_row(term->grid, term->vimode.cursor.row); - return row->cells[term->vimode.cursor.col].wc; -} - -enum c32_class cursor_class(struct terminal *const term) { - char32_t const c = cursor_char(term); - return get_class(c); -} - -int row_length(struct terminal *const term, int const row_index) { - struct row *const row = grid_row(term->grid, row_index); - int length = 0; - while (length < term->grid->num_cols) { - if (row->cells[length].wc == '\0') { - break; +enum c32_class get_class(char32_t const c) +{ + if (c == '\0') { + return CLASS_BLANK; } - length += 1; - } - return length; + + // We consider an underscore to be a word character instead of + // punctuation. + if (c == '_') { + return CLASS_WORD; + } + + bool const whitespace = isc32space(c); + if (whitespace) { + return CLASS_BLANK; + } + + // TODO (kociap): unsure whether this handles all possible + // punctuation, a subset of it or just the latin characters. + bool const punctuation = isc32punct(c); + if (punctuation) { + return CLASS_PUNCTUATION; + } + + // Most other characters may be considered "word" characters. + return CLASS_WORD; +} + +char32_t cursor_char(struct terminal *const term) +{ + struct row *const row = grid_row(term->grid, term->vimode.cursor.row); + return row->cells[term->vimode.cursor.col].wc; +} + +enum c32_class cursor_class(struct terminal *const term) +{ + char32_t const c = cursor_char(term); + return get_class(c); +} + +int row_length(struct terminal *const term, int const row_index) +{ + struct row *const row = grid_row(term->grid, row_index); + int length = 0; + while (length < term->grid->num_cols) { + if (row->cells[length].wc == '\0') { + break; + } + length += 1; + } + return length; } // increment_cursor @@ -862,32 +906,35 @@ int row_length(struct terminal *const term, int const row_index) { // false when at the end of the scrollback. // true otherwise. // -bool increment_cursor(struct terminal *const term) { - char32_t const c = cursor_char(term); - // Within a row, move to the next column. - if (c != '\0') { - term->vimode.cursor.col += 1; - struct row const *const row = grid_row(term->grid, term->vimode.cursor.row); - // If the row does not contain a linebreak, we want to move to the - // next row immediately. - if (row->linebreak || term->vimode.cursor.col < term->cols) { - return true; +bool increment_cursor(struct terminal *const term) +{ + char32_t const c = cursor_char(term); + // Within a row, move to the next column. + if (c != '\0') { + term->vimode.cursor.col += 1; + struct row const *const row = + grid_row(term->grid, term->vimode.cursor.row); + // If the row does not contain a linebreak, we want to move to the + // next row immediately. + if (row->linebreak || term->vimode.cursor.col < term->cols) { + return true; + } } - } - // Not in the last row. - if (term->vimode.cursor.row != term->rows - 1) { - term->vimode.cursor.row += 1; - term->vimode.cursor.col = 0; - // If the cursor moved outside the view, follow it. - struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); - if (cursor.row >= term->rows) { - cmd_scrollback_down(term, 1); + // Not in the last row. + if (term->vimode.cursor.row != term->rows - 1) { + term->vimode.cursor.row += 1; + term->vimode.cursor.col = 0; + // If the cursor moved outside the view, follow it. + struct coord cursor = + cursor_to_view_relative(term, term->vimode.cursor); + if (cursor.row >= term->rows) { + cmd_scrollback_down(term, 1); + } + return true; } - return true; - } - return false; + return false; } // decrement_cursor @@ -899,33 +946,35 @@ bool increment_cursor(struct terminal *const term) { // false when at the start of the scrollback. // true otherwise. // -bool decrement_cursor(struct terminal *const term) { - // Within a row, move to the previous column. - if (term->vimode.cursor.col > 0) { - term->vimode.cursor.col -= 1; - return true; - } - - // TODO (kociap): this seems like a terrible way (performance-wise) - // to figure out the current scrollback position. Could maybe store - // it in the grid instead of recalculating it repeatedly? - int const sb_start = - grid_sb_start_ignore_uninitialized(term->grid, term->rows); - int const sb_row = grid_row_abs_to_sb_precalc_sb_start( - term->grid, sb_start, - grid_row_absolute(term->grid, term->vimode.cursor.row)); - // Not in the first row. - if (sb_row > 0) { - term->vimode.cursor.row -= 1; - term->vimode.cursor.col = row_length(term, term->vimode.cursor.row) - 1; - // If the cursor moved outside the view, follow it. - struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); - if (cursor.row < 0) { - cmd_scrollback_up(term, 1); +bool decrement_cursor(struct terminal *const term) +{ + // Within a row, move to the previous column. + if (term->vimode.cursor.col > 0) { + term->vimode.cursor.col -= 1; + return true; } - return true; - } - return false; + + // TODO (kociap): this seems like a terrible way (performance-wise) + // to figure out the current scrollback position. Could maybe store + // it in the grid instead of recalculating it repeatedly? + int const sb_start = + grid_sb_start_ignore_uninitialized(term->grid, term->rows); + int const sb_row = grid_row_abs_to_sb_precalc_sb_start( + term->grid, sb_start, + grid_row_absolute(term->grid, term->vimode.cursor.row)); + // Not in the first row. + if (sb_row > 0) { + term->vimode.cursor.row -= 1; + term->vimode.cursor.col = row_length(term, term->vimode.cursor.row) - 1; + // If the cursor moved outside the view, follow it. + struct coord cursor = + cursor_to_view_relative(term, term->vimode.cursor); + if (cursor.row < 0) { + cmd_scrollback_up(term, 1); + } + return true; + } + return false; } // Skip characters of the same class. @@ -934,14 +983,14 @@ bool decrement_cursor(struct terminal *const term) { // false when at the end of the scrollback. // true otherwise. // -bool skip_chars_forward(struct terminal *const term, - enum c32_class const class) { - while (cursor_class(term) == class) { - if (increment_cursor(term) == false) { - return false; +bool skip_chars_forward(struct terminal *const term, enum c32_class const class) +{ + while (cursor_class(term) == class) { + if (increment_cursor(term) == false) { + return false; + } } - } - return true; + return true; } // Skip characters of the same class. @@ -951,597 +1000,620 @@ bool skip_chars_forward(struct terminal *const term, // true otherwise. // bool skip_chars_backward(struct terminal *const term, - enum c32_class const class) { - while (cursor_class(term) == class) { - if (decrement_cursor(term) == false) { - return false; + enum c32_class const class) +{ + while (cursor_class(term) == class) { + if (decrement_cursor(term) == false) { + return false; + } } - } - return true; + return true; } // MOTIONS // Move the cursor back to the start of a word. // -void motion_begin_word(struct terminal *const term) { - if (decrement_cursor(term) == false) { - return; - } - - // Skip whitespace. If we encounter an empty row, stop. - while (cursor_class(term) == CLASS_BLANK) { - bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; - if (row_empty && term->vimode.cursor.col == 0) { - return; - } - +void motion_begin_word(struct terminal *const term) +{ if (decrement_cursor(term) == false) { - return; + return; } - } - // Go to the start of the next word. - enum c32_class const current_class = cursor_class(term); - if (skip_chars_backward(term, current_class) == false) { - return; - } + // Skip whitespace. If we encounter an empty row, stop. + while (cursor_class(term) == CLASS_BLANK) { + bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; + if (row_empty && term->vimode.cursor.col == 0) { + return; + } - // We overshot. Move forward one character. - increment_cursor(term); + if (decrement_cursor(term) == false) { + return; + } + } + + // Go to the start of the next word. + enum c32_class const current_class = cursor_class(term); + if (skip_chars_backward(term, current_class) == false) { + return; + } + + // We overshot. Move forward one character. + increment_cursor(term); } // Move the cursor forward to the end of a word. // -void motion_end_word(struct terminal *const term) { - if (increment_cursor(term) == false) { - return; - } - - // Skip whitespace. If we encounter an empty row, stop. - while (cursor_class(term) == CLASS_BLANK) { - bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; - if (row_empty && term->vimode.cursor.col == 0) { - return; - } - +void motion_end_word(struct terminal *const term) +{ if (increment_cursor(term) == false) { - return; + return; } - } - // Go to the end of the next word. - enum c32_class current_class = cursor_class(term); - if (skip_chars_forward(term, current_class) == false) { - return; - } - // We overshot. Go back one character. - decrement_cursor(term); + // Skip whitespace. If we encounter an empty row, stop. + while (cursor_class(term) == CLASS_BLANK) { + bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; + if (row_empty && term->vimode.cursor.col == 0) { + return; + } + + if (increment_cursor(term) == false) { + return; + } + } + + // Go to the end of the next word. + enum c32_class current_class = cursor_class(term); + if (skip_chars_forward(term, current_class) == false) { + return; + } + // We overshot. Go back one character. + decrement_cursor(term); } // Move the cursor forward to the start of a word. // -void motion_fwd_begin_word(struct terminal *const term) { - enum c32_class const starting_class = cursor_class(term); - if (increment_cursor(term) == false) { - return; - } - - // Move to the end of this word. - if (starting_class != CLASS_BLANK) { - if (skip_chars_forward(term, starting_class) == false) { - - return; - } - } - - // Skip whitespace. If we encounter an empty row, stop. - while (cursor_class(term) == CLASS_BLANK) { - bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; - if (row_empty && term->vimode.cursor.col == 0) { - return; - } - +void motion_fwd_begin_word(struct terminal *const term) +{ + enum c32_class const starting_class = cursor_class(term); if (increment_cursor(term) == false) { - return; + return; + } + + // Move to the end of this word. + if (starting_class != CLASS_BLANK) { + if (skip_chars_forward(term, starting_class) == false) { + + return; + } + } + + // Skip whitespace. If we encounter an empty row, stop. + while (cursor_class(term) == CLASS_BLANK) { + bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; + if (row_empty && term->vimode.cursor.col == 0) { + return; + } + + if (increment_cursor(term) == false) { + return; + } } - } } // Move the cursor back to the end of a word. // -void motion_back_end_word(struct terminal *const term) { - enum c32_class const starting_class = cursor_class(term); - if (decrement_cursor(term) == false) { - return; - } - - // Move to before the start of this word. - if (starting_class != CLASS_BLANK) { - if (skip_chars_backward(term, starting_class) == false) { - return; - } - } - - // Skip whitespace. If we encounter an empty row, stop. - while (cursor_class(term) == CLASS_BLANK) { - bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; - if (row_empty && term->vimode.cursor.col == 0) { - return; - } - +void motion_back_end_word(struct terminal *const term) +{ + enum c32_class const starting_class = cursor_class(term); if (decrement_cursor(term) == false) { - return; + return; + } + + // Move to before the start of this word. + if (starting_class != CLASS_BLANK) { + if (skip_chars_backward(term, starting_class) == false) { + return; + } + } + + // Skip whitespace. If we encounter an empty row, stop. + while (cursor_class(term) == CLASS_BLANK) { + bool const row_empty = row_length(term, term->vimode.cursor.row) == 0; + if (row_empty && term->vimode.cursor.col == 0) { + return; + } + + if (decrement_cursor(term) == false) { + return; + } } - } } static void execute_vimode_binding(struct seat *seat, struct terminal *term, const struct key_binding *binding, - uint32_t serial) { - const enum bind_action_vimode action = binding->action; + uint32_t serial) +{ + const enum bind_action_vimode action = binding->action; - if (term->grid != &term->normal) { - return; - } - LOG_DBG("PRE-ACTION DATA [offset=%d; view=%d]", term->grid->offset, - term->grid->view); - switch (action) { - case BIND_ACTION_VIMODE_NONE: - break; - - case BIND_ACTION_VIMODE_UP: - move_cursor_vertical(term, -1); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_DOWN: - move_cursor_vertical(term, 1); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_LEFT: - move_cursor_horizontal(term, -1); - update_selection(term); - break; - - case BIND_ACTION_VIMODE_RIGHT: - move_cursor_horizontal(term, 1); - update_selection(term); - break; - - case BIND_ACTION_VIMODE_UP_PAGE: - cmd_scrollback_up(term, term->rows); - clip_cursor_to_view(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_DOWN_PAGE: - cmd_scrollback_down(term, term->rows); - clip_cursor_to_view(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_UP_HALF_PAGE: - cmd_scrollback_up(term, max(term->rows / 2, 1)); - clip_cursor_to_view(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_DOWN_HALF_PAGE: - cmd_scrollback_down(term, max(term->rows / 2, 1)); - clip_cursor_to_view(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_UP_LINE: - cmd_scrollback_up(term, 1); - clip_cursor_to_view(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_DOWN_LINE: - cmd_scrollback_down(term, 1); - clip_cursor_to_view(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_FIRST_LINE: { - cmd_scrollback_up(term, term->grid->num_rows); - damage_cursor_cell(term); - int const view_row = view_to_scrollback_relative(term); - term->vimode.cursor.row = cursor_from_scrollback_relative(term, view_row); - damage_cursor_cell(term); - update_selection(term); - update_highlights(term); - } break; - - case BIND_ACTION_VIMODE_LAST_LINE: - cmd_scrollback_down(term, term->grid->num_rows); - damage_cursor_cell(term); - term->vimode.cursor.row = term->rows - 1; - damage_cursor_cell(term); - update_selection(term); - update_highlights(term); - break; - - case BIND_ACTION_VIMODE_LINE_BEGIN: - damage_cursor_cell(term); - term->vimode.cursor.col = 0; - damage_cursor_cell(term); - break; - - case BIND_ACTION_VIMODE_LINE_END: { - damage_cursor_cell(term); - struct row const *const row = grid_row(term->grid, term->vimode.cursor.row); - int col = term->cols - 1; - while (col > 0) { - if (row->cells[col].wc != '\0') { + if (term->grid != &term->normal) { + return; + } + LOG_DBG("PRE-ACTION DATA [offset=%d; view=%d]", term->grid->offset, + term->grid->view); + switch (action) { + case BIND_ACTION_VIMODE_NONE: break; - } - col -= 1; - } - term->vimode.cursor.col = col; - damage_cursor_cell(term); - } break; - case BIND_ACTION_VIMODE_TEXT_BEGIN: { - damage_cursor_cell(term); - struct row const *const row = grid_row(term->grid, term->vimode.cursor.row); - int col = 0; - while (col < term->cols - 1) { - if (isc32graph(row->cells[col].wc)) { + case BIND_ACTION_VIMODE_UP: + move_cursor_vertical(term, -1); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_DOWN: + move_cursor_vertical(term, 1); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_LEFT: + move_cursor_horizontal(term, -1); + update_selection(term); + break; + + case BIND_ACTION_VIMODE_RIGHT: + move_cursor_horizontal(term, 1); + update_selection(term); + break; + + case BIND_ACTION_VIMODE_UP_PAGE: + cmd_scrollback_up(term, term->rows); + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_DOWN_PAGE: + cmd_scrollback_down(term, term->rows); + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_UP_HALF_PAGE: + cmd_scrollback_up(term, max(term->rows / 2, 1)); + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_DOWN_HALF_PAGE: + cmd_scrollback_down(term, max(term->rows / 2, 1)); + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_UP_LINE: + cmd_scrollback_up(term, 1); + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_DOWN_LINE: + cmd_scrollback_down(term, 1); + clip_cursor_to_view(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_FIRST_LINE: { + cmd_scrollback_up(term, term->grid->num_rows); + damage_cursor_cell(term); + int const view_row = view_to_scrollback_relative(term); + term->vimode.cursor.row = + cursor_from_scrollback_relative(term, view_row); + damage_cursor_cell(term); + update_selection(term); + update_highlights(term); + } break; + + case BIND_ACTION_VIMODE_LAST_LINE: + cmd_scrollback_down(term, term->grid->num_rows); + damage_cursor_cell(term); + term->vimode.cursor.row = term->rows - 1; + damage_cursor_cell(term); + update_selection(term); + update_highlights(term); + break; + + case BIND_ACTION_VIMODE_LINE_BEGIN: + damage_cursor_cell(term); + term->vimode.cursor.col = 0; + damage_cursor_cell(term); + break; + + case BIND_ACTION_VIMODE_LINE_END: { + damage_cursor_cell(term); + struct row const *const row = + grid_row(term->grid, term->vimode.cursor.row); + int col = term->cols - 1; + while (col > 0) { + if (row->cells[col].wc != '\0') { + break; + } + col -= 1; + } + term->vimode.cursor.col = col; + damage_cursor_cell(term); + } break; + + case BIND_ACTION_VIMODE_TEXT_BEGIN: { + damage_cursor_cell(term); + struct row const *const row = + grid_row(term->grid, term->vimode.cursor.row); + int col = 0; + while (col < term->cols - 1) { + if (isc32graph(row->cells[col].wc)) { + break; + } + col += 1; + } + term->vimode.cursor.col = col; + damage_cursor_cell(term); + } break; + + case BIND_ACTION_VIMODE_WORD_BEGIN: + damage_cursor_cell(term); + motion_begin_word(term); + damage_cursor_cell(term); + update_selection(term); + break; + + case BIND_ACTION_VIMODE_WORD_END: + damage_cursor_cell(term); + motion_end_word(term); + damage_cursor_cell(term); + update_selection(term); + break; + + case BIND_ACTION_VIMODE_NEXT_WORD_BEGIN: + damage_cursor_cell(term); + motion_fwd_begin_word(term); + damage_cursor_cell(term); + update_selection(term); + break; + + case BIND_ACTION_VIMODE_PREV_WORD_END: + damage_cursor_cell(term); + motion_back_end_word(term); + damage_cursor_cell(term); + update_selection(term); + break; + + case BIND_ACTION_VIMODE_CANCEL: { + // We handle multiple actions here (in that exact order): + // - return to the normal mode, + // - exit vimode. + // Clearing search is handled by vimode-search bindings. + if (is_mode_visual(term->vimode.mode)) { + selection_cancel(term); + term->vimode.mode = VI_MODE_NORMAL; + } else { + vimode_cancel(term); + } + } break; + + case BIND_ACTION_VIMODE_START_SEARCH_FORWARD: + start_search(term, SEARCH_FORWARD); + break; + + case BIND_ACTION_VIMODE_START_SEARCH_BACKWARD: + start_search(term, SEARCH_BACKWARD); + break; + + case BIND_ACTION_VIMODE_FIND_PREV: + case BIND_ACTION_VIMODE_FIND_NEXT: { + enum search_direction const direction = + (action == BIND_ACTION_VIMODE_FIND_NEXT) + ? term->vimode.confirmed_search.direction + : invert_direction(term->vimode.confirmed_search.direction); + struct range match; + bool const matched = find_next_from_cursor( + term, term->vimode.confirmed_search.buf, + term->vimode.confirmed_search.len, direction, &match); + // TODO (kociap): feedback for the user when no match? + if (matched) { + struct coord const delta = + delta_cursor_in_abs_coord(term, match.start); + LOG_DBG( + "FIND %s [direction=%s; location=%d; cursor=%d; match=(%d, " + "%d)]\n", + (action == BIND_ACTION_VIMODE_FIND_NEXT) ? "NEXT" : "PREV", + (direction == SEARCH_FORWARD ? "forward" : "backward"), + grid_row_abs_to_sb(term->grid, term->rows, match.start.row), + cursor_to_scrollback_relative(term, term->vimode.cursor.row), + match.start.row, match.start.col); + move_cursor_delta(term, delta); + update_selection(term); + } + update_highlights(term); + } break; + + case BIND_ACTION_VIMODE_ENTER_VISUAL: + case BIND_ACTION_VIMODE_ENTER_VLINE: + case BIND_ACTION_VIMODE_ENTER_VBLOCK: { + enum vi_mode mode = VI_MODE_VISUAL; + if (action == BIND_ACTION_VIMODE_ENTER_VLINE) { + mode = VI_MODE_VLINE; + } else if (action == BIND_ACTION_VIMODE_ENTER_VBLOCK) { + mode = VI_MODE_VBLOCK; + } + + enum selection_kind const selection = selection_kind_from_vi_mode(mode); + if (is_mode_visual(term->vimode.mode)) { + // "Entering" the same mode exits it. Otherwise, we switch from + // another visual mode. + if (term->vimode.mode == mode) { + selection_cancel(term); + term->vimode.mode = VI_MODE_NORMAL; + } else { + selection_cancel(term); + struct coord const start = term->vimode.selection.start; + selection_start(term, start, selection, false); + struct coord const cursor = + cursor_to_view_relative(term, term->vimode.cursor); + selection_update(term, cursor); + term->vimode.mode = mode; + } + } else if (term->vimode.mode == VI_MODE_NORMAL) { + // Enter the visual mode. + struct coord const cursor = + cursor_to_view_relative(term, term->vimode.cursor); + selection_start(term, cursor, selection, false); + term->vimode.selection.start = cursor; + term->vimode.mode = mode; + } + } break; + + case BIND_ACTION_VIMODE_YANK: + // TODO (kociap): Should yank executed in non-visual mode copy the + // current line? + if (is_mode_visual(term->vimode.mode)) { + // Copy, clear the selection and exit the visual mode. + selection_finalize(seat, term, serial); + selection_cancel(term); + term->vimode.mode = VI_MODE_NORMAL; + } + break; + + case BIND_ACTION_VIMODE_COUNT: + BUG("Invalid action type"); + break; + + default: + BUG("Unhandled action type"); break; - } - col += 1; } - term->vimode.cursor.col = col; - damage_cursor_cell(term); - } break; - - case BIND_ACTION_VIMODE_WORD_BEGIN: - damage_cursor_cell(term); - motion_begin_word(term); - damage_cursor_cell(term); - update_selection(term); - break; - - case BIND_ACTION_VIMODE_WORD_END: - damage_cursor_cell(term); - motion_end_word(term); - damage_cursor_cell(term); - update_selection(term); - break; - - case BIND_ACTION_VIMODE_NEXT_WORD_BEGIN: - damage_cursor_cell(term); - motion_fwd_begin_word(term); - damage_cursor_cell(term); - update_selection(term); - break; - - case BIND_ACTION_VIMODE_PREV_WORD_END: - damage_cursor_cell(term); - motion_back_end_word(term); - damage_cursor_cell(term); - update_selection(term); - break; - - case BIND_ACTION_VIMODE_CANCEL: { - // We handle multiple actions here (in that exact order): - // - return to the normal mode, - // - exit vimode. - // Clearing search is handled by vimode-search bindings. - if (is_mode_visual(term->vimode.mode)) { - selection_cancel(term); - term->vimode.mode = VI_MODE_NORMAL; - } else { - vimode_cancel(term); - } - } break; - - case BIND_ACTION_VIMODE_START_SEARCH_FORWARD: - start_search(term, SEARCH_FORWARD); - break; - - case BIND_ACTION_VIMODE_START_SEARCH_BACKWARD: - start_search(term, SEARCH_BACKWARD); - break; - - case BIND_ACTION_VIMODE_FIND_PREV: - case BIND_ACTION_VIMODE_FIND_NEXT: { - enum search_direction const direction = - (action == BIND_ACTION_VIMODE_FIND_NEXT) - ? term->vimode.confirmed_search.direction - : invert_direction(term->vimode.confirmed_search.direction); - struct range match; - bool const matched = find_next_from_cursor( - term, term->vimode.confirmed_search.buf, - term->vimode.confirmed_search.len, direction, &match); - // TODO (kociap): feedback for the user when no match? - if (matched) { - struct coord const delta = delta_cursor_in_abs_coord(term, match.start); - LOG_DBG("FIND %s [direction=%s; location=%d; cursor=%d; match=(%d, " - "%d)]\n", - (action == BIND_ACTION_VIMODE_FIND_NEXT) ? "NEXT" : "PREV", - (direction == SEARCH_FORWARD ? "forward" : "backward"), - grid_row_abs_to_sb(term->grid, term->rows, match.start.row), - cursor_to_scrollback_relative(term, term->vimode.cursor.row), - match.start.row, match.start.col); - move_cursor_delta(term, delta); - update_selection(term); - } - update_highlights(term); - } break; - - case BIND_ACTION_VIMODE_ENTER_VISUAL: - case BIND_ACTION_VIMODE_ENTER_VLINE: - case BIND_ACTION_VIMODE_ENTER_VBLOCK: { - enum vi_mode mode = VI_MODE_VISUAL; - if (action == BIND_ACTION_VIMODE_ENTER_VLINE) { - mode = VI_MODE_VLINE; - } else if (action == BIND_ACTION_VIMODE_ENTER_VBLOCK) { - mode = VI_MODE_VBLOCK; - } - - enum selection_kind const selection = selection_kind_from_vi_mode(mode); - if (is_mode_visual(term->vimode.mode)) { - // "Entering" the same mode exits it. Otherwise, we switch from - // another visual mode. - if (term->vimode.mode == mode) { - selection_cancel(term); - term->vimode.mode = VI_MODE_NORMAL; - } else { - selection_cancel(term); - struct coord const start = term->vimode.selection.start; - selection_start(term, start, selection, false); - struct coord const cursor = - cursor_to_view_relative(term, term->vimode.cursor); - selection_update(term, cursor); - term->vimode.mode = mode; - } - } else if (term->vimode.mode == VI_MODE_NORMAL) { - // Enter the visual mode. - struct coord const cursor = - cursor_to_view_relative(term, term->vimode.cursor); - selection_start(term, cursor, selection, false); - term->vimode.selection.start = cursor; - term->vimode.mode = mode; - } - } break; - - case BIND_ACTION_VIMODE_YANK: - // TODO (kociap): Should yank executed in non-visual mode copy the - // current line? - if (is_mode_visual(term->vimode.mode)) { - // Copy, clear the selection and exit the visual mode. - selection_finalize(seat, term, serial); - selection_cancel(term); - term->vimode.mode = VI_MODE_NORMAL; - } - break; - - case BIND_ACTION_VIMODE_COUNT: - BUG("Invalid action type"); - break; - - default: - BUG("Unhandled action type"); - break; - } } static void execute_vimode_search_binding(struct seat *seat, struct terminal *const term, const struct key_binding *binding, uint32_t serial, - bool *search_string_changed) { - const enum bind_action_vimode action = binding->action; - struct vimode_search *const search = &term->vimode.search; - *search_string_changed = false; + bool *search_string_changed) +{ + const enum bind_action_vimode action = binding->action; + struct vimode_search *const search = &term->vimode.search; + *search_string_changed = false; - if (term->grid != &term->normal) { - return; - } - - switch (action) { - case BIND_ACTION_VIMODE_SEARCH_NONE: - break; - - case BIND_ACTION_VIMODE_SEARCH_CONFIRM: - if (search->match_len > 0) { - struct coord const delta = delta_cursor_in_abs_coord(term, search->match); - LOG_DBG("CONFIRM SEARCH [location=%d; cursor=%d; match=(%d, %d)]", - grid_row_abs_to_sb(term->grid, term->rows, search->match.row), - cursor_to_scrollback_relative(term, term->vimode.cursor.row), - search->match.row, search->match.col); - move_cursor_delta(term, delta); - center_view_on_cursor(term); - update_selection(term); + if (term->grid != &term->normal) { + return; } - confirm_search(term); - break; - case BIND_ACTION_VIMODE_SEARCH_CANCEL: - cancel_search(term, true); - break; + switch (action) { + case BIND_ACTION_VIMODE_SEARCH_NONE: + break; - case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR: - if (search->cursor > 0) { - memmove(&search->buf[search->cursor - 1], &search->buf[search->cursor], - (search->len - search->cursor) * sizeof(char32_t)); - search->cursor -= 1; - search->len -= 1; - search->buf[search->len] = U'\0'; - render_refresh_vimode_search_box(term); - *search_string_changed = true; + case BIND_ACTION_VIMODE_SEARCH_CONFIRM: + if (search->match_len > 0) { + struct coord const delta = + delta_cursor_in_abs_coord(term, search->match); + LOG_DBG( + "CONFIRM SEARCH [location=%d; cursor=%d; match=(%d, %d)]", + grid_row_abs_to_sb(term->grid, term->rows, search->match.row), + cursor_to_scrollback_relative(term, term->vimode.cursor.row), + search->match.row, search->match.col); + move_cursor_delta(term, delta); + center_view_on_cursor(term); + update_selection(term); + } + confirm_search(term); + break; + + case BIND_ACTION_VIMODE_SEARCH_CANCEL: + cancel_search(term, true); + break; + + case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR: + if (search->cursor > 0) { + memmove(&search->buf[search->cursor - 1], + &search->buf[search->cursor], + (search->len - search->cursor) * sizeof(char32_t)); + search->cursor -= 1; + search->len -= 1; + search->buf[search->len] = U'\0'; + render_refresh_vimode_search_box(term); + *search_string_changed = true; + } + break; + + case BIND_ACTION_VIMODE_SEARCH_LEFT: + if (search->cursor > 0) { + search->cursor -= 1; + render_refresh_vimode_search_box(term); + } + break; + + case BIND_ACTION_VIMODE_SEARCH_RIGHT: + if (search->cursor < search->len) { + search->cursor += 1; + render_refresh_vimode_search_box(term); + } + break; + + // case BIND_ACTION_SEARCH_CLIPBOARD_PASTE: + // text_from_clipboard(seat, term, &from_clipboard_cb, + // &from_clipboard_done, + // term); + // *update_search_result = *redraw = true; + // return true; + // + // case BIND_ACTION_SEARCH_PRIMARY_PASTE: + // text_from_primary(seat, term, &from_clipboard_cb, + // &from_clipboard_done, + // term); + // *update_search_result = *redraw = true; + // return true; + // + // case BIND_ACTION_SEARCH_UNICODE_INPUT: + // unicode_mode_activate(term); + // return true; + + case BIND_ACTION_VIMODE_COUNT: + BUG("Invalid action type"); + break; + + default: + BUG("Unhandled action type"); + break; } - break; - - case BIND_ACTION_VIMODE_SEARCH_LEFT: - if (search->cursor > 0) { - search->cursor -= 1; - render_refresh_vimode_search_box(term); - } - break; - - case BIND_ACTION_VIMODE_SEARCH_RIGHT: - if (search->cursor < search->len) { - search->cursor += 1; - render_refresh_vimode_search_box(term); - } - break; - - // case BIND_ACTION_SEARCH_CLIPBOARD_PASTE: - // text_from_clipboard(seat, term, &from_clipboard_cb, - // &from_clipboard_done, - // term); - // *update_search_result = *redraw = true; - // return true; - // - // case BIND_ACTION_SEARCH_PRIMARY_PASTE: - // text_from_primary(seat, term, &from_clipboard_cb, &from_clipboard_done, - // term); - // *update_search_result = *redraw = true; - // return true; - // - // case BIND_ACTION_SEARCH_UNICODE_INPUT: - // unicode_mode_activate(term); - // return true; - - case BIND_ACTION_VIMODE_COUNT: - BUG("Invalid action type"); - break; - - default: - BUG("Unhandled action type"); - break; - } } static struct key_binding const * match_binding(key_binding_list_t const *bindings, uint32_t key, xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed, - const xkb_keysym_t *raw_syms, size_t raw_count) { - /* Match untranslated symbols */ - tll_foreach(*bindings, it) { - const struct key_binding *bind = &it->item; + const xkb_keysym_t *raw_syms, size_t raw_count) +{ + /* Match untranslated symbols */ + tll_foreach(*bindings, it) + { + const struct key_binding *bind = &it->item; - if (bind->mods != mods || bind->mods == 0) - continue; + if (bind->mods != mods || bind->mods == 0) + continue; - for (size_t i = 0; i < raw_count; i++) { - if (bind->k.sym == raw_syms[i]) { - return bind; - } + for (size_t i = 0; i < raw_count; i++) { + if (bind->k.sym == raw_syms[i]) { + return bind; + } + } } - } - /* Match translated symbol */ - tll_foreach(*bindings, it) { - const struct key_binding *bind = &it->item; + /* Match translated symbol */ + tll_foreach(*bindings, it) + { + const struct key_binding *bind = &it->item; - if (bind->k.sym == sym && bind->mods == (mods & ~consumed)) { - return bind; + if (bind->k.sym == sym && bind->mods == (mods & ~consumed)) { + return bind; + } } - } - /* Match raw key code */ - tll_foreach(*bindings, it) { - const struct key_binding *bind = &it->item; + /* Match raw key code */ + tll_foreach(*bindings, it) + { + const struct key_binding *bind = &it->item; - if (bind->mods != mods || bind->mods == 0) - continue; + if (bind->mods != mods || bind->mods == 0) + continue; - tll_foreach(bind->k.key_codes, code) { - if (code->item == key) { - return bind; - } + tll_foreach(bind->k.key_codes, code) + { + if (code->item == key) { + return bind; + } + } } - } - return NULL; + return NULL; } void vimode_input(struct seat *seat, struct terminal *term, const struct key_binding_set *bindings, uint32_t key, 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) { - LOG_DBG("VIMODE INPUT [sym=%d/0x%x, mods=0x%08x, consumed=0x%08x]", sym, sym, - mods, consumed); + size_t raw_count, uint32_t serial) +{ + LOG_DBG("VIMODE INPUT [sym=%d/0x%x, mods=0x%08x, consumed=0x%08x]", sym, + sym, mods, consumed); - enum xkb_compose_status compose_status = - seat->kbd.xkb_compose_state != NULL - ? xkb_compose_state_get_status(seat->kbd.xkb_compose_state) - : XKB_COMPOSE_NOTHING; + enum xkb_compose_status compose_status = + seat->kbd.xkb_compose_state != NULL + ? xkb_compose_state_get_status(seat->kbd.xkb_compose_state) + : XKB_COMPOSE_NOTHING; - if (!term->vimode.searching) { - struct key_binding const *const binding = match_binding( - &bindings->vimode, key, sym, mods, consumed, raw_syms, raw_count); - if (binding != NULL) { - execute_vimode_binding(seat, term, binding, serial); - } - } else { - struct key_binding const *const binding = - match_binding(&bindings->vimode_search, key, sym, mods, consumed, - raw_syms, raw_count); - bool search_string_updated = false; - if (binding != NULL) { - execute_vimode_search_binding(seat, term, binding, serial, - &search_string_updated); + if (!term->vimode.searching) { + struct key_binding const *const binding = match_binding( + &bindings->vimode, key, sym, mods, consumed, raw_syms, raw_count); + if (binding != NULL) { + execute_vimode_binding(seat, term, binding, serial); + } } else { - // If not a binding, then handle it as text input. - uint8_t buf[64] = {0}; - int count = 0; + struct key_binding const *const binding = + match_binding(&bindings->vimode_search, key, sym, mods, consumed, + raw_syms, raw_count); + bool search_string_updated = false; + if (binding != NULL) { + execute_vimode_search_binding(seat, term, binding, serial, + &search_string_updated); + } else { + // If not a binding, then handle it as text input. + uint8_t buf[64] = {0}; + int count = 0; - if (compose_status == XKB_COMPOSE_COMPOSED) { - count = xkb_compose_state_get_utf8(seat->kbd.xkb_compose_state, - (char *)buf, sizeof(buf)); - xkb_compose_state_reset(seat->kbd.xkb_compose_state); - } else if (compose_status == XKB_COMPOSE_CANCELLED) { - count = 0; - } else { - count = xkb_state_key_get_utf8(seat->kbd.xkb_state, key, (char *)buf, - sizeof(buf)); - } + if (compose_status == XKB_COMPOSE_COMPOSED) { + count = xkb_compose_state_get_utf8(seat->kbd.xkb_compose_state, + (char *)buf, sizeof(buf)); + xkb_compose_state_reset(seat->kbd.xkb_compose_state); + } else if (compose_status == XKB_COMPOSE_CANCELLED) { + count = 0; + } else { + count = xkb_state_key_get_utf8(seat->kbd.xkb_state, key, + (char *)buf, sizeof(buf)); + } - if (count > 0) { - vimode_search_add_chars(term, (const char *)buf, count); - render_refresh_vimode_search_box(term); - search_string_updated = true; - } + if (count > 0) { + vimode_search_add_chars(term, (const char *)buf, count); + render_refresh_vimode_search_box(term); + search_string_updated = true; + } + } + + if (search_string_updated) { + LOG_DBG("SEARCH UPDATED [%ls]", + (const wchar_t *)term->vimode.search.buf); + struct range match; + // TODO (kociap): when several consecutive searches succeed, the + // cursor is not moved to its original position in-between + // searches. + bool const matched = find_next_from_cursor( + term, term->vimode.search.buf, term->vimode.search.len, + term->vimode.search.direction, &match); + if (matched > 0) { + term->vimode.search.match = match.start; + term->vimode.search.match_len = term->vimode.search.len; + struct coord const delta = + delta_cursor_in_abs_coord(term, term->vimode.search.match); + move_cursor_delta(term, delta); + center_view_on_cursor(term); + update_selection(term); + } else { + restore_pre_search_state(term); + } + update_highlights(term); + } } - - if (search_string_updated) { - LOG_DBG("SEARCH UPDATED [%ls]", (const wchar_t *)term->vimode.search.buf); - struct range match; - // TODO (kociap): when several consecutive searches succeed, the - // cursor is not moved to its original position in-between - // searches. - bool const matched = find_next_from_cursor( - term, term->vimode.search.buf, term->vimode.search.len, - term->vimode.search.direction, &match); - if (matched > 0) { - term->vimode.search.match = match.start; - term->vimode.search.match_len = term->vimode.search.len; - struct coord const delta = - delta_cursor_in_abs_coord(term, term->vimode.search.match); - move_cursor_delta(term, delta); - center_view_on_cursor(term); - update_selection(term); - } else { - restore_pre_search_state(term); - } - update_highlights(term); - } - } } diff --git a/vimode.h b/vimode.h index 4523117e..696d75dd 100644 --- a/vimode.h +++ b/vimode.h @@ -24,10 +24,10 @@ void vimode_search_add_chars(struct terminal *term, const char *text, size_t len); struct search_match_iterator { - struct terminal *term; - struct coord start; - char32_t const *buf; - size_t len; + struct terminal *term; + struct coord start; + char32_t const *buf; + size_t len; }; struct search_match_iterator search_matches_new_iter(struct terminal *term,