X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/5edeec1b20fcb5900d4f1408594d1e76b6c544f0..821a6e00a5a9395f40c10c00d19c569bd0f2688e:/st.c

diff --git a/st.c b/st.c
index 17142a4..e0aae9d 100644
--- a/st.c
+++ b/st.c
@@ -76,8 +76,7 @@ char *argv0;
 #define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 #define IS_SET(flag) ((term.mode & (flag)) != 0)
-#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/10E6)
-#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6)
 #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 
 #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
@@ -91,14 +90,17 @@ char *argv0;
 
 enum glyph_attribute {
 	ATTR_NULL      = 0,
-	ATTR_REVERSE   = 1,
-	ATTR_UNDERLINE = 2,
-	ATTR_BOLD      = 4,
-	ATTR_ITALIC    = 8,
+	ATTR_BOLD      = 1,
+	ATTR_FAINT     = 2,
+	ATTR_ITALIC    = 4,
+	ATTR_UNDERLINE = 8,
 	ATTR_BLINK     = 16,
-	ATTR_WRAP      = 32,
-	ATTR_WIDE      = 64,
-	ATTR_WDUMMY    = 128,
+	ATTR_REVERSE   = 32,
+	ATTR_INVISIBLE = 64,
+	ATTR_STRUCK    = 128,
+	ATTR_WRAP      = 256,
+	ATTR_WIDE      = 512,
+	ATTR_WDUMMY    = 1024,
 };
 
 enum cursor_movement {
@@ -372,6 +374,7 @@ static void tdeletechar(int);
 static void tdeleteline(int);
 static void tinsertblank(int);
 static void tinsertblankline(int);
+static int tlinelen(int);
 static void tmoveto(int, int);
 static void tmoveato(int, int);
 static void tnew(int, int);
@@ -401,6 +404,7 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
+static void tstrsequence(uchar c);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -917,7 +921,7 @@ bpress(XEvent *e) {
 char *
 getsel(void) {
 	char *str, *ptr;
-	int x, y, bufsize, size, ex;
+	int y, bufsize, size, lastx, linelen;
 	Glyph *gp, *last;
 
 	if(sel.ob.x == -1)
@@ -928,16 +932,19 @@ getsel(void) {
 
 	/* append every set & selected glyph to the selection */
 	for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
-		gp = &term.line[y][0];
-		last = &gp[term.col-1];
+		linelen = tlinelen(y);
 
-		while(last >= gp && !(selected(last - gp, y) &&
-				      strcmp(last->c, " ") != 0)) {
-			--last;
+		if(sel.type == SEL_RECTANGULAR) {
+			gp = &term.line[y][sel.nb.x];
+			lastx = sel.ne.x;
+		} else {
+			gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
+			lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
 		}
+		last = &term.line[y][MIN(lastx, linelen-1)];
 
-		for(x = 0; gp <= last; x++, ++gp) {
-			if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
+		for( ; gp <= last; ++gp) {
+			if(gp->mode & ATTR_WDUMMY)
 				continue;
 
 			size = utf8len(gp->c);
@@ -954,20 +961,8 @@ getsel(void) {
 		 * st.
 		 * FIXME: Fix the computer world.
 		 */
-		if(y < sel.ne.y && !(x > 0 && (gp-1)->mode & ATTR_WRAP))
+		if(sel.ne.y > y || lastx >= linelen)
 			*ptr++ = '\n';
-
-		/*
-		 * If the last selected line expands in the selection
-		 * after the visible text '\n' is appended.
-		 */
-		if(y == sel.ne.y) {
-			ex = sel.ne.x;
-			if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
-				ex = sel.nb.x;
-			if(tlinelen(y) < ex)
-				*ptr++ = '\n';
-		}
 	}
 	*ptr = 0;
 	return str;
@@ -1181,16 +1176,15 @@ execsh(void) {
 
 void
 sigchld(int a) {
-	int stat = 0;
+	int stat, ret;
 
 	if(waitpid(pid, &stat, 0) < 0)
 		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
-	if(WIFEXITED(stat)) {
-		exit(WEXITSTATUS(stat));
-	} else {
-		exit(EXIT_FAILURE);
-	}
+	ret = WIFEXITED(stat) ? WEXITSTATUS(stat) : EXIT_FAILURE;
+	if (ret != EXIT_SUCCESS)
+		die("child finished with error '%d'\n", stat);
+	exit(EXIT_SUCCESS);
 }
 
 void
@@ -1559,6 +1553,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 void
 tclearregion(int x1, int y1, int x2, int y2) {
 	int x, y, temp;
+	Glyph *gp;
 
 	if(x1 > x2)
 		temp = x1, x1 = x2, x2 = temp;
@@ -1573,10 +1568,13 @@ tclearregion(int x1, int y1, int x2, int y2) {
 	for(y = y1; y <= y2; y++) {
 		term.dirty[y] = 1;
 		for(x = x1; x <= x2; x++) {
+			gp = &term.line[y][x];
 			if(selected(x, y))
 				selclear(NULL);
-			term.line[y][x] = term.c.attr;
-			memcpy(term.line[y][x].c, " ", 2);
+			gp->fg = term.c.attr.fg;
+			gp->bg = term.c.attr.bg;
+			gp->mode = 0;
+			memcpy(gp->c, " ", 2);
 		}
 	}
 }
@@ -1682,15 +1680,24 @@ tsetattr(int *attr, int l) {
 	for(i = 0; i < l; i++) {
 		switch(attr[i]) {
 		case 0:
-			term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE \
-					| ATTR_BOLD | ATTR_ITALIC \
-					| ATTR_BLINK);
+			term.c.attr.mode &= ~(
+				ATTR_BOLD       |
+				ATTR_FAINT      |
+				ATTR_ITALIC     |
+				ATTR_UNDERLINE  |
+				ATTR_BLINK      |
+				ATTR_REVERSE    |
+				ATTR_INVISIBLE  |
+				ATTR_STRUCK     );
 			term.c.attr.fg = defaultfg;
 			term.c.attr.bg = defaultbg;
 			break;
 		case 1:
 			term.c.attr.mode |= ATTR_BOLD;
 			break;
+		case 2:
+			term.c.attr.mode |= ATTR_FAINT;
+			break;
 		case 3:
 			term.c.attr.mode |= ATTR_ITALIC;
 			break;
@@ -1698,15 +1705,21 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode |= ATTR_UNDERLINE;
 			break;
 		case 5: /* slow blink */
+			/* FALLTHROUGH */
 		case 6: /* rapid blink */
 			term.c.attr.mode |= ATTR_BLINK;
 			break;
 		case 7:
 			term.c.attr.mode |= ATTR_REVERSE;
 			break;
-		case 21:
+		case 8:
+			term.c.attr.mode |= ATTR_INVISIBLE;
+			break;
+		case 9:
+			term.c.attr.mode |= ATTR_STRUCK;
+			break;
 		case 22:
-			term.c.attr.mode &= ~ATTR_BOLD;
+			term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
 			break;
 		case 23:
 			term.c.attr.mode &= ~ATTR_ITALIC;
@@ -1715,12 +1728,17 @@ tsetattr(int *attr, int l) {
 			term.c.attr.mode &= ~ATTR_UNDERLINE;
 			break;
 		case 25:
-		case 26:
 			term.c.attr.mode &= ~ATTR_BLINK;
 			break;
 		case 27:
 			term.c.attr.mode &= ~ATTR_REVERSE;
 			break;
+		case 28:
+			term.c.attr.mode &= ~ATTR_INVISIBLE;
+			break;
+		case 29:
+			term.c.attr.mode &= ~ATTR_STRUCK;
+			break;
 		case 38:
 			if ((idx = tdefcolor(attr, &i, l)) >= 0)
 				term.c.attr.fg = idx;
@@ -2256,12 +2274,10 @@ tdumpline(int n) {
 	Glyph *bp, *end;
 
 	bp = &term.line[n][0];
-	end = &bp[term.col-1];
-	while(end > bp && !strcmp(" ", end->c))
-		--end;
-	if(bp != end || strcmp(bp->c, " ")) {
+	end = &bp[MIN(tlinelen(n), term.col) - 1];
+	if(bp != end || bp->c[0] != ' ') {
 		for( ;bp <= end; ++bp)
-			tprinter(bp->c, strlen(bp->c));
+			tprinter(bp->c, utf8len(bp->c));
 	}
 	tprinter("\n", 1);
 }
@@ -2326,6 +2342,30 @@ tdeftran(char ascii) {
 	}
 }
 
+void
+tstrsequence(uchar c) {
+	if (c & 0x80) {
+		switch (c) {
+		case 0x90:   /* DCS -- Device Control String */
+			c = 'P';
+			break;
+		case 0x9f:   /* APC -- Application Program Command */
+			c = '_';
+			break;
+		case 0x9e:   /* PM -- Privacy Message */
+			c = '^';
+			break;
+		case 0x9d:   /* OSC -- Operating System Command */
+			c = ']';
+			break;
+		}
+	}
+	strreset();
+	strescseq.type = c;
+	term.esc |= ESC_STR;
+	return;
+}
+
 void
 tcontrolcode(uchar ascii) {
 	static char question[UTF_SIZ] = "?";
@@ -2380,20 +2420,30 @@ tcontrolcode(uchar ascii) {
 	case 0177:   /* DEL (IGNORED) */
 		return;
 	case 0x84:   /* TODO: IND */
-	case 0x85:   /* TODO: NEL */
-	case 0x88:   /* TODO: HTS */
+		break;
+	case 0x85:   /* NEL -- Next line */
+		tnewline(1); /* always go to first col */
+		break;
+	case 0x88:   /* HTS -- Horizontal tab stop */
+		term.tabs[term.c.x] = 1;
+		break;
 	case 0x8d:   /* TODO: RI */
 	case 0x8e:   /* TODO: SS2 */
 	case 0x8f:   /* TODO: SS3 */
-	case 0x90:   /* TODO: DCS */
 	case 0x98:   /* TODO: SOS */
-	case 0x9a:   /* TODO: DECID */
+		break;
+	case 0x9a:   /* DECID -- Identify Terminal */
+		ttywrite(VT102ID, sizeof(VT102ID) - 1);
+		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
-	case 0x9d:   /* TODO: OSC */
-	case 0x9e:   /* TODO: PM */
-	case 0x9f:   /* TODO: APC */
 		break;
+	case 0x90:   /* DCS -- Device Control String */
+	case 0x9f:   /* APC -- Application Program Command */
+	case 0x9e:   /* PM -- Privacy Message */
+	case 0x9d:   /* OSC -- Operating System Command */
+		tstrsequence(ascii);
+		return;
 	}
 	/* only CAN, SUB, \a and C1 chars interrupt a sequence */
 	term.esc &= ~(ESC_STR_END|ESC_STR);
@@ -2509,9 +2559,7 @@ tputc(char *c, int len) {
 			case '^': /* PM -- Privacy Message */
 			case ']': /* OSC -- Operating System Command */
 			case 'k': /* old title set compatibility */
-				strreset();
-				strescseq.type = ascii;
-				term.esc |= ESC_STR;
+				tstrsequence(ascii);
 				return;
 			case '(': /* set primary charset G0 */
 			case ')': /* set secondary charset G1 */
@@ -2892,6 +2940,7 @@ xloadfonts(char *fontstr, double fontsize) {
 	FcPattern *pattern;
 	FcResult r_sz, r_psz;
 	double fontval;
+	float ceilf(float);
 
 	if(fontstr[0] == '-') {
 		pattern = XftXlfdParse(fontstr, False, False);
@@ -2937,8 +2986,8 @@ xloadfonts(char *fontstr, double fontsize) {
 	}
 
 	/* Setting character width and height. */
-	xw.cw = CEIL(dc.font.width * cwscale);
-	xw.ch = CEIL(dc.font.height * chscale);
+	xw.cw = ceilf(dc.font.width * cwscale);
+	xw.ch = ceilf(dc.font.height * chscale);
 
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
@@ -3157,7 +3206,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		 * change basic system colors [0-7]
 		 * to bright system colors [8-15]
 		 */
-		if(BETWEEN(base.fg, 0, 7))
+		if(BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
 			fg = &dc.col[base.fg + 8];
 
 		if(base.mode & ATTR_ITALIC) {
@@ -3201,9 +3250,20 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		bg = temp;
 	}
 
+	if(base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) {
+		colfg.red = fg->color.red / 2;
+		colfg.green = fg->color.green / 2;
+		colfg.blue = fg->color.blue / 2;
+		XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
+		fg = &revfg;
+	}
+
 	if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
 		fg = bg;
 
+	if(base.mode & ATTR_INVISIBLE)
+		fg = bg;
+
 	/* Intelligent cleaning up of the borders. */
 	if(x == 0) {
 		xclear(0, (y == 0)? 0 : winy, borderpx,
@@ -3348,6 +3408,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 				width, 1);
 	}
 
+	if(base.mode & ATTR_STRUCK) {
+		XftDrawRect(xw.draw, fg, winx, winy + 2 * font->ascent / 3,
+				width, 1);
+	}
+
 	/* Reset clip to none. */
 	XftDrawSetClip(xw.draw, 0);
 }
@@ -3715,6 +3780,8 @@ run(void) {
 	/* Waiting for window mapping */
 	while(1) {
 		XNextEvent(xw.dpy, &ev);
+		if(XFilterEvent(&ev, None))
+			continue;
 		if(ev.type == ConfigureNotify) {
 			w = ev.xconfigure.width;
 			h = ev.xconfigure.height;
@@ -3753,7 +3820,7 @@ run(void) {
 
 		clock_gettime(CLOCK_MONOTONIC, &now);
 		drawtimeout.tv_sec = 0;
-		drawtimeout.tv_nsec = (1000/xfps) * 10E6;
+		drawtimeout.tv_nsec = (1000/xfps) * 1E6;
 		tv = &drawtimeout;
 
 		dodraw = 0;
@@ -3790,7 +3857,7 @@ run(void) {
 							> blinktimeout) {
 						drawtimeout.tv_nsec = 1000;
 					} else {
-						drawtimeout.tv_nsec = (10E6 * \
+						drawtimeout.tv_nsec = (1E6 * \
 							(blinktimeout - \
 							TIMEDIFF(now,
 								lastblink)));