You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
6.2 KiB
244 lines
6.2 KiB
diff --git a/st.c b/st.c
|
|
index 76b7e0d..542ab3a 100644
|
|
--- 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
|
|
|
|
@@ -139,6 +140,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 */
|
|
@@ -159,6 +161,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);
|
|
@@ -1131,6 +1134,28 @@ tnewline(int first_col)
|
|
tmoveto(first_col ? 0 : term.c.x, y);
|
|
}
|
|
|
|
+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)
|
|
{
|
|
@@ -1153,6 +1178,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++;
|
|
@@ -1369,6 +1395,10 @@ tsetattr(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;
|
|
@@ -1380,7 +1410,14 @@ tsetattr(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 */
|
|
@@ -1431,6 +1468,18 @@ tsetattr(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
|
|
index 3d351b6..2cfac88 100644
|
|
--- a/st.h
|
|
+++ b/st.h
|
|
@@ -34,6 +34,7 @@ enum glyph_attribute {
|
|
ATTR_WIDE = 1 << 9,
|
|
ATTR_WDUMMY = 1 << 10,
|
|
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
|
+ ATTR_DIRTYUNDERLINE = 1 << 15,
|
|
};
|
|
|
|
enum selection_mode {
|
|
@@ -65,6 +66,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
|
|
index 8201ad6..659878c 100644
|
|
--- 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
|
|
index 210f184..9a6a2bd 100644
|
|
--- a/x.c
|
|
+++ b/x.c
|
|
@@ -1461,8 +1461,95 @@ 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 + 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) {
|
|
|