From 2c454a71f14da912f5623336b93ec8f48f2d1cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 6 Apr 2026 15:47:26 +0200 Subject: [PATCH] config: add url.style=none|single|double|curly|dotted|dashed This option allows you to configure which underline style to use with URLs. The default is dotted. Since before this patch, URL underlines were always plain underlines, this means the default URL underline style has changed, from single to dotted. Closes #2302 --- CHANGELOG.md | 13 +++++++++++++ config.c | 9 +++++++++ config.h | 10 ++++++++++ doc/foot.ini.5.scd | 8 ++++++++ foot.ini | 1 + render.c | 7 +++++-- terminal.h | 9 --------- tests/test-config.c | 4 ++++ 8 files changed, 50 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78803ea3..7efa126a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,7 +71,20 @@ ## Unreleased ### Added + +* `url.style=none|single|double|curly|dotted|dashed` option added, + allowing you to configure how URL underlines are drawn. The default + is `dotted` ([#2302][2302]). + +[2302]: https://codeberg.org/dnkl/foot/issues/2302 + + ### Changed + +* URL underlines are now dotted by default, instead of plain + underlines. This can be changed with the new `url.style` option. + + ### Deprecated ### Removed ### Fixed diff --git a/config.c b/config.c index 12c594bc..481d4c4f 100644 --- a/config.c +++ b/config.c @@ -1304,6 +1304,14 @@ parse_section_url(struct context *ctx) else if (streq(key, "label-letters")) return value_to_wchars(ctx, &conf->url.label_letters); + else if (streq(key, "style")) { + _Static_assert(sizeof(conf->url.style) == sizeof(int), + "enum is not 32-bit"); + return value_to_enum( + ctx, (const char *[]){"none", "single", "double", "curly", "dotted", "dashed", NULL}, + (int *)&conf->url.style); + } + else if (streq(key, "osc8-underline")) { _Static_assert(sizeof(conf->url.osc8_underline) == sizeof(int), "enum is not 32-bit"); @@ -3518,6 +3526,7 @@ config_load(struct config *conf, const char *conf_path, .url = { .label_letters = xc32dup(U"sadfjklewcmpgh"), .osc8_underline = OSC8_UNDERLINE_URL_MODE, + .style = UNDERLINE_DOTTED, }, .custom_regexes = tll_init(), .can_shape_grapheme = fcft_caps & FCFT_CAPABILITY_GRAPHEME_SHAPING, diff --git a/config.h b/config.h index a3522f44..f8e99df3 100644 --- a/config.h +++ b/config.h @@ -218,6 +218,15 @@ enum center_when { CENTER_ALWAYS, }; +enum underline_style { + UNDERLINE_NONE, + UNDERLINE_SINGLE, /* Legacy underline */ + UNDERLINE_DOUBLE, + UNDERLINE_CURLY, + UNDERLINE_DOTTED, + UNDERLINE_DASHED, +}; + struct config { char *conf_path; char *term; @@ -327,6 +336,7 @@ struct config { OSC8_UNDERLINE_URL_MODE, OSC8_UNDERLINE_ALWAYS, } osc8_underline; + enum underline_style style; char *regex; regex_t preg; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index a1ee326f..66daaea9 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -867,6 +867,14 @@ section. Default: _url-mode_ +*style* + The underline style to use when rendering URL underlines. This + applies to both OSC-8 underlines when *osc8-underline=always*, and + all detected URLs in URL mode. One of *none*, *single*, *double*, + *curly*, *dotted* or *dashed*. + + Default: _dotted_ + *label-letters* String of characters to use when generating key sequences for URL jump labels. diff --git a/foot.ini b/foot.ini index a9b4b83d..81419d88 100644 --- a/foot.ini +++ b/foot.ini @@ -72,6 +72,7 @@ [url] # launch=xdg-open ${url} # label-letters=sadfjklewcmpgh +# style=dotted (none|single|double|curly|dotted|dashed) # osc8-underline=url-mode # regex=(((https?://|mailto:|ftp://|file:|ssh:|ssh://|git://|tel:|magnet:|ipfs://|ipns://|gemini://|gopher://|news:)|www\.)([0-9a-zA-Z:/?#@!$&*+,;=.~_%^\-]+|\([]\["0-9a-zA-Z:/?#@!$&'*+,;=.~_%^\-]*\)|\[[\(\)"0-9a-zA-Z:/?#@!$&'*+,;=.~_%^\-]*\]|"[]\[\(\)0-9a-zA-Z:/?#@!$&'*+,;=.~_%^\-]*"|'[]\[\(\)0-9a-zA-Z:/?#@!$&*+,;=.~_%^\-]*')+([0-9a-zA-Z/#@$&*+=~_%^\-]|\([]\["0-9a-zA-Z:/?#@!$&'*+,;=.~_%^\-]*\)|\[[\(\)"0-9a-zA-Z:/?#@!$&'*+,;=.~_%^\-]*\]|"[]\[\(\)0-9a-zA-Z:/?#@!$&'*+,;=.~_%^\-]*"|'[]\[\(\)0-9a-zA-Z:/?#@!$&*+,;=.~_%^\-]*')) diff --git a/render.c b/render.c index c47133b3..f74e9251 100644 --- a/render.c +++ b/render.c @@ -1171,13 +1171,16 @@ render_cell(struct terminal *term, pixman_image_t *pix, if (cell->attrs.strikethrough) draw_strikeout(term, pix, font, &fg, x, y, cell_cols); - if (unlikely(cell->attrs.url)) { + if (unlikely(cell->attrs.url && term->conf->url.style != UNDERLINE_NONE)) { pixman_color_t url_color = color_hex_to_pixman( term->conf->colors_dark.use_custom.url ? term->conf->colors_dark.url : term->colors.table[3], gamma_correct); - draw_underline(term, pix, font, &url_color, x, y, cell_cols); + + draw_styled_underline( + term, pix, font, &url_color, term->conf->url.style, + x, y, cell_cols); } draw_cursor: diff --git a/terminal.h b/terminal.h index 5a2a57aa..446d5f23 100644 --- a/terminal.h +++ b/terminal.h @@ -105,15 +105,6 @@ struct uri_range_data { char *uri; }; -enum underline_style { - UNDERLINE_NONE, - UNDERLINE_SINGLE, /* Legacy underline */ - UNDERLINE_DOUBLE, - UNDERLINE_CURLY, - UNDERLINE_DOTTED, - UNDERLINE_DASHED, -}; - struct underline_range_data { enum underline_style style; enum color_source color_src; diff --git a/tests/test-config.c b/tests/test-config.c index 9774cba9..16cfb2b0 100644 --- a/tests/test-config.c +++ b/tests/test-config.c @@ -632,6 +632,10 @@ test_section_url(void) (const char *[]){"url-mode", "always"}, (int []){OSC8_UNDERLINE_URL_MODE, OSC8_UNDERLINE_ALWAYS}, (int *)&conf.url.osc8_underline); + test_enum(&ctx, &parse_section_url, "style", + 6, (const char *[]){"none", "single", "double", "curly", "dotted", "dashed"}, + (int []){UNDERLINE_NONE, UNDERLINE_SINGLE, UNDERLINE_DOUBLE, UNDERLINE_CURLY, UNDERLINE_DOTTED, UNDERLINE_DASHED}, + (int *)&conf.url.style); test_c32string(&ctx, &parse_section_url, "label-letters", &conf.url.label_letters); config_free(&conf);