# st

Unnamed repository; edit this file 'description' to name the repository.

| Log | Files | Refs | README | LICENSE

    commit 210dda9570095443bac887c2bfcd75f2bcc23780
    parent a4358a1fbd1c71269129404c9af4f539b2d7627c
    Author: Christoph Lohmann <20h@r-36.net>
    Date:   Sat,  7 Sep 2013 12:41:36 +0200

    Wide character support.

    Thanks "Eon S. Jeon" <esjeon@hyunmu.am>!

    Diffstat:
    MTODO | 1-
    Mst.c | 84++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------

    2 files changed, 68 insertions(+), 17 deletions(-)
    diff --git a/TODO b/TODO
    @@ -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
    @@ -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);