From 548d7be4c60601fe9321d31aa3d8c47c2fa039fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 30 Sep 2021 13:39:23 +0200 Subject: [PATCH] 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 --- CHANGELOG.md | 2 + selection.c | 101 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c08b29c5..f15256b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/selection.c b/selection.c index b40215e6..b6bae978 100644 --- a/selection.c +++ b/selection.c @@ -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: