diff options
| author | Christoph Lohmann <20h@r-36.net> | 2013-09-07 12:41:36 +0200 | 
|---|---|---|
| committer | Christoph Lohmann <20h@r-36.net> | 2013-09-07 12:41:36 +0200 | 
| commit | 210dda9570095443bac887c2bfcd75f2bcc23780 (patch) | |
| tree | 91136e0906b2443653858bdddb1e4669c8854876 | |
| parent | a4358a1fbd1c71269129404c9af4f539b2d7627c (diff) | |
Wide character support.
Thanks "Eon S. Jeon" <esjeon@hyunmu.am>!
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | st.c | 84 | 
2 files changed, 68 insertions, 17 deletions
| @@ -1,7 +1,6 @@  vt emulation  ------------ -* wide-character support in conjunction with fallback xft code   * double-height support  code & interface @@ -27,6 +27,7 @@  #include <X11/keysym.h>  #include <X11/Xft/Xft.h>  #include <fontconfig/fontconfig.h> +#include <wchar.h>  #include "arg.h" @@ -96,6 +97,8 @@ enum glyph_attribute {  	ATTR_ITALIC    = 16,  	ATTR_BLINK     = 32,  	ATTR_WRAP      = 64, +	ATTR_WIDE      = 128, +	ATTR_WDUMMY    = 256,  };  enum cursor_movement { @@ -165,7 +168,7 @@ typedef unsigned short ushort;  typedef struct {  	char c[UTF_SIZ]; /* character code */ -	uchar mode;      /* attribute flags */ +	ushort mode;      /* attribute flags */  	ulong fg;        /* foreground  */  	ulong bg;        /* background  */  } Glyph; @@ -719,8 +722,13 @@ selsnap(int mode, int *x, int *y, int direction) {  				}  			} +			if(term.line[*y][*x+direction].mode & ATTR_WDUMMY) { +				*x += direction; +				continue; +			} +  			if(strchr(worddelimiters, -					term.line[*y][*x + direction].c[0])) { +					term.line[*y][*x+direction].c[0])) {  				break;  			} @@ -932,7 +940,7 @@ selcopy(void) {  				/* nothing */;  			for(x = 0; gp <= last; x++, ++gp) { -				if(!selected(x, y)) +				if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))  					continue;  				size = utf8size(gp->c); @@ -1533,6 +1541,16 @@ tsetchar(char *c, Glyph *attr, int x, int y) {  		}  	} +	if(term.line[y][x].mode & ATTR_WIDE) { +		if(x+1 < term.col) { +			term.line[y][x+1].c[0] = ' '; +			term.line[y][x+1].mode &= ~ATTR_WDUMMY; +		} +	} else if(term.line[y][x].mode & ATTR_WDUMMY) { +		term.line[y][x-1].c[0] = ' '; +		term.line[y][x-1].mode &= ~ATTR_WIDE; +	} +  	term.dirty[y] = 1;  	term.line[y][x] = *attr;  	memcpy(term.line[y][x].c, c, UTF_SIZ); @@ -2222,6 +2240,15 @@ void  tputc(char *c, int len) {  	uchar ascii = *c;  	bool control = ascii < '\x20' || ascii == 0177; +	long u8char; +	int width; + +	if(len == 1) { +		width = 1; +	} else { +		utf8decode(c, &u8char); +		width = wcwidth(u8char); +	}  	if(iofd != -1) {  		if(xwrite(iofd, c, len) < 0) { @@ -2469,9 +2496,20 @@ tputc(char *c, int len) {  			(term.col - term.c.x - 1) * sizeof(Glyph));  	} +	if(term.c.x+width > term.col) +		tnewline(1); +  	tsetchar(c, &term.c.attr, term.c.x, term.c.y); -	if(term.c.x+1 < term.col) { -		tmoveto(term.c.x+1, term.c.y); + +	if(width == 2) { +		term.line[term.c.y][term.c.x].mode |= ATTR_WIDE; +		if(term.c.x+1 < term.col) { +			term.line[term.c.y][term.c.x+1].c[0] = '\0'; +			term.line[term.c.y][term.c.x+1].mode = ATTR_WDUMMY; +		} +	} +	if(term.c.x+width < term.col) { +		tmoveto(term.c.x+width, term.c.y);  	} else {  		term.c.state |= CURSOR_WRAPNEXT;  	} @@ -3173,7 +3211,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {  				xp, winy + frc[i].font->ascent,  				(FcChar8 *)u8c, u8cblen); -		xp += xw.cw; +		xp += xw.cw * wcwidth(u8char);  	}  	/* @@ -3193,18 +3231,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {  void  xdrawcursor(void) {  	static int oldx = 0, oldy = 0; -	int sl; +	int sl, width, curx;  	Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};  	LIMIT(oldx, 0, term.col-1);  	LIMIT(oldy, 0, term.row-1); +	curx = term.c.x; + +	/* adjust position if in dummy */ +	if(term.line[oldy][oldx].mode & ATTR_WDUMMY) +		oldx--; +	if(term.line[term.c.y][curx].mode & ATTR_WDUMMY) +		curx--; +  	memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);  	/* remove the old cursor */  	sl = utf8size(term.line[oldy][oldx].c); +	width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1;  	xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, -			oldy, 1, sl); +			oldy, width, sl);  	/* draw the new one */  	if(!(IS_SET(MODE_HIDE))) { @@ -3216,26 +3263,28 @@ xdrawcursor(void) {  			}  			sl = utf8size(g.c); -			xdraws(g.c, g, term.c.x, term.c.y, 1, sl); +			width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\ +				? 2 : 1; +			xdraws(g.c, g, term.c.x, term.c.y, width, sl);  		} else {  			XftDrawRect(xw.draw, &dc.col[defaultcs], -					borderpx + term.c.x * xw.cw, +					borderpx + curx * xw.cw,  					borderpx + term.c.y * xw.ch,  					xw.cw - 1, 1);  			XftDrawRect(xw.draw, &dc.col[defaultcs], -					borderpx + term.c.x * xw.cw, +					borderpx + curx * xw.cw,  					borderpx + term.c.y * xw.ch,  					1, xw.ch - 1);  			XftDrawRect(xw.draw, &dc.col[defaultcs], -					borderpx + (term.c.x + 1) * xw.cw - 1, +					borderpx + (curx + 1) * xw.cw - 1,  					borderpx + term.c.y * xw.ch,  					1, xw.ch - 1);  			XftDrawRect(xw.draw, &dc.col[defaultcs], -					borderpx + term.c.x * xw.cw, +					borderpx + curx * xw.cw,  					borderpx + (term.c.y + 1) * xw.ch - 1,  					xw.cw, 1);  		} -		oldx = term.c.x, oldy = term.c.y; +		oldx = curx, oldy = term.c.y;  	}  } @@ -3284,6 +3333,7 @@ drawregion(int x1, int y1, int x2, int y2) {  	Glyph base, new;  	char buf[DRAW_BUF_SIZ];  	bool ena_sel = sel.ob.x != -1; +	long u8char;  	if(sel.alt ^ IS_SET(MODE_ALTSCREEN))  		ena_sel = 0; @@ -3301,6 +3351,8 @@ drawregion(int x1, int y1, int x2, int y2) {  		ic = ib = ox = 0;  		for(x = x1; x < x2; x++) {  			new = term.line[y][x]; +			if(new.mode == ATTR_WDUMMY) +				continue;  			if(ena_sel && selected(x, y))  				new.mode ^= ATTR_REVERSE;  			if(ib > 0 && (ATTRCMP(base, new) @@ -3313,10 +3365,10 @@ drawregion(int x1, int y1, int x2, int y2) {  				base = new;  			} -			sl = utf8size(new.c); +			sl = utf8decode(new.c, &u8char);  			memcpy(buf+ib, new.c, sl);  			ib += sl; -			++ic; +			ic += (new.mode & ATTR_WIDE)? 2 : 1;  		}  		if(ib > 0)  			xdraws(buf, base, ox, y, ic, ib); | 
