mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-07 04:06:07 -05:00
csi: wip: styled underlines
This is work in progress, and fairly untested. This adds initial tracking of styled underlines. Setting attributes seems to work (both color and underline style). Grid reflow has *not* been tested. When rendering, style is currently ignored (all styles are rendered as a plain, legacy underline). Color however, *is* applied.
This commit is contained in:
parent
20923bb2e8
commit
32effc6657
6 changed files with 371 additions and 66 deletions
58
csi.c
58
csi.c
|
|
@ -32,7 +32,14 @@
|
|||
static void
|
||||
sgr_reset(struct terminal *term)
|
||||
{
|
||||
/* TODO: can we drop this check? */
|
||||
const enum curly_style curly_style = term->vt.curly.style;
|
||||
|
||||
memset(&term->vt.attrs, 0, sizeof(term->vt.attrs));
|
||||
memset(&term->vt.curly, 0, sizeof(term->vt.curly));
|
||||
|
||||
if (unlikely(curly_style > CURLY_SINGLE))
|
||||
term_update_ascii_printer(term);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -88,7 +95,34 @@ csi_sgr(struct terminal *term)
|
|||
case 1: term->vt.attrs.bold = true; break;
|
||||
case 2: term->vt.attrs.dim = true; break;
|
||||
case 3: term->vt.attrs.italic = true; break;
|
||||
case 4: term->vt.attrs.underline = true; break;
|
||||
case 4: {
|
||||
term->vt.attrs.underline = true;
|
||||
term->vt.curly.style = CURLY_SINGLE;
|
||||
|
||||
if (unlikely(term->vt.params.v[i].sub.idx == 1)) {
|
||||
enum curly_style style = term->vt.params.v[i].sub.value[0];
|
||||
|
||||
switch (style) {
|
||||
default:
|
||||
case CURLY_NONE:
|
||||
term->vt.attrs.underline = false;
|
||||
term->vt.curly.style = CURLY_NONE;
|
||||
break;
|
||||
|
||||
case CURLY_SINGLE:
|
||||
case CURLY_DOUBLE:
|
||||
case CURLY_CURLY:
|
||||
case CURLY_DOTTED:
|
||||
case CURLY_DASHED:
|
||||
term->vt.curly.style = style; break;
|
||||
break;
|
||||
}
|
||||
|
||||
term_update_ascii_printer(term);
|
||||
}
|
||||
LOG_WARN("CURLY: %d", term->vt.curly.style);
|
||||
break;
|
||||
}
|
||||
case 5: term->vt.attrs.blink = true; break;
|
||||
case 6: LOG_WARN("ignored: rapid blink"); break;
|
||||
case 7: term->vt.attrs.reverse = true; break;
|
||||
|
|
@ -98,7 +132,12 @@ csi_sgr(struct terminal *term)
|
|||
case 21: break; /* double-underline, not implemented */
|
||||
case 22: term->vt.attrs.bold = term->vt.attrs.dim = false; break;
|
||||
case 23: term->vt.attrs.italic = false; break;
|
||||
case 24: term->vt.attrs.underline = false; break;
|
||||
case 24: {
|
||||
term->vt.attrs.underline = false;
|
||||
term->vt.curly.style = CURLY_NONE;
|
||||
term_update_ascii_printer(term);
|
||||
break;
|
||||
}
|
||||
case 25: term->vt.attrs.blink = false; break;
|
||||
case 26: break; /* rapid blink, ignored */
|
||||
case 27: term->vt.attrs.reverse = false; break;
|
||||
|
|
@ -119,7 +158,8 @@ csi_sgr(struct terminal *term)
|
|||
break;
|
||||
|
||||
case 38:
|
||||
case 48: {
|
||||
case 48:
|
||||
case 58: {
|
||||
uint32_t color;
|
||||
enum color_source src;
|
||||
|
||||
|
|
@ -194,7 +234,11 @@ csi_sgr(struct terminal *term)
|
|||
break;
|
||||
}
|
||||
|
||||
if (param == 38) {
|
||||
if (unlikely(param == 58)) {
|
||||
term->vt.curly.color_src = src;
|
||||
term->vt.curly.color = color;
|
||||
term_update_ascii_printer(term);
|
||||
} else if (param == 38) {
|
||||
term->vt.attrs.fg_src = src;
|
||||
term->vt.attrs.fg = color;
|
||||
} else {
|
||||
|
|
@ -226,6 +270,12 @@ csi_sgr(struct terminal *term)
|
|||
term->vt.attrs.bg_src = COLOR_DEFAULT;
|
||||
break;
|
||||
|
||||
case 59:
|
||||
term->vt.curly.color_src = COLOR_DEFAULT;
|
||||
term->vt.curly.color = 0;
|
||||
term_update_ascii_printer(term);
|
||||
break;
|
||||
|
||||
/* Bright foreground colors */
|
||||
case 90:
|
||||
case 91:
|
||||
|
|
|
|||
277
grid.c
277
grid.c
|
|
@ -105,6 +105,11 @@ verify_no_overlapping_ranges_of_type(const struct row_ranges *ranges,
|
|||
r1->uri.uri, r1->start, r1->end,
|
||||
r2->uri.uri, r2->start, r2->end);
|
||||
break;
|
||||
|
||||
case ROW_RANGE_CURLY:
|
||||
BUG("curly underline overlap: %d-%d, %d-%d",
|
||||
r1->start, r1->end, r2->start, r2->end);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,6 +121,7 @@ static void
|
|||
verify_no_overlapping_ranges(const struct row_data *extra)
|
||||
{
|
||||
verify_no_overlapping_ranges_of_type(&extra->uri_ranges, ROW_RANGE_URI);
|
||||
verify_no_overlapping_ranges_of_type(&extra->curly_ranges, ROW_RANGE_CURLY);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -137,6 +143,12 @@ verify_ranges_of_type_are_sorted(const struct row_ranges *ranges,
|
|||
last->uri.uri, last->start, last->end,
|
||||
r->uri.uri, r->start, r->end);
|
||||
break;
|
||||
|
||||
case ROW_RANGE_CURLY:
|
||||
BUG("curly ranges not sorted correctly: "
|
||||
"%d-%d came before %d-%d",
|
||||
last->start, last->end, r->start, r->end);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,19 +162,37 @@ static void
|
|||
verify_ranges_are_sorted(const struct row_data *extra)
|
||||
{
|
||||
verify_ranges_of_type_are_sorted(&extra->uri_ranges, ROW_RANGE_URI);
|
||||
verify_ranges_of_type_are_sorted(&extra->curly_ranges, ROW_RANGE_CURLY);
|
||||
}
|
||||
|
||||
static void
|
||||
uri_range_ensure_size(struct row_data *extra, uint32_t count_to_add)
|
||||
range_ensure_size(struct row_ranges *ranges, int count_to_add)
|
||||
{
|
||||
if (extra->uri_ranges.count + count_to_add > extra->uri_ranges.size) {
|
||||
extra->uri_ranges.size = extra->uri_ranges.count + count_to_add;
|
||||
extra->uri_ranges.v = xrealloc(
|
||||
extra->uri_ranges.v,
|
||||
extra->uri_ranges.size * sizeof(extra->uri_ranges.v[0]));
|
||||
if (ranges->count + count_to_add > ranges->size) {
|
||||
ranges->size = ranges->count + count_to_add;
|
||||
ranges->v = xrealloc(ranges->v, ranges->size * sizeof(ranges->v[0]));
|
||||
}
|
||||
|
||||
xassert(extra->uri_ranges.count + count_to_add <= extra->uri_ranges.size);
|
||||
xassert(ranges->count + count_to_add <= ranges->size);
|
||||
}
|
||||
|
||||
static void
|
||||
range_insert(struct row_ranges *ranges, size_t idx, int start, int end)
|
||||
{
|
||||
range_ensure_size(ranges, 1);
|
||||
|
||||
xassert(idx <= ranges->count);
|
||||
|
||||
const size_t move_count = ranges->count - idx;
|
||||
memmove(&ranges->v[idx + 1],
|
||||
&ranges->v[idx],
|
||||
move_count * sizeof(ranges->v[0]));
|
||||
|
||||
ranges->count++;
|
||||
ranges->v[idx] = (struct row_range){
|
||||
.start = start,
|
||||
.end = end,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -170,34 +200,27 @@ uri_range_ensure_size(struct row_data *extra, uint32_t count_to_add)
|
|||
* invalidating pointers into it.
|
||||
*/
|
||||
static void
|
||||
uri_range_insert(struct row_data *extra, size_t idx, int start, int end,
|
||||
uri_range_insert(struct row_ranges *ranges, size_t idx, int start, int end,
|
||||
uint64_t id, const char *uri)
|
||||
{
|
||||
uri_range_ensure_size(extra, 1);
|
||||
range_insert(ranges, idx, start, end);
|
||||
ranges->v[idx].uri.id = id;
|
||||
ranges->v[idx].uri.uri = xstrdup(uri);
|
||||
}
|
||||
|
||||
xassert(idx <= extra->uri_ranges.count);
|
||||
|
||||
const size_t move_count = extra->uri_ranges.count - idx;
|
||||
memmove(&extra->uri_ranges.v[idx + 1],
|
||||
&extra->uri_ranges.v[idx],
|
||||
move_count * sizeof(extra->uri_ranges.v[0]));
|
||||
|
||||
extra->uri_ranges.count++;
|
||||
extra->uri_ranges.v[idx] = (struct row_range){
|
||||
.start = start,
|
||||
.end = end,
|
||||
.uri = {
|
||||
.id = id,
|
||||
.uri = xstrdup(uri),
|
||||
},
|
||||
};
|
||||
static void
|
||||
curly_range_insert(struct row_ranges *ranges, size_t idx, int start, int end,
|
||||
struct curly_range_data data)
|
||||
{
|
||||
range_insert(ranges, idx, start, end);
|
||||
ranges->v[idx].curly = data;
|
||||
}
|
||||
|
||||
static void
|
||||
uri_range_append_no_strdup(struct row_data *extra, int start, int end,
|
||||
uint64_t id, char *uri)
|
||||
{
|
||||
uri_range_ensure_size(extra, 1);
|
||||
range_ensure_size(&extra->uri_ranges, 1);
|
||||
extra->uri_ranges.v[extra->uri_ranges.count++] = (struct row_range){
|
||||
.start = start,
|
||||
.end = end,
|
||||
|
|
@ -216,16 +239,16 @@ uri_range_append(struct row_data *extra, int start, int end, uint64_t id,
|
|||
}
|
||||
|
||||
static void
|
||||
uri_range_delete(struct row_data *extra, size_t idx)
|
||||
range_delete(struct row_ranges *ranges, enum row_range_type type, size_t idx)
|
||||
{
|
||||
xassert(idx < extra->uri_ranges.count);
|
||||
grid_row_uri_range_destroy(&extra->uri_ranges.v[idx]);
|
||||
xassert(idx < ranges->count);
|
||||
grid_row_range_destroy(&ranges->v[idx], type);
|
||||
|
||||
const size_t move_count = extra->uri_ranges.count - idx - 1;
|
||||
memmove(&extra->uri_ranges.v[idx],
|
||||
&extra->uri_ranges.v[idx + 1],
|
||||
move_count * sizeof(extra->uri_ranges.v[0]));
|
||||
extra->uri_ranges.count--;
|
||||
const size_t move_count = ranges->count - idx - 1;
|
||||
memmove(&ranges->v[idx],
|
||||
&ranges->v[idx + 1],
|
||||
move_count * sizeof(ranges->v[0]));
|
||||
ranges->count--;
|
||||
}
|
||||
|
||||
struct grid *
|
||||
|
|
@ -269,14 +292,20 @@ grid_snapshot(const struct grid *grid)
|
|||
struct row_data *clone_extra = xcalloc(1, sizeof(*clone_extra));
|
||||
clone_row->extra = clone_extra;
|
||||
|
||||
uri_range_ensure_size(clone_extra, extra->uri_ranges.count);
|
||||
range_ensure_size(&clone_extra->uri_ranges, extra->uri_ranges.count);
|
||||
range_ensure_size(&clone_extra->curly_ranges, extra->curly_ranges.count);
|
||||
|
||||
for (size_t i = 0; i < extra->uri_ranges.count; i++) {
|
||||
for (int i = 0; i < extra->uri_ranges.count; i++) {
|
||||
const struct row_range *range = &extra->uri_ranges.v[i];
|
||||
uri_range_append(
|
||||
clone_extra,
|
||||
range->start, range->end, range->uri.id, range->uri.uri);
|
||||
}
|
||||
|
||||
for (int i = 0; i < extra->curly_ranges.count; i++) {
|
||||
//const struct row_range *range = &extra->curly_ranges.v[i];
|
||||
BUG("TODO");
|
||||
}
|
||||
} else
|
||||
clone_row->extra = NULL;
|
||||
}
|
||||
|
|
@ -490,9 +519,10 @@ grid_resize_without_reflow(
|
|||
ensure_row_has_extra_data(new_row);
|
||||
struct row_data *new_extra = new_row->extra;
|
||||
|
||||
uri_range_ensure_size(new_extra, old_extra->uri_ranges.count);
|
||||
range_ensure_size(&new_extra->uri_ranges, old_extra->uri_ranges.count);
|
||||
range_ensure_size(&new_extra->curly_ranges, old_extra->curly_ranges.count);
|
||||
|
||||
for (size_t i = 0; i < old_extra->uri_ranges.count; i++) {
|
||||
for (int i = 0; i < old_extra->uri_ranges.count; i++) {
|
||||
const struct row_range *range = &old_extra->uri_ranges.v[i];
|
||||
|
||||
if (range->start >= new_cols) {
|
||||
|
|
@ -504,7 +534,21 @@ grid_resize_without_reflow(
|
|||
const int end = min(range->end, new_cols - 1);
|
||||
uri_range_append(new_extra, start, end, range->uri.id, range->uri.uri);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < old_extra->uri_ranges.count; i++) {
|
||||
const struct row_range *range = &old_extra->uri_ranges.v[i];
|
||||
|
||||
if (range->start >= new_cols) {
|
||||
/* The whole range is truncated */
|
||||
continue;
|
||||
}
|
||||
|
||||
//const int start = range->start;
|
||||
//const int end = min(range->end, new_cols - 1);
|
||||
//uri_range_append(new_extra, start, end, range->uri.id, range->uri.uri);
|
||||
BUG("TODO");
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear "new" lines */
|
||||
for (int r = min(old_screen_rows, new_screen_rows); r < new_screen_rows; r++) {
|
||||
|
|
@ -1161,7 +1205,7 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
|||
bool run_merge_pass = false;
|
||||
|
||||
struct row_data *extra = row->extra;
|
||||
for (ssize_t i = (ssize_t)extra->uri_ranges.count - 1; i >= 0; i--) {
|
||||
for (int i = extra->uri_ranges.count - 1; i >= 0; i--) {
|
||||
struct row_range *r = &extra->uri_ranges.v[i];
|
||||
|
||||
const bool matching_id = r->uri.id == id;
|
||||
|
|
@ -1203,7 +1247,8 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
|||
xassert(r->start < col);
|
||||
xassert(r->end > col);
|
||||
|
||||
uri_range_insert(extra, i + 1, col + 1, r->end, r->uri.id, r->uri.uri);
|
||||
uri_range_insert(
|
||||
&extra->uri_ranges, i + 1, col + 1, r->end, r->uri.id, r->uri.uri);
|
||||
|
||||
/* The insertion may xrealloc() the vector, making our
|
||||
* 'old' pointer invalid */
|
||||
|
|
@ -1231,7 +1276,7 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
|||
},
|
||||
};
|
||||
} else
|
||||
uri_range_insert(extra, insert_idx, col, col, id, uri);
|
||||
uri_range_insert(&extra->uri_ranges, insert_idx, col, col, id, uri);
|
||||
|
||||
if (run_merge_pass) {
|
||||
for (size_t i = 1; i < extra->uri_ranges.count; i++) {
|
||||
|
|
@ -1240,7 +1285,111 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
|||
|
||||
if (r1->uri.id == r2->uri.id && r1->end + 1 == r2->start) {
|
||||
r1->end = r2->end;
|
||||
uri_range_delete(extra, i);
|
||||
range_delete(&extra->uri_ranges, ROW_RANGE_URI, i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
verify_no_overlapping_ranges(extra);
|
||||
verify_ranges_are_sorted(extra);
|
||||
}
|
||||
|
||||
void
|
||||
grid_row_curly_range_put(struct row *row, int col, struct curly_range_data data)
|
||||
{
|
||||
ensure_row_has_extra_data(row);
|
||||
|
||||
size_t insert_idx = 0;
|
||||
bool replace = false;
|
||||
bool run_merge_pass = false;
|
||||
|
||||
struct row_data *extra = row->extra;
|
||||
for (int i = extra->curly_ranges.count - 1; i >= 0; i--) {
|
||||
struct row_range *r = &extra->curly_ranges.v[i];
|
||||
|
||||
const bool matching = r->curly.style == data.style &&
|
||||
r->curly.color_src == data.color_src &&
|
||||
r->curly.color == data.color;
|
||||
|
||||
if (matching && r->end + 1 == col) {
|
||||
/* Extend existing curly tail */
|
||||
r->end++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
else if (r->end < col) {
|
||||
insert_idx = i + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (r->start > col)
|
||||
continue;
|
||||
|
||||
else {
|
||||
xassert(r->start <= col);
|
||||
xassert(r->end >= col);
|
||||
|
||||
if (matching)
|
||||
goto out;
|
||||
|
||||
if (r->start == r->end) {
|
||||
replace = true;
|
||||
run_merge_pass = true;
|
||||
insert_idx = i;
|
||||
} else if (r->start == col) {
|
||||
run_merge_pass = true;
|
||||
r->start++;
|
||||
insert_idx = i;
|
||||
} else if (r->end == col) {
|
||||
run_merge_pass = true;
|
||||
r->end--;
|
||||
insert_idx = i + 1;
|
||||
} else {
|
||||
xassert(r->start < col);
|
||||
xassert(r->end > col);
|
||||
|
||||
curly_range_insert(
|
||||
&extra->curly_ranges, i + 1, col + 1, r->end, data);
|
||||
|
||||
/* The insertion may xrealloc() the vector, making our
|
||||
* 'old' pointer invalid */
|
||||
r = &extra->curly_ranges.v[i];
|
||||
r->end = col - 1;
|
||||
xassert(r->start <= r->end);
|
||||
|
||||
insert_idx = i + 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xassert(insert_idx <= extra->curly_ranges.count);
|
||||
|
||||
if (replace) {
|
||||
grid_row_curly_range_destroy(&extra->curly_ranges.v[insert_idx]);
|
||||
extra->curly_ranges.v[insert_idx] = (struct row_range){
|
||||
.start = col,
|
||||
.end = col,
|
||||
.curly = data,
|
||||
};
|
||||
} else
|
||||
curly_range_insert(&extra->curly_ranges, insert_idx, col, col, data);
|
||||
|
||||
if (run_merge_pass) {
|
||||
for (size_t i = 1; i < extra->curly_ranges.count; i++) {
|
||||
struct row_range *r1 = &extra->curly_ranges.v[i - 1];
|
||||
struct row_range *r2 = &extra->curly_ranges.v[i];
|
||||
|
||||
if (r1->curly.style == r2->curly.style &&
|
||||
r1->curly.color_src == r2->curly.color_src &&
|
||||
r1->curly.color == r2->curly.color &&
|
||||
r1->end + 1 == r2->start)
|
||||
{
|
||||
r1->end = r2->end;
|
||||
range_delete(&extra->curly_ranges, ROW_RANGE_CURLY, i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
|
@ -1316,17 +1465,15 @@ UNITTEST
|
|||
#undef verify_range
|
||||
}
|
||||
|
||||
void
|
||||
grid_row_uri_range_erase(struct row *row, int start, int end)
|
||||
static void
|
||||
grid_row_range_erase(struct row_ranges *ranges, enum row_range_type type,
|
||||
int start, int end)
|
||||
{
|
||||
xassert(row->extra != NULL);
|
||||
xassert(start <= end);
|
||||
|
||||
struct row_data *extra = row->extra;
|
||||
|
||||
/* Split up, or remove, URI ranges affected by the erase */
|
||||
for (ssize_t i = (ssize_t)extra->uri_ranges.count - 1; i >= 0; i--) {
|
||||
struct row_range *old = &extra->uri_ranges.v[i];
|
||||
for (int i = ranges->count - 1; i >= 0; i--) {
|
||||
struct row_range *old = &ranges->v[i];
|
||||
|
||||
if (old->end < start)
|
||||
return;
|
||||
|
|
@ -1336,17 +1483,25 @@ grid_row_uri_range_erase(struct row *row, int start, int end)
|
|||
|
||||
if (start <= old->start && end >= old->end) {
|
||||
/* Erase range covers URI completely - remove it */
|
||||
uri_range_delete(extra, i);
|
||||
range_delete(ranges, type, i);
|
||||
}
|
||||
|
||||
else if (start > old->start && end < old->end) {
|
||||
/* Erase range erases a part in the middle of the URI */
|
||||
uri_range_insert(
|
||||
extra, i + 1, end + 1, old->end, old->uri.id, old->uri.uri);
|
||||
switch (type) {
|
||||
case ROW_RANGE_URI:
|
||||
uri_range_insert(
|
||||
ranges, i + 1, end + 1, old->end, old->uri.id, old->uri.uri);
|
||||
break;
|
||||
|
||||
case ROW_RANGE_CURLY:
|
||||
curly_range_insert(ranges, i + 1, end + 1, old->end, old->curly);
|
||||
break;
|
||||
}
|
||||
|
||||
/* The insertion may xrealloc() the vector, making our
|
||||
* 'old' pointer invalid */
|
||||
old = &extra->uri_ranges.v[i];
|
||||
old = &ranges->v[i];
|
||||
old->end = start - 1;
|
||||
return; /* There can be no more URIs affected by the erase range */
|
||||
}
|
||||
|
|
@ -1366,6 +1521,20 @@ grid_row_uri_range_erase(struct row *row, int start, int end)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
grid_row_uri_range_erase(struct row *row, int start, int end)
|
||||
{
|
||||
xassert(row->extra != NULL);
|
||||
grid_row_range_erase(&row->extra->uri_ranges, ROW_RANGE_URI, start, end);
|
||||
}
|
||||
|
||||
void
|
||||
grid_row_curly_range_erase(struct row *row, int start, int end)
|
||||
{
|
||||
xassert(row->extra != NULL);
|
||||
grid_row_range_erase(&row->extra->curly_ranges, ROW_RANGE_CURLY, start, end);
|
||||
}
|
||||
|
||||
UNITTEST
|
||||
{
|
||||
struct row_data row_data = {.uri_ranges = {0}};
|
||||
|
|
|
|||
15
grid.h
15
grid.h
|
|
@ -88,17 +88,27 @@ void grid_row_uri_range_put(
|
|||
struct row *row, int col, const char *uri, uint64_t id);
|
||||
void grid_row_uri_range_erase(struct row *row, int start, int end);
|
||||
|
||||
void grid_row_curly_range_put(
|
||||
struct row *row, int col, struct curly_range_data data);
|
||||
void grid_row_curly_range_erase(struct row *row, int start, int end);
|
||||
|
||||
static inline void
|
||||
grid_row_uri_range_destroy(struct row_range *range)
|
||||
{
|
||||
free(range->uri.uri);
|
||||
}
|
||||
|
||||
static inline void
|
||||
grid_row_curly_range_destroy(struct row_range *range)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
grid_row_range_destroy(struct row_range *range, enum row_range_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case ROW_RANGE_URI: grid_row_uri_range_destroy(range); break;
|
||||
case ROW_RANGE_CURLY: grid_row_curly_range_destroy(range); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,9 +128,10 @@ grid_row_reset_extra(struct row *row)
|
|||
if (likely(extra == NULL))
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < extra->uri_ranges.count; i++)
|
||||
grid_row_uri_range_destroy(&extra->uri_ranges.v[i]);
|
||||
grid_row_ranges_destroy(&extra->uri_ranges, ROW_RANGE_URI);
|
||||
grid_row_ranges_destroy(&extra->curly_ranges, ROW_RANGE_CURLY);
|
||||
free(extra->uri_ranges.v);
|
||||
free(extra->curly_ranges.v);
|
||||
|
||||
free(extra);
|
||||
row->extra = NULL;
|
||||
|
|
|
|||
39
render.c
39
render.c
|
|
@ -847,8 +847,43 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
pixman_image_unref(clr_pix);
|
||||
|
||||
/* Underline */
|
||||
if (cell->attrs.underline)
|
||||
draw_underline(term, pix, font, &fg, x, y, cell_cols);
|
||||
if (cell->attrs.underline) {
|
||||
pixman_color_t underline_color = fg;
|
||||
|
||||
/* Check if cell has a styled underline. This lookup is fairly
|
||||
expensive... */
|
||||
if (row->extra != NULL) {
|
||||
for (int i = 0; i < row->extra->curly_ranges.count; i++) {
|
||||
const struct row_range *range = &row->extra->curly_ranges.v[i];
|
||||
|
||||
if (range->start <= col && col <= range->end) {
|
||||
switch (range->curly.color_src) {
|
||||
case COLOR_BASE256:
|
||||
underline_color = color_hex_to_pixman(
|
||||
term->colors.table[range->curly.color]);
|
||||
break;
|
||||
|
||||
case COLOR_RGB:
|
||||
underline_color =
|
||||
color_hex_to_pixman(range->curly.color);
|
||||
break;
|
||||
|
||||
case COLOR_DEFAULT:
|
||||
break;
|
||||
|
||||
case COLOR_BASE16:
|
||||
BUG("underline color can't be base-16");
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw_underline(term, pix, font, &underline_color, x, y, cell_cols);
|
||||
|
||||
}
|
||||
|
||||
if (cell->attrs.strikethrough)
|
||||
draw_strikeout(term, pix, font, &fg, x, y, cell_cols);
|
||||
|
|
|
|||
22
terminal.c
22
terminal.c
|
|
@ -1940,8 +1940,10 @@ erase_cell_range(struct terminal *term, struct row *row, int start, int end)
|
|||
} else
|
||||
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
|
||||
|
||||
if (unlikely(row->extra != NULL))
|
||||
if (unlikely(row->extra != NULL)) {
|
||||
grid_row_uri_range_erase(row, start, end);
|
||||
grid_row_curly_range_erase(row, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -3621,6 +3623,7 @@ term_fill(struct terminal *term, int r, int c, uint8_t data, size_t count,
|
|||
cell->wc = data;
|
||||
cell->attrs = attrs;
|
||||
|
||||
/* TODO: why do we print the URI here, and then erase it below? */
|
||||
if (unlikely(term->vt.osc8.uri != NULL)) {
|
||||
grid_row_uri_range_put(row, c, term->vt.osc8.uri, term->vt.osc8.id);
|
||||
|
||||
|
|
@ -3635,8 +3638,10 @@ term_fill(struct terminal *term, int r, int c, uint8_t data, size_t count,
|
|||
}
|
||||
}
|
||||
|
||||
if (unlikely(row->extra != NULL))
|
||||
if (unlikely(row->extra != NULL)) {
|
||||
grid_row_uri_range_erase(row, c, c + count - 1);
|
||||
grid_row_curly_range_erase(row, c, c + count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3706,6 +3711,13 @@ term_print(struct terminal *term, char32_t wc, int width)
|
|||
} else if (row->extra != NULL)
|
||||
grid_row_uri_range_erase(row, col, col + width - 1);
|
||||
|
||||
if (unlikely(term->vt.curly.style > CURLY_SINGLE ||
|
||||
term->vt.curly.color_src != COLOR_DEFAULT))
|
||||
{
|
||||
grid_row_curly_range_put(row, col, term->vt.curly);
|
||||
} else if (row->extra != NULL)
|
||||
grid_row_curly_range_erase(row, col, col + width - 1);
|
||||
|
||||
/* Advance cursor the 'additional' columns while dirty:ing the cells */
|
||||
for (int i = 1; i < width && (col + 1) < term->cols; i++) {
|
||||
col++;
|
||||
|
|
@ -3763,8 +3775,10 @@ ascii_printer_fast(struct terminal *term, char32_t wc)
|
|||
|
||||
grid->cursor.point.col = col;
|
||||
|
||||
if (unlikely(row->extra != NULL))
|
||||
if (unlikely(row->extra != NULL)) {
|
||||
grid_row_uri_range_erase(row, uri_start, uri_start);
|
||||
grid_row_curly_range_erase(row, uri_start, uri_start);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -3781,6 +3795,8 @@ term_update_ascii_printer(struct terminal *term)
|
|||
void (*new_printer)(struct terminal *term, char32_t wc) =
|
||||
unlikely(tll_length(term->grid->sixel_images) > 0 ||
|
||||
term->vt.osc8.uri != NULL ||
|
||||
term->vt.curly.style > CURLY_SINGLE ||
|
||||
term->vt.curly.color_src != COLOR_DEFAULT ||
|
||||
term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC ||
|
||||
term->insert_mode)
|
||||
? &ascii_printer_generic
|
||||
|
|
|
|||
26
terminal.h
26
terminal.h
|
|
@ -104,12 +104,33 @@ struct uri_range_data {
|
|||
char *uri;
|
||||
};
|
||||
|
||||
enum curly_style {
|
||||
CURLY_NONE,
|
||||
CURLY_SINGLE, /* Legacy underline */
|
||||
CURLY_DOUBLE,
|
||||
CURLY_CURLY,
|
||||
CURLY_DOTTED,
|
||||
CURLY_DASHED,
|
||||
};
|
||||
|
||||
struct curly_range_data {
|
||||
enum curly_style style;
|
||||
enum color_source color_src;
|
||||
uint32_t color;
|
||||
};
|
||||
|
||||
union row_range_data {
|
||||
struct uri_range_data uri;
|
||||
struct curly_range_data curly;
|
||||
};
|
||||
|
||||
struct row_range {
|
||||
int start;
|
||||
int end;
|
||||
|
||||
union {
|
||||
struct uri_range_data uri;
|
||||
struct curly_range_data curly;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -119,10 +140,11 @@ struct row_ranges {
|
|||
int count;
|
||||
};
|
||||
|
||||
enum row_range_type {ROW_RANGE_URI};
|
||||
enum row_range_type {ROW_RANGE_URI, ROW_RANGE_CURLY};
|
||||
|
||||
struct row_data {
|
||||
struct row_ranges uri_ranges;
|
||||
struct row_ranges curly_ranges;
|
||||
};
|
||||
|
||||
struct row {
|
||||
|
|
@ -271,6 +293,8 @@ struct vt {
|
|||
char *uri;
|
||||
} osc8;
|
||||
|
||||
struct curly_range_data curly;
|
||||
|
||||
struct {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue