mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
selection: foreach: sort start/end based on their scrollback-start relative values
When iterating the characters in a selection, we want to go from the “start” to the “end”, where start is the upper left-most character, and “end” is the lower right-most character. There are two things to consider: * The ‘start’ coordinate may actually sort after the ‘end’ coordinate (user selected from bottom of the window and upward) * The scrollback wraparound. What we do is calculate both the star and end coordinates’ scrollback-start relative row numbers. That is, the number of rows from the beginning of the scrollback. So if the very first row (i.e. the oldest) in the scrollback is selected, that has the scrollback-start relative number “0”. Then we loop from whichever (start or end coordinate) is highest up in the scrollback, to the “other” coordinate.
This commit is contained in:
parent
0800515c04
commit
ef522e292f
1 changed files with 56 additions and 20 deletions
76
selection.c
76
selection.c
|
|
@ -107,24 +107,34 @@ selection_view_down(struct terminal *term, int new_view)
|
||||||
static void
|
static void
|
||||||
foreach_selected_normal(
|
foreach_selected_normal(
|
||||||
struct terminal *term, struct coord _start, struct coord _end,
|
struct terminal *term, struct coord _start, struct coord _end,
|
||||||
bool (*cb)(struct terminal *term, struct row *row, struct cell *cell, int row_no, int col, void *data),
|
bool (*cb)(struct terminal *term, struct row *row, struct cell *cell,
|
||||||
|
int row_no, int col, void *data),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
const struct coord *start = &_start;
|
const struct coord *start = &_start;
|
||||||
const struct coord *end = &_end;
|
const struct coord *end = &_end;
|
||||||
|
|
||||||
|
const int scrollback_start = term->grid->offset + term->rows;
|
||||||
|
const int grid_rows = term->grid->num_rows;
|
||||||
|
|
||||||
|
/* Start/end rows, relative to the scrollback start */
|
||||||
|
const int rel_start_row =
|
||||||
|
(start->row - scrollback_start + grid_rows) & (grid_rows - 1);
|
||||||
|
const int rel_end_row =
|
||||||
|
(end->row - scrollback_start + grid_rows) & (grid_rows - 1);
|
||||||
|
|
||||||
int start_row, end_row;
|
int start_row, end_row;
|
||||||
int start_col, end_col;
|
int start_col, end_col;
|
||||||
|
|
||||||
if (start->row < end->row) {
|
if (rel_start_row < rel_end_row) {
|
||||||
start_row = start->row;
|
start_row = start->row;
|
||||||
end_row = end->row;
|
|
||||||
start_col = start->col;
|
start_col = start->col;
|
||||||
|
end_row = end->row;
|
||||||
end_col = end->col;
|
end_col = end->col;
|
||||||
} else if (start->row > end->row) {
|
} else if (rel_start_row > rel_end_row) {
|
||||||
start_row = end->row;
|
start_row = end->row;
|
||||||
end_row = start->row;
|
|
||||||
start_col = end->col;
|
start_col = end->col;
|
||||||
|
end_row = start->row;
|
||||||
end_col = start->col;
|
end_col = start->col;
|
||||||
} else {
|
} else {
|
||||||
start_row = end_row = start->row;
|
start_row = end_row = start->row;
|
||||||
|
|
@ -132,51 +142,77 @@ foreach_selected_normal(
|
||||||
end_col = max(start->col, end->col);
|
end_col = max(start->col, end->col);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int r = start_row; r <= end_row; r++) {
|
start_row &= (grid_rows - 1);
|
||||||
size_t real_r = r & (term->grid->num_rows - 1);
|
end_row &= (grid_rows - 1);
|
||||||
struct row *row = term->grid->rows[real_r];
|
|
||||||
|
for (int r = start_row; r != end_row; r = (r + 1) & (grid_rows - 1)) {
|
||||||
|
struct row *row = term->grid->rows[r];
|
||||||
xassert(row != NULL);
|
xassert(row != NULL);
|
||||||
|
|
||||||
for (int c = start_col;
|
for (int c = start_col; c <= term->cols - 1; c++) {
|
||||||
c <= (r == end_row ? end_col : term->cols - 1);
|
if (!cb(term, row, &row->cells[c], r, c, data))
|
||||||
c++)
|
|
||||||
{
|
|
||||||
if (!cb(term, row, &row->cells[c], real_r, c, data))
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_col = 0;
|
start_col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Last, partial row */
|
||||||
|
struct row *row = term->grid->rows[end_row];
|
||||||
|
xassert(row != NULL);
|
||||||
|
|
||||||
|
for (int c = start_col; c <= end_col; c++) {
|
||||||
|
if (!cb(term, row, &row->cells[c], end_row, c, data))
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
foreach_selected_block(
|
foreach_selected_block(
|
||||||
struct terminal *term, struct coord _start, struct coord _end,
|
struct terminal *term, struct coord _start, struct coord _end,
|
||||||
bool (*cb)(struct terminal *term, struct row *row, struct cell *cell, int row_no, int col, void *data),
|
bool (*cb)(struct terminal *term, struct row *row, struct cell *cell,
|
||||||
|
int row_no, int col, void *data),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
const struct coord *start = &_start;
|
const struct coord *start = &_start;
|
||||||
const struct coord *end = &_end;
|
const struct coord *end = &_end;
|
||||||
|
|
||||||
|
const int scrollback_start = term->grid->offset + term->rows;
|
||||||
|
const int grid_rows = term->grid->num_rows;
|
||||||
|
|
||||||
|
/* Start/end rows, relative to the scrollback start */
|
||||||
|
const int rel_start_row =
|
||||||
|
(start->row - scrollback_start + grid_rows) & (grid_rows - 1);
|
||||||
|
const int rel_end_row =
|
||||||
|
(end->row - scrollback_start + grid_rows) & (grid_rows - 1);
|
||||||
|
|
||||||
struct coord top_left = {
|
struct coord top_left = {
|
||||||
.row = min(start->row, end->row),
|
.row = (rel_start_row < rel_end_row
|
||||||
|
? start->row : end->row) & (grid_rows - 1),
|
||||||
.col = min(start->col, end->col),
|
.col = min(start->col, end->col),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct coord bottom_right = {
|
struct coord bottom_right = {
|
||||||
.row = max(start->row, end->row),
|
.row = (rel_start_row > rel_end_row
|
||||||
|
? start->row : end->row) & (grid_rows - 1),
|
||||||
.col = max(start->col, end->col),
|
.col = max(start->col, end->col),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int r = top_left.row; r <= bottom_right.row; r++) {
|
int r = top_left.row;
|
||||||
size_t real_r = r & (term->grid->num_rows - 1);
|
while (true) {
|
||||||
struct row *row = term->grid->rows[real_r];
|
struct row *row = term->grid->rows[r];
|
||||||
xassert(row != NULL);
|
xassert(row != NULL);
|
||||||
|
|
||||||
for (int c = top_left.col; c <= bottom_right.col; c++) {
|
for (int c = top_left.col; c <= bottom_right.col; c++) {
|
||||||
if (!cb(term, row, &row->cells[c], real_r, c, data))
|
if (!cb(term, row, &row->cells[c], r, c, data))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r == bottom_right.row)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r++;
|
||||||
|
r &= grid_rows - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue