# st

Unnamed repository; edit this file 'description' to name the repository.

| Log | Files | Refs | README | LICENSE

    commit be17937c42013057c5112bb6200297341092ef22
    parent c60e94b7845807ed63cee6e8d5b8bd8e204afdc1
    Author: c0dev0id <sh+github@codevoid.de>
    Date:   Sat, 31 Jul 2021 20:04:45 +0200

    sdk-undercurl

    Diffstat:
    Mst.c | 51++++++++++++++++++++++++++++++++++++++++++++++++++-
    Mst.h | 3+++
    Mst.info | 1+
    Mx.c | 91++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-

    4 files changed, 144 insertions(+), 2 deletions(-)
    diff --git a/st.c b/st.c
    @@ -33,6 +33,7 @@
     #define UTF_SIZ       4
     #define ESC_BUF_SIZ   (128*UTF_SIZ)
     #define ESC_ARG_SIZ   16
    +#define CAR_PER_ARG   4
     #define STR_BUF_SIZ   ESC_BUF_SIZ
     #define STR_ARG_SIZ   ESC_ARG_SIZ
     #define HISTSIZE      2000
    @@ -146,6 +147,7 @@ typedef struct {
     	int arg[ESC_ARG_SIZ];
     	int narg;              /* nb of args */
     	char mode[2];
    +	int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */
     } CSIEscape;

     /* STR Escape sequence structs */
    @@ -166,6 +168,7 @@ static void ttywriteraw(const char *, size_t);

     static void csidump(void);
     static void csihandle(void);
    +static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
     static void csiparse(void);
     static void csireset(void);
     static int eschandle(uchar);
    @@ -1199,6 +1202,28 @@ tnewline(int first_col)
     }

     void
    +readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG])
    +{
    +	int i = 0;
    +	for (; i < CAR_PER_ARG; i++)
    +		params[cursor][i] = -1;
    +
    +	if (**p != ':')
    +		return;
    +
    +	char *np = NULL;
    +	i = 0;
    +
    +	while (**p == ':' && i < CAR_PER_ARG) {
    +		while (**p == ':')
    +			(*p)++;
    +		params[cursor][i] = strtol(*p, &np, 10);
    +		*p = np;
    +		i++;
    +	}
    +}
    +
    +void
     csiparse(void)
     {
     	char *p = csiescseq.buf, *np;
    @@ -1220,6 +1245,7 @@ csiparse(void)
     			v = -1;
     		csiescseq.arg[csiescseq.narg++] = v;
     		p = np;
    +		readcolonargs(&p, csiescseq.narg-1, csiescseq.carg);
     		if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
     			break;
     		p++;
    @@ -1439,6 +1465,10 @@ tsetattr(const int *attr, int l)
     				ATTR_STRUCK     );
     			term.c.attr.fg = defaultfg;
     			term.c.attr.bg = defaultbg;
    +			term.c.attr.ustyle = -1;
    +			term.c.attr.ucolor[0] = -1;
    +			term.c.attr.ucolor[1] = -1;
    +			term.c.attr.ucolor[2] = -1;
     			break;
     		case 1:
     			term.c.attr.mode |= ATTR_BOLD;
    @@ -1450,7 +1480,14 @@ tsetattr(const int *attr, int l)
     			term.c.attr.mode |= ATTR_ITALIC;
     			break;
     		case 4:
    -			term.c.attr.mode |= ATTR_UNDERLINE;
    +			term.c.attr.ustyle = csiescseq.carg[i][0];
    +
    +			if (term.c.attr.ustyle != 0)
    +				term.c.attr.mode |= ATTR_UNDERLINE;
    +			else
    +				term.c.attr.mode &= ~ATTR_UNDERLINE;
    +
    +			term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
     			break;
     		case 5: /* slow blink */
     			/* FALLTHROUGH */
    @@ -1501,6 +1538,18 @@ tsetattr(const int *attr, int l)
     		case 49:
     			term.c.attr.bg = defaultbg;
     			break;
    +		case 58:
    +			term.c.attr.ucolor[0] = csiescseq.carg[i][1];
    +			term.c.attr.ucolor[1] = csiescseq.carg[i][2];
    +			term.c.attr.ucolor[2] = csiescseq.carg[i][3];
    +			term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
    +			break;
    +		case 59:
    +			term.c.attr.ucolor[0] = -1;
    +			term.c.attr.ucolor[1] = -1;
    +			term.c.attr.ucolor[2] = -1;
    +			term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
    +			break;
     		default:
     			if (BETWEEN(attr[i], 30, 37)) {
     				term.c.attr.fg = attr[i] - 30;
    diff --git a/st.h b/st.h
    @@ -35,6 +35,7 @@ enum glyph_attribute {
     	ATTR_WDUMMY     = 1 << 10,
     	ATTR_BOXDRAW    = 1 << 11,
     	ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
    +	ATTR_DIRTYUNDERLINE = 1 << 15,
     };

     enum selection_mode {
    @@ -66,6 +67,8 @@ typedef struct {
     	ushort mode;      /* attribute flags */
     	uint32_t fg;      /* foreground  */
     	uint32_t bg;      /* background  */
    +	int ustyle;	  /* underline style */
    +	int ucolor[3];    /* underline color */
     } Glyph;

     typedef Glyph *Line;
    diff --git a/st.info b/st.info
    @@ -1,4 +1,5 @@
     st-mono| simpleterm monocolor,
    +	Su,
     	acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
     	am,
     	bce,
    diff --git a/x.c b/x.c
    @@ -1483,8 +1483,97 @@ 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 + win.cyo + dc.font.ascent + 1,
    +		XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
     				width, 1);
    +		// Underline Color
    +		int wlw = 1; // Wave Line Width
    +		int linecolor;
    +		if ((base.ucolor[0] >= 0) &&
    +			!(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) &&
    +			!(base.mode & ATTR_INVISIBLE)
    +		) {
    +			// Special color for underline
    +			// Index
    +			if (base.ucolor[1] < 0) {
    +				linecolor = dc.col[base.ucolor[0]].pixel;
    +			}
    +			// RGB
    +			else {
    +				XColor lcolor;
    +				lcolor.red = base.ucolor[0] * 257;
    +				lcolor.green = base.ucolor[1] * 257;
    +				lcolor.blue = base.ucolor[2] * 257;
    +				lcolor.flags = DoRed | DoGreen | DoBlue;
    +				XAllocColor(xw.dpy, xw.cmap, &lcolor);
    +				linecolor = lcolor.pixel;
    +			}
    +		} else {
    +			// Foreground color for underline
    +			linecolor = fg->pixel;
    +		}
    +
    +		XGCValues ugcv = {
    +			.foreground = linecolor,
    +			.line_width = wlw,
    +			.line_style = LineSolid,
    +			.cap_style = CapNotLast
    +		};
    +
    +		GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
    +			GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
    +			&ugcv);
    +
    +		// Underline Style
    +		if (base.ustyle != 3) {
    +			//XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1);
    +			XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx,
    +				winy + dc.font.ascent + 1, width, wlw);
    +		} else if (base.ustyle == 3) {
    +			int ww = win.cw;//width;
    +			int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
    +			int wx = winx;
    +			int wy = winy + win.ch - dc.font.descent;
    +
    +			// Draw waves
    +			int narcs = charlen * 2 + 1;
    +			XArc *arcs = xmalloc(sizeof(XArc) * narcs);
    +
    +			int i = 0;
    +			for (i = 0; i < charlen-1; i++) {
    +				arcs[i*2] = (XArc) {
    +					.x = wx + win.cw * i + ww / 4,
    +					.y = wy,
    +					.width = win.cw / 2,
    +					.height = wh,
    +					.angle1 = 0,
    +					.angle2 = 180 * 64
    +				};
    +				arcs[i*2+1] = (XArc) {
    +					.x = wx + win.cw * i + ww * 0.75,
    +					.y = wy,
    +					.width = win.cw/2,
    +					.height = wh,
    +					.angle1 = 180 * 64,
    +					.angle2 = 180 * 64
    +				};
    +			}
    +			// Last wave
    +			arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh,
    +			0, 180 * 64 };
    +			// Last wave tail
    +			arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.),
    +			wh, 180 * 64, 90 * 64};
    +			// First wave tail
    +			i++;
    +			arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64,
    +			90 * 64 };
    +
    +			XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs);
    +
    +			free(arcs);
    +		}
    +
    +		XFreeGC(xw.dpy, ugc);
     	}

     	if (base.mode & ATTR_STRUCK) {