mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-22 05:33:45 -04:00
selection: don't highlight trailing empty cells in a selection
This makes it clear which cells contain spaces (that will be copied) or are empty (will *not* be copied).
This commit is contained in:
parent
e1648bd2b7
commit
cb9626741a
1 changed files with 55 additions and 11 deletions
66
selection.c
66
selection.c
|
|
@ -240,6 +240,13 @@ selection_start(struct terminal *term, int col, int row,
|
||||||
term->selection.ongoing = true;
|
term->selection.ongoing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Context used while (un)marking selected cells, to be able to
|
||||||
|
* exclude empty cells */
|
||||||
|
struct mark_context {
|
||||||
|
const struct row *last_row;
|
||||||
|
int empty_count;
|
||||||
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
unmark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
unmark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||||
int col, void *data)
|
int col, void *data)
|
||||||
|
|
@ -260,8 +267,23 @@ static bool
|
||||||
premark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
premark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||||
int col, void *data)
|
int col, void *data)
|
||||||
{
|
{
|
||||||
|
struct mark_context *ctx = data;
|
||||||
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
if (ctx->last_row != row) {
|
||||||
|
ctx->last_row = row;
|
||||||
|
ctx->empty_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->wc == 0 && term->selection.kind == SELECTION_NORMAL) {
|
||||||
|
ctx->empty_count++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tell unmark to leave this be */
|
/* Tell unmark to leave this be */
|
||||||
cell->attrs.selected |= 2;
|
for (int i = 0; i < ctx->empty_count + 1; i++)
|
||||||
|
row->cells[col - i].attrs.selected |= 2;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,14 +291,30 @@ static bool
|
||||||
mark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
mark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||||
int col, void *data)
|
int col, void *data)
|
||||||
{
|
{
|
||||||
if (cell->attrs.selected & 1) {
|
struct mark_context *ctx = data;
|
||||||
cell->attrs.selected = 1; /* Clear the pre-mark bit */
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
if (ctx->last_row != row) {
|
||||||
|
ctx->last_row = row;
|
||||||
|
ctx->empty_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->wc == 0 && term->selection.kind == SELECTION_NORMAL) {
|
||||||
|
ctx->empty_count++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
row->dirty = true;
|
for (int i = 0; i < ctx->empty_count + 1; i++) {
|
||||||
cell->attrs.selected = 1;
|
struct cell *c = &row->cells[col - i];
|
||||||
cell->attrs.clean = 0;
|
if (c->attrs.selected & 1)
|
||||||
|
c->attrs.selected = 1; /* Clear the pre-mark bit */
|
||||||
|
else {
|
||||||
|
row->dirty = true;
|
||||||
|
c->attrs.selected = 1;
|
||||||
|
c->attrs.clean = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,21 +325,25 @@ selection_modify(struct terminal *term, struct coord start, struct coord end)
|
||||||
assert(start.row != -1 && start.col != -1);
|
assert(start.row != -1 && start.col != -1);
|
||||||
assert(end.row != -1 && end.col != -1);
|
assert(end.row != -1 && end.col != -1);
|
||||||
|
|
||||||
|
struct mark_context ctx = {};
|
||||||
|
|
||||||
/* Premark all cells that *will* be selected */
|
/* Premark all cells that *will* be selected */
|
||||||
foreach_selected(term, start, end, &premark_selected, NULL);
|
foreach_selected(term, start, end, &premark_selected, &ctx);
|
||||||
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
|
|
||||||
if (term->selection.end.row >= 0) {
|
if (term->selection.end.row >= 0) {
|
||||||
/* Unmark previous selection, ignoring cells that are part of
|
/* Unmark previous selection, ignoring cells that are part of
|
||||||
* the new selection */
|
* the new selection */
|
||||||
foreach_selected(term, term->selection.start, term->selection.end,
|
foreach_selected(term, term->selection.start, term->selection.end,
|
||||||
&unmark_selected, NULL);
|
&unmark_selected, &ctx);
|
||||||
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
term->selection.start = start;
|
term->selection.start = start;
|
||||||
term->selection.end = end;
|
term->selection.end = end;
|
||||||
|
|
||||||
/* Mark new selection */
|
/* Mark new selection */
|
||||||
foreach_selected(term, start, end, &mark_selected, NULL);
|
foreach_selected(term, start, end, &mark_selected, &ctx);
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -409,7 +451,8 @@ selection_dirty_cells(struct terminal *term)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach_selected(
|
foreach_selected(
|
||||||
term, term->selection.start, term->selection.end, &mark_selected, NULL);
|
term, term->selection.start, term->selection.end, &mark_selected,
|
||||||
|
&(struct mark_context){});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -600,10 +643,11 @@ selection_cancel(struct terminal *term)
|
||||||
term->selection.start.row, term->selection.start.col,
|
term->selection.start.row, term->selection.start.col,
|
||||||
term->selection.end.row, term->selection.end.col);
|
term->selection.end.row, term->selection.end.col);
|
||||||
|
|
||||||
|
|
||||||
if (term->selection.start.row >= 0 && term->selection.end.row >= 0) {
|
if (term->selection.start.row >= 0 && term->selection.end.row >= 0) {
|
||||||
foreach_selected(
|
foreach_selected(
|
||||||
term, term->selection.start, term->selection.end,
|
term, term->selection.start, term->selection.end,
|
||||||
&unmark_selected, NULL);
|
&unmark_selected, &(struct mark_context){});
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue