|  |  | @ -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); | 
			
		
	
	
		
			
				
					|  |  | 
 |