tWide character support. - st - [fork] customized build of st, the simple termi… | |
git clone git://src.adamsgaard.dk/st | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 210dda9570095443bac887c2bfcd75f2bcc23780 | |
parent a4358a1fbd1c71269129404c9af4f539b2d7627c | |
Author: Christoph Lohmann <[email protected]> | |
Date: Sat, 7 Sep 2013 12:41:36 +0200 | |
Wide character support. | |
Thanks "Eon S. Jeon" <[email protected]>! | |
Diffstat: | |
M TODO | 1 - | |
M st.c | 84 +++++++++++++++++++++++++----… | |
2 files changed, 68 insertions(+), 17 deletions(-) | |
--- | |
diff --git a/TODO b/TODO | |
t@@ -1,7 +1,6 @@ | |
vt emulation | |
------------ | |
-* wide-character support in conjunction with fallback xft code | |
* double-height support | |
code & interface | |
diff --git a/st.c b/st.c | |
t@@ -27,6 +27,7 @@ | |
#include <X11/keysym.h> | |
#include <X11/Xft/Xft.h> | |
#include <fontconfig/fontconfig.h> | |
+#include <wchar.h> | |
#include "arg.h" | |
t@@ -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 { | |
t@@ -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; | |
t@@ -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; | |
} | |
t@@ -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); | |
t@@ -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); | |
t@@ -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) { | |
t@@ -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; | |
} | |
t@@ -3173,7 +3211,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, i… | |
xp, winy + frc[i].font->ascent, | |
(FcChar8 *)u8c, u8cblen); | |
- xp += xw.cw; | |
+ xp += xw.cw * wcwidth(u8char); | |
} | |
/* | |
t@@ -3193,18 +3231,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen,… | |
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))) { | |
t@@ -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; | |
} | |
} | |
t@@ -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; | |
t@@ -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) | |
t@@ -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); |