selection: line-wise selection now handles soft line-wrapping

Previously, soft-wrapped lines were not selected correctly, as the
selection logic was hardcoded to simply select everything between the
first and last column on the current terminal row.

Now, we scan backward and forward, looking for hard-wrapped
lines. This is similar to how word-based selection works.

Closes #726
This commit is contained in:
Daniel Eklöf 2021-09-30 13:39:23 +02:00
parent df8aea6cb6
commit 548d7be4c6
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 86 additions and 17 deletions

View file

@ -68,6 +68,8 @@
* Added workaround for GNOME bug where multiple button press events
(for the same button) is sent to the CSDs without any release or
leave events in between (https://codeberg.org/dnkl/foot/issues/709).
* Line-wise selection not taking soft line-wrapping into account
(https://codeberg.org/dnkl/foot/issues/726).
### Security

View file

@ -378,6 +378,50 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
}
}
void
selection_find_line_boundary_left(struct terminal *term, struct coord *pos,
bool spaces_only)
{
int next_row = pos->row;
pos->col = 0;
while (true) {
if (--next_row < 0)
return;
const struct row *row = grid_row_in_view(term->grid, next_row);
assert(row != NULL);
if (row->linebreak)
return;
pos->col = 0;
pos->row = next_row;
}
}
void
selection_find_line_boundary_right(struct terminal *term, struct coord *pos,
bool spaces_only)
{
int next_row = pos->row;
pos->col = term->cols - 1;
while (true) {
const struct row *row = grid_row_in_view(term->grid, next_row);
assert(row != NULL);
if (row->linebreak)
return;
if (++next_row >= term->rows)
return;
pos->col = term->cols - 1;
pos->row = next_row;
}
}
void
selection_start(struct terminal *term, int col, int row,
enum selection_kind kind,
@ -421,13 +465,19 @@ selection_start(struct terminal *term, int col, int row,
break;
}
case SELECTION_LINE_WISE:
term->selection.start = (struct coord){0, term->grid->view + row};
term->selection.pivot.start = term->selection.start;
term->selection.pivot.end = (struct coord){term->cols - 1, term->grid->view + row};
case SELECTION_LINE_WISE: {
struct coord start = {0, row}, end = {term->cols - 1, row};
selection_find_line_boundary_left(term, &start, spaces_only);
selection_find_line_boundary_right(term, &end, spaces_only);
selection_update(term, term->cols - 1, row);
term->selection.start = (struct coord){
start.col, term->grid->view + start.row};
term->selection.pivot.start = term->selection.start;
term->selection.pivot.end = (struct coord){end.col, term->grid->view + end.row};
selection_update(term, end.col, end.row);
break;
}
case SELECTION_NONE:
BUG("Invalid selection kind");
@ -756,13 +806,21 @@ selection_update(struct terminal *term, int col, int row)
case SELECTION_LINE_WISE:
switch (term->selection.direction) {
case SELECTION_LEFT:
new_end.col = 0;
case SELECTION_LEFT: {
struct coord end = {0, row};
selection_find_line_boundary_left(
term, &end, term->selection.spaces_only);
new_end = (struct coord){end.col, term->grid->view + end.row};
break;
}
case SELECTION_RIGHT:
new_end.col = term->cols - 1;
case SELECTION_RIGHT: {
struct coord end = {col, row};
selection_find_line_boundary_right(
term, &end, term->selection.spaces_only);
new_end = (struct coord){end.col, term->grid->view + end.row};
break;
}
case SELECTION_UNDIR:
break;
@ -870,6 +928,8 @@ selection_extend_normal(struct terminal *term, int col, int row,
}
}
const bool spaces_only = term->selection.spaces_only;
switch (term->selection.kind) {
case SELECTION_CHAR_WISE:
xassert(new_kind == SELECTION_CHAR_WISE);
@ -883,10 +943,8 @@ selection_extend_normal(struct terminal *term, int col, int row,
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
struct coord pivot_end = pivot_start;
selection_find_word_boundary_left(
term, &pivot_start, term->selection.spaces_only);
selection_find_word_boundary_right(
term, &pivot_end, term->selection.spaces_only);
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
selection_find_word_boundary_right(term, &pivot_end, spaces_only);
term->selection.pivot.start =
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
@ -895,13 +953,22 @@ selection_extend_normal(struct terminal *term, int col, int row,
break;
}
case SELECTION_LINE_WISE:
case SELECTION_LINE_WISE: {
xassert(new_kind == SELECTION_CHAR_WISE ||
new_kind == SELECTION_LINE_WISE);
new_kind == SELECTION_LINE_WISE);
term->selection.pivot.start = (struct coord){0, new_start.row};
term->selection.pivot.end = (struct coord){term->cols - 1, new_start.row};
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
struct coord pivot_end = pivot_start;
selection_find_line_boundary_left(term, &pivot_start, spaces_only);
selection_find_line_boundary_right(term, &pivot_end, spaces_only);
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};
break;
}
case SELECTION_BLOCK:
case SELECTION_NONE: