mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-06 07:15:30 -04:00
selection: extract_selection now uses foreach_selected()
This "automagically" adds support for block selections, since foreach_selected already handles block selections.
This commit is contained in:
parent
b7c970010d
commit
975a35ae16
1 changed files with 110 additions and 62 deletions
172
selection.c
172
selection.c
|
|
@ -135,84 +135,132 @@ foreach_selected(
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static size_t
|
||||||
extract_selection(const struct terminal *term)
|
selection_cell_count(const struct terminal *term)
|
||||||
{
|
{
|
||||||
const struct coord *start = &term->selection.start;
|
const struct coord *start = &term->selection.start;
|
||||||
const struct coord *end = &term->selection.end;
|
const struct coord *end = &term->selection.end;
|
||||||
|
|
||||||
assert(start->row <= end->row);
|
switch (term->selection.kind) {
|
||||||
|
case SELECTION_NONE:
|
||||||
|
return 0;
|
||||||
|
|
||||||
size_t max_cells = 0;
|
case SELECTION_NORMAL:
|
||||||
if (start->row == end->row) {
|
if (term->selection.end.row == -1)
|
||||||
assert(start->col <= end->col);
|
return 0;
|
||||||
max_cells = end->col - start->col + 1;
|
|
||||||
} else {
|
|
||||||
max_cells = term->cols - start->col;
|
|
||||||
max_cells += term->cols * (end->row - start->row - 1);
|
|
||||||
max_cells += end->col + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t buf_size = max_cells * 4 + 1;
|
assert(term->selection.start.row != -1);
|
||||||
char *buf = malloc(buf_size);
|
|
||||||
int idx = 0;
|
|
||||||
|
|
||||||
int start_col = start->col;
|
if (start->row > end->row) {
|
||||||
for (int r = start->row; r <= end->row; r++) {
|
const struct coord *tmp = start;
|
||||||
const struct row *row = grid_row_in_view(term->grid, r - term->grid->view);
|
start = end;
|
||||||
if (row == NULL)
|
end = tmp;
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Trailing empty cells are never included in the selection.
|
|
||||||
*
|
|
||||||
* Empty cells between non-empty cells however are replaced
|
|
||||||
* with spaces.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (int col = start_col, empty_count = 0;
|
|
||||||
col <= (r == end->row ? end->col : term->cols - 1);
|
|
||||||
col++)
|
|
||||||
{
|
|
||||||
const struct cell *cell = &row->cells[col];
|
|
||||||
|
|
||||||
if (cell->wc == 0) {
|
|
||||||
empty_count++;
|
|
||||||
if (col == term->cols - 1)
|
|
||||||
buf[idx++] = '\n';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(idx + empty_count <= buf_size);
|
|
||||||
memset(&buf[idx], ' ', empty_count);
|
|
||||||
idx += empty_count;
|
|
||||||
empty_count = 0;
|
|
||||||
|
|
||||||
assert(idx + 1 <= buf_size);
|
|
||||||
|
|
||||||
mbstate_t ps = {0};
|
|
||||||
size_t len = wcrtomb(&buf[idx], cell->wc, &ps);
|
|
||||||
assert(len >= 0); /* All wchars were valid multibyte strings to begin with */
|
|
||||||
idx += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start_col = 0;
|
if (start->row == end->row)
|
||||||
|
return end->col - start->col + 1;
|
||||||
|
else {
|
||||||
|
size_t cells = term->cols - start->col;
|
||||||
|
cells += term->cols * (end->row - start->row - 1);
|
||||||
|
cells += end->col + 1;
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SELECTION_BLOCK: {
|
||||||
|
struct coord top_left = {
|
||||||
|
.row = min(start->row, end->row),
|
||||||
|
.col = min(start->col, end->col),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct coord bottom_right = {
|
||||||
|
.row = max(start->row, end->row),
|
||||||
|
.col = max(start->col, end->col),
|
||||||
|
};
|
||||||
|
|
||||||
|
int cols = bottom_right.col - top_left.col + 1;
|
||||||
|
int rows = bottom_right.row - top_left.row + 1;
|
||||||
|
return rows * cols;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == 0) {
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct extract {
|
||||||
|
char *buf;
|
||||||
|
size_t size;
|
||||||
|
size_t idx;
|
||||||
|
size_t empty_count;
|
||||||
|
struct row *last_row;
|
||||||
|
struct cell *last_cell;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
extract_one(struct terminal *term, struct row *row, struct cell *cell,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct extract *ctx = data;
|
||||||
|
|
||||||
|
if (ctx->last_row != NULL && row != ctx->last_row &&
|
||||||
|
((term->selection.kind == SELECTION_NORMAL && ctx->last_cell->wc == 0) ||
|
||||||
|
term->selection.kind == SELECTION_BLOCK))
|
||||||
|
{
|
||||||
|
/* Last cell was the last column in the selection */
|
||||||
|
ctx->buf[ctx->idx++] = '\n';
|
||||||
|
ctx->empty_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (cell->wc == 0)
|
||||||
|
ctx->empty_count++;
|
||||||
|
|
||||||
|
else {
|
||||||
|
/* Replace empty cells with spaces when followed by non-empty cell */
|
||||||
|
assert(ctx->idx + ctx->empty_count <= ctx->size);
|
||||||
|
memset(&ctx->buf[ctx->idx], ' ', ctx->empty_count);
|
||||||
|
ctx->idx += ctx->empty_count;
|
||||||
|
ctx->empty_count = 0;
|
||||||
|
|
||||||
|
assert(ctx->idx + 1 <= ctx->size);
|
||||||
|
|
||||||
|
mbstate_t ps = {0};
|
||||||
|
size_t len = wcrtomb(&ctx->buf[ctx->idx], cell->wc, &ps);
|
||||||
|
assert(len >= 0); /* All wchars were valid multibyte strings to begin with */
|
||||||
|
assert(ctx->idx + len <= ctx->size);
|
||||||
|
ctx->idx += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->last_row = row;
|
||||||
|
ctx->last_cell = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
extract_selection(const struct terminal *term)
|
||||||
|
{
|
||||||
|
const size_t max_cells = selection_cell_count(term);
|
||||||
|
const size_t buf_size = max_cells * 4 + 1; /* Multiply by 4 to handle multibyte chars */
|
||||||
|
|
||||||
|
struct extract ctx = {
|
||||||
|
.buf = malloc(buf_size),
|
||||||
|
.size = buf_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach_selected((struct terminal *)term, &extract_one, &ctx);
|
||||||
|
|
||||||
|
if (ctx.idx == 0) {
|
||||||
/* Selection of empty cells only */
|
/* Selection of empty cells only */
|
||||||
buf[idx] = '\0';
|
ctx.buf[ctx.idx] = '\0';
|
||||||
return buf;
|
return ctx.buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(idx > 0);
|
assert(ctx.idx > 0);
|
||||||
assert(idx < buf_size);
|
assert(ctx.idx < ctx.size);
|
||||||
if (buf[idx - 1] == '\n')
|
if (ctx.buf[ctx.idx - 1] == '\n')
|
||||||
buf[idx - 1] = '\0';
|
ctx.buf[ctx.idx - 1] = '\0';
|
||||||
else
|
else
|
||||||
buf[idx] = '\0';
|
ctx.buf[ctx.idx] = '\0';
|
||||||
|
|
||||||
return buf;
|
return ctx.buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue