St was faking the set underline color sequence from the Kitty [1] terminal. This patch implements correctly the sequences SGR 58 and SGR 59 to enable or disable chaging the color.
[1] https://sw.kovidgoyal.net/kitty/underlines/ --- st.c | 15 ++++++++++----- st.h | 2 ++ st.info | 2 ++ x.c | 20 +++++++++++++++++--- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/st.c b/st.c index e55e7b3..4fd230d 100644 --- a/st.c +++ b/st.c @@ -1015,7 +1015,8 @@ treset(void) term.c = (TCursor){{ .mode = ATTR_NULL, .fg = defaultfg, - .bg = defaultbg + .bg = defaultbg, + .un = defaultfg, }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; memset(term.tabs, 0, term.col * sizeof(*term.tabs)); @@ -1362,6 +1363,7 @@ tsetattr(const int *attr, int l) ATTR_FAINT | ATTR_ITALIC | ATTR_UNDERLINE | + ATTR_UNDERCOLOR | ATTR_BLINK | ATTR_REVERSE | ATTR_INVISIBLE | @@ -1431,10 +1433,13 @@ tsetattr(const int *attr, int l) term.c.attr.bg = defaultbg; break; case 58: - /* This starts a sequence to change the color of - * "underline" pixels. We don't support that and - * instead eat up a following "5;n" or "2;r;g;b". */ - tdefcolor(attr, &i, l); + if ((idx = tdefcolor(attr, &i, l)) >= 0) { + term.c.attr.mode |= ATTR_UNDERCOLOR; + term.c.attr.un = idx; + } + break; + case 59: + term.c.attr.mode &= ~ATTR_UNDERCOLOR; break; default: if (BETWEEN(attr[i], 30, 37)) { diff --git a/st.h b/st.h index fd3b0d8..4cc16e3 100644 --- a/st.h +++ b/st.h @@ -33,6 +33,7 @@ enum glyph_attribute { ATTR_WRAP = 1 << 8, ATTR_WIDE = 1 << 9, ATTR_WDUMMY = 1 << 10, + ATTR_UNDERCOLOR = 1 << 11, ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; @@ -65,6 +66,7 @@ typedef struct { ushort mode; /* attribute flags */ uint32_t fg; /* foreground */ uint32_t bg; /* background */ + uint32_t un; /* underline */ } Glyph; typedef Glyph *Line; diff --git a/st.info b/st.info index efab2cf..05a05f6 100644 --- a/st.info +++ b/st.info @@ -195,6 +195,8 @@ st-mono| simpleterm monocolor, Ms=\E]52;%p1%s;%p2%s\007, Se=\E[2 q, Ss=\E[%p1%d q, +# kitty extensions + Su, st| simpleterm, use=st-mono, diff --git a/x.c b/x.c index d73152b..d5b1dd3 100644 --- a/x.c +++ b/x.c @@ -1380,8 +1380,8 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; - Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; - XRenderColor colfg, colbg; + Color *un, *fg, *bg, *temp, revfg, revbg, trueun, truefg, truebg; + XRenderColor colun, colfg, colbg; XRectangle r; /* Fallback on color display for attributes not supported by the font */ @@ -1466,6 +1466,20 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i if (base.mode & ATTR_INVISIBLE) fg = bg; + un = fg; + if (base.mode & ATTR_UNDERCOLOR) { + if (IS_TRUECOL(base.un)) { + colun.alpha = 0xffff; + colun.red = TRUERED(base.un); + colun.green = TRUEGREEN(base.un); + colun.blue = TRUEBLUE(base.un); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colun, &trueun); + un = &trueun; + } else { + un = &dc.col[base.un]; + } + } + /* Intelligent cleaning up of the borders. */ if (x == 0) { xclear(0, (y == 0)? 0 : winy, borderpx, @@ -1496,7 +1510,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Render underline and strikethrough. */ if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, + XftDrawRect(xw.draw, un, winx, winy + dc.font.ascent * chscale + 1, width, 1); } -- 2.46.1
