commit 953439a2efe7bf8be200be0d384377d1d96f4d48
parent 4f2bc0ed04d5afc5dfd11651fe84747eb3ec55bb
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(-)
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
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();
}