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


Reply via email to