mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-10 05:33:51 -04:00
commit
b2d59a0e54
3 changed files with 67 additions and 30 deletions
|
|
@ -55,6 +55,8 @@
|
||||||
about a non-monospaced primary font.
|
about a non-monospaced primary font.
|
||||||
* Rare crash when the window is resized while a mouse selection is
|
* Rare crash when the window is resized while a mouse selection is
|
||||||
ongoing (https://codeberg.org/dnkl/foot/issues/922).
|
ongoing (https://codeberg.org/dnkl/foot/issues/922).
|
||||||
|
* Large selections crossing the scrollback wrap-around
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/924).
|
||||||
|
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
||||||
7
grid.c
7
grid.c
|
|
@ -482,6 +482,13 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row,
|
||||||
tll_remove(old_grid->sixel_images, it);
|
tll_remove(old_grid->sixel_images, it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: detect if the re-used row is covered by the
|
||||||
|
* selection. Of so, cancel the selection. The problem: we
|
||||||
|
* don’t know if we’ve translated the selection coordinates
|
||||||
|
* yet.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
struct row_data *extra = row->extra;
|
struct row_data *extra = row->extra;
|
||||||
|
|
|
||||||
88
selection.c
88
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1108,16 +1144,8 @@ selection_finalize(struct seat *seat, struct terminal *term, uint32_t serial)
|
||||||
xassert(term->selection.start.row != -1);
|
xassert(term->selection.start.row != -1);
|
||||||
xassert(term->selection.end.row != -1);
|
xassert(term->selection.end.row != -1);
|
||||||
|
|
||||||
if (term->selection.start.row > term->selection.end.row ||
|
term->selection.start.row &= (term->grid->num_rows - 1);
|
||||||
(term->selection.start.row == term->selection.end.row &&
|
term->selection.end.row &= (term->grid->num_rows - 1);
|
||||||
term->selection.start.col > term->selection.end.col))
|
|
||||||
{
|
|
||||||
struct coord tmp = term->selection.start;
|
|
||||||
term->selection.start = term->selection.end;
|
|
||||||
term->selection.end = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
xassert(term->selection.start.row <= term->selection.end.row);
|
|
||||||
|
|
||||||
switch (term->conf->selection_target) {
|
switch (term->conf->selection_target) {
|
||||||
case SELECTION_TARGET_NONE:
|
case SELECTION_TARGET_NONE:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue