Wide character support. - st - Personal fork of st
 (HTM) git clone git://git.drkhsh.at/st.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 210dda9570095443bac887c2bfcd75f2bcc23780
 (DIR) parent a4358a1fbd1c71269129404c9af4f539b2d7627c
 (HTM) 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:
         M TODO                                |       1 -
         M st.c                                |      84 +++++++++++++++++++++++++------
       
       2 files changed, 68 insertions(+), 17 deletions(-)
       ---
 (DIR) 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
 (DIR) 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);