diff options
| author | David T. Sadler <davidtsadler@googlemail.com> | 2023-12-30 17:12:50 +0000 | 
|---|---|---|
| committer | David T. Sadler <davidtsadler@googlemail.com> | 2023-12-30 17:12:50 +0000 | 
| commit | f08b35d51292c85e5afcfa00c1e4c2ce38eb17bb (patch) | |
| tree | 958b5eea03287131974cd80ea3e03c337c8b2829 /st.c | |
| parent | 12e2061b709fbacd6ca62099bc3916f2b84621cb (diff) | |
| parent | e569a8e6f600038c5047b82f16ae566d35b9b9d7 (diff) | |
Diffstat (limited to 'st.c')
| -rw-r--r-- | st.c | 310 | 
1 files changed, 233 insertions, 77 deletions
@@ -35,6 +35,7 @@  #define ESC_ARG_SIZ   16  #define STR_BUF_SIZ   ESC_BUF_SIZ  #define STR_ARG_SIZ   ESC_ARG_SIZ +#define HISTSIZE      2000  /* macros */  #define IS_SET(flag)		((term.mode & (flag)) != 0) @@ -42,6 +43,9 @@  #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))  #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))  #define ISDELIM(u)		(u && wcschr(worddelimiters, u)) +#define TLINE(y)		((y) < term.scr ? term.hist[((y) + term.histi - \ +				term.scr + HISTSIZE + 1) % HISTSIZE] : \ +				term.line[(y) - term.scr])  enum term_mode {  	MODE_WRAP        = 1 << 0, @@ -51,7 +55,6 @@ enum term_mode {  	MODE_ECHO        = 1 << 4,  	MODE_PRINT       = 1 << 5,  	MODE_UTF8        = 1 << 6, -	MODE_SIXEL       = 1 << 7,  };  enum cursor_movement { @@ -78,12 +81,11 @@ enum charset {  enum escape_state {  	ESC_START      = 1,  	ESC_CSI        = 2, -	ESC_STR        = 4,  /* OSC, PM, APC */ +	ESC_STR        = 4,  /* DCS, OSC, PM, APC */  	ESC_ALTCHARSET = 8,  	ESC_STR_END    = 16, /* a final string was encountered */  	ESC_TEST       = 32, /* Enter in test mode */  	ESC_UTF8       = 64, -	ESC_DCS        =128,  };  typedef struct { @@ -117,6 +119,9 @@ typedef struct {  	int col;      /* nb col */  	Line *line;   /* screen */  	Line *alt;    /* alternate screen */ +	Line hist[HISTSIZE]; /* history buffer */ +	int histi;    /* history index */ +	int scr;      /* scroll back */  	int *dirty;   /* dirtyness of lines */  	TCursor c;    /* cursor */  	int ocx;      /* old cursor col */ @@ -129,6 +134,7 @@ typedef struct {  	int charset;  /* current charset */  	int icharset; /* selected charset for sequence */  	int *tabs; +	Rune lastc;   /* last printed char outside of sequence, 0 if control */  } Term;  /* CSI Escape sequence structs */ @@ -185,20 +191,20 @@ static void tnewline(int);  static void tputtab(int);  static void tputc(Rune);  static void treset(void); -static void tscrollup(int, int); -static void tscrolldown(int, int); -static void tsetattr(int *, int); -static void tsetchar(Rune, Glyph *, int, int); +static void tscrollup(int, int, int); +static void tscrolldown(int, int, int); +static void tsetattr(const int *, int); +static void tsetchar(Rune, const Glyph *, int, int);  static void tsetdirt(int, int);  static void tsetscroll(int, int);  static void tswapscreen(void); -static void tsetmode(int, int, int *, int); +static void tsetmode(int, int, const int *, int);  static int twrite(const char *, int, int);  static void tfulldirt(void);  static void tcontrolcode(uchar );  static void tdectest(char );  static void tdefutf8(char); -static int32_t tdefcolor(int *, int *, int); +static int32_t tdefcolor(const int *, int *, int);  static void tdeftran(char);  static void tstrsequence(uchar); @@ -227,10 +233,10 @@ static int iofd = 1;  static int cmdfd;  static pid_t pid; -static uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0}; -static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000}; -static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; +static const uchar utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0}; +static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000}; +static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};  ssize_t  xwrite(int fd, const char *s, size_t len) @@ -270,12 +276,14 @@ xrealloc(void *p, size_t len)  }  char * -xstrdup(char *s) +xstrdup(const char *s)  { -	if ((s = strdup(s)) == NULL) +	char *p; + +	if ((p = strdup(s)) == NULL)  		die("strdup: %s\n", strerror(errno)); -	return s; +	return p;  }  size_t @@ -415,10 +423,10 @@ tlinelen(int y)  {  	int i = term.col; -	if (term.line[y][i - 1].mode & ATTR_WRAP) +	if (TLINE(y)[i - 1].mode & ATTR_WRAP)  		return i; -	while (i > 0 && term.line[y][i - 1].u == ' ') +	while (i > 0 && TLINE(y)[i - 1].u == ' ')  		--i;  	return i; @@ -519,7 +527,7 @@ selsnap(int *x, int *y, int direction)  {  	int newx, newy, xt, yt;  	int delim, prevdelim; -	Glyph *gp, *prevgp; +	const Glyph *gp, *prevgp;  	switch (sel.snap) {  	case SNAP_WORD: @@ -527,7 +535,7 @@ selsnap(int *x, int *y, int direction)  		 * Snap around if the word wraps around at the end or  		 * beginning of a line.  		 */ -		prevgp = &term.line[*y][*x]; +		prevgp = &TLINE(*y)[*x];  		prevdelim = ISDELIM(prevgp->u);  		for (;;) {  			newx = *x + direction; @@ -542,14 +550,14 @@ selsnap(int *x, int *y, int direction)  					yt = *y, xt = *x;  				else  					yt = newy, xt = newx; -				if (!(term.line[yt][xt].mode & ATTR_WRAP)) +				if (!(TLINE(yt)[xt].mode & ATTR_WRAP))  					break;  			}  			if (newx >= tlinelen(newy))  				break; -			gp = &term.line[newy][newx]; +			gp = &TLINE(newy)[newx];  			delim = ISDELIM(gp->u);  			if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim  					|| (delim && gp->u != prevgp->u))) @@ -570,14 +578,14 @@ selsnap(int *x, int *y, int direction)  		*x = (direction < 0) ? 0 : term.col - 1;  		if (direction < 0) {  			for (; *y > 0; *y += direction) { -				if (!(term.line[*y-1][term.col-1].mode +				if (!(TLINE(*y-1)[term.col-1].mode  						& ATTR_WRAP)) {  					break;  				}  			}  		} else if (direction > 0) {  			for (; *y < term.row-1; *y += direction) { -				if (!(term.line[*y][term.col-1].mode +				if (!(TLINE(*y)[term.col-1].mode  						& ATTR_WRAP)) {  					break;  				} @@ -592,7 +600,7 @@ getsel(void)  {  	char *str, *ptr;  	int y, bufsize, lastx, linelen; -	Glyph *gp, *last; +	const Glyph *gp, *last;  	if (sel.ob.x == -1)  		return NULL; @@ -608,13 +616,13 @@ getsel(void)  		}  		if (sel.type == SEL_RECTANGULAR) { -			gp = &term.line[y][sel.nb.x]; +			gp = &TLINE(y)[sel.nb.x];  			lastx = sel.ne.x;  		} else { -			gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; +			gp = &TLINE(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)]; +		last = &TLINE(y)[MIN(lastx, linelen-1)];  		while (last >= gp && last->u == ' ')  			--last; @@ -759,7 +767,7 @@ stty(char **args)  }  int -ttynew(char *line, char *cmd, char *out, char **args) +ttynew(const char *line, char *cmd, const char *out, char **args)  {  	int m, s; @@ -792,14 +800,15 @@ ttynew(char *line, char *cmd, char *out, char **args)  		break;  	case 0:  		close(iofd); +		close(m);  		setsid(); /* create a new process group */  		dup2(s, 0);  		dup2(s, 1);  		dup2(s, 2);  		if (ioctl(s, TIOCSCTTY, NULL) < 0)  			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); -		close(s); -		close(m); +		if (s > 2) +			close(s);  #ifdef __OpenBSD__  		if (pledge("stdio getpw proc exec", NULL) == -1)  			die("pledge\n"); @@ -842,7 +851,6 @@ ttyread(void)  		if (buflen > 0)  			memmove(buf, buf + written, buflen);  		return ret; -  	}  } @@ -850,6 +858,9 @@ void  ttywrite(const char *s, size_t n, int may_echo)  {  	const char *next; +	Arg arg = (Arg) { .i = term.scr }; + +	kscrolldown(&arg);  	if (may_echo && IS_SET(MODE_ECHO))  		twrite(s, n, 1); @@ -1061,12 +1072,52 @@ tswapscreen(void)  }  void -tscrolldown(int orig, int n) +kscrolldown(const Arg* a) +{ +	int n = a->i; + +	if (n < 0) +		n = term.row + n; + +	if (n > term.scr) +		n = term.scr; + +	if (term.scr > 0) { +		term.scr -= n; +		selscroll(0, -n); +		tfulldirt(); +	} +} + +void +kscrollup(const Arg* a) +{ +	int n = a->i; + +	if (n < 0) +		n = term.row + n; + +	if (term.scr <= HISTSIZE-n) { +		term.scr += n; +		selscroll(0, n); +		tfulldirt(); +	} +} + +void +tscrolldown(int orig, int n, int copyhist)  {  	int i;  	Line temp;  	LIMIT(n, 0, term.bot-orig+1); +	if (copyhist) { +		term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; +		temp = term.hist[term.histi]; +		term.hist[term.histi] = term.line[term.bot]; +		term.line[term.bot] = temp; +	} +  	tsetdirt(orig, term.bot-n);  	tclearregion(0, term.bot-n+1, term.col-1, term.bot); @@ -1077,17 +1128,28 @@ tscrolldown(int orig, int n)  		term.line[i-n] = temp;  	} -	selscroll(orig, n); +	if (term.scr == 0) +		selscroll(orig, n);  }  void -tscrollup(int orig, int n) +tscrollup(int orig, int n, int copyhist)  {  	int i;  	Line temp;  	LIMIT(n, 0, term.bot-orig+1); +	if (copyhist) { +		term.histi = (term.histi + 1) % HISTSIZE; +		temp = term.hist[term.histi]; +		term.hist[term.histi] = term.line[orig]; +		term.line[orig] = temp; +	} + +	if (term.scr > 0 && term.scr < HISTSIZE) +		term.scr = MIN(term.scr + n, HISTSIZE-1); +  	tclearregion(0, orig, term.col-1, orig+n-1);  	tsetdirt(orig+n, term.bot); @@ -1097,7 +1159,8 @@ tscrollup(int orig, int n)  		term.line[i+n] = temp;  	} -	selscroll(orig, -n); +	if (term.scr == 0) +		selscroll(orig, -n);  }  void @@ -1126,7 +1189,7 @@ tnewline(int first_col)  	int y = term.c.y;  	if (y == term.bot) { -		tscrollup(term.top, 1); +		tscrollup(term.top, 1, 1);  	} else {  		y++;  	} @@ -1188,9 +1251,9 @@ tmoveto(int x, int y)  }  void -tsetchar(Rune u, Glyph *attr, int x, int y) +tsetchar(Rune u, const Glyph *attr, int x, int y)  { -	static char *vt100_0[62] = { /* 0x41 - 0x7e */ +	static const char *vt100_0[62] = { /* 0x41 - 0x7e */  		"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */  		0, 0, 0, 0, 0, 0, 0, 0, /* H - O */  		0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ @@ -1291,18 +1354,18 @@ void  tinsertblankline(int n)  {  	if (BETWEEN(term.c.y, term.top, term.bot)) -		tscrolldown(term.c.y, n); +		tscrolldown(term.c.y, n, 0);  }  void  tdeleteline(int n)  {  	if (BETWEEN(term.c.y, term.top, term.bot)) -		tscrollup(term.c.y, n); +		tscrollup(term.c.y, n, 0);  }  int32_t -tdefcolor(int *attr, int *npar, int l) +tdefcolor(const int *attr, int *npar, int l)  {  	int32_t idx = -1;  	uint r, g, b; @@ -1352,7 +1415,7 @@ tdefcolor(int *attr, int *npar, int l)  }  void -tsetattr(int *attr, int l) +tsetattr(const int *attr, int l)  {  	int i;  	int32_t idx; @@ -1470,9 +1533,9 @@ tsetscroll(int t, int b)  }  void -tsetmode(int priv, int set, int *args, int narg) +tsetmode(int priv, int set, const int *args, int narg)  { -	int alt, *lim; +	int alt; const int *lim;  	for (lim = args + narg; args < lim; ++args) {  		if (priv) { @@ -1648,6 +1711,12 @@ csihandle(void)  		if (csiescseq.arg[0] == 0)  			ttywrite(vtiden, strlen(vtiden), 0);  		break; +	case 'b': /* REP -- if last char is printable print it <n> more times */ +		DEFAULT(csiescseq.arg[0], 1); +		if (term.lastc) +			while (csiescseq.arg[0]-- > 0) +				tputc(term.lastc); +		break;  	case 'C': /* CUF -- Cursor <n> Forward */  	case 'a': /* HPR -- Cursor <n> Forward */  		DEFAULT(csiescseq.arg[0], 1); @@ -1729,11 +1798,11 @@ csihandle(void)  		break;  	case 'S': /* SU -- Scroll <n> line up */  		DEFAULT(csiescseq.arg[0], 1); -		tscrollup(term.top, csiescseq.arg[0]); +		tscrollup(term.top, csiescseq.arg[0], 0);  		break;  	case 'T': /* SD -- Scroll <n> line down */  		DEFAULT(csiescseq.arg[0], 1); -		tscrolldown(term.top, csiescseq.arg[0]); +		tscrolldown(term.top, csiescseq.arg[0], 0);  		break;  	case 'L': /* IL -- Insert <n> blank lines */  		DEFAULT(csiescseq.arg[0], 1); @@ -1771,7 +1840,7 @@ csihandle(void)  		break;  	case 'n': /* DSR – Device Status Report (cursor position) */  		if (csiescseq.arg[0] == 6) { -			len = snprintf(buf, sizeof(buf),"\033[%i;%iR", +			len = snprintf(buf, sizeof(buf), "\033[%i;%iR",  					term.c.y+1, term.c.x+1);  			ttywrite(buf, len, 0);  		} @@ -1836,6 +1905,42 @@ csireset(void)  }  void +osc4_color_response(int num) +{ +	int n; +	char buf[32]; +	unsigned char r, g, b; + +	if (xgetcolor(num, &r, &g, &b)) { +		fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num); +		return; +	} + +	n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", +		     num, r, r, g, g, b, b); + +	ttywrite(buf, n, 1); +} + +void +osc_color_response(int index, int num) +{ +	int n; +	char buf[32]; +	unsigned char r, g, b; + +	if (xgetcolor(index, &r, &g, &b)) { +		fprintf(stderr, "erresc: failed to fetch osc color %d\n", index); +		return; +	} + +	n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", +		     num, r, r, g, g, b, b); + +	ttywrite(buf, n, 1); +} + +void  strhandle(void)  {  	char *p = NULL, *dec; @@ -1849,13 +1954,21 @@ strhandle(void)  	case ']': /* OSC -- Operating System Command */  		switch (par) {  		case 0: +			if (narg > 1) { +				xsettitle(strescseq.args[1]); +				xseticontitle(strescseq.args[1]); +			} +			return;  		case 1: +			if (narg > 1) +				xseticontitle(strescseq.args[1]); +			return;  		case 2:  			if (narg > 1)  				xsettitle(strescseq.args[1]);  			return;  		case 52: -			if (narg > 2) { +			if (narg > 2 && allowwindowops) {  				dec = base64dec(strescseq.args[2]);  				if (dec) {  					xsetsel(dec); @@ -1865,14 +1978,56 @@ strhandle(void)  				}  			}  			return; +		case 10: +			if (narg < 2) +				break; + +			p = strescseq.args[1]; + +			if (!strcmp(p, "?")) +				osc_color_response(defaultfg, 10); +			else if (xsetcolorname(defaultfg, p)) +				fprintf(stderr, "erresc: invalid foreground color: %s\n", p); +			else +				redraw(); +			return; +		case 11: +			if (narg < 2) +				break; + +			p = strescseq.args[1]; + +			if (!strcmp(p, "?")) +				osc_color_response(defaultbg, 11); +			else if (xsetcolorname(defaultbg, p)) +				fprintf(stderr, "erresc: invalid background color: %s\n", p); +			else +				redraw(); +			return; +		case 12: +			if (narg < 2) +				break; + +			p = strescseq.args[1]; + +			if (!strcmp(p, "?")) +				osc_color_response(defaultcs, 12); +			else if (xsetcolorname(defaultcs, p)) +				fprintf(stderr, "erresc: invalid cursor color: %s\n", p); +			else +				redraw(); +			return;  		case 4: /* color set */  			if (narg < 3)  				break;  			p = strescseq.args[2];  			/* FALLTHROUGH */ -		case 104: /* color reset, here p = NULL */ +		case 104: /* color reset */  			j = (narg > 1) ? atoi(strescseq.args[1]) : -1; -			if (xsetcolorname(j, p)) { + +			if (p && !strcmp(p, "?")) +				osc4_color_response(j); +			else if (xsetcolorname(j, p)) {  				if (par == 104 && narg <= 1)  					return; /* color reset without parameter */  				fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", @@ -1891,7 +2046,6 @@ strhandle(void)  		xsettitle(strescseq.args[0]);  		return;  	case 'P': /* DCS -- Device Control String */ -		term.mode |= ESC_DCS;  	case '_': /* APC -- Application Program Command */  	case '^': /* PM -- Privacy Message */  		return; @@ -2009,7 +2163,7 @@ void  tdumpline(int n)  {  	char buf[UTF_SIZ]; -	Glyph *bp, *end; +	const Glyph *bp, *end;  	bp = &term.line[n][0];  	end = &bp[MIN(tlinelen(n), term.col) - 1]; @@ -2085,12 +2239,9 @@ tdectest(char c)  void  tstrsequence(uchar c)  { -	strreset(); -  	switch (c) {  	case 0x90:   /* DCS -- Device Control String */  		c = 'P'; -		term.esc |= ESC_DCS;  		break;  	case 0x9f:   /* APC -- Application Program Command */  		c = '_'; @@ -2102,6 +2253,7 @@ tstrsequence(uchar c)  		c = ']';  		break;  	} +	strreset();  	strescseq.type = c;  	term.esc |= ESC_STR;  } @@ -2240,7 +2392,7 @@ eschandle(uchar ascii)  		return 0;  	case 'D': /* IND -- Linefeed */  		if (term.c.y == term.bot) { -			tscrollup(term.top, 1); +			tscrollup(term.top, 1, 1);  		} else {  			tmoveto(term.c.x, term.c.y+1);  		} @@ -2253,7 +2405,7 @@ eschandle(uchar ascii)  		break;  	case 'M': /* RI -- Reverse index */  		if (term.c.y == term.top) { -			tscrolldown(term.top, 1); +			tscrolldown(term.top, 1, 1);  		} else {  			tmoveto(term.c.x, term.c.y-1);  		} @@ -2299,7 +2451,7 @@ tputc(Rune u)  	Glyph *gp;  	control = ISCONTROL(u); -	if (u < 127 || !IS_SET(MODE_UTF8 | MODE_SIXEL)) { +	if (u < 127 || !IS_SET(MODE_UTF8)) {  		c[0] = u;  		width = len = 1;  	} else { @@ -2320,23 +2472,11 @@ tputc(Rune u)  	if (term.esc & ESC_STR) {  		if (u == '\a' || u == 030 || u == 032 || u == 033 ||  		   ISCONTROLC1(u)) { -			term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); -			if (IS_SET(MODE_SIXEL)) { -				/* TODO: render sixel */; -				term.mode &= ~MODE_SIXEL; -				return; -			} +			term.esc &= ~(ESC_START|ESC_STR);  			term.esc |= ESC_STR_END;  			goto check_control_code;  		} -		if (IS_SET(MODE_SIXEL)) { -			/* TODO: implement sixel mode */ -			return; -		} -		if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q') -			term.mode |= MODE_SIXEL; -  		if (strescseq.len+len >= strescseq.siz) {  			/*  			 * Here is a bug in terminals. If the user never sends @@ -2373,6 +2513,8 @@ check_control_code:  		/*  		 * control codes are not shown ever  		 */ +		if (!term.esc) +			term.lastc = 0;  		return;  	} else if (term.esc & ESC_START) {  		if (term.esc & ESC_CSI) { @@ -2422,10 +2564,15 @@ check_control_code:  	}  	tsetchar(u, &term.c.attr, term.c.x, term.c.y); +	term.lastc = u;  	if (width == 2) {  		gp->mode |= ATTR_WIDE;  		if (term.c.x+1 < term.col) { +			if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) { +				gp[2].u = ' '; +				gp[2].mode &= ~ATTR_WDUMMY; +			}  			gp[1].u = '\0';  			gp[1].mode = ATTR_WDUMMY;  		} @@ -2445,7 +2592,7 @@ twrite(const char *buf, int buflen, int show_ctrl)  	int n;  	for (n = 0; n < buflen; n += charsize) { -		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { +		if (IS_SET(MODE_UTF8)) {  			/* process a complete utf8 char */  			charsize = utf8decode(buf + n, &u, buflen - n);  			if (charsize == 0) @@ -2472,7 +2619,7 @@ twrite(const char *buf, int buflen, int show_ctrl)  void  tresize(int col, int row)  { -	int i; +	int i, j;  	int minrow = MIN(row, term.row);  	int mincol = MIN(col, term.col);  	int *bp; @@ -2509,6 +2656,14 @@ tresize(int col, int row)  	term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));  	term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); +	for (i = 0; i < HISTSIZE; i++) { +		term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); +		for (j = mincol; j < col; j++) { +			term.hist[i][j] = term.c.attr; +			term.hist[i][j].u = ' '; +		} +	} +  	/* resize each row to new width, zero-pad if needed */  	for (i = 0; i < minrow; i++) {  		term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); @@ -2567,7 +2722,7 @@ drawregion(int x1, int y1, int x2, int y2)  			continue;  		term.dirty[y] = 0; -		xdrawline(term.line[y], x1, y, x2); +		xdrawline(TLINE(y), x1, y, x2);  	}  } @@ -2588,8 +2743,9 @@ draw(void)  		cx--;  	drawregion(0, 0, term.col, term.row); -	xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], -			term.ocx, term.ocy, term.line[term.ocy][term.ocx]); +	if (term.scr == 0) +		xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], +				term.ocx, term.ocy, term.line[term.ocy][term.ocx]);  	term.ocx = cx;  	term.ocy = term.c.y;  	xfinishdraw();  | 
