add support for characters that are bigger than 1 column - sob - simple output bar
 (HTM) git clone git://git.codemadness.org/sob
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 953439a2efe7bf8be200be0d384377d1d96f4d48
 (DIR) parent 4f2bc0ed04d5afc5dfd11651fe84747eb3ec55bb
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Fri, 10 Oct 2014 18:47:55 +0000
       
       add support for characters that are bigger than 1 column
       
       Diffstat:
         M README                              |       4 +++-
         M sob.c                               |      78 +++++++++++++++++++++++++------
       
       2 files changed, 67 insertions(+), 15 deletions(-)
       ---
 (DIR) diff --git a/README b/README
       @@ -10,6 +10,8 @@ Dependencies
        Features
        --------
        - Small (in size and memory), not much dependencies.
       +- UTF-8 input and output support.
       +        - Support for characters that are bigger than 1 column.
        - Custom prompt (including color support).
        - Easy to write custom completion scripts or special actions.
        - Custom action on SIGWINCH (window resize).
       @@ -23,7 +25,7 @@ Features
        
        Known issues
        ------------
       -line yank doesn't work with xclip, but does work with xsel.
       +- Line yank doesn't work with xclip, but does work with xsel.
        
        
        Author
 (DIR) diff --git a/sob.c b/sob.c
       @@ -12,6 +12,9 @@
        #include <unistd.h>
        #include <termios.h>
        
       +#define __XOPEN_SOURCE
       +#include <wchar.h>
       +
        #include "arg.h"
        char *argv0;
        
       @@ -27,6 +30,8 @@ struct line {
                size_t utflen;     /* length in characters */
                size_t bytepos;    /* index position (in bytes) */
                size_t utfpos;     /* pos in characters */
       +        size_t colpos;     /* cursor position (in columns) */
       +        size_t collen;     /* total length (in columns) */
        };
        
        static void   line_clear(void);
       @@ -69,10 +74,11 @@ static void   setup(void);
        static void   sighandler(int);
        static void   usage(void);
        
       +static size_t colw(const char *, size_t);
        static int    nonspace(int c);
        static size_t utf8len(const char *);
       -static size_t utfprevn(const char *, size_t , size_t);
       -static size_t utfnextn(const char *, size_t , size_t);
       +static size_t utfprevn(const char *, size_t, size_t);
       +static size_t utfnextn(const char *, size_t, size_t);
        static void   utfuntilchar(size_t *, size_t *, int (*)(int), int);
        
        static struct termios ttystate, ttysave;
       @@ -92,6 +98,25 @@ nonspace(int c)
        }
        
        static size_t
       +colw(const char *s, size_t max)
       +{
       +        size_t len = 0, i;
       +        wchar_t w = 0;
       +        int r;
       +
       +        for(i = 0; *s; s++, i++) {
       +                if((*s & 0xc0) != 0x80) {
       +                        if((r = mbtowc(&w, s, i + 4 > max ? max - i : 4)) == -1)
       +                                break;
       +                        if((r = wcwidth(w)) == -1)
       +                                break;
       +                        len += r;
       +                }
       +        }
       +        return len;
       +}
       +
       +static size_t
        utf8len(const char *s)
        {
                size_t i;
       @@ -133,7 +158,7 @@ utfnextn(const char *s, size_t p, size_t n)
                return 0;
        }
        
       -/* b is byte start pos, u is utf pos, f is filter function,
       +/* b is byte start pos, u is utf pos, c is column pos, f is filter function,
         * dir is -1 or +1 for prev or next */
        static void
        utfuntilchar(size_t *b, size_t *u, int (*f)(int), int dir)
       @@ -165,12 +190,13 @@ utfuntilchar(size_t *b, size_t *u, int (*f)(int), int dir)
        static void
        line_inserttext(const char *s)
        {
       -        size_t siz, len;
       +        size_t siz, ulen, clen;
        
                siz = strlen(s);
                if(line.bytepos + siz + 1 > sizeof(line.line))
                        return;
       -        len = utf8len(s);
       +        clen = colw(s, siz);
       +        ulen = utf8len(s);
                /* append */
                if(line.bytepos == line.bytesiz) {
                        memmove(&line.line[line.bytepos], s, siz);
       @@ -184,7 +210,9 @@ line_inserttext(const char *s)
                line.bytesiz += siz;
                line.line[line.bytesiz + 1] = '\0';
                line.utflen = utf8len(line.line);
       -        line.utfpos += len;
       +        line.utfpos += ulen;
       +        line.colpos += clen;
       +        line.collen = colw(line.line, line.bytesiz);
                line_draw();
        }
        
       @@ -202,6 +230,8 @@ line_set(const char *s)
                line.bytepos = line.bytesiz;
                line.utflen = utf8len(line.line);
                line.utfpos = line.utflen;
       +        line.collen = colw(line.line, line.bytesiz);
       +        line.colpos = line.collen;
        }
        
        /* like mksh, toggle counting of escape codes in prompt with "\x01" */
       @@ -237,7 +267,7 @@ line_draw(void)
                fprintf(outfp, "\x1b[2J\x1b[H"); /* clear */
                line_prompt();
                fwrite(line.line, 1, line.bytesiz, outfp);
       -        line_cursor_move(line.utfpos);
       +        line_cursor_move(line.colpos);
        }
        
        static void
       @@ -268,14 +298,16 @@ static void
        line_cursor_wordprev(void)
        {
                line_getwordposprev(line.bytepos, line.utfpos, &line.bytepos, &line.utfpos);
       -        line_cursor_move(line.utfpos);
       +        line.colpos = colw(line.line, line.bytepos);
       +        line_cursor_move(line.colpos);
        }
        
        static void
        line_cursor_wordnext(void)
        {
                line_getwordposnext(line.bytepos, line.utfpos, &line.bytepos, &line.utfpos);
       -        line_cursor_move(line.utfpos);
       +        line.colpos = colw(line.line, line.bytepos);
       +        line_cursor_move(line.colpos);
        }
        
        static void
       @@ -283,7 +315,8 @@ line_cursor_begin(void)
        {
                line.bytepos = 0;
                line.utfpos = 0;
       -        line_cursor_move(line.utfpos);
       +        line.colpos = 0;
       +        line_cursor_move(line.colpos);
        }
        
        static void
       @@ -298,7 +331,8 @@ line_cursor_prev(void)
        
                line.bytepos -= n;
                line.utfpos--;
       -        line_cursor_move(line.utfpos);
       +        line.colpos -= colw(&line.line[line.bytepos], n);
       +        line_cursor_move(line.colpos);
        }
        
        static void
       @@ -311,9 +345,10 @@ line_cursor_next(void)
        
                if((n = utfnextn(line.line, line.bytepos, 1)) == 0)
                        return;
       +        line.colpos += colw(&line.line[line.bytepos], n);
                line.bytepos += n;
                line.utfpos++;
       -        line_cursor_move(line.utfpos);
       +        line_cursor_move(line.colpos);
        }
        
        static void
       @@ -321,7 +356,8 @@ line_cursor_end(void)
        {
                line.bytepos = line.bytesiz;
                line.utfpos = line.utflen;
       -        line_cursor_move(line.utfpos);
       +        line.colpos = line.collen;
       +        line_cursor_move(line.colpos);
        }
        
        static void
       @@ -342,6 +378,9 @@ line_delcharnext(void)
        
                if((siz = utfnextn(line.line, line.bytepos, 1)) == 0)
                        return;
       +
       +        line.collen -= colw(&line.line[line.bytepos], siz);
       +
                memmove(&line.line[line.bytepos], &line.line[line.bytepos + siz],
                        line.bytesiz - line.bytepos - siz);
        
       @@ -354,20 +393,25 @@ line_delcharnext(void)
        static void
        line_delcharprev(void)
        {
       -        size_t siz;
       +        size_t siz, col;
        
                if(line.utfpos <= 0 || line.utflen <= 0)
                        return;
                if((siz = utfprevn(line.line, line.bytepos, 1)) == 0)
                        return;
        
       +        col = colw(&line.line[line.bytepos - siz], siz);
       +
                memmove(&line.line[line.bytepos - siz], &line.line[line.bytepos],
                        line.bytesiz - line.bytepos);
       +
                line.bytepos -= siz;
                line.bytesiz -= siz;
                line.line[line.bytesiz] = '\0';
                line.utflen--;
                line.utfpos--;
       +        line.colpos -= col;
       +        line.collen -= col;
        
                line_draw();
        }
       @@ -379,6 +423,8 @@ line_deltoend(void)
                line.bytesiz = line.bytepos;
                line.utflen = utf8len(line.line);
                line.utfpos = line.utflen;
       +        line.collen = colw(line.line, line.bytesiz);
       +        line.colpos = line.collen;
        
                line_draw();
        }
       @@ -400,6 +446,8 @@ line_delwordcursor(void)
                line.line[line.bytesiz] = '\0';
                line.utfpos -= len;
                line.utflen -= len;
       +        line.collen = colw(line.line, line.bytesiz);
       +        line.colpos = colw(line.line, bs);
        
                line_draw();
        }
       @@ -415,6 +463,7 @@ line_delwordprev(void)
                line_getwordposprev(line.bytepos, line.utfpos, &bs, &us);
        
                siz = line.bytepos - bs;
       +        line.colpos -= colw(&line.line[bs], siz);
                memmove(&line.line[bs], &line.line[line.bytepos],
                        line.bytesiz - line.bytepos);
        
       @@ -425,6 +474,7 @@ line_delwordprev(void)
                line.line[line.bytesiz] = '\0';
                line.utfpos -= len;
                line.utflen -= len;
       +        line.collen = colw(line.line, line.bytesiz);
        
                line_draw();
        }