mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
search: add more key bindings to extend the current match
This patch adds the following new search key bindings: * extend-char (shift+right) * extend-line-down (shift+down) * extend-backward-char (shift+left) * extend-backward-to-word-boundary (ctrl+shift+left) * extend-backward-to-next-whitespace (ctrl+shift+alt+left) * extend-line-up (shift+up) They can be used to extend the search match (i.e. the selection). This patch also adds an initial set of key bindings to scroll in the scrollback history: * scrollback-up-page * scrollback-down-page These work just like the key bindings for the normal mode. Also note that it was already possible to scroll using the mouse. This patch also fixes a couple of search mode bugs: * crashing when a search match ends in the last column * grapheme clusters not being matched correctly * Search match not being "extendable" after a pointer leave event * A few others, related to either large matches, or extending matches after moving the viewport. There are still a couple of (known) issues: * A search match isn't correctly highlighted if its *starting* point is outside the viewport. * Extending the match to end of the scrollback (i.e. the most recent output) is simply buggy. Related to #419
This commit is contained in:
parent
56d5d4cc21
commit
78665a7e80
6 changed files with 457 additions and 106 deletions
93
selection.c
93
selection.c
|
|
@ -340,16 +340,18 @@ selection_to_text(const struct terminal *term)
|
|||
return extract_finish(ctx, &text, NULL) ? text : NULL;
|
||||
}
|
||||
|
||||
/* Coordinates are in *absolute* row numbers (NOT view local) */
|
||||
void
|
||||
selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
||||
selection_find_word_boundary_left(const struct terminal *term, struct coord *pos,
|
||||
bool spaces_only)
|
||||
{
|
||||
xassert(pos->row >= 0);
|
||||
xassert(pos->row < term->rows);
|
||||
xassert(pos->row < term->grid->num_rows);
|
||||
xassert(pos->col >= 0);
|
||||
xassert(pos->col < term->cols);
|
||||
|
||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||
const struct grid *grid = term->grid;
|
||||
const struct row *r = grid->rows[pos->row];
|
||||
char32_t c = r->cells[pos->col].wc;
|
||||
|
||||
while (c >= CELL_SPACER) {
|
||||
|
|
@ -373,15 +375,22 @@ selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
|||
int next_col = pos->col - 1;
|
||||
int next_row = pos->row;
|
||||
|
||||
const struct row *row = grid_row_in_view(term->grid, next_row);
|
||||
const struct row *row = grid->rows[next_row];
|
||||
|
||||
/* Linewrap */
|
||||
if (next_col < 0) {
|
||||
next_col = term->cols - 1;
|
||||
if (--next_row < 0)
|
||||
break;
|
||||
|
||||
row = grid_row_in_view(term->grid, next_row);
|
||||
next_row = (next_row - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||
|
||||
if (grid_row_abs_to_sb(grid, term->rows, next_row) == term->grid->num_rows - 1 ||
|
||||
grid->rows[next_row] == NULL)
|
||||
{
|
||||
/* Scrollback wrap-around */
|
||||
break;
|
||||
}
|
||||
|
||||
row = grid->rows[next_row];
|
||||
|
||||
if (row->linebreak) {
|
||||
/* Hard linebreak, treat as space. I.e. break selection */
|
||||
|
|
@ -418,17 +427,19 @@ selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
|||
}
|
||||
}
|
||||
|
||||
/* Coordinates are in *absolute* row numbers (NOT view local) */
|
||||
void
|
||||
selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
||||
selection_find_word_boundary_right(const struct terminal *term, struct coord *pos,
|
||||
bool spaces_only,
|
||||
bool stop_on_space_to_word_boundary)
|
||||
{
|
||||
xassert(pos->row >= 0);
|
||||
xassert(pos->row < term->rows);
|
||||
xassert(pos->row < term->grid->num_rows);
|
||||
xassert(pos->col >= 0);
|
||||
xassert(pos->col < term->cols);
|
||||
|
||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||
const struct grid *grid = term->grid;
|
||||
const struct row *r = grid->rows[pos->row];
|
||||
char32_t c = r->cells[pos->col].wc;
|
||||
|
||||
while (c >= CELL_SPACER) {
|
||||
|
|
@ -453,7 +464,7 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
|||
int next_col = pos->col + 1;
|
||||
int next_row = pos->row;
|
||||
|
||||
const struct row *row = grid_row_in_view(term->grid, next_row);
|
||||
const struct row *row = term->grid->rows[next_row];
|
||||
|
||||
/* Linewrap */
|
||||
if (next_col >= term->cols) {
|
||||
|
|
@ -463,10 +474,14 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
|||
}
|
||||
|
||||
next_col = 0;
|
||||
if (++next_row >= term->rows)
|
||||
break;
|
||||
next_row = (next_row + 1) & (grid->num_rows - 1);
|
||||
|
||||
row = grid_row_in_view(term->grid, next_row);
|
||||
if (grid_row_abs_to_sb(grid, term->rows, next_row) == 0) {
|
||||
/* Scrollback wrap-around */
|
||||
break;
|
||||
}
|
||||
|
||||
row = grid->rows[next_row];
|
||||
}
|
||||
|
||||
c = row->cells[next_col].wc;
|
||||
|
|
@ -659,15 +674,15 @@ selection_start(struct terminal *term, int col, int row,
|
|||
break;
|
||||
|
||||
case SELECTION_WORD_WISE: {
|
||||
struct coord start = {col, row}, end = {col, row};
|
||||
struct coord start = {col, term->grid->view + row};
|
||||
struct coord end = {col, term->grid->view + row};
|
||||
selection_find_word_boundary_left(term, &start, spaces_only);
|
||||
selection_find_word_boundary_right(term, &end, spaces_only, true);
|
||||
|
||||
term->selection.coords.start = (struct coord){
|
||||
start.col, term->grid->view + start.row};
|
||||
term->selection.coords.start = start;
|
||||
|
||||
term->selection.pivot.start = term->selection.coords.start;
|
||||
term->selection.pivot.end = (struct coord){end.col, term->grid->view + end.row};
|
||||
term->selection.pivot.end = end;
|
||||
|
||||
selection_update(term, end.col, end.row);
|
||||
break;
|
||||
|
|
@ -1085,22 +1100,26 @@ set_pivot_point_for_block_and_char_wise(struct terminal *term,
|
|||
void
|
||||
selection_update(struct terminal *term, int col, int row)
|
||||
{
|
||||
if (term->selection.coords.start.row < 0)
|
||||
if (term->selection.coords.start.row < 0) {
|
||||
LOG_ERR("NO SELECTION");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!term->selection.ongoing)
|
||||
if (!term->selection.ongoing) {
|
||||
LOG_ERR("NOT ON-GOING");
|
||||
return;
|
||||
|
||||
LOG_DBG("selection updated: start = %d,%d, end = %d,%d -> %d, %d",
|
||||
term->selection.coords.start.row, term->selection.coords.start.col,
|
||||
term->selection.coords.end.row, term->selection.coords.end.col,
|
||||
row, col);
|
||||
}
|
||||
|
||||
xassert(term->grid->view + row != -1);
|
||||
|
||||
struct coord new_start = term->selection.coords.start;
|
||||
struct coord new_end = {col, term->grid->view + row};
|
||||
|
||||
LOG_DBG("selection updated: start = %d,%d, end = %d,%d -> %d, %d",
|
||||
term->selection.coords.start.row, term->selection.coords.start.col,
|
||||
term->selection.coords.end.row, term->selection.coords.end.col,
|
||||
new_end.row, new_end.col);
|
||||
|
||||
/* Adjust start point if the selection has changed 'direction' */
|
||||
if (!(new_end.row == new_start.row && new_end.col == new_start.col)) {
|
||||
enum selection_direction new_direction = term->selection.direction;
|
||||
|
|
@ -1160,21 +1179,17 @@ selection_update(struct terminal *term, int col, int row)
|
|||
|
||||
case SELECTION_WORD_WISE:
|
||||
switch (term->selection.direction) {
|
||||
case SELECTION_LEFT: {
|
||||
struct coord end = {col, row};
|
||||
case SELECTION_LEFT:
|
||||
new_end = (struct coord){col, term->grid->view + row};
|
||||
selection_find_word_boundary_left(
|
||||
term, &end, term->selection.spaces_only);
|
||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||
term, &new_end, term->selection.spaces_only);
|
||||
break;
|
||||
}
|
||||
|
||||
case SELECTION_RIGHT: {
|
||||
struct coord end = {col, row};
|
||||
case SELECTION_RIGHT:
|
||||
new_end = (struct coord){col, term->grid->view + row};
|
||||
selection_find_word_boundary_right(
|
||||
term, &end, term->selection.spaces_only, true);
|
||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||
term, &new_end, term->selection.spaces_only, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case SELECTION_UNDIR:
|
||||
break;
|
||||
|
|
@ -1346,16 +1361,14 @@ selection_extend_normal(struct terminal *term, int col, int row,
|
|||
xassert(new_kind == SELECTION_CHAR_WISE ||
|
||||
new_kind == SELECTION_WORD_WISE);
|
||||
|
||||
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
|
||||
struct coord pivot_start = {new_start.col, new_start.row};
|
||||
struct coord pivot_end = pivot_start;
|
||||
|
||||
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
|
||||
selection_find_word_boundary_right(term, &pivot_end, spaces_only, true);
|
||||
|
||||
term->selection.pivot.start =
|
||||
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
||||
term->selection.pivot.end =
|
||||
(struct coord){pivot_end.col, term->grid->view + pivot_end.row};
|
||||
term->selection.pivot.start = pivot_start;
|
||||
term->selection.pivot.end = pivot_end;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue