~petersanchez/st

210dda9570095443bac887c2bfcd75f2bcc23780 — Christoph Lohmann 10 years ago a4358a1
Wide character support.

Thanks "Eon S. Jeon" <esjeon@hyunmu.am>!
2 files changed, 68 insertions(+), 17 deletions(-)

M TODO
M st.c
M TODO => TODO +0 -1
@@ 1,7 1,6 @@
vt emulation
------------

* wide-character support in conjunction with fallback xft code 
* double-height support

code & interface

M st.c => st.c +68 -16
@@ 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);