This commit is contained in:
Piotr Kocia 2025-03-31 23:31:44 +02:00
parent 41987537cf
commit 210325d8aa
2 changed files with 1269 additions and 1197 deletions

252
vimode.c
View file

@ -21,13 +21,14 @@
// TODO (kociap): jump list? // TODO (kociap): jump list?
// TODO (kociap): WORD motions. // TODO (kociap): WORD motions.
static bool is_mode_visual(enum vi_mode const mode) { static bool is_mode_visual(enum vi_mode const mode)
{
return mode == VI_MODE_VISUAL || mode == VI_MODE_VLINE || return mode == VI_MODE_VISUAL || mode == VI_MODE_VLINE ||
mode == VI_MODE_VBLOCK; mode == VI_MODE_VBLOCK;
} }
static enum selection_kind static enum selection_kind selection_kind_from_vi_mode(enum vi_mode const mode)
selection_kind_from_vi_mode(enum vi_mode const mode) { {
switch (mode) { switch (mode) {
case VI_MODE_VISUAL: case VI_MODE_VISUAL:
return SELECTION_CHAR_WISE; return SELECTION_CHAR_WISE;
@ -41,43 +42,49 @@ selection_kind_from_vi_mode(enum vi_mode const mode) {
} }
} }
static enum search_direction invert_direction(enum search_direction direction) { static enum search_direction invert_direction(enum search_direction direction)
{
return direction == SEARCH_FORWARD ? SEARCH_BACKWARD : SEARCH_FORWARD; return direction == SEARCH_FORWARD ? SEARCH_BACKWARD : SEARCH_FORWARD;
} }
static struct coord cursor_to_view_relative(struct terminal *const term, static struct coord cursor_to_view_relative(struct terminal *const term,
struct coord cursor) { struct coord cursor)
{
cursor.row += term->grid->offset; cursor.row += term->grid->offset;
cursor.row -= term->grid->view; cursor.row -= term->grid->view;
return cursor; return cursor;
} }
static struct coord cursor_from_view_relative(struct terminal *const term, static struct coord cursor_from_view_relative(struct terminal *const term,
struct coord coord) { struct coord coord)
{
coord.row += term->grid->view; coord.row += term->grid->view;
coord.row -= term->grid->offset; coord.row -= term->grid->offset;
return coord; return coord;
} }
static int cursor_to_scrollback_relative(struct terminal *const term, int row) { static int cursor_to_scrollback_relative(struct terminal *const term, int row)
{
row = grid_row_abs_to_sb(term->grid, term->rows, row = grid_row_abs_to_sb(term->grid, term->rows,
grid_row_absolute(term->grid, row)); grid_row_absolute(term->grid, row));
return row; return row;
} }
static int cursor_from_scrollback_relative(struct terminal *const term, static int cursor_from_scrollback_relative(struct terminal *const term, int row)
int row) { {
row = grid_row_sb_to_abs(term->grid, term->rows, row); row = grid_row_sb_to_abs(term->grid, term->rows, row);
row -= term->grid->offset; row -= term->grid->offset;
return row; return row;
} }
static int view_to_scrollback_relative(struct terminal *const term) { static int view_to_scrollback_relative(struct terminal *const term)
{
return grid_row_abs_to_sb(term->grid, term->rows, term->grid->view); 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, static struct coord delta_cursor_in_abs_coord(struct terminal *const term,
struct coord const coord) { struct coord const coord)
{
int const location = grid_row_abs_to_sb(term->grid, term->rows, coord.row); int const location = grid_row_abs_to_sb(term->grid, term->rows, coord.row);
int const cursor = int const cursor =
cursor_to_scrollback_relative(term, term->vimode.cursor.row); cursor_to_scrollback_relative(term, term->vimode.cursor.row);
@ -87,16 +94,19 @@ static struct coord delta_cursor_in_abs_coord(struct terminal *const term,
}; };
} }
static void damage_cursor_cell(struct terminal *const term) { static void damage_cursor_cell(struct terminal *const term)
{
struct coord const cursor = struct coord const cursor =
cursor_to_view_relative(term, term->vimode.cursor); cursor_to_view_relative(term, term->vimode.cursor);
term_damage_cell_in_view(term, cursor.row, cursor.col); term_damage_cell_in_view(term, cursor.row, cursor.col);
render_refresh(term); render_refresh(term);
} }
static void clip_cursor_to_view(struct terminal *const term) { static void clip_cursor_to_view(struct terminal *const term)
{
damage_cursor_cell(term); damage_cursor_cell(term);
int cursor_row = cursor_to_scrollback_relative(term, term->vimode.cursor.row); int cursor_row =
cursor_to_scrollback_relative(term, term->vimode.cursor.row);
int const view_row = view_to_scrollback_relative(term); int const view_row = view_to_scrollback_relative(term);
if (cursor_row < view_row) { if (cursor_row < view_row) {
// Cursor is located above the current view. Move it to the top of // Cursor is located above the current view. Move it to the top of
@ -114,7 +124,8 @@ static void clip_cursor_to_view(struct terminal *const term) {
render_refresh(term); render_refresh(term);
} }
static void center_view_on_cursor(struct terminal *const term) { static void center_view_on_cursor(struct terminal *const term)
{
int const cursor = int const cursor =
cursor_to_scrollback_relative(term, term->vimode.cursor.row); cursor_to_scrollback_relative(term, term->vimode.cursor.row);
int const current_view = view_to_scrollback_relative(term); int const current_view = view_to_scrollback_relative(term);
@ -122,7 +133,8 @@ static void center_view_on_cursor(struct terminal *const term) {
int const delta = (cursor - half_viewport) - current_view; int const delta = (cursor - half_viewport) - current_view;
LOG_DBG("CENTER VIEW [cursor=(%d, %d); current_view=%d; half_viewport=%d; " LOG_DBG("CENTER VIEW [cursor=(%d, %d); current_view=%d; half_viewport=%d; "
"delta=%d]", "delta=%d]",
cursor, term->vimode.cursor.col, current_view, half_viewport, delta); cursor, term->vimode.cursor.col, current_view, half_viewport,
delta);
if (delta < 0) { if (delta < 0) {
cmd_scrollback_up(term, -delta); cmd_scrollback_up(term, -delta);
} else if (delta > 0) { } else if (delta > 0) {
@ -130,20 +142,22 @@ static void center_view_on_cursor(struct terminal *const term) {
} }
} }
static void update_selection(struct terminal *const term) { static void update_selection(struct terminal *const term)
{
enum vi_mode const mode = term->vimode.mode; enum vi_mode const mode = term->vimode.mode;
if (is_mode_visual(mode)) { if (is_mode_visual(mode)) {
struct coord const cursor = struct coord const cursor =
cursor_to_view_relative(term, term->vimode.cursor); cursor_to_view_relative(term, term->vimode.cursor);
selection_update(term, cursor); selection_update(term, cursor);
LOG_DBG( LOG_DBG("UPDATE SELECTION [view=%d; cursor=(%d, %d); "
"UPDATE SELECTION [view=%d; cursor=(%d, %d); selection.end=(%d,%d)]", "selection.end=(%d,%d)]",
term->grid->view, cursor.row, cursor.col, term->grid->view, cursor.row, cursor.col,
term->selection.coords.end.row, term->selection.coords.end.col); term->selection.coords.end.row, term->selection.coords.end.col);
} }
} }
static void damage_highlights(struct terminal *const term) { static void damage_highlights(struct terminal *const term)
{
struct highlight_location const *location = term->vimode.highlights; struct highlight_location const *location = term->vimode.highlights;
int const offset = term->grid->offset; int const offset = term->grid->offset;
while (location != NULL) { while (location != NULL) {
@ -157,7 +171,8 @@ static void damage_highlights(struct terminal *const term) {
render_refresh(term); render_refresh(term);
} }
static void clear_highlights(struct terminal *const term) { static void clear_highlights(struct terminal *const term)
{
damage_highlights(term); damage_highlights(term);
struct highlight_location const *location = term->vimode.highlights; struct highlight_location const *location = term->vimode.highlights;
while (location != NULL) { while (location != NULL) {
@ -177,7 +192,8 @@ static void clear_highlights(struct terminal *const term) {
// The regions are split so that each one spans at most // The regions are split so that each one spans at most
// a single line. The regions are in absolute row coordinates. // a single line. The regions are in absolute row coordinates.
// //
static void calculate_highlight_regions(struct terminal *const term) { static void calculate_highlight_regions(struct terminal *const term)
{
char32_t const *search_buf = term->vimode.search.buf; char32_t const *search_buf = term->vimode.search.buf;
size_t search_len = term->vimode.search.len; size_t search_len = term->vimode.search.len;
if (search_buf == NULL) { if (search_buf == NULL) {
@ -223,7 +239,8 @@ static void calculate_highlight_regions(struct terminal *const term) {
term->vimode.highlights = start; term->vimode.highlights = start;
} }
static void update_highlights(struct terminal *const term) { static void update_highlights(struct terminal *const term)
{
clear_highlights(term); clear_highlights(term);
calculate_highlight_regions(term); calculate_highlight_regions(term);
damage_highlights(term); damage_highlights(term);
@ -240,7 +257,8 @@ static void update_highlights(struct terminal *const term) {
* row, and if it is NULL, we move the viewport *backward* until the * row, and if it is NULL, we move the viewport *backward* until the
* last row is non-NULL. * last row is non-NULL.
*/ */
static int ensure_view_is_allocated(struct terminal *term, int new_view) { static int ensure_view_is_allocated(struct terminal *term, int new_view)
{
struct grid *grid = term->grid; struct grid *grid = term->grid;
int view_end = (new_view + term->rows - 1) & (grid->num_rows - 1); int view_end = (new_view + term->rows - 1) & (grid->num_rows - 1);
@ -266,11 +284,13 @@ static int ensure_view_is_allocated(struct terminal *term, int new_view) {
return new_view; return new_view;
} }
static bool search_ensure_size(struct terminal *term, size_t wanted_size) { static bool search_ensure_size(struct terminal *term, size_t wanted_size)
{
struct vimode_search *const search = &term->vimode.search; struct vimode_search *const search = &term->vimode.search;
while (wanted_size >= search->sz) { while (wanted_size >= search->sz) {
size_t new_sz = search->sz == 0 ? 64 : search->sz * 2; size_t new_sz = search->sz == 0 ? 64 : search->sz * 2;
char32_t *new_buf = realloc(search->buf, new_sz * sizeof(search->buf[0])); char32_t *new_buf =
realloc(search->buf, new_sz * sizeof(search->buf[0]));
if (new_buf == NULL) { if (new_buf == NULL) {
LOG_ERRNO("failed to resize search buffer"); LOG_ERRNO("failed to resize search buffer");
@ -285,7 +305,8 @@ static bool search_ensure_size(struct terminal *term, size_t wanted_size) {
} }
static void start_search(struct terminal *term, static void start_search(struct terminal *term,
enum search_direction const direction) { enum search_direction const direction)
{
if (term->vimode.searching) { if (term->vimode.searching) {
return; return;
} }
@ -313,7 +334,8 @@ static void start_search(struct terminal *term,
render_refresh_vimode_search_box(term); render_refresh_vimode_search_box(term);
} }
static void restore_pre_search_state(struct terminal *const term) { static void restore_pre_search_state(struct terminal *const term)
{
damage_cursor_cell(term); damage_cursor_cell(term);
term->vimode.cursor = term->vimode.search.original_cursor; term->vimode.cursor = term->vimode.search.original_cursor;
damage_cursor_cell(term); damage_cursor_cell(term);
@ -325,7 +347,8 @@ static void restore_pre_search_state(struct terminal *const term) {
} }
static void cancel_search(struct terminal *const term, static void cancel_search(struct terminal *const term,
bool const restore_original) { bool const restore_original)
{
if (!term->vimode.searching) { if (!term->vimode.searching) {
return; return;
} }
@ -348,7 +371,8 @@ static void cancel_search(struct terminal *const term,
term->render.search_glyph_offset = 0; term->render.search_glyph_offset = 0;
} }
static void confirm_search(struct terminal *const term) { static void confirm_search(struct terminal *const term)
{
if (term->vimode.confirmed_search.buf != NULL) { if (term->vimode.confirmed_search.buf != NULL) {
free(term->vimode.confirmed_search.buf); free(term->vimode.confirmed_search.buf);
} }
@ -359,13 +383,15 @@ static void confirm_search(struct terminal *const term) {
cancel_search(term, false); cancel_search(term, false);
} }
void vimode_search_begin(struct terminal *term) { void vimode_search_begin(struct terminal *term)
{
vimode_begin(term); vimode_begin(term);
start_search(term, SEARCH_FORWARD); start_search(term, SEARCH_FORWARD);
term_xcursor_update(term); term_xcursor_update(term);
} }
void vimode_begin(struct terminal *term) { void vimode_begin(struct terminal *term)
{
LOG_DBG("VIMODE BEGIN"); LOG_DBG("VIMODE BEGIN");
vimode_cancel(term); vimode_cancel(term);
@ -387,7 +413,8 @@ void vimode_begin(struct terminal *term) {
term_xcursor_update(term); term_xcursor_update(term);
} }
void vimode_cancel(struct terminal *term) { void vimode_cancel(struct terminal *term)
{
if (!term->vimode.active) { if (!term->vimode.active) {
return; return;
} }
@ -419,7 +446,8 @@ void vimode_cancel(struct terminal *term) {
static ssize_t matches_cell(const struct terminal *term, static ssize_t matches_cell(const struct terminal *term,
const struct cell *cell, char32_t const *const buf, 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); assert(search_ofs < len);
char32_t base = cell->wc; char32_t base = cell->wc;
@ -452,7 +480,8 @@ static ssize_t matches_cell(const struct terminal *term,
static bool find_next(struct terminal *term, char32_t const *const buf, static bool find_next(struct terminal *term, char32_t const *const buf,
size_t const len, enum search_direction direction, size_t const len, enum search_direction direction,
struct coord abs_start, struct coord abs_end, 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_DEC(_r) ((_r) = ((_r) - 1 + grid->num_rows) & (grid->num_rows - 1))
#define ROW_INC(_r) ((_r) = ((_r) + 1) & (grid->num_rows - 1)) #define ROW_INC(_r) ((_r) = ((_r) + 1) & (grid->num_rows - 1))
@ -484,8 +513,10 @@ static bool find_next(struct terminal *term, char32_t const *const buf,
for (; backward ? match_start_col >= 0 : match_start_col < term->cols; for (; backward ? match_start_col >= 0 : match_start_col < term->cols;
backward ? match_start_col-- : match_start_col++) { backward ? match_start_col-- : match_start_col++) {
if (matches_cell(term, &row->cells[match_start_col], buf, len, 0) < 0) { if (matches_cell(term, &row->cells[match_start_col], buf, len, 0) <
if (match_start_row == abs_end.row && match_start_col == abs_end.col) { 0) {
if (match_start_row == abs_end.row &&
match_start_col == abs_end.col) {
break; break;
} }
continue; continue;
@ -519,8 +550,8 @@ static bool find_next(struct terminal *term, char32_t const *const buf,
continue; continue;
} }
ssize_t additional_chars = ssize_t additional_chars = matches_cell(
matches_cell(term, &match_row->cells[match_end_col], buf, len, i); term, &match_row->cells[match_end_col], buf, len, i);
if (additional_chars < 0) if (additional_chars < 0)
break; break;
@ -537,7 +568,8 @@ static bool find_next(struct terminal *term, char32_t const *const buf,
if (match_len != len) { if (match_len != len) {
/* Didn't match (completely) */ /* Didn't match (completely) */
if (match_start_row == abs_end.row && match_start_col == abs_end.col) { if (match_start_row == abs_end.row &&
match_start_col == abs_end.col) {
break; break;
} }
@ -565,7 +597,8 @@ static bool find_next(struct terminal *term, char32_t const *const buf,
static bool find_next_from_cursor(struct terminal *const term, static bool find_next_from_cursor(struct terminal *const term,
char32_t *const buf, size_t const len, char32_t *const buf, size_t const len,
enum search_direction const direction, enum search_direction const direction,
struct range *const match) { struct range *const match)
{
if (len == 0 || buf == NULL) { if (len == 0 || buf == NULL) {
return false; return false;
} }
@ -629,7 +662,8 @@ static bool find_next_from_cursor(struct terminal *const term,
struct search_match_iterator struct search_match_iterator
search_matches_new_iter(struct terminal *const term, char32_t const *const buf, search_matches_new_iter(struct terminal *const term, char32_t const *const buf,
size_t const len) { size_t const len)
{
return (struct search_match_iterator){ return (struct search_match_iterator){
.term = term, .term = term,
.start = {0, 0}, .start = {0, 0},
@ -638,7 +672,8 @@ search_matches_new_iter(struct terminal *const term, char32_t const *const buf,
}; };
} }
struct range search_matches_next(struct search_match_iterator *iter) { struct range search_matches_next(struct search_match_iterator *iter)
{
struct terminal *term = iter->term; struct terminal *term = iter->term;
struct grid *grid = term->grid; struct grid *grid = term->grid;
if (iter->buf == NULL || iter->len == 0 || iter->start.row >= term->rows) { if (iter->buf == NULL || iter->len == 0 || iter->start.row >= term->rows) {
@ -661,8 +696,8 @@ struct range search_matches_next(struct search_match_iterator *iter) {
/* BUG: matches *starting* outside the view, but ending *inside*, aren't /* BUG: matches *starting* outside the view, but ending *inside*, aren't
* matched */ * matched */
struct range match; struct range match;
bool found = find_next(term, iter->buf, iter->len, SEARCH_FORWARD, abs_start, bool found = find_next(term, iter->buf, iter->len, SEARCH_FORWARD,
abs_end, &match); abs_start, abs_end, &match);
if (!found) { if (!found) {
iter->start.row = -1; iter->start.row = -1;
iter->start.col = -1; iter->start.col = -1;
@ -698,7 +733,8 @@ struct range search_matches_next(struct search_match_iterator *iter) {
return match; return match;
} }
static void add_wchars(struct terminal *term, char32_t *src, size_t count) { static void add_wchars(struct terminal *term, char32_t *src, size_t count)
{
/* Strip non-printable characters */ /* Strip non-printable characters */
for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) { for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) {
if (isc32print(src[i])) if (isc32print(src[i]))
@ -726,7 +762,8 @@ static void add_wchars(struct terminal *term, char32_t *src, size_t count) {
} }
void vimode_search_add_chars(struct terminal *term, const char *src, void vimode_search_add_chars(struct terminal *term, const char *src,
size_t count) { size_t count)
{
size_t chars = mbsntoc32(NULL, src, count, 0); size_t chars = mbsntoc32(NULL, src, count, 0);
if (chars == (size_t)-1) { if (chars == (size_t)-1) {
LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src); LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src);
@ -738,7 +775,8 @@ void vimode_search_add_chars(struct terminal *term, const char *src,
add_wchars(term, c32s, chars); add_wchars(term, c32s, chars);
} }
void vimode_view_down(struct terminal *const term, int const delta) { void vimode_view_down(struct terminal *const term, int const delta)
{
if (!term->vimode.active) { if (!term->vimode.active) {
return; return;
} }
@ -760,7 +798,8 @@ void vimode_view_down(struct terminal *const term, int const delta) {
// up/left, positive down/right. // up/left, positive down/right.
// //
static void move_cursor_delta(struct terminal *const term, static void move_cursor_delta(struct terminal *const term,
struct coord const delta) { struct coord const delta)
{
damage_cursor_cell(term); damage_cursor_cell(term);
struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor);
cursor.row += delta.row; cursor.row += delta.row;
@ -789,12 +828,13 @@ static void move_cursor_delta(struct terminal *const term,
render_refresh(term); render_refresh(term);
} }
static void move_cursor_vertical(struct terminal *const term, int const count) { static void move_cursor_vertical(struct terminal *const term, int const count)
{
move_cursor_delta(term, (struct coord){.row = count, .col = 0}); move_cursor_delta(term, (struct coord){.row = count, .col = 0});
} }
static void move_cursor_horizontal(struct terminal *const term, static void move_cursor_horizontal(struct terminal *const term, int const count)
int const count) { {
move_cursor_delta(term, (struct coord){.row = 0, .col = count}); move_cursor_delta(term, (struct coord){.row = 0, .col = count});
} }
@ -804,7 +844,8 @@ enum c32_class {
CLASS_WORD, CLASS_WORD,
}; };
enum c32_class get_class(char32_t const c) { enum c32_class get_class(char32_t const c)
{
if (c == '\0') { if (c == '\0') {
return CLASS_BLANK; return CLASS_BLANK;
} }
@ -831,17 +872,20 @@ enum c32_class get_class(char32_t const c) {
return CLASS_WORD; return CLASS_WORD;
} }
char32_t cursor_char(struct terminal *const term) { char32_t cursor_char(struct terminal *const term)
{
struct row *const row = grid_row(term->grid, term->vimode.cursor.row); struct row *const row = grid_row(term->grid, term->vimode.cursor.row);
return row->cells[term->vimode.cursor.col].wc; return row->cells[term->vimode.cursor.col].wc;
} }
enum c32_class cursor_class(struct terminal *const term) { enum c32_class cursor_class(struct terminal *const term)
{
char32_t const c = cursor_char(term); char32_t const c = cursor_char(term);
return get_class(c); return get_class(c);
} }
int row_length(struct terminal *const term, int const row_index) { int row_length(struct terminal *const term, int const row_index)
{
struct row *const row = grid_row(term->grid, row_index); struct row *const row = grid_row(term->grid, row_index);
int length = 0; int length = 0;
while (length < term->grid->num_cols) { while (length < term->grid->num_cols) {
@ -862,12 +906,14 @@ int row_length(struct terminal *const term, int const row_index) {
// false when at the end of the scrollback. // false when at the end of the scrollback.
// true otherwise. // true otherwise.
// //
bool increment_cursor(struct terminal *const term) { bool increment_cursor(struct terminal *const term)
{
char32_t const c = cursor_char(term); char32_t const c = cursor_char(term);
// Within a row, move to the next column. // Within a row, move to the next column.
if (c != '\0') { if (c != '\0') {
term->vimode.cursor.col += 1; term->vimode.cursor.col += 1;
struct row const *const row = grid_row(term->grid, term->vimode.cursor.row); 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 // If the row does not contain a linebreak, we want to move to the
// next row immediately. // next row immediately.
if (row->linebreak || term->vimode.cursor.col < term->cols) { if (row->linebreak || term->vimode.cursor.col < term->cols) {
@ -880,7 +926,8 @@ bool increment_cursor(struct terminal *const term) {
term->vimode.cursor.row += 1; term->vimode.cursor.row += 1;
term->vimode.cursor.col = 0; term->vimode.cursor.col = 0;
// If the cursor moved outside the view, follow it. // If the cursor moved outside the view, follow it.
struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); struct coord cursor =
cursor_to_view_relative(term, term->vimode.cursor);
if (cursor.row >= term->rows) { if (cursor.row >= term->rows) {
cmd_scrollback_down(term, 1); cmd_scrollback_down(term, 1);
} }
@ -899,7 +946,8 @@ bool increment_cursor(struct terminal *const term) {
// false when at the start of the scrollback. // false when at the start of the scrollback.
// true otherwise. // true otherwise.
// //
bool decrement_cursor(struct terminal *const term) { bool decrement_cursor(struct terminal *const term)
{
// Within a row, move to the previous column. // Within a row, move to the previous column.
if (term->vimode.cursor.col > 0) { if (term->vimode.cursor.col > 0) {
term->vimode.cursor.col -= 1; term->vimode.cursor.col -= 1;
@ -919,7 +967,8 @@ bool decrement_cursor(struct terminal *const term) {
term->vimode.cursor.row -= 1; term->vimode.cursor.row -= 1;
term->vimode.cursor.col = row_length(term, 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. // If the cursor moved outside the view, follow it.
struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); struct coord cursor =
cursor_to_view_relative(term, term->vimode.cursor);
if (cursor.row < 0) { if (cursor.row < 0) {
cmd_scrollback_up(term, 1); cmd_scrollback_up(term, 1);
} }
@ -934,8 +983,8 @@ bool decrement_cursor(struct terminal *const term) {
// false when at the end of the scrollback. // false when at the end of the scrollback.
// true otherwise. // true otherwise.
// //
bool skip_chars_forward(struct terminal *const term, bool skip_chars_forward(struct terminal *const term, enum c32_class const class)
enum c32_class const class) { {
while (cursor_class(term) == class) { while (cursor_class(term) == class) {
if (increment_cursor(term) == false) { if (increment_cursor(term) == false) {
return false; return false;
@ -951,7 +1000,8 @@ bool skip_chars_forward(struct terminal *const term,
// true otherwise. // true otherwise.
// //
bool skip_chars_backward(struct terminal *const term, bool skip_chars_backward(struct terminal *const term,
enum c32_class const class) { enum c32_class const class)
{
while (cursor_class(term) == class) { while (cursor_class(term) == class) {
if (decrement_cursor(term) == false) { if (decrement_cursor(term) == false) {
return false; return false;
@ -964,7 +1014,8 @@ bool skip_chars_backward(struct terminal *const term,
// Move the cursor back to the start of a word. // Move the cursor back to the start of a word.
// //
void motion_begin_word(struct terminal *const term) { void motion_begin_word(struct terminal *const term)
{
if (decrement_cursor(term) == false) { if (decrement_cursor(term) == false) {
return; return;
} }
@ -993,7 +1044,8 @@ void motion_begin_word(struct terminal *const term) {
// Move the cursor forward to the end of a word. // Move the cursor forward to the end of a word.
// //
void motion_end_word(struct terminal *const term) { void motion_end_word(struct terminal *const term)
{
if (increment_cursor(term) == false) { if (increment_cursor(term) == false) {
return; return;
} }
@ -1021,7 +1073,8 @@ void motion_end_word(struct terminal *const term) {
// Move the cursor forward to the start of a word. // Move the cursor forward to the start of a word.
// //
void motion_fwd_begin_word(struct terminal *const term) { void motion_fwd_begin_word(struct terminal *const term)
{
enum c32_class const starting_class = cursor_class(term); enum c32_class const starting_class = cursor_class(term);
if (increment_cursor(term) == false) { if (increment_cursor(term) == false) {
return; return;
@ -1050,7 +1103,8 @@ void motion_fwd_begin_word(struct terminal *const term) {
// Move the cursor back to the end of a word. // Move the cursor back to the end of a word.
// //
void motion_back_end_word(struct terminal *const term) { void motion_back_end_word(struct terminal *const term)
{
enum c32_class const starting_class = cursor_class(term); enum c32_class const starting_class = cursor_class(term);
if (decrement_cursor(term) == false) { if (decrement_cursor(term) == false) {
return; return;
@ -1078,7 +1132,8 @@ void motion_back_end_word(struct terminal *const term) {
static void execute_vimode_binding(struct seat *seat, struct terminal *term, static void execute_vimode_binding(struct seat *seat, struct terminal *term,
const struct key_binding *binding, const struct key_binding *binding,
uint32_t serial) { uint32_t serial)
{
const enum bind_action_vimode action = binding->action; const enum bind_action_vimode action = binding->action;
if (term->grid != &term->normal) { if (term->grid != &term->normal) {
@ -1158,7 +1213,8 @@ static void execute_vimode_binding(struct seat *seat, struct terminal *term,
cmd_scrollback_up(term, term->grid->num_rows); cmd_scrollback_up(term, term->grid->num_rows);
damage_cursor_cell(term); damage_cursor_cell(term);
int const view_row = view_to_scrollback_relative(term); int const view_row = view_to_scrollback_relative(term);
term->vimode.cursor.row = cursor_from_scrollback_relative(term, view_row); term->vimode.cursor.row =
cursor_from_scrollback_relative(term, view_row);
damage_cursor_cell(term); damage_cursor_cell(term);
update_selection(term); update_selection(term);
update_highlights(term); update_highlights(term);
@ -1181,7 +1237,8 @@ static void execute_vimode_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_VIMODE_LINE_END: { case BIND_ACTION_VIMODE_LINE_END: {
damage_cursor_cell(term); damage_cursor_cell(term);
struct row const *const row = grid_row(term->grid, term->vimode.cursor.row); struct row const *const row =
grid_row(term->grid, term->vimode.cursor.row);
int col = term->cols - 1; int col = term->cols - 1;
while (col > 0) { while (col > 0) {
if (row->cells[col].wc != '\0') { if (row->cells[col].wc != '\0') {
@ -1195,7 +1252,8 @@ static void execute_vimode_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_VIMODE_TEXT_BEGIN: { case BIND_ACTION_VIMODE_TEXT_BEGIN: {
damage_cursor_cell(term); damage_cursor_cell(term);
struct row const *const row = grid_row(term->grid, term->vimode.cursor.row); struct row const *const row =
grid_row(term->grid, term->vimode.cursor.row);
int col = 0; int col = 0;
while (col < term->cols - 1) { while (col < term->cols - 1) {
if (isc32graph(row->cells[col].wc)) { if (isc32graph(row->cells[col].wc)) {
@ -1268,8 +1326,10 @@ static void execute_vimode_binding(struct seat *seat, struct terminal *term,
term->vimode.confirmed_search.len, direction, &match); term->vimode.confirmed_search.len, direction, &match);
// TODO (kociap): feedback for the user when no match? // TODO (kociap): feedback for the user when no match?
if (matched) { if (matched) {
struct coord const delta = delta_cursor_in_abs_coord(term, match.start); struct coord const delta =
LOG_DBG("FIND %s [direction=%s; location=%d; cursor=%d; match=(%d, " delta_cursor_in_abs_coord(term, match.start);
LOG_DBG(
"FIND %s [direction=%s; location=%d; cursor=%d; match=(%d, "
"%d)]\n", "%d)]\n",
(action == BIND_ACTION_VIMODE_FIND_NEXT) ? "NEXT" : "PREV", (action == BIND_ACTION_VIMODE_FIND_NEXT) ? "NEXT" : "PREV",
(direction == SEARCH_FORWARD ? "forward" : "backward"), (direction == SEARCH_FORWARD ? "forward" : "backward"),
@ -1343,7 +1403,8 @@ static void execute_vimode_search_binding(struct seat *seat,
struct terminal *const term, struct terminal *const term,
const struct key_binding *binding, const struct key_binding *binding,
uint32_t serial, uint32_t serial,
bool *search_string_changed) { bool *search_string_changed)
{
const enum bind_action_vimode action = binding->action; const enum bind_action_vimode action = binding->action;
struct vimode_search *const search = &term->vimode.search; struct vimode_search *const search = &term->vimode.search;
*search_string_changed = false; *search_string_changed = false;
@ -1358,8 +1419,10 @@ static void execute_vimode_search_binding(struct seat *seat,
case BIND_ACTION_VIMODE_SEARCH_CONFIRM: case BIND_ACTION_VIMODE_SEARCH_CONFIRM:
if (search->match_len > 0) { if (search->match_len > 0) {
struct coord const delta = delta_cursor_in_abs_coord(term, search->match); struct coord const delta =
LOG_DBG("CONFIRM SEARCH [location=%d; cursor=%d; match=(%d, %d)]", 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), grid_row_abs_to_sb(term->grid, term->rows, search->match.row),
cursor_to_scrollback_relative(term, term->vimode.cursor.row), cursor_to_scrollback_relative(term, term->vimode.cursor.row),
search->match.row, search->match.col); search->match.row, search->match.col);
@ -1376,7 +1439,8 @@ static void execute_vimode_search_binding(struct seat *seat,
case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR: case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR:
if (search->cursor > 0) { if (search->cursor > 0) {
memmove(&search->buf[search->cursor - 1], &search->buf[search->cursor], memmove(&search->buf[search->cursor - 1],
&search->buf[search->cursor],
(search->len - search->cursor) * sizeof(char32_t)); (search->len - search->cursor) * sizeof(char32_t));
search->cursor -= 1; search->cursor -= 1;
search->len -= 1; search->len -= 1;
@ -1408,7 +1472,8 @@ static void execute_vimode_search_binding(struct seat *seat,
// return true; // return true;
// //
// case BIND_ACTION_SEARCH_PRIMARY_PASTE: // case BIND_ACTION_SEARCH_PRIMARY_PASTE:
// text_from_primary(seat, term, &from_clipboard_cb, &from_clipboard_done, // text_from_primary(seat, term, &from_clipboard_cb,
// &from_clipboard_done,
// term); // term);
// *update_search_result = *redraw = true; // *update_search_result = *redraw = true;
// return true; // return true;
@ -1430,9 +1495,11 @@ static void execute_vimode_search_binding(struct seat *seat,
static struct key_binding const * static struct key_binding const *
match_binding(key_binding_list_t const *bindings, uint32_t key, 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, xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
const xkb_keysym_t *raw_syms, size_t raw_count) { const xkb_keysym_t *raw_syms, size_t raw_count)
{
/* Match untranslated symbols */ /* Match untranslated symbols */
tll_foreach(*bindings, it) { tll_foreach(*bindings, it)
{
const struct key_binding *bind = &it->item; const struct key_binding *bind = &it->item;
if (bind->mods != mods || bind->mods == 0) if (bind->mods != mods || bind->mods == 0)
@ -1446,7 +1513,8 @@ match_binding(key_binding_list_t const *bindings, uint32_t key,
} }
/* Match translated symbol */ /* Match translated symbol */
tll_foreach(*bindings, it) { tll_foreach(*bindings, it)
{
const struct key_binding *bind = &it->item; const struct key_binding *bind = &it->item;
if (bind->k.sym == sym && bind->mods == (mods & ~consumed)) { if (bind->k.sym == sym && bind->mods == (mods & ~consumed)) {
@ -1455,13 +1523,15 @@ match_binding(key_binding_list_t const *bindings, uint32_t key,
} }
/* Match raw key code */ /* Match raw key code */
tll_foreach(*bindings, it) { tll_foreach(*bindings, it)
{
const struct key_binding *bind = &it->item; const struct key_binding *bind = &it->item;
if (bind->mods != mods || bind->mods == 0) if (bind->mods != mods || bind->mods == 0)
continue; continue;
tll_foreach(bind->k.key_codes, code) { tll_foreach(bind->k.key_codes, code)
{
if (code->item == key) { if (code->item == key) {
return bind; return bind;
} }
@ -1475,9 +1545,10 @@ void vimode_input(struct seat *seat, struct terminal *term,
const struct key_binding_set *bindings, uint32_t key, const struct key_binding_set *bindings, uint32_t key,
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_keysym_t sym, xkb_mod_mask_t mods,
xkb_mod_mask_t consumed, const xkb_keysym_t *raw_syms, xkb_mod_mask_t consumed, const xkb_keysym_t *raw_syms,
size_t raw_count, uint32_t serial) { 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); LOG_DBG("VIMODE INPUT [sym=%d/0x%x, mods=0x%08x, consumed=0x%08x]", sym,
sym, mods, consumed);
enum xkb_compose_status compose_status = enum xkb_compose_status compose_status =
seat->kbd.xkb_compose_state != NULL seat->kbd.xkb_compose_state != NULL
@ -1510,8 +1581,8 @@ void vimode_input(struct seat *seat, struct terminal *term,
} else if (compose_status == XKB_COMPOSE_CANCELLED) { } else if (compose_status == XKB_COMPOSE_CANCELLED) {
count = 0; count = 0;
} else { } else {
count = xkb_state_key_get_utf8(seat->kbd.xkb_state, key, (char *)buf, count = xkb_state_key_get_utf8(seat->kbd.xkb_state, key,
sizeof(buf)); (char *)buf, sizeof(buf));
} }
if (count > 0) { if (count > 0) {
@ -1522,7 +1593,8 @@ void vimode_input(struct seat *seat, struct terminal *term,
} }
if (search_string_updated) { if (search_string_updated) {
LOG_DBG("SEARCH UPDATED [%ls]", (const wchar_t *)term->vimode.search.buf); LOG_DBG("SEARCH UPDATED [%ls]",
(const wchar_t *)term->vimode.search.buf);
struct range match; struct range match;
// TODO (kociap): when several consecutive searches succeed, the // TODO (kociap): when several consecutive searches succeed, the
// cursor is not moved to its original position in-between // cursor is not moved to its original position in-between