From 33106514db44cfbd1aa1c6364cb9d7e0bc0a5a98 Mon Sep 17 00:00:00 2001 From: Andrew Savchenko Date: Fri, 2 Jan 2026 13:37:26 +1100 Subject: [PATCH] main: Support overline, SGR 53/55 Similar to the underline, incl. the *-thickness and *-offset options. --- config.c | 8 ++++++++ config.h | 3 +++ csi.c | 3 +++ doc/foot-ctlseqs.7.scd | 4 ++++ doc/foot.ini.5.scd | 23 +++++++++++++++++++++++ render.c | 24 ++++++++++++++++++++++++ terminal.h | 7 +++++-- 7 files changed, 70 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index 14e836c1..a0f2b27a 100644 --- a/config.c +++ b/config.c @@ -1078,6 +1078,12 @@ parse_section_main(struct context *ctx) else if (streq(key, "strikeout-thickness")) return value_to_pt_or_px(ctx, &conf->strikeout_thickness); + else if (streq(key, "overline-thickness")) + return value_to_pt_or_px(ctx, &conf->overline_thickness); + + else if (streq(key, "overline-offset")) + return value_to_pt_or_px(ctx, &conf->overline_offset); + else if (streq(key, "dpi-aware")) return value_to_bool(ctx, &conf->dpi_aware); @@ -3476,6 +3482,8 @@ config_load(struct config *conf, const char *conf_path, .box_drawings_uses_font_glyphs = false, .underline_thickness = {.pt = 0., .px = -1}, .strikeout_thickness = {.pt = 0., .px = -1}, + .overline_thickness = {.pt = 0., .px = -1}, + .overline_offset = {.pt = 0., .px = -1}, .dpi_aware = false, .gamma_correct = false, .uppercase_regex_insert = true, diff --git a/config.h b/config.h index 9ca47753..a04944cb 100644 --- a/config.h +++ b/config.h @@ -273,6 +273,9 @@ struct config { struct pt_or_px strikeout_thickness; + struct pt_or_px overline_thickness; + struct pt_or_px overline_offset; + bool box_drawings_uses_font_glyphs; bool can_shape_grapheme; diff --git a/csi.c b/csi.c index 87af215e..47bfc364 100644 --- a/csi.c +++ b/csi.c @@ -150,6 +150,9 @@ csi_sgr(struct terminal *term) case 28: term->vt.attrs.conceal = false; break; case 29: term->vt.attrs.strikethrough = false; break; + case 53: term->vt.attrs.overline = true; break; + case 55: term->vt.attrs.overline = false; break; + /* Regular foreground colors */ case 30: case 31: diff --git a/doc/foot-ctlseqs.7.scd b/doc/foot-ctlseqs.7.scd index 40906ebf..b4e1e327 100644 --- a/doc/foot-ctlseqs.7.scd +++ b/doc/foot-ctlseqs.7.scd @@ -175,6 +175,10 @@ m*. : Disable conceal | 29 : Disable crossed-out +| 53 +: Overline +| 55 +: Disable overline | 30-37 : Select foreground color (using *regularN* in *foot.ini*(5)) | 38 diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 8bff9629..53824fbf 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -198,6 +198,29 @@ empty string to be set, but it must be quoted: *KEY=""*) Default: _unset_ +*overline-thickness* + Use a custom thickness (height) for overlines. The thickness is, by + default, in _points_. + + To specify a thickness in _pixels_, append *px*: + *overline-thickness=1px*. + + If left unset (the default), the font's underline thickness is used. + + Default: _unset_ + +*overline-offset* + Vertical offset of the overline from the top of the cell. The offset is, + by default, in _points_. + + To specify an offset in _pixels_, append *px*: + *overline-offset=2px*. + + If left unset (the default), the overline is drawn at the absolute top + of the cell (offset = 0). + + Default: _unset_ (0) + *gamma-correct-blending* Boolean. When enabled, foot will do gamma-correct blending in linear color space. This is how font glyphs are supposed to be diff --git a/render.c b/render.c index ac8ece37..a8f25629 100644 --- a/render.c +++ b/render.c @@ -598,6 +598,27 @@ draw_strikeout(const struct terminal *term, pixman_image_t *pix, cols * term->cell_width, thickness}); } +static void +draw_overline(const struct terminal *term, pixman_image_t *pix, + const struct fcft_font *font, + const pixman_color_t *color, int x, int y, int cols) +{ + const int thickness = term->conf->overline_thickness.px >= 0 + ? term_pt_or_px_as_pixels( + term, &term->conf->overline_thickness) + : font->underline.thickness; + + const int offset = term->conf->overline_offset.px >= 0 + ? term_pt_or_px_as_pixels( + term, &term->conf->overline_offset) + : 0; + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, pix, color, + 1, &(pixman_rectangle16_t){ + x, y + offset, cols * term->cell_width, thickness}); +} + static void cursor_colors_for_cell(const struct terminal *term, const struct cell *cell, const pixman_color_t *fg, const pixman_color_t *bg, @@ -1173,6 +1194,9 @@ render_cell(struct terminal *term, pixman_image_t *pix, if (cell->attrs.strikethrough) draw_strikeout(term, pix, font, &fg, x, y, cell_cols); + if (cell->attrs.overline) + draw_overline(term, pix, font, &fg, x, y, cell_cols); + if (unlikely(cell->attrs.url)) { pixman_color_t url_color = color_hex_to_pixman( term->conf->colors_dark.use_custom.url diff --git a/terminal.h b/terminal.h index fe39341d..397be48a 100644 --- a/terminal.h +++ b/terminal.h @@ -57,8 +57,11 @@ struct attributes { bool selected:1; bool url:1; uint32_t bg:24; + + bool overline:1; + uint32_t reserved:31; /* Future attributes? */ }; -static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large"); +static_assert(sizeof(struct attributes) == 12, "VT attribute struct size mismatch"); /* Last valid Unicode code point is 0x0010FFFFul */ #define CELL_COMB_CHARS_LO 0x00200000ul @@ -69,7 +72,7 @@ struct cell { char32_t wc; struct attributes attrs; }; -static_assert(sizeof(struct cell) == 12, "bad size"); +static_assert(sizeof(struct cell) == 16, "bad size"); struct scroll_region { int start;