mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-26 06:46:45 -04:00
vt: underline colors and style from kitty
This commit is contained in:
parent
642f9910c2
commit
2e6bc3c61a
5 changed files with 202 additions and 3 deletions
46
csi.c
46
csi.c
|
|
@ -88,17 +88,44 @@ 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: {
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
const struct vt_subparams p = term->vt.params.v[i].sub;
|
||||
struct attributes *attr = &term->vt.attrs;
|
||||
if (p.idx == 0) {
|
||||
attr->ul_style = UNDERLINE_STRAIGHT;
|
||||
break;
|
||||
}
|
||||
switch (p.value[0]) {
|
||||
case 0: attr->ul_style = UNDERLINE_NONE; break;
|
||||
case 1: attr->ul_style = UNDERLINE_STRAIGHT; break;
|
||||
case 2: attr->ul_style = UNDERLINE_DOUBLE; break;
|
||||
case 3: attr->ul_style = UNDERLINE_CURLY; break;
|
||||
case 4: attr->ul_style = UNDERLINE_DOTTED; break;
|
||||
case 5: attr->ul_style = UNDERLINE_DASHED; break;
|
||||
}
|
||||
#else
|
||||
term->vt.attrs.underline = true;
|
||||
#endif
|
||||
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;
|
||||
case 8: term->vt.attrs.conceal = true; break;
|
||||
case 9: term->vt.attrs.strikethrough = true; break;
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
case 21: term->vt.attrs.ul_style = UNDERLINE_DOUBLE; break;
|
||||
#else
|
||||
case 21: break; /* double-underline, not implemented */
|
||||
#endif
|
||||
case 22: term->vt.attrs.bold = term->vt.attrs.dim = false; break;
|
||||
case 23: term->vt.attrs.italic = false; break;
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
case 24: term->vt.attrs.ul_style = UNDERLINE_NONE; break;
|
||||
#else
|
||||
case 24: term->vt.attrs.underline = false; break;
|
||||
#endif
|
||||
case 25: term->vt.attrs.blink = false; break;
|
||||
case 26: break; /* rapid blink, ignored */
|
||||
case 27: term->vt.attrs.reverse = false; break;
|
||||
|
|
@ -119,6 +146,9 @@ csi_sgr(struct terminal *term)
|
|||
break;
|
||||
|
||||
case 38:
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
case 58:
|
||||
#endif
|
||||
case 48: {
|
||||
uint32_t color;
|
||||
enum color_source src;
|
||||
|
|
@ -197,18 +227,30 @@ csi_sgr(struct terminal *term)
|
|||
if (param == 38) {
|
||||
term->vt.attrs.fg_src = src;
|
||||
term->vt.attrs.fg = color;
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
} else if (param == 58) {
|
||||
term->vt.attrs.ul_src = src;
|
||||
term->vt.attrs.ul = color;
|
||||
#endif
|
||||
} else {
|
||||
xassert(param == 48);
|
||||
term->vt.attrs.bg_src = src;
|
||||
term->vt.attrs.bg = color;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 39:
|
||||
term->vt.attrs.fg_src = COLOR_DEFAULT;
|
||||
break;
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
case 59:
|
||||
term->vt.attrs.ul_src = COLOR_DEFAULT;
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Regular background colors */
|
||||
case 40:
|
||||
case 41:
|
||||
|
|
|
|||
|
|
@ -76,7 +76,10 @@ add_project_arguments(
|
|||
cc.get_supported_arguments(
|
||||
['-pedantic',
|
||||
'-fstrict-aliasing',
|
||||
'-Wstrict-aliasing']),
|
||||
'-Wstrict-aliasing']) +
|
||||
(get_option('ext-underline')
|
||||
? ['-DFOOT_EXT_UNDERLINE=1']
|
||||
: ['-DFOOT_EXT_UNDERLINE=0']),
|
||||
language: 'c',
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,3 +27,6 @@ option('utmp-backend', type: 'combo', value: 'auto', choices: ['none', 'libutemp
|
|||
description: 'Which utmp logging backend to use. This affects how (with what arguments) the utmp helper binary (see \'utmp-default-helper-path\')is called. Default: auto (linux=libutempter, freebsd=ulog, others=none)')
|
||||
option('utmp-default-helper-path', type: 'string', value: 'auto',
|
||||
description: 'Default path to the utmp helper binary. Default: auto-detect')
|
||||
|
||||
option('ext-underline', type: 'boolean', value: true,
|
||||
description: 'Enable underline styles & colors from xterm-kitty')
|
||||
|
|
|
|||
125
render.c
125
render.c
|
|
@ -384,6 +384,99 @@ draw_underline(const struct terminal *term, pixman_image_t *pix,
|
|||
x, y + y_ofs, cols * term->cell_width, thickness});
|
||||
}
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
static void
|
||||
draw_ext_underline(const struct terminal *term, pixman_image_t *pix,
|
||||
const struct fcft_font *font,
|
||||
const pixman_color_t *color,
|
||||
const enum underline_style style,
|
||||
int x, int y, int cols)
|
||||
{
|
||||
if (style == UNDERLINE_NONE)
|
||||
return;
|
||||
const int thickness = font->underline.thickness;
|
||||
|
||||
int y_ofs;
|
||||
/* Make sure the line isn't positioned below the cell */
|
||||
switch (style) {
|
||||
case UNDERLINE_DOUBLE:
|
||||
y_ofs = min(underline_offset(term, font),
|
||||
term->cell_height - thickness * 3);
|
||||
break;
|
||||
default:
|
||||
y_ofs = min(underline_offset(term, font),
|
||||
term->cell_height - thickness);
|
||||
break;
|
||||
}
|
||||
|
||||
const int ceil_w = cols * term->cell_width;
|
||||
switch (style) {
|
||||
case UNDERLINE_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 UNDERLINE_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 UNDERLINE_DOTTED: {
|
||||
const int ceil_w = cols * term->cell_width;
|
||||
const int nrects = min(ceil_w / thickness / 2, 16);
|
||||
pixman_rectangle16_t rects[16] = {0};
|
||||
for (int i = 0; i < nrects; i++) {
|
||||
rects[i] = (pixman_rectangle16_t){
|
||||
x + i * thickness * 2, y + y_ofs, thickness, thickness};
|
||||
}
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_SRC, pix, color, nrects, rects);
|
||||
break;
|
||||
}
|
||||
case UNDERLINE_CURLY: {
|
||||
#define I(x) pixman_int_to_fixed(x)
|
||||
const int top = y + y_ofs;
|
||||
const int bot = top + thickness * 3;
|
||||
const int th = thickness;
|
||||
const int half_x = x + ceil_w / 2, full_x = x + ceil_w;
|
||||
const pixman_trapezoid_t traps[] = {
|
||||
{
|
||||
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)}},
|
||||
}};
|
||||
// TODO: reuse the fill across all cells
|
||||
pixman_image_t *fill = pixman_image_create_solid_fill(color);
|
||||
pixman_composite_trapezoids(
|
||||
PIXMAN_OP_OVER, fill, pix, PIXMAN_a8, 0, 0, 0, 0, 2, traps);
|
||||
pixman_image_unref(fill);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const pixman_rectangle16_t rects[] = {
|
||||
{x, y + y_ofs, ceil_w, thickness}};
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_SRC, pix, color, 1, rects);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
draw_strikeout(const struct terminal *term, pixman_image_t *pix,
|
||||
const struct fcft_font *font,
|
||||
|
|
@ -478,12 +571,18 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
|
||||
uint32_t _fg = 0;
|
||||
uint32_t _bg = 0;
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
uint32_t _ul = 0;
|
||||
#endif
|
||||
|
||||
uint16_t alpha = 0xffff;
|
||||
|
||||
if (is_selected && term->colors.use_custom_selection) {
|
||||
_fg = term->colors.selection_fg;
|
||||
_bg = term->colors.selection_bg;
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
_ul = _fg;
|
||||
#endif
|
||||
} else {
|
||||
/* Use cell specific color, if set, otherwise the default colors (possible reversed) */
|
||||
switch (cell->attrs.fg_src) {
|
||||
|
|
@ -518,6 +617,24 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
break;
|
||||
}
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
switch (cell->attrs.ul_src) {
|
||||
case COLOR_RGB:
|
||||
_ul = cell->attrs.ul;
|
||||
break;
|
||||
|
||||
case COLOR_BASE16:
|
||||
case COLOR_BASE256:
|
||||
xassert(cell->attrs.ul < ALEN(term->colors.table));
|
||||
_ul = term->colors.table[cell->attrs.bg];
|
||||
break;
|
||||
|
||||
case COLOR_DEFAULT:
|
||||
_ul = _fg;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cell->attrs.reverse ^ is_selected) {
|
||||
uint32_t swap = _fg;
|
||||
_fg = _bg;
|
||||
|
|
@ -581,6 +698,9 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
|
||||
pixman_color_t fg = color_hex_to_pixman(_fg);
|
||||
pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, alpha);
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
pixman_color_t ul = color_hex_to_pixman(_ul);
|
||||
#endif
|
||||
|
||||
struct fcft_font *font = attrs_to_font(term, &cell->attrs);
|
||||
const struct composed *composed = NULL;
|
||||
|
|
@ -834,8 +954,13 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_region32_t *damag
|
|||
pixman_image_unref(clr_pix);
|
||||
|
||||
/* Underline */
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
draw_ext_underline(term, pix, font, &ul, cell->attrs.ul_style,
|
||||
x, y, cell_cols);
|
||||
#else
|
||||
if (cell->attrs.underline)
|
||||
draw_underline(term, pix, font, &fg, x, y, cell_cols);
|
||||
#endif
|
||||
|
||||
if (cell->attrs.strikethrough)
|
||||
draw_strikeout(term, pix, font, &fg, x, y, cell_cols);
|
||||
|
|
|
|||
26
terminal.h
26
terminal.h
|
|
@ -31,6 +31,17 @@ enum color_source {
|
|||
COLOR_RGB,
|
||||
};
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
enum underline_style {
|
||||
UNDERLINE_NONE,
|
||||
UNDERLINE_STRAIGHT,
|
||||
UNDERLINE_CURLY,
|
||||
UNDERLINE_DOUBLE,
|
||||
UNDERLINE_DASHED,
|
||||
UNDERLINE_DOTTED,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note: we want the cells to be as small as possible. Larger cells
|
||||
* means fewer scrollback lines (or performance drops due to cache
|
||||
|
|
@ -56,8 +67,19 @@ struct attributes {
|
|||
bool selected:1;
|
||||
bool url:1;
|
||||
uint32_t bg:24;
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
enum underline_style ul_style:4;
|
||||
enum color_source ul_src:4;
|
||||
uint32_t ul:24;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
static_assert(sizeof(struct attributes) == 12, "VT attribute struct too large");
|
||||
#else
|
||||
static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large");
|
||||
#endif
|
||||
|
||||
/* Last valid Unicode code point is 0x0010FFFFul */
|
||||
#define CELL_COMB_CHARS_LO 0x00200000ul
|
||||
|
|
@ -68,7 +90,11 @@ struct cell {
|
|||
char32_t wc;
|
||||
struct attributes attrs;
|
||||
};
|
||||
#if FOOT_EXT_UNDERLINE
|
||||
static_assert(sizeof(struct cell) == 16, "bad size");
|
||||
#else
|
||||
static_assert(sizeof(struct cell) == 12, "bad size");
|
||||
#endif
|
||||
|
||||
struct scroll_region {
|
||||
int start;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue