mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-22 05:33:45 -04:00
commit
94b9014f95
13 changed files with 911 additions and 213 deletions
|
|
@ -61,10 +61,11 @@
|
||||||
will now utilize the new single-pixel buffer protocol. This mainly
|
will now utilize the new single-pixel buffer protocol. This mainly
|
||||||
reduces the memory usage, but should also be slightly faster.
|
reduces the memory usage, but should also be slightly faster.
|
||||||
* Support for high-res mouse wheel scroll events ([#1738][1738]).
|
* Support for high-res mouse wheel scroll events ([#1738][1738]).
|
||||||
|
* Styled and colored underlines ([#828][828]).
|
||||||
|
|
||||||
[1707]: https://codeberg.org/dnkl/foot/issues/1707
|
[1707]: https://codeberg.org/dnkl/foot/issues/1707
|
||||||
[1738]: https://codeberg.org/dnkl/foot/issues/1738
|
[1738]: https://codeberg.org/dnkl/foot/issues/1738
|
||||||
|
[828]: https://codeberg.org/dnkl/foot/issues/828
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
|
||||||
* IME (via `text-input-v3`)
|
* IME (via `text-input-v3`)
|
||||||
* Multi-seat
|
* Multi-seat
|
||||||
* True Color (24bpp)
|
* True Color (24bpp)
|
||||||
|
* [Styled and colored underlines](https://sw.kovidgoyal.net/kitty/underlines/)
|
||||||
* [Synchronized Updates](https://gitlab.freedesktop.org/terminal-wg/specifications/-/merge_requests/2) support
|
* [Synchronized Updates](https://gitlab.freedesktop.org/terminal-wg/specifications/-/merge_requests/2) support
|
||||||
* [Sixel image support](https://en.wikipedia.org/wiki/Sixel)
|
* [Sixel image support](https://en.wikipedia.org/wiki/Sixel)
|
||||||
|
|
||||||
|
|
|
||||||
67
csi.c
67
csi.c
|
|
@ -32,7 +32,12 @@
|
||||||
static void
|
static void
|
||||||
sgr_reset(struct terminal *term)
|
sgr_reset(struct terminal *term)
|
||||||
{
|
{
|
||||||
memset(&term->vt.attrs, 0, sizeof(term->vt.attrs));
|
term->vt.attrs = (struct attributes){0};
|
||||||
|
term->vt.curly = (struct curly_range_data){0};
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.curly_style = false;
|
||||||
|
term->bits_affecting_ascii_printer.curly_color = false;
|
||||||
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
|
@ -88,7 +93,36 @@ csi_sgr(struct terminal *term)
|
||||||
case 1: term->vt.attrs.bold = true; break;
|
case 1: term->vt.attrs.bold = true; break;
|
||||||
case 2: term->vt.attrs.dim = true; break;
|
case 2: term->vt.attrs.dim = true; break;
|
||||||
case 3: term->vt.attrs.italic = 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;
|
||||||
|
term->bits_affecting_ascii_printer.curly_style = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLY_SINGLE:
|
||||||
|
case CURLY_DOUBLE:
|
||||||
|
case CURLY_CURLY:
|
||||||
|
case CURLY_DOTTED:
|
||||||
|
case CURLY_DASHED:
|
||||||
|
term->vt.curly.style = style;
|
||||||
|
term->bits_affecting_ascii_printer.curly_style =
|
||||||
|
style > CURLY_SINGLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
term_update_ascii_printer(term);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 5: term->vt.attrs.blink = true; break;
|
case 5: term->vt.attrs.blink = true; break;
|
||||||
case 6: LOG_WARN("ignored: rapid blink"); break;
|
case 6: LOG_WARN("ignored: rapid blink"); break;
|
||||||
case 7: term->vt.attrs.reverse = true; break;
|
case 7: term->vt.attrs.reverse = true; break;
|
||||||
|
|
@ -98,7 +132,13 @@ csi_sgr(struct terminal *term)
|
||||||
case 21: break; /* double-underline, not implemented */
|
case 21: break; /* double-underline, not implemented */
|
||||||
case 22: term->vt.attrs.bold = term->vt.attrs.dim = false; break;
|
case 22: term->vt.attrs.bold = term->vt.attrs.dim = false; break;
|
||||||
case 23: term->vt.attrs.italic = 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->bits_affecting_ascii_printer.curly_style = false;
|
||||||
|
term_update_ascii_printer(term);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 25: term->vt.attrs.blink = false; break;
|
case 25: term->vt.attrs.blink = false; break;
|
||||||
case 26: break; /* rapid blink, ignored */
|
case 26: break; /* rapid blink, ignored */
|
||||||
case 27: term->vt.attrs.reverse = false; break;
|
case 27: term->vt.attrs.reverse = false; break;
|
||||||
|
|
@ -119,7 +159,8 @@ csi_sgr(struct terminal *term)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 38:
|
case 38:
|
||||||
case 48: {
|
case 48:
|
||||||
|
case 58: {
|
||||||
uint32_t color;
|
uint32_t color;
|
||||||
enum color_source src;
|
enum color_source src;
|
||||||
|
|
||||||
|
|
@ -194,7 +235,12 @@ csi_sgr(struct terminal *term)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param == 38) {
|
if (unlikely(param == 58)) {
|
||||||
|
term->vt.curly.color_src = src;
|
||||||
|
term->vt.curly.color = color;
|
||||||
|
term->bits_affecting_ascii_printer.curly_color = true;
|
||||||
|
term_update_ascii_printer(term);
|
||||||
|
} else if (param == 38) {
|
||||||
term->vt.attrs.fg_src = src;
|
term->vt.attrs.fg_src = src;
|
||||||
term->vt.attrs.fg = color;
|
term->vt.attrs.fg = color;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -226,6 +272,13 @@ csi_sgr(struct terminal *term)
|
||||||
term->vt.attrs.bg_src = COLOR_DEFAULT;
|
term->vt.attrs.bg_src = COLOR_DEFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 59:
|
||||||
|
term->vt.curly.color_src = COLOR_DEFAULT;
|
||||||
|
term->vt.curly.color = 0;
|
||||||
|
term->bits_affecting_ascii_printer.curly_color = false;
|
||||||
|
term_update_ascii_printer(term);
|
||||||
|
break;
|
||||||
|
|
||||||
/* Bright foreground colors */
|
/* Bright foreground colors */
|
||||||
case 90:
|
case 90:
|
||||||
case 91:
|
case 91:
|
||||||
|
|
@ -478,6 +531,9 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
|
||||||
tll_free(term->alt.scroll_damage);
|
tll_free(term->alt.scroll_damage);
|
||||||
term_damage_view(term);
|
term_damage_view(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.sixels =
|
||||||
|
tll_length(term->grid->sixel_images) > 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1116,6 +1172,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
if (param == 4) {
|
if (param == 4) {
|
||||||
/* Insertion Replacement Mode (IRM) */
|
/* Insertion Replacement Mode (IRM) */
|
||||||
term->insert_mode = sm;
|
term->insert_mode = sm;
|
||||||
|
term->bits_affecting_ascii_printer.insert_mode = sm;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ m*.
|
||||||
| 3
|
| 3
|
||||||
: Italic
|
: Italic
|
||||||
| 4
|
| 4
|
||||||
: Underline
|
: Underline, including styled underlines
|
||||||
| 5
|
| 5
|
||||||
: Blink
|
: Blink
|
||||||
| 7
|
| 7
|
||||||
|
|
@ -176,15 +176,19 @@ m*.
|
||||||
| 30-37
|
| 30-37
|
||||||
: Select foreground color (using *regularN* in *foot.ini*(5))
|
: Select foreground color (using *regularN* in *foot.ini*(5))
|
||||||
| 38
|
| 38
|
||||||
: See "indexed and RGB colors" below
|
: Select foreground color, see "indexed and RGB colors" below
|
||||||
| 39
|
| 39
|
||||||
: Use the default foreground color (*foreground* in *foot.ini*(5))
|
: Use the default foreground color (*foreground* in *foot.ini*(5))
|
||||||
| 40-47
|
| 40-47
|
||||||
: Select background color (using *regularN* in *foot.ini*(5))
|
: Select background color (using *regularN* in *foot.ini*(5))
|
||||||
| 48
|
| 48
|
||||||
: See "indexed and RGB colors" below
|
: Select background color, see "indexed and RGB colors" below
|
||||||
| 49
|
| 49
|
||||||
: Use the default background color (*background* in *foot.ini*(5))
|
: Use the default background color (*background* in *foot.ini*(5))
|
||||||
|
| 58
|
||||||
|
: Select underline color, see "indexed and RGB colors" below
|
||||||
|
| 59
|
||||||
|
: Use the default underline color
|
||||||
| 90-97
|
| 90-97
|
||||||
: Select foreground color (using *brightN* in *foot.ini*(5))
|
: Select foreground color (using *brightN* in *foot.ini*(5))
|
||||||
| 100-107
|
| 100-107
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
@default_terminfo@+base|foot base fragment,
|
@default_terminfo@+base|foot base fragment,
|
||||||
AX,
|
AX,
|
||||||
|
Su,
|
||||||
Tc,
|
Tc,
|
||||||
XF,
|
XF,
|
||||||
XT,
|
XT,
|
||||||
|
|
@ -40,6 +41,8 @@
|
||||||
RV=\E[>c,
|
RV=\E[>c,
|
||||||
Rect=\E[%p1%d;%p2%d;%p3%d;%p4%d;%p5%d$x,
|
Rect=\E[%p1%d;%p2%d;%p3%d;%p4%d;%p5%d$x,
|
||||||
Se=\E[ q,
|
Se=\E[ q,
|
||||||
|
Setulc=\E[58\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
|
||||||
|
Smulx=\E[4:%p1%dm,
|
||||||
Ss=\E[%p1%d q,
|
Ss=\E[%p1%d q,
|
||||||
Sync=\E[?2026%?%p1%{1}%-%tl%eh%;,
|
Sync=\E[?2026%?%p1%{1}%-%tl%eh%;,
|
||||||
TS=\E]2;,
|
TS=\E]2;,
|
||||||
|
|
|
||||||
625
grid.c
625
grid.c
|
|
@ -85,22 +85,32 @@ ensure_row_has_extra_data(struct row *row)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
verify_no_overlapping_uris(const struct row_data *extra)
|
verify_no_overlapping_ranges_of_type(const struct row_ranges *ranges,
|
||||||
|
enum row_range_type type)
|
||||||
{
|
{
|
||||||
#if defined(_DEBUG)
|
#if defined(_DEBUG)
|
||||||
for (size_t i = 0; i < extra->uri_ranges.count; i++) {
|
for (size_t i = 0; i < ranges->count; i++) {
|
||||||
const struct row_uri_range *r1 = &extra->uri_ranges.v[i];
|
const struct row_range *r1 = &ranges->v[i];
|
||||||
|
|
||||||
for (size_t j = i + 1; j < extra->uri_ranges.count; j++) {
|
for (size_t j = i + 1; j < ranges->count; j++) {
|
||||||
const struct row_uri_range *r2 = &extra->uri_ranges.v[j];
|
const struct row_range *r2 = &ranges->v[j];
|
||||||
xassert(r1 != r2);
|
xassert(r1 != r2);
|
||||||
|
|
||||||
if ((r1->start <= r2->start && r1->end >= r2->start) ||
|
if ((r1->start <= r2->start && r1->end >= r2->start) ||
|
||||||
(r1->start <= r2->end && r1->end >= r2->end))
|
(r1->start <= r2->end && r1->end >= r2->end))
|
||||||
{
|
{
|
||||||
BUG("OSC-8 URI overlap: %s: %d-%d: %s: %d-%d",
|
switch (type) {
|
||||||
r1->uri, r1->start, r1->end,
|
case ROW_RANGE_URI:
|
||||||
r2->uri, r2->start, r2->end);
|
BUG("OSC-8 URI overlap: %s: %d-%d: %s: %d-%d",
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,20 +118,38 @@ verify_no_overlapping_uris(const struct row_data *extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
verify_uris_are_sorted(const struct row_data *extra)
|
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
|
||||||
|
verify_ranges_of_type_are_sorted(const struct row_ranges *ranges,
|
||||||
|
enum row_range_type type)
|
||||||
{
|
{
|
||||||
#if defined(_DEBUG)
|
#if defined(_DEBUG)
|
||||||
const struct row_uri_range *last = NULL;
|
const struct row_range *last = NULL;
|
||||||
|
|
||||||
for (size_t i = 0; i < extra->uri_ranges.count; i++) {
|
for (size_t i = 0; i < ranges->count; i++) {
|
||||||
const struct row_uri_range *r = &extra->uri_ranges.v[i];
|
const struct row_range *r = &ranges->v[i];
|
||||||
|
|
||||||
if (last != NULL) {
|
if (last != NULL) {
|
||||||
if (last->start >= r->start || last->end >= r->end) {
|
if (last->start >= r->start || last->end >= r->end) {
|
||||||
BUG("OSC-8 URI not sorted correctly: "
|
switch (type) {
|
||||||
"%s: %d-%d came before %s: %d-%d",
|
case ROW_RANGE_URI:
|
||||||
last->uri, last->start, last->end,
|
BUG("OSC-8 URI not sorted correctly: "
|
||||||
r->uri, r->start, r->end);
|
"%s: %d-%d came before %s: %d-%d",
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,16 +159,21 @@ verify_uris_are_sorted(const struct row_data *extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
uri_range_ensure_size(struct row_data *extra, uint32_t count_to_add)
|
verify_ranges_are_sorted(const struct row_data *extra)
|
||||||
{
|
{
|
||||||
if (extra->uri_ranges.count + count_to_add > extra->uri_ranges.size) {
|
verify_ranges_of_type_are_sorted(&extra->uri_ranges, ROW_RANGE_URI);
|
||||||
extra->uri_ranges.size = extra->uri_ranges.count + count_to_add;
|
verify_ranges_of_type_are_sorted(&extra->curly_ranges, ROW_RANGE_CURLY);
|
||||||
extra->uri_ranges.v = xrealloc(
|
}
|
||||||
extra->uri_ranges.v,
|
|
||||||
extra->uri_ranges.size * sizeof(extra->uri_ranges.v[0]));
|
static void
|
||||||
|
range_ensure_size(struct row_ranges *ranges, int count_to_add)
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -148,58 +181,88 @@ uri_range_ensure_size(struct row_data *extra, uint32_t count_to_add)
|
||||||
* invalidating pointers into it.
|
* invalidating pointers into it.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
uri_range_insert(struct row_data *extra, size_t idx, int start, int end,
|
range_insert(struct row_ranges *ranges, size_t idx, int start, int end,
|
||||||
uint64_t id, const char *uri)
|
enum row_range_type type, const union row_range_data *data)
|
||||||
{
|
{
|
||||||
uri_range_ensure_size(extra, 1);
|
range_ensure_size(ranges, 1);
|
||||||
|
|
||||||
xassert(idx <= extra->uri_ranges.count);
|
xassert(idx <= ranges->count);
|
||||||
|
|
||||||
const size_t move_count = extra->uri_ranges.count - idx;
|
const size_t move_count = ranges->count - idx;
|
||||||
memmove(&extra->uri_ranges.v[idx + 1],
|
memmove(&ranges->v[idx + 1],
|
||||||
&extra->uri_ranges.v[idx],
|
&ranges->v[idx],
|
||||||
move_count * sizeof(extra->uri_ranges.v[0]));
|
move_count * sizeof(ranges->v[0]));
|
||||||
|
|
||||||
extra->uri_ranges.count++;
|
ranges->count++;
|
||||||
extra->uri_ranges.v[idx] = (struct row_uri_range){
|
|
||||||
.start = start,
|
struct row_range *r = &ranges->v[idx];
|
||||||
.end = end,
|
r->start = start;
|
||||||
.id = id,
|
r->end = end;
|
||||||
.uri = xstrdup(uri),
|
|
||||||
};
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
r->uri.id = data->uri.id;
|
||||||
|
r->uri.uri = xstrdup(data->uri.uri);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
r->curly = data->curly;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
uri_range_append_no_strdup(struct row_data *extra, int start, int end,
|
range_append_by_ref(struct row_ranges *ranges, int start, int end,
|
||||||
uint64_t id, char *uri)
|
enum row_range_type type, const union row_range_data *data)
|
||||||
{
|
{
|
||||||
uri_range_ensure_size(extra, 1);
|
range_ensure_size(ranges, 1);
|
||||||
extra->uri_ranges.v[extra->uri_ranges.count++] = (struct row_uri_range){
|
|
||||||
.start = start,
|
struct row_range *r = &ranges->v[ranges->count++];
|
||||||
.end = end,
|
|
||||||
.id = id,
|
r->start = start;
|
||||||
.uri = uri,
|
r->end = end;
|
||||||
};
|
|
||||||
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
r->uri.id = data->uri.id;;
|
||||||
|
r->uri.uri = data->uri.uri;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
r->curly = data->curly;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
uri_range_append(struct row_data *extra, int start, int end, uint64_t id,
|
range_append(struct row_ranges *ranges, int start, int end,
|
||||||
const char *uri)
|
enum row_range_type type, const union row_range_data *data)
|
||||||
{
|
{
|
||||||
uri_range_append_no_strdup(extra, start, end, id, xstrdup(uri));
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
range_append_by_ref(
|
||||||
|
ranges, start, end, type,
|
||||||
|
&(union row_range_data){.uri = {.id = data->uri.id,
|
||||||
|
.uri = xstrdup(data->uri.uri)}});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
range_append_by_ref(ranges, start, end, type, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
xassert(idx < ranges->count);
|
||||||
grid_row_uri_range_destroy(&extra->uri_ranges.v[idx]);
|
grid_row_range_destroy(&ranges->v[idx], type);
|
||||||
|
|
||||||
const size_t move_count = extra->uri_ranges.count - idx - 1;
|
const size_t move_count = ranges->count - idx - 1;
|
||||||
memmove(&extra->uri_ranges.v[idx],
|
memmove(&ranges->v[idx],
|
||||||
&extra->uri_ranges.v[idx + 1],
|
&ranges->v[idx + 1],
|
||||||
move_count * sizeof(extra->uri_ranges.v[0]));
|
move_count * sizeof(ranges->v[0]));
|
||||||
extra->uri_ranges.count--;
|
ranges->count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct grid *
|
struct grid *
|
||||||
|
|
@ -243,13 +306,21 @@ grid_snapshot(const struct grid *grid)
|
||||||
struct row_data *clone_extra = xcalloc(1, sizeof(*clone_extra));
|
struct row_data *clone_extra = xcalloc(1, sizeof(*clone_extra));
|
||||||
clone_row->extra = 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_uri_range *range = &extra->uri_ranges.v[i];
|
const struct row_range *range = &extra->uri_ranges.v[i];
|
||||||
uri_range_append(
|
range_append(
|
||||||
clone_extra,
|
&clone_extra->uri_ranges,
|
||||||
range->start, range->end, range->id, range->uri);
|
range->start, range->end, ROW_RANGE_URI, &range->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < extra->curly_ranges.count; i++) {
|
||||||
|
const struct row_range *range = &extra->curly_ranges.v[i];
|
||||||
|
range_append_by_ref(
|
||||||
|
&clone_extra->curly_ranges, range->start, range->end,
|
||||||
|
ROW_RANGE_CURLY, &range->data);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
clone_row->extra = NULL;
|
clone_row->extra = NULL;
|
||||||
|
|
@ -464,10 +535,11 @@ grid_resize_without_reflow(
|
||||||
ensure_row_has_extra_data(new_row);
|
ensure_row_has_extra_data(new_row);
|
||||||
struct row_data *new_extra = new_row->extra;
|
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_uri_range *range = &old_extra->uri_ranges.v[i];
|
const struct row_range *range = &old_extra->uri_ranges.v[i];
|
||||||
|
|
||||||
if (range->start >= new_cols) {
|
if (range->start >= new_cols) {
|
||||||
/* The whole range is truncated */
|
/* The whole range is truncated */
|
||||||
|
|
@ -476,9 +548,22 @@ grid_resize_without_reflow(
|
||||||
|
|
||||||
const int start = range->start;
|
const int start = range->start;
|
||||||
const int end = min(range->end, new_cols - 1);
|
const int end = min(range->end, new_cols - 1);
|
||||||
uri_range_append(new_extra, start, end, range->id, range->uri);
|
range_append(&new_extra->uri_ranges, start, end, ROW_RANGE_URI, &range->data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
for (int i = 0; i < old_extra->curly_ranges.count; i++) {
|
||||||
|
const struct row_range *range = &old_extra->curly_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);
|
||||||
|
range_append_by_ref(&new_extra->curly_ranges, start, end, ROW_RANGE_CURLY, &range->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear "new" lines */
|
/* Clear "new" lines */
|
||||||
for (int r = min(old_screen_rows, new_screen_rows); r < new_screen_rows; r++) {
|
for (int r = min(old_screen_rows, new_screen_rows); r < new_screen_rows; r++) {
|
||||||
|
|
@ -498,8 +583,8 @@ grid_resize_without_reflow(
|
||||||
if (row->extra == NULL)
|
if (row->extra == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
verify_no_overlapping_uris(row->extra);
|
verify_no_overlapping_ranges(row->extra);
|
||||||
verify_uris_are_sorted(row->extra);
|
verify_ranges_are_sorted(row->extra);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -549,27 +634,60 @@ grid_resize_without_reflow(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reflow_uri_range_start(struct row_uri_range *range, struct row *new_row,
|
reflow_range_start(struct row_range *range, enum row_range_type type,
|
||||||
int new_col_idx)
|
struct row *new_row, int new_col_idx)
|
||||||
{
|
{
|
||||||
ensure_row_has_extra_data(new_row);
|
ensure_row_has_extra_data(new_row);
|
||||||
uri_range_append_no_strdup
|
|
||||||
(new_row->extra, new_col_idx, -1, range->id, range->uri);
|
struct row_ranges *new_ranges = NULL;
|
||||||
range->uri = NULL;
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI: new_ranges = &new_row->extra->uri_ranges; break;
|
||||||
|
case ROW_RANGE_CURLY: new_ranges = &new_row->extra->curly_ranges; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_ranges == NULL)
|
||||||
|
BUG("unhandled range type");
|
||||||
|
|
||||||
|
range_append_by_ref(new_ranges, new_col_idx, -1, type, &range->data);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI: range->uri.uri = NULL; break; /* Owned by new_ranges */
|
||||||
|
case ROW_RANGE_CURLY: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reflow_uri_range_end(struct row_uri_range *range, struct row *new_row,
|
reflow_range_end(struct row_range *range, enum row_range_type type,
|
||||||
int new_col_idx)
|
struct row *new_row, int new_col_idx)
|
||||||
{
|
{
|
||||||
struct row_data *extra = new_row->extra;
|
struct row_data *extra = new_row->extra;
|
||||||
xassert(extra->uri_ranges.count > 0);
|
struct row_ranges *ranges = NULL;
|
||||||
|
|
||||||
struct row_uri_range *new_range =
|
switch (type) {
|
||||||
&extra->uri_ranges.v[extra->uri_ranges.count - 1];
|
case ROW_RANGE_URI: ranges = &extra->uri_ranges; break;
|
||||||
|
case ROW_RANGE_CURLY: ranges = &extra->curly_ranges; break;
|
||||||
|
}
|
||||||
|
|
||||||
xassert(new_range->id == range->id);
|
if (ranges == NULL)
|
||||||
|
BUG("unhandled range type");
|
||||||
|
|
||||||
|
xassert(ranges->count > 0);
|
||||||
|
|
||||||
|
struct row_range *new_range = &ranges->v[ranges->count - 1];
|
||||||
xassert(new_range->end < 0);
|
xassert(new_range->end < 0);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
xassert(new_range->uri.id == range->uri.id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
xassert(new_range->curly.style == range->curly.style);
|
||||||
|
xassert(new_range->curly.color_src == range->curly.color_src);
|
||||||
|
xassert(new_range->curly.color == range->curly.color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
new_range->end = new_col_idx;
|
new_range->end = new_col_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -619,7 +737,7 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row,
|
||||||
* next/current row.
|
* next/current row.
|
||||||
*/
|
*/
|
||||||
if (extra->uri_ranges.count > 0) {
|
if (extra->uri_ranges.count > 0) {
|
||||||
struct row_uri_range *range =
|
struct row_range *range =
|
||||||
&extra->uri_ranges.v[extra->uri_ranges.count - 1];
|
&extra->uri_ranges.v[extra->uri_ranges.count - 1];
|
||||||
|
|
||||||
if (range->end < 0) {
|
if (range->end < 0) {
|
||||||
|
|
@ -629,7 +747,24 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row,
|
||||||
|
|
||||||
/* Open a new range on the new/current row */
|
/* Open a new range on the new/current row */
|
||||||
ensure_row_has_extra_data(new_row);
|
ensure_row_has_extra_data(new_row);
|
||||||
uri_range_append(new_row->extra, 0, -1, range->id, range->uri);
|
range_append(&new_row->extra->uri_ranges, 0, -1,
|
||||||
|
ROW_RANGE_URI, &range->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extra->curly_ranges.count > 0) {
|
||||||
|
struct row_range *range =
|
||||||
|
&extra->curly_ranges.v[extra->curly_ranges.count - 1];
|
||||||
|
|
||||||
|
if (range->end < 0) {
|
||||||
|
|
||||||
|
/* Terminate URI range on the previous row */
|
||||||
|
range->end = col_count - 1;
|
||||||
|
|
||||||
|
/* Open a new range on the new/current row */
|
||||||
|
ensure_row_has_extra_data(new_row);
|
||||||
|
range_append(&new_row->extra->curly_ranges, 0, -1,
|
||||||
|
ROW_RANGE_CURLY, &range->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -817,31 +952,46 @@ grid_resize_and_reflow(
|
||||||
tp = NULL;
|
tp = NULL;
|
||||||
|
|
||||||
/* Does this row have any URIs? */
|
/* Does this row have any URIs? */
|
||||||
struct row_uri_range *range, *range_terminator;
|
struct row_range *uri_range, *uri_range_terminator;
|
||||||
|
struct row_range *curly_range, *curly_range_terminator;
|
||||||
struct row_data *extra = old_row->extra;
|
struct row_data *extra = old_row->extra;
|
||||||
|
|
||||||
if (extra != NULL && extra->uri_ranges.count > 0) {
|
if (extra != NULL && extra->uri_ranges.count > 0) {
|
||||||
range = &extra->uri_ranges.v[0];
|
uri_range = &extra->uri_ranges.v[0];
|
||||||
range_terminator = &extra->uri_ranges.v[extra->uri_ranges.count];
|
uri_range_terminator = &extra->uri_ranges.v[extra->uri_ranges.count];
|
||||||
|
|
||||||
/* Make sure the *last* URI range's end point is included
|
/* Make sure the *last* URI range's end point is included
|
||||||
* in the copy */
|
* in the copy */
|
||||||
const struct row_uri_range *last_on_row =
|
const struct row_range *last_on_row =
|
||||||
&extra->uri_ranges.v[extra->uri_ranges.count - 1];
|
&extra->uri_ranges.v[extra->uri_ranges.count - 1];
|
||||||
col_count = max(col_count, last_on_row->end + 1);
|
col_count = max(col_count, last_on_row->end + 1);
|
||||||
} else
|
} else
|
||||||
range = range_terminator = NULL;
|
uri_range = uri_range_terminator = NULL;
|
||||||
|
|
||||||
|
if (extra != NULL && extra->curly_ranges.count > 0) {
|
||||||
|
curly_range = &extra->curly_ranges.v[0];
|
||||||
|
curly_range_terminator = &extra->curly_ranges.v[extra->curly_ranges.count];
|
||||||
|
|
||||||
|
const struct row_range *last_on_row =
|
||||||
|
&extra->curly_ranges.v[extra->curly_ranges.count - 1];
|
||||||
|
col_count = max(col_count, last_on_row->end + 1);
|
||||||
|
} else
|
||||||
|
curly_range = curly_range_terminator = NULL;
|
||||||
|
|
||||||
for (int start = 0, left = col_count; left > 0;) {
|
for (int start = 0, left = col_count; left > 0;) {
|
||||||
int end;
|
int end;
|
||||||
bool tp_break = false;
|
bool tp_break = false;
|
||||||
bool uri_break = false;
|
bool uri_break = false;
|
||||||
|
bool curly_break = false;
|
||||||
bool ftcs_break = false;
|
bool ftcs_break = false;
|
||||||
|
|
||||||
/* Figure out where to end this chunk */
|
/* Figure out where to end this chunk */
|
||||||
{
|
{
|
||||||
const int uri_col = range != range_terminator
|
const int uri_col = uri_range != uri_range_terminator
|
||||||
? ((range->start >= start ? range->start : range->end) + 1)
|
? ((uri_range->start >= start ? uri_range->start : uri_range->end) + 1)
|
||||||
|
: INT_MAX;
|
||||||
|
const int curly_col = curly_range != curly_range_terminator
|
||||||
|
? ((curly_range->start >= start ? curly_range->start : curly_range->end) + 1)
|
||||||
: INT_MAX;
|
: INT_MAX;
|
||||||
const int tp_col = tp != NULL ? tp->col + 1 : INT_MAX;
|
const int tp_col = tp != NULL ? tp->col + 1 : INT_MAX;
|
||||||
const int ftcs_col = old_row->shell_integration.cmd_start >= start
|
const int ftcs_col = old_row->shell_integration.cmd_start >= start
|
||||||
|
|
@ -850,9 +1000,10 @@ grid_resize_and_reflow(
|
||||||
? old_row->shell_integration.cmd_end + 1
|
? old_row->shell_integration.cmd_end + 1
|
||||||
: INT_MAX;
|
: INT_MAX;
|
||||||
|
|
||||||
end = min(col_count, min(min(tp_col, uri_col), ftcs_col));
|
end = min(col_count, min(min(tp_col, min(uri_col, curly_col)), ftcs_col));
|
||||||
|
|
||||||
uri_break = end == uri_col;
|
uri_break = end == uri_col;
|
||||||
|
curly_break = end == curly_col;
|
||||||
tp_break = end == tp_col;
|
tp_break = end == tp_col;
|
||||||
ftcs_break = end == ftcs_col;
|
ftcs_break = end == ftcs_col;
|
||||||
}
|
}
|
||||||
|
|
@ -963,15 +1114,32 @@ grid_resize_and_reflow(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri_break) {
|
if (uri_break) {
|
||||||
xassert(range != NULL);
|
xassert(uri_range != NULL);
|
||||||
|
|
||||||
if (range->start == end - 1)
|
if (uri_range->start == end - 1)
|
||||||
reflow_uri_range_start(range, new_row, new_col_idx - 1);
|
reflow_range_start(
|
||||||
|
uri_range, ROW_RANGE_URI, new_row, new_col_idx - 1);
|
||||||
|
|
||||||
if (range->end == end - 1) {
|
if (uri_range->end == end - 1) {
|
||||||
reflow_uri_range_end(range, new_row, new_col_idx - 1);
|
reflow_range_end(
|
||||||
grid_row_uri_range_destroy(range);
|
uri_range, ROW_RANGE_URI, new_row, new_col_idx - 1);
|
||||||
range++;
|
grid_row_uri_range_destroy(uri_range);
|
||||||
|
uri_range++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curly_break) {
|
||||||
|
xassert(curly_range != NULL);
|
||||||
|
|
||||||
|
if (curly_range->start == end - 1)
|
||||||
|
reflow_range_start(
|
||||||
|
curly_range, ROW_RANGE_CURLY, new_row, new_col_idx - 1);
|
||||||
|
|
||||||
|
if (curly_range->end == end - 1) {
|
||||||
|
reflow_range_end(
|
||||||
|
curly_range, ROW_RANGE_CURLY, new_row, new_col_idx - 1);
|
||||||
|
grid_row_curly_range_destroy(curly_range);
|
||||||
|
curly_range++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -997,20 +1165,26 @@ grid_resize_and_reflow(
|
||||||
|
|
||||||
if (r + 1 < old_rows)
|
if (r + 1 < old_rows)
|
||||||
line_wrap();
|
line_wrap();
|
||||||
else if (new_row->extra != NULL &&
|
else if (new_row->extra != NULL) {
|
||||||
new_row->extra->uri_ranges.count > 0)
|
if (new_row->extra->uri_ranges.count > 0) {
|
||||||
{
|
/*
|
||||||
/*
|
* line_wrap() "closes" still-open URIs. Since
|
||||||
* line_wrap() "closes" still-open URIs. Since this is
|
* this is the *last* row, and since we're
|
||||||
* the *last* row, and since we're line-breaking due
|
* line-breaking due to a hard line-break (rather
|
||||||
* to a hard line-break (rather than running out of
|
* than running out of cells in the "new_row"),
|
||||||
* cells in the "new_row"), there shouldn't be an open
|
* there shouldn't be an open URI (it would have
|
||||||
* URI (it would have been closed when we reached the
|
* been closed when we reached the end of the URI
|
||||||
* end of the URI while reflowing the last "old"
|
* while reflowing the last "old" row).
|
||||||
* row).
|
*/
|
||||||
*/
|
int last_idx = new_row->extra->uri_ranges.count - 1;
|
||||||
uint32_t last_idx = new_row->extra->uri_ranges.count - 1;
|
xassert(new_row->extra->uri_ranges.v[last_idx].end >= 0);
|
||||||
xassert(new_row->extra->uri_ranges.v[last_idx].end >= 0);
|
}
|
||||||
|
|
||||||
|
if (new_row->extra->curly_ranges.count > 0) {
|
||||||
|
int last_idx = new_row->extra->curly_ranges.count - 1;
|
||||||
|
xassert(new_row->extra->curly_ranges.v[last_idx].end >= 0);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1042,9 +1216,11 @@ grid_resize_and_reflow(
|
||||||
|
|
||||||
for (size_t i = 0; i < row->extra->uri_ranges.count; i++)
|
for (size_t i = 0; i < row->extra->uri_ranges.count; i++)
|
||||||
xassert(row->extra->uri_ranges.v[i].end >= 0);
|
xassert(row->extra->uri_ranges.v[i].end >= 0);
|
||||||
|
for (size_t i = 0; i < row->extra->curly_ranges.count; i++)
|
||||||
|
xassert(row->extra->curly_ranges.v[i].end >= 0);
|
||||||
|
|
||||||
verify_no_overlapping_uris(row->extra);
|
verify_no_overlapping_ranges(row->extra);
|
||||||
verify_uris_are_sorted(row->extra);
|
verify_ranges_are_sorted(row->extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify all old rows have been free:d */
|
/* Verify all old rows have been free:d */
|
||||||
|
|
@ -1125,25 +1301,60 @@ grid_resize_and_reflow(
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static bool
|
||||||
grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
ranges_match(const struct row_range *r1, const struct row_range *r2,
|
||||||
|
enum row_range_type type)
|
||||||
{
|
{
|
||||||
ensure_row_has_extra_data(row);
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
/* TODO: also match URI? */
|
||||||
|
return r1->uri.id == r2->uri.id;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
return r1->curly.style == r2->curly.style &&
|
||||||
|
r1->curly.color_src == r2->curly.color_src &&
|
||||||
|
r1->curly.color == r2->curly.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG("invalid range type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
range_match_data(const struct row_range *r, const union row_range_data *data,
|
||||||
|
enum row_range_type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
return r->uri.id == data->uri.id;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
return r->curly.style == data->curly.style &&
|
||||||
|
r->curly.color_src == data->curly.color_src &&
|
||||||
|
r->curly.color == data->curly.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG("invalid range type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grid_row_range_put(struct row_ranges *ranges, int col,
|
||||||
|
const union row_range_data *data, enum row_range_type type)
|
||||||
|
{
|
||||||
size_t insert_idx = 0;
|
size_t insert_idx = 0;
|
||||||
bool replace = false;
|
bool replace = false;
|
||||||
bool run_merge_pass = false;
|
bool run_merge_pass = false;
|
||||||
|
|
||||||
struct row_data *extra = row->extra;
|
for (int i = ranges->count - 1; i >= 0; i--) {
|
||||||
for (ssize_t i = (ssize_t)extra->uri_ranges.count - 1; i >= 0; i--) {
|
struct row_range *r = &ranges->v[i];
|
||||||
struct row_uri_range *r = &extra->uri_ranges.v[i];
|
|
||||||
|
|
||||||
const bool matching_id = r->id == id;
|
const bool matching = range_match_data(r, data, type);
|
||||||
|
|
||||||
if (matching_id && r->end + 1 == col) {
|
if (matching && r->end + 1 == col) {
|
||||||
/* Extend existing URI's tail */
|
/* Extend existing range tail */
|
||||||
r->end++;
|
r->end++;
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (r->end < col) {
|
else if (r->end < col) {
|
||||||
|
|
@ -1158,8 +1369,8 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
||||||
xassert(r->start <= col);
|
xassert(r->start <= col);
|
||||||
xassert(r->end >= col);
|
xassert(r->end >= col);
|
||||||
|
|
||||||
if (matching_id)
|
if (matching)
|
||||||
goto out;
|
return;
|
||||||
|
|
||||||
if (r->start == r->end) {
|
if (r->start == r->end) {
|
||||||
replace = true;
|
replace = true;
|
||||||
|
|
@ -1177,11 +1388,17 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
||||||
xassert(r->start < col);
|
xassert(r->start < col);
|
||||||
xassert(r->end > col);
|
xassert(r->end > col);
|
||||||
|
|
||||||
uri_range_insert(extra, i + 1, col + 1, r->end, r->id, r->uri);
|
union row_range_data insert_data;
|
||||||
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI: insert_data.uri = r->uri; break;
|
||||||
|
case ROW_RANGE_CURLY: insert_data.curly = r->curly; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_insert(ranges, i + 1, col + 1, r->end, type, &insert_data);
|
||||||
|
|
||||||
/* The insertion may xrealloc() the vector, making our
|
/* The insertion may xrealloc() the vector, making our
|
||||||
* 'old' pointer invalid */
|
* 'old' pointer invalid */
|
||||||
r = &extra->uri_ranges.v[i];
|
r = &ranges->v[i];
|
||||||
r->end = col - 1;
|
r->end = col - 1;
|
||||||
xassert(r->start <= r->end);
|
xassert(r->start <= r->end);
|
||||||
|
|
||||||
|
|
@ -1192,35 +1409,68 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xassert(insert_idx <= extra->uri_ranges.count);
|
xassert(insert_idx <= ranges->count);
|
||||||
|
|
||||||
if (replace) {
|
if (replace) {
|
||||||
grid_row_uri_range_destroy(&extra->uri_ranges.v[insert_idx]);
|
grid_row_range_destroy(&ranges->v[insert_idx], type);
|
||||||
extra->uri_ranges.v[insert_idx] = (struct row_uri_range){
|
ranges->v[insert_idx] = (struct row_range){
|
||||||
.start = col,
|
.start = col,
|
||||||
.end = col,
|
.end = col,
|
||||||
.id = id,
|
|
||||||
.uri = xstrdup(uri),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ROW_RANGE_URI:
|
||||||
|
ranges->v[insert_idx].uri.id = data->uri.id;
|
||||||
|
ranges->v[insert_idx].uri.uri = xstrdup(data->uri.uri);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROW_RANGE_CURLY:
|
||||||
|
ranges->v[insert_idx].curly = data->curly;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
uri_range_insert(extra, insert_idx, col, col, id, uri);
|
range_insert(ranges, insert_idx, col, col, type, data);
|
||||||
|
|
||||||
if (run_merge_pass) {
|
if (run_merge_pass) {
|
||||||
for (size_t i = 1; i < extra->uri_ranges.count; i++) {
|
for (size_t i = 1; i < ranges->count; i++) {
|
||||||
struct row_uri_range *r1 = &extra->uri_ranges.v[i - 1];
|
struct row_range *r1 = &ranges->v[i - 1];
|
||||||
struct row_uri_range *r2 = &extra->uri_ranges.v[i];
|
struct row_range *r2 = &ranges->v[i];
|
||||||
|
|
||||||
if (r1->id == r2->id && r1->end + 1 == r2->start) {
|
if (ranges_match(r1, r2, type) && r1->end + 1 == r2->start) {
|
||||||
r1->end = r2->end;
|
r1->end = r2->end;
|
||||||
uri_range_delete(extra, i);
|
range_delete(ranges, type, i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
void
|
||||||
verify_no_overlapping_uris(extra);
|
grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
|
||||||
verify_uris_are_sorted(extra);
|
{
|
||||||
|
ensure_row_has_extra_data(row);
|
||||||
|
|
||||||
|
grid_row_range_put(
|
||||||
|
&row->extra->uri_ranges, col,
|
||||||
|
&(union row_range_data){.uri = {.id = id, .uri = (char *)uri}},
|
||||||
|
ROW_RANGE_URI);
|
||||||
|
|
||||||
|
verify_no_overlapping_ranges(row->extra);
|
||||||
|
verify_ranges_are_sorted(row->extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grid_row_curly_range_put(struct row *row, int col, struct curly_range_data data)
|
||||||
|
{
|
||||||
|
ensure_row_has_extra_data(row);
|
||||||
|
|
||||||
|
grid_row_range_put(
|
||||||
|
&row->extra->curly_ranges, col,
|
||||||
|
&(union row_range_data){.curly = data},
|
||||||
|
ROW_RANGE_CURLY);
|
||||||
|
|
||||||
|
verify_no_overlapping_ranges(row->extra);
|
||||||
|
verify_ranges_are_sorted(row->extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNITTEST
|
UNITTEST
|
||||||
|
|
@ -1233,7 +1483,7 @@ UNITTEST
|
||||||
xassert(idx < row_data.uri_ranges.count); \
|
xassert(idx < row_data.uri_ranges.count); \
|
||||||
xassert(row_data.uri_ranges.v[idx].start == _start); \
|
xassert(row_data.uri_ranges.v[idx].start == _start); \
|
||||||
xassert(row_data.uri_ranges.v[idx].end == _end); \
|
xassert(row_data.uri_ranges.v[idx].end == _end); \
|
||||||
xassert(row_data.uri_ranges.v[idx].id == _id); \
|
xassert(row_data.uri_ranges.v[idx].uri.id == _id); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
grid_row_uri_range_put(&row, 0, "http://foo.bar", 123);
|
grid_row_uri_range_put(&row, 0, "http://foo.bar", 123);
|
||||||
|
|
@ -1288,17 +1538,15 @@ UNITTEST
|
||||||
#undef verify_range
|
#undef verify_range
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
grid_row_uri_range_erase(struct row *row, int start, int end)
|
grid_row_range_erase(struct row_ranges *ranges, enum row_range_type type,
|
||||||
|
int start, int end)
|
||||||
{
|
{
|
||||||
xassert(row->extra != NULL);
|
|
||||||
xassert(start <= end);
|
xassert(start <= end);
|
||||||
|
|
||||||
struct row_data *extra = row->extra;
|
|
||||||
|
|
||||||
/* Split up, or remove, URI ranges affected by the erase */
|
/* Split up, or remove, URI ranges affected by the erase */
|
||||||
for (ssize_t i = (ssize_t)extra->uri_ranges.count - 1; i >= 0; i--) {
|
for (int i = ranges->count - 1; i >= 0; i--) {
|
||||||
struct row_uri_range *old = &extra->uri_ranges.v[i];
|
struct row_range *old = &ranges->v[i];
|
||||||
|
|
||||||
if (old->end < start)
|
if (old->end < start)
|
||||||
return;
|
return;
|
||||||
|
|
@ -1308,17 +1556,23 @@ grid_row_uri_range_erase(struct row *row, int start, int end)
|
||||||
|
|
||||||
if (start <= old->start && end >= old->end) {
|
if (start <= old->start && end >= old->end) {
|
||||||
/* Erase range covers URI completely - remove it */
|
/* 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) {
|
else if (start > old->start && end < old->end) {
|
||||||
/* Erase range erases a part in the middle of the URI */
|
/*
|
||||||
uri_range_insert(
|
* Erase range erases a part in the middle of the URI
|
||||||
extra, i + 1, end + 1, old->end, old->id, old->uri);
|
*
|
||||||
|
* Must copy, since range_insert() may xrealloc() (thus
|
||||||
|
* causing 'old' to be invalid) before it dereferences
|
||||||
|
* old->data
|
||||||
|
*/
|
||||||
|
union row_range_data data = old->data;
|
||||||
|
range_insert(ranges, i + 1, end + 1, old->end, type, &data);
|
||||||
|
|
||||||
/* The insertion may xrealloc() the vector, making our
|
/* The insertion may xrealloc() the vector, making our
|
||||||
* 'old' pointer invalid */
|
* 'old' pointer invalid */
|
||||||
old = &extra->uri_ranges.v[i];
|
old = &ranges->v[i];
|
||||||
old->end = start - 1;
|
old->end = start - 1;
|
||||||
return; /* There can be no more URIs affected by the erase range */
|
return; /* There can be no more URIs affected by the erase range */
|
||||||
}
|
}
|
||||||
|
|
@ -1338,59 +1592,79 @@ 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
|
UNITTEST
|
||||||
{
|
{
|
||||||
struct row_data row_data = {.uri_ranges = {0}};
|
struct row_data row_data = {.uri_ranges = {0}};
|
||||||
struct row row = {.extra = &row_data};
|
struct row row = {.extra = &row_data};
|
||||||
|
const union row_range_data data = {
|
||||||
|
.uri = {
|
||||||
|
.id = 0,
|
||||||
|
.uri = (char *)"dummy",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* Try erasing a row without any URIs */
|
/* Try erasing a row without any URIs */
|
||||||
grid_row_uri_range_erase(&row, 0, 200);
|
grid_row_uri_range_erase(&row, 0, 200);
|
||||||
xassert(row_data.uri_ranges.count == 0);
|
xassert(row_data.uri_ranges.count == 0);
|
||||||
|
|
||||||
uri_range_append(&row_data, 1, 10, 0, "dummy");
|
range_append(&row_data.uri_ranges, 1, 10, ROW_RANGE_URI, &data);
|
||||||
uri_range_append(&row_data, 11, 20, 0, "dummy");
|
range_append(&row_data.uri_ranges, 11, 20, ROW_RANGE_URI, &data);
|
||||||
xassert(row_data.uri_ranges.count == 2);
|
xassert(row_data.uri_ranges.count == 2);
|
||||||
xassert(row_data.uri_ranges.v[1].start == 11);
|
xassert(row_data.uri_ranges.v[1].start == 11);
|
||||||
xassert(row_data.uri_ranges.v[1].end == 20);
|
xassert(row_data.uri_ranges.v[1].end == 20);
|
||||||
verify_no_overlapping_uris(&row_data);
|
verify_no_overlapping_ranges(&row_data);
|
||||||
verify_uris_are_sorted(&row_data);
|
verify_ranges_are_sorted(&row_data);
|
||||||
|
|
||||||
/* Erase both URis */
|
/* Erase both URis */
|
||||||
grid_row_uri_range_erase(&row, 1, 20);
|
grid_row_uri_range_erase(&row, 1, 20);
|
||||||
xassert(row_data.uri_ranges.count == 0);
|
xassert(row_data.uri_ranges.count == 0);
|
||||||
verify_no_overlapping_uris(&row_data);
|
verify_no_overlapping_ranges(&row_data);
|
||||||
verify_uris_are_sorted(&row_data);
|
verify_ranges_are_sorted(&row_data);
|
||||||
|
|
||||||
/* Two URIs, then erase second half of the first, first half of
|
/* Two URIs, then erase second half of the first, first half of
|
||||||
the second */
|
the second */
|
||||||
uri_range_append(&row_data, 1, 10, 0, "dummy");
|
range_append(&row_data.uri_ranges, 1, 10, ROW_RANGE_URI, &data);
|
||||||
uri_range_append(&row_data, 11, 20, 0, "dummy");
|
range_append(&row_data.uri_ranges, 11, 20, ROW_RANGE_URI, &data);
|
||||||
grid_row_uri_range_erase(&row, 5, 15);
|
grid_row_uri_range_erase(&row, 5, 15);
|
||||||
xassert(row_data.uri_ranges.count == 2);
|
xassert(row_data.uri_ranges.count == 2);
|
||||||
xassert(row_data.uri_ranges.v[0].start == 1);
|
xassert(row_data.uri_ranges.v[0].start == 1);
|
||||||
xassert(row_data.uri_ranges.v[0].end == 4);
|
xassert(row_data.uri_ranges.v[0].end == 4);
|
||||||
xassert(row_data.uri_ranges.v[1].start == 16);
|
xassert(row_data.uri_ranges.v[1].start == 16);
|
||||||
xassert(row_data.uri_ranges.v[1].end == 20);
|
xassert(row_data.uri_ranges.v[1].end == 20);
|
||||||
verify_no_overlapping_uris(&row_data);
|
verify_no_overlapping_ranges(&row_data);
|
||||||
verify_uris_are_sorted(&row_data);
|
verify_ranges_are_sorted(&row_data);
|
||||||
|
|
||||||
grid_row_uri_range_destroy(&row_data.uri_ranges.v[0]);
|
grid_row_range_destroy(&row_data.uri_ranges.v[0], ROW_RANGE_URI);
|
||||||
grid_row_uri_range_destroy(&row_data.uri_ranges.v[1]);
|
grid_row_range_destroy(&row_data.uri_ranges.v[1], ROW_RANGE_URI);
|
||||||
row_data.uri_ranges.count = 0;
|
row_data.uri_ranges.count = 0;
|
||||||
|
|
||||||
/* One URI, erase middle part of it */
|
/* One URI, erase middle part of it */
|
||||||
uri_range_append(&row_data, 1, 10, 0, "dummy");
|
range_append(&row_data.uri_ranges, 1, 10, ROW_RANGE_URI, &data);
|
||||||
grid_row_uri_range_erase(&row, 5, 6);
|
grid_row_uri_range_erase(&row, 5, 6);
|
||||||
xassert(row_data.uri_ranges.count == 2);
|
xassert(row_data.uri_ranges.count == 2);
|
||||||
xassert(row_data.uri_ranges.v[0].start == 1);
|
xassert(row_data.uri_ranges.v[0].start == 1);
|
||||||
xassert(row_data.uri_ranges.v[0].end == 4);
|
xassert(row_data.uri_ranges.v[0].end == 4);
|
||||||
xassert(row_data.uri_ranges.v[1].start == 7);
|
xassert(row_data.uri_ranges.v[1].start == 7);
|
||||||
xassert(row_data.uri_ranges.v[1].end == 10);
|
xassert(row_data.uri_ranges.v[1].end == 10);
|
||||||
verify_no_overlapping_uris(&row_data);
|
verify_no_overlapping_ranges(&row_data);
|
||||||
verify_uris_are_sorted(&row_data);
|
verify_ranges_are_sorted(&row_data);
|
||||||
|
|
||||||
grid_row_uri_range_destroy(&row_data.uri_ranges.v[0]);
|
grid_row_range_destroy(&row_data.uri_ranges.v[0], ROW_RANGE_URI);
|
||||||
grid_row_uri_range_destroy(&row_data.uri_ranges.v[1]);
|
grid_row_range_destroy(&row_data.uri_ranges.v[1], ROW_RANGE_URI);
|
||||||
row_data.uri_ranges.count = 0;
|
row_data.uri_ranges.count = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1410,13 +1684,12 @@ UNITTEST
|
||||||
free(row_data.uri_ranges.v);
|
free(row_data.uri_ranges.v);
|
||||||
row_data.uri_ranges.v = NULL;
|
row_data.uri_ranges.v = NULL;
|
||||||
row_data.uri_ranges.size = 0;
|
row_data.uri_ranges.size = 0;
|
||||||
uri_range_append(&row_data, 1, 10, 0, "dummy");
|
range_append(&row_data.uri_ranges, 1, 10, ROW_RANGE_URI, &data);
|
||||||
xassert(row_data.uri_ranges.size == 1);
|
xassert(row_data.uri_ranges.size == 1);
|
||||||
|
|
||||||
grid_row_uri_range_erase(&row, 5, 7);
|
grid_row_uri_range_erase(&row, 5, 7);
|
||||||
xassert(row_data.uri_ranges.count == 2);
|
xassert(row_data.uri_ranges.count == 2);
|
||||||
|
|
||||||
for (size_t i = 0; i < row_data.uri_ranges.count; i++)
|
grid_row_ranges_destroy(&row_data.uri_ranges, ROW_RANGE_URI);
|
||||||
grid_row_uri_range_destroy(&row_data.uri_ranges.v[i]);
|
|
||||||
free(row_data.uri_ranges.v);
|
free(row_data.uri_ranges.v);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
grid.h
35
grid.h
|
|
@ -88,10 +88,36 @@ void grid_row_uri_range_put(
|
||||||
struct row *row, int col, const char *uri, uint64_t id);
|
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_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
|
static inline void
|
||||||
grid_row_uri_range_destroy(struct row_uri_range *range)
|
grid_row_uri_range_destroy(struct row_range *range)
|
||||||
{
|
{
|
||||||
free(range->uri);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
grid_row_ranges_destroy(struct row_ranges *ranges, enum row_range_type type)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ranges->count; i++) {
|
||||||
|
grid_row_range_destroy(&ranges->v[i], type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
@ -102,9 +128,10 @@ grid_row_reset_extra(struct row *row)
|
||||||
if (likely(extra == NULL))
|
if (likely(extra == NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < extra->uri_ranges.count; i++)
|
grid_row_ranges_destroy(&extra->uri_ranges, ROW_RANGE_URI);
|
||||||
grid_row_uri_range_destroy(&extra->uri_ranges.v[i]);
|
grid_row_ranges_destroy(&extra->curly_ranges, ROW_RANGE_CURLY);
|
||||||
free(extra->uri_ranges.v);
|
free(extra->uri_ranges.v);
|
||||||
|
free(extra->curly_ranges.v);
|
||||||
|
|
||||||
free(extra);
|
free(extra);
|
||||||
row->extra = NULL;
|
row->extra = NULL;
|
||||||
|
|
|
||||||
223
render.c
223
render.c
|
|
@ -384,6 +384,161 @@ draw_underline(const struct terminal *term, pixman_image_t *pix,
|
||||||
x, y + y_ofs, cols * term->cell_width, thickness});
|
x, y + y_ofs, cols * term->cell_width, thickness});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_styled_underline(const struct terminal *term, pixman_image_t *pix,
|
||||||
|
const struct fcft_font *font,
|
||||||
|
const pixman_color_t *color,
|
||||||
|
enum curly_style style, int x, int y, int cols)
|
||||||
|
{
|
||||||
|
xassert(style != CURLY_NONE);
|
||||||
|
|
||||||
|
if (style == CURLY_SINGLE) {
|
||||||
|
draw_underline(term, pix, font, color, x, y, cols);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int thickness = term->conf->underline_thickness.px >= 0
|
||||||
|
? term_pt_or_px_as_pixels(
|
||||||
|
term, &term->conf->underline_thickness)
|
||||||
|
: font->underline.thickness;
|
||||||
|
|
||||||
|
int y_ofs;
|
||||||
|
|
||||||
|
/* Make sure the line isn't positioned below the cell */
|
||||||
|
switch (style) {
|
||||||
|
case CURLY_DOUBLE:
|
||||||
|
case CURLY_CURLY:
|
||||||
|
y_ofs = min(underline_offset(term, font),
|
||||||
|
term->cell_height - thickness * 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLY_DASHED:
|
||||||
|
case CURLY_DOTTED:
|
||||||
|
y_ofs = min(underline_offset(term, font),
|
||||||
|
term->cell_height - thickness);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLY_NONE:
|
||||||
|
case CURLY_SINGLE:
|
||||||
|
BUG("underline styles not supposed to be handled here");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int ceil_w = cols * term->cell_width;
|
||||||
|
|
||||||
|
switch (style) {
|
||||||
|
case CURLY_DOUBLE: {
|
||||||
|
const pixman_rectangle16_t rects[] = {
|
||||||
|
{x, y + y_ofs, ceil_w, thickness},
|
||||||
|
{x, y + y_ofs + thickness * 2, ceil_w, thickness}};
|
||||||
|
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, color, 2, rects);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CURLY_DASHED: {
|
||||||
|
const int ceil_w = cols * term->cell_width;
|
||||||
|
const int dash_w = ceil_w / 3 + (ceil_w % 3 > 0);
|
||||||
|
const pixman_rectangle16_t rects[] = {
|
||||||
|
{x, y + y_ofs, dash_w, thickness},
|
||||||
|
{x + dash_w * 2, y + y_ofs, dash_w, thickness},
|
||||||
|
};
|
||||||
|
pixman_image_fill_rectangles(
|
||||||
|
PIXMAN_OP_SRC, pix, color, 2, rects);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CURLY_DOTTED: {
|
||||||
|
/* Number of dots per cell */
|
||||||
|
int per_cell = (term->cell_width / thickness) / 2;
|
||||||
|
if (per_cell == 0)
|
||||||
|
per_cell = 1;
|
||||||
|
|
||||||
|
xassert(per_cell >= 1);
|
||||||
|
|
||||||
|
/* Spacing between dots; start with the same width as the dots
|
||||||
|
themselves, then widen them if necessary, to consume unused
|
||||||
|
pixels */
|
||||||
|
int spacing[per_cell];
|
||||||
|
for (int i = 0; i < per_cell; i++)
|
||||||
|
spacing[i] = thickness;
|
||||||
|
|
||||||
|
/* Pixels remaining at the end of the cell */
|
||||||
|
int remaining = term->cell_width - (per_cell * 2) * thickness;
|
||||||
|
|
||||||
|
/* Spread out the left-over pixels across the spacing between
|
||||||
|
the dots */
|
||||||
|
for (int i = 0; remaining > 0; i = (i + 1) % per_cell, remaining--)
|
||||||
|
spacing[i]++;
|
||||||
|
|
||||||
|
xassert(remaining <= 0);
|
||||||
|
|
||||||
|
pixman_rectangle16_t rects[per_cell];
|
||||||
|
int dot_x = x;
|
||||||
|
for (int i = 0; i < per_cell; i++) {
|
||||||
|
rects[i] = (pixman_rectangle16_t){
|
||||||
|
dot_x, y + y_ofs, thickness, thickness
|
||||||
|
};
|
||||||
|
|
||||||
|
dot_x += thickness + spacing[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, color, per_cell, rects);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CURLY_CURLY: {
|
||||||
|
const int top = y + y_ofs;
|
||||||
|
const int bot = top + thickness * 3;
|
||||||
|
const int half_x = x + ceil_w / 2.0, full_x = x + ceil_w;
|
||||||
|
|
||||||
|
const double bt_2 = (bot - top) * (bot - top);
|
||||||
|
const double th_2 = thickness * thickness;
|
||||||
|
const double hx_2 = ceil_w * ceil_w / 4.0;
|
||||||
|
const int th = round(sqrt(th_2 + (th_2 * bt_2 / hx_2)) / 2.);
|
||||||
|
|
||||||
|
#define I(x) pixman_int_to_fixed(x)
|
||||||
|
const pixman_trapezoid_t traps[] = {
|
||||||
|
#if 0 /* characters sit within the "dips" of the curlies */
|
||||||
|
{
|
||||||
|
I(top), I(bot),
|
||||||
|
{{I(x), I(top + th)}, {I(half_x), I(bot + th)}},
|
||||||
|
{{I(x), I(top - th)}, {I(half_x), I(bot - th)}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
I(top), I(bot),
|
||||||
|
{{I(half_x), I(bot - th)}, {I(full_x), I(top - th)}},
|
||||||
|
{{I(half_x), I(bot + th)}, {I(full_x), I(top + th)}},
|
||||||
|
}
|
||||||
|
#else /* characters sit on top of the curlies */
|
||||||
|
{
|
||||||
|
I(top), I(bot),
|
||||||
|
{{I(x), I(bot - th)}, {I(half_x), I(top - th)}},
|
||||||
|
{{I(x), I(bot + th)}, {I(half_x), I(top + th)}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
I(top), I(bot),
|
||||||
|
{{I(half_x), I(top + th)}, {I(full_x), I(bot + th)}},
|
||||||
|
{{I(half_x), I(top - th)}, {I(full_x), I(bot - th)}},
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
pixman_image_t *fill = pixman_image_create_solid_fill(color);
|
||||||
|
pixman_composite_trapezoids(
|
||||||
|
PIXMAN_OP_OVER, fill, pix, PIXMAN_a8, 0, 0, 0, 0,
|
||||||
|
sizeof(traps) / sizeof(traps[0]), traps);
|
||||||
|
|
||||||
|
pixman_image_unref(fill);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CURLY_NONE:
|
||||||
|
case CURLY_SINGLE:
|
||||||
|
BUG("underline styles not supposed to be handled here");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_strikeout(const struct terminal *term, pixman_image_t *pix,
|
draw_strikeout(const struct terminal *term, pixman_image_t *pix,
|
||||||
const struct fcft_font *font,
|
const struct fcft_font *font,
|
||||||
|
|
@ -847,8 +1002,49 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
||||||
pixman_image_unref(clr_pix);
|
pixman_image_unref(clr_pix);
|
||||||
|
|
||||||
/* Underline */
|
/* Underline */
|
||||||
if (cell->attrs.underline)
|
if (cell->attrs.underline) {
|
||||||
draw_underline(term, pix, font, &fg, x, y, cell_cols);
|
pixman_color_t underline_color = fg;
|
||||||
|
enum curly_style underline_style = CURLY_SINGLE;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
break;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
underline_style = range->curly.style;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_styled_underline(
|
||||||
|
term, pix, font, &underline_color, underline_style, x, y, cell_cols);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (cell->attrs.strikethrough)
|
if (cell->attrs.strikethrough)
|
||||||
draw_strikeout(term, pix, font, &fg, x, y, cell_cols);
|
draw_strikeout(term, pix, font, &fg, x, y, cell_cols);
|
||||||
|
|
@ -4243,6 +4439,29 @@ render_resize(struct terminal *term, int width, int height, uint8_t opts)
|
||||||
memcpy(g.rows[i]->cells,
|
memcpy(g.rows[i]->cells,
|
||||||
orig->rows[j]->cells,
|
orig->rows[j]->cells,
|
||||||
g.num_cols * sizeof(g.rows[i]->cells[0]));
|
g.num_cols * sizeof(g.rows[i]->cells[0]));
|
||||||
|
|
||||||
|
if (orig->rows[j]->extra == NULL ||
|
||||||
|
orig->rows[j]->extra->curly_ranges.count == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy undercurly ranges
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct row_ranges *curly_src = &orig->rows[j]->extra->curly_ranges;
|
||||||
|
|
||||||
|
const int count = curly_src->count;
|
||||||
|
g.rows[i]->extra = xcalloc(1, sizeof(*g.rows[i]->extra));
|
||||||
|
g.rows[i]->extra->curly_ranges.v = xmalloc(
|
||||||
|
count * sizeof(g.rows[i]->extra->curly_ranges.v[0]));
|
||||||
|
|
||||||
|
struct row_ranges *curly_dst = &g.rows[i]->extra->curly_ranges;
|
||||||
|
curly_dst->count = curly_dst->size = count;
|
||||||
|
|
||||||
|
for (int k = 0; k < count; k++)
|
||||||
|
curly_dst->v[k] = curly_src->v[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
term->normal = g;
|
term->normal = g;
|
||||||
|
|
|
||||||
11
sixel.c
11
sixel.c
|
|
@ -420,6 +420,8 @@ sixel_scroll_up(struct terminal *term, int rows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.sixels =
|
||||||
|
tll_length(term->grid->sixel_images) > 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
verify_sixels(term);
|
verify_sixels(term);
|
||||||
}
|
}
|
||||||
|
|
@ -444,6 +446,8 @@ sixel_scroll_down(struct terminal *term, int rows)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.sixels =
|
||||||
|
tll_length(term->grid->sixel_images) > 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
verify_sixels(term);
|
verify_sixels(term);
|
||||||
}
|
}
|
||||||
|
|
@ -852,6 +856,8 @@ sixel_overwrite_by_rectangle(
|
||||||
} else
|
} else
|
||||||
_sixel_overwrite_by_rectangle(term, start, col, height, width, NULL, NULL);
|
_sixel_overwrite_by_rectangle(term, start, col, height, width, NULL, NULL);
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.sixels =
|
||||||
|
tll_length(term->grid->sixel_images) > 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -908,6 +914,8 @@ sixel_overwrite_by_row(struct terminal *term, int _row, int col, int width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.sixels =
|
||||||
|
tll_length(term->grid->sixel_images) > 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1387,6 +1395,9 @@ sixel_unhook(struct terminal *term)
|
||||||
LOG_DBG("you now have %zu sixels in current grid",
|
LOG_DBG("you now have %zu sixels in current grid",
|
||||||
tll_length(term->grid->sixel_images));
|
tll_length(term->grid->sixel_images));
|
||||||
|
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.sixels =
|
||||||
|
tll_length(term->grid->sixel_images) > 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
60
terminal.c
60
terminal.c
|
|
@ -1940,8 +1940,10 @@ erase_cell_range(struct terminal *term, struct row *row, int start, int end)
|
||||||
} else
|
} else
|
||||||
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
|
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_uri_range_erase(row, start, end);
|
||||||
|
grid_row_curly_range_erase(row, start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
@ -2021,6 +2023,7 @@ term_reset(struct terminal *term, bool hard)
|
||||||
term_ime_enable(term);
|
term_ime_enable(term);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.value = 0;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
|
|
||||||
if (!hard)
|
if (!hard)
|
||||||
|
|
@ -3019,6 +3022,9 @@ term_restore_cursor(struct terminal *term, const struct cursor *cursor)
|
||||||
|
|
||||||
term->vt.attrs = term->vt.saved_attrs;
|
term->vt.attrs = term->vt.saved_attrs;
|
||||||
term->charsets = term->saved_charsets;
|
term->charsets = term->saved_charsets;
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3621,7 +3627,8 @@ term_fill(struct terminal *term, int r, int c, uint8_t data, size_t count,
|
||||||
cell->wc = data;
|
cell->wc = data;
|
||||||
cell->attrs = attrs;
|
cell->attrs = attrs;
|
||||||
|
|
||||||
if (unlikely(term->vt.osc8.uri != NULL)) {
|
/* TODO: why do we print the URI here, and then erase it below? */
|
||||||
|
if (unlikely(use_sgr_attrs && term->vt.osc8.uri != NULL)) {
|
||||||
grid_row_uri_range_put(row, c, term->vt.osc8.uri, term->vt.osc8.id);
|
grid_row_uri_range_put(row, c, term->vt.osc8.uri, term->vt.osc8.id);
|
||||||
|
|
||||||
switch (term->conf->url.osc8_underline) {
|
switch (term->conf->url.osc8_underline) {
|
||||||
|
|
@ -3633,10 +3640,27 @@ term_fill(struct terminal *term, int r, int c, uint8_t data, size_t count,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(use_sgr_attrs &&
|
||||||
|
(term->vt.curly.style > CURLY_SINGLE ||
|
||||||
|
term->vt.curly.color_src != COLOR_DEFAULT)))
|
||||||
|
{
|
||||||
|
grid_row_curly_range_put(row, c, term->vt.curly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(row->extra != NULL))
|
if (unlikely(row->extra != NULL)) {
|
||||||
grid_row_uri_range_erase(row, c, c + count - 1);
|
if (likely(term->vt.osc8.uri != NULL))
|
||||||
|
grid_row_uri_range_erase(row, c, c + count - 1);
|
||||||
|
|
||||||
|
if (likely(term->vt.curly.style <= CURLY_SINGLE &&
|
||||||
|
term->vt.curly.color_src == COLOR_DEFAULT))
|
||||||
|
{
|
||||||
|
/* No extended/styled underlines active, so erase any such
|
||||||
|
attributes at the target columns */
|
||||||
|
grid_row_curly_range_erase(row, c, c + count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3706,6 +3730,13 @@ term_print(struct terminal *term, char32_t wc, int width)
|
||||||
} else if (row->extra != NULL)
|
} else if (row->extra != NULL)
|
||||||
grid_row_uri_range_erase(row, col, col + width - 1);
|
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 */
|
/* Advance cursor the 'additional' columns while dirty:ing the cells */
|
||||||
for (int i = 1; i < width && (col + 1) < term->cols; i++) {
|
for (int i = 1; i < width && (col + 1) < term->cols; i++) {
|
||||||
col++;
|
col++;
|
||||||
|
|
@ -3763,8 +3794,10 @@ ascii_printer_fast(struct terminal *term, char32_t wc)
|
||||||
|
|
||||||
grid->cursor.point.col = col;
|
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_uri_range_erase(row, uri_start, uri_start);
|
||||||
|
grid_row_curly_range_erase(row, uri_start, uri_start);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -3772,19 +3805,21 @@ ascii_printer_single_shift(struct terminal *term, char32_t wc)
|
||||||
{
|
{
|
||||||
ascii_printer_generic(term, wc);
|
ascii_printer_generic(term, wc);
|
||||||
term->charsets.selected = term->charsets.saved;
|
term->charsets.selected = term->charsets.saved;
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
term_update_ascii_printer(struct terminal *term)
|
term_update_ascii_printer(struct terminal *term)
|
||||||
{
|
{
|
||||||
|
_Static_assert(sizeof(term->bits_affecting_ascii_printer) == sizeof(uint8_t), "bad size");
|
||||||
|
|
||||||
void (*new_printer)(struct terminal *term, char32_t wc) =
|
void (*new_printer)(struct terminal *term, char32_t wc) =
|
||||||
unlikely(tll_length(term->grid->sixel_images) > 0 ||
|
unlikely(term->bits_affecting_ascii_printer.value != 0)
|
||||||
term->vt.osc8.uri != NULL ||
|
? &ascii_printer_generic
|
||||||
term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC ||
|
: &ascii_printer_fast;
|
||||||
term->insert_mode)
|
|
||||||
? &ascii_printer_generic
|
|
||||||
: &ascii_printer_fast;
|
|
||||||
|
|
||||||
#if defined(_DEBUG) && LOG_ENABLE_DBG
|
#if defined(_DEBUG) && LOG_ENABLE_DBG
|
||||||
if (term->ascii_printer != new_printer) {
|
if (term->ascii_printer != new_printer) {
|
||||||
|
|
@ -4077,6 +4112,8 @@ term_osc8_open(struct terminal *term, uint64_t id, const char *uri)
|
||||||
|
|
||||||
term->vt.osc8.id = id;
|
term->vt.osc8.id = id;
|
||||||
term->vt.osc8.uri = xstrdup(uri);
|
term->vt.osc8.uri = xstrdup(uri);
|
||||||
|
|
||||||
|
term->bits_affecting_ascii_printer.osc8 = true;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4086,6 +4123,7 @@ term_osc8_close(struct terminal *term)
|
||||||
free(term->vt.osc8.uri);
|
free(term->vt.osc8.uri);
|
||||||
term->vt.osc8.uri = NULL;
|
term->vt.osc8.uri = NULL;
|
||||||
term->vt.osc8.id = 0;
|
term->vt.osc8.id = 0;
|
||||||
|
term->bits_affecting_ascii_printer.osc8 = false;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
68
terminal.h
68
terminal.h
|
|
@ -99,19 +99,58 @@ struct damage {
|
||||||
uint16_t lines;
|
uint16_t lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct row_uri_range {
|
struct uri_range_data {
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
char *uri;
|
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 {
|
||||||
|
/* This is just an expanded union row_range_data, but
|
||||||
|
* anonymous, so that we don't have to write range->u.uri.id,
|
||||||
|
* but can instead do range->uri.id */
|
||||||
|
union {
|
||||||
|
struct uri_range_data uri;
|
||||||
|
struct curly_range_data curly;
|
||||||
|
};
|
||||||
|
union row_range_data data;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct row_ranges {
|
||||||
|
struct row_range *v;
|
||||||
|
int size;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum row_range_type {ROW_RANGE_URI, ROW_RANGE_CURLY};
|
||||||
|
|
||||||
struct row_data {
|
struct row_data {
|
||||||
struct {
|
struct row_ranges uri_ranges;
|
||||||
struct row_uri_range *v;
|
struct row_ranges curly_ranges;
|
||||||
uint32_t size;
|
|
||||||
uint32_t count;
|
|
||||||
} uri_ranges;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct row {
|
struct row {
|
||||||
|
|
@ -260,6 +299,8 @@ struct vt {
|
||||||
char *uri;
|
char *uri;
|
||||||
} osc8;
|
} osc8;
|
||||||
|
|
||||||
|
struct curly_range_data curly;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
@ -358,6 +399,17 @@ struct terminal {
|
||||||
const struct config *conf;
|
const struct config *conf;
|
||||||
|
|
||||||
void (*ascii_printer)(struct terminal *term, char32_t c);
|
void (*ascii_printer)(struct terminal *term, char32_t c);
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
bool sixels:1;
|
||||||
|
bool osc8:1;
|
||||||
|
bool curly_style:1;
|
||||||
|
bool curly_color:1;
|
||||||
|
bool insert_mode:1;
|
||||||
|
bool charset:1;
|
||||||
|
};
|
||||||
|
uint8_t value;
|
||||||
|
} bits_affecting_ascii_printer;
|
||||||
|
|
||||||
pid_t slave;
|
pid_t slave;
|
||||||
int ptmx;
|
int ptmx;
|
||||||
|
|
|
||||||
|
|
@ -509,7 +509,7 @@ osc8_uris(const struct terminal *term, enum url_action action, url_list_t *urls)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (size_t i = 0; i < extra->uri_ranges.count; i++) {
|
for (size_t i = 0; i < extra->uri_ranges.count; i++) {
|
||||||
const struct row_uri_range *range = &extra->uri_ranges.v[i];
|
const struct row_range *range = &extra->uri_ranges.v[i];
|
||||||
|
|
||||||
struct coord start = {
|
struct coord start = {
|
||||||
.col = range->start,
|
.col = range->start,
|
||||||
|
|
@ -522,8 +522,8 @@ osc8_uris(const struct terminal *term, enum url_action action, url_list_t *urls)
|
||||||
tll_push_back(
|
tll_push_back(
|
||||||
*urls,
|
*urls,
|
||||||
((struct url){
|
((struct url){
|
||||||
.id = range->id,
|
.id = range->uri.id,
|
||||||
.url = xstrdup(range->uri),
|
.url = xstrdup(range->uri.uri),
|
||||||
.range = {
|
.range = {
|
||||||
.start = start,
|
.start = start,
|
||||||
.end = end,
|
.end = end,
|
||||||
|
|
|
||||||
12
vt.c
12
vt.c
|
|
@ -243,12 +243,16 @@ action_execute(struct terminal *term, uint8_t c)
|
||||||
case '\x0e':
|
case '\x0e':
|
||||||
/* SO - shift out */
|
/* SO - shift out */
|
||||||
term->charsets.selected = G1;
|
term->charsets.selected = G1;
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '\x0f':
|
case '\x0f':
|
||||||
/* SI - shift in */
|
/* SI - shift in */
|
||||||
term->charsets.selected = G0;
|
term->charsets.selected = G0;
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -482,12 +486,16 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
case 'n':
|
case 'n':
|
||||||
/* LS2 - Locking Shift 2 */
|
/* LS2 - Locking Shift 2 */
|
||||||
term->charsets.selected = G2;
|
term->charsets.selected = G2;
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
/* LS3 - Locking Shift 3 */
|
/* LS3 - Locking Shift 3 */
|
||||||
term->charsets.selected = G3;
|
term->charsets.selected = G3;
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -546,6 +554,8 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
size_t idx = term->vt.private - '(';
|
size_t idx = term->vt.private - '(';
|
||||||
xassert(idx <= G3);
|
xassert(idx <= G3);
|
||||||
term->charsets.set[idx] = CHARSET_GRAPHIC;
|
term->charsets.set[idx] = CHARSET_GRAPHIC;
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -554,6 +564,8 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
||||||
size_t idx = term->vt.private - '(';
|
size_t idx = term->vt.private - '(';
|
||||||
xassert(idx <= G3);
|
xassert(idx <= G3);
|
||||||
term->charsets.set[idx] = CHARSET_ASCII;
|
term->charsets.set[idx] = CHARSET_ASCII;
|
||||||
|
term->bits_affecting_ascii_printer.charset =
|
||||||
|
term->charsets.set[term->charsets.selected] != CHARSET_ASCII;
|
||||||
term_update_ascii_printer(term);
|
term_update_ascii_printer(term);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue