diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2015-07-18 10:35:32 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2015-07-20 12:05:45 +0200 |
| commit | 38f00e3e8a50e1690dcb78cf1eca8b6befb7173b (patch) | |
| tree | f613eec7ee39a312229e97d22557623ef7a2510f | |
| parent | 0fa9885cda0778467ca5737ac888ece5ef371b3d (diff) | |
| download | vis-38f00e3e8a50e1690dcb78cf1eca8b6befb7173b.tar.gz vis-38f00e3e8a50e1690dcb78cf1eca8b6befb7173b.tar.xz | |
vis: improve insertion of verbatim characters via CTRL-V in insert mode
Recognized formats are:
CTRL-V nnn decimal value nnn
CTRL-V onnn or CTRL-V Onnn octal value nnn
CTRL-V xnn or CTRL-V Xnn hex value nn
CTRL-V unnnn Unicode codepoint nnnn
CTRL-V Unnnnnnnn Unicode codepoint nnnnnnnn
Leading zeros can be omitted, any illegal character for the given
format will be ignored and terminates the numerical code.
| -rw-r--r-- | libutf.c | 52 | ||||
| -rw-r--r-- | libutf.h | 34 | ||||
| -rw-r--r-- | vis.c | 65 |
3 files changed, 144 insertions, 7 deletions
diff --git a/libutf.c b/libutf.c new file mode 100644 index 0000000..5f6ff45 --- /dev/null +++ b/libutf.c @@ -0,0 +1,52 @@ +/* libutf8 © 2012-2015 Connor Lane Smith <cls@lubutu.com> */ +#include "libutf.h" + +int +runelen(Rune r) +{ + if(r <= 0x7F) + return 1; + else if(r <= 0x07FF) + return 2; + else if(r <= 0xD7FF) + return 3; + else if(r <= 0xDFFF) + return 0; /* surrogate character */ + else if(r <= 0xFFFD) + return 3; + else if(r <= 0xFFFF) + return 0; /* illegal character */ + else if(r <= Runemax) + return 4; + else + return 0; /* rune too large */ +} + +int +runetochar(char *s, const Rune *p) +{ + Rune r = *p; + + switch(runelen(r)) { + case 1: /* 0aaaaaaa */ + s[0] = r; + return 1; + case 2: /* 00000aaa aabbbbbb */ + s[0] = 0xC0 | ((r & 0x0007C0) >> 6); /* 110aaaaa */ + s[1] = 0x80 | (r & 0x00003F); /* 10bbbbbb */ + return 2; + case 3: /* aaaabbbb bbcccccc */ + s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */ + s[1] = 0x80 | ((r & 0x000FC0) >> 6); /* 10bbbbbb */ + s[2] = 0x80 | (r & 0x00003F); /* 10cccccc */ + return 3; + case 4: /* 000aaabb bbbbcccc ccdddddd */ + s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */ + s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */ + s[2] = 0x80 | ((r & 0x000FC0) >> 6); /* 10cccccc */ + s[3] = 0x80 | (r & 0x00003F); /* 10dddddd */ + return 4; + default: + return 0; /* error */ + } +} diff --git a/libutf.h b/libutf.h new file mode 100644 index 0000000..4d3f91c --- /dev/null +++ b/libutf.h @@ -0,0 +1,34 @@ +#ifndef LIBUTF_H +#define LIBUTF_H + +/* libutf8 © 2012-2015 Connor Lane Smith <cls@lubutu.com> */ +#include <stddef.h> +#include <stdint.h> + +#if __STDC_VERSION__ >= 201112L +#include <uchar.h> +#ifdef __STDC_UTF_32__ +#define RUNE_C INT32_C +typedef char32_t Rune; +#endif +#endif + +#ifndef RUNE_C +#ifdef INT32_C +#define RUNE_C INT32_C +typedef uint_least32_t Rune; +#else +#define RUNE_C(x) x##L +typedef unsigned long Rune; +#endif +#endif + +#define UTFmax 6 /* maximum bytes per rune */ + +#define Runeself 0x80 /* rune and utf are equal (<) */ +#define Runemax RUNE_C(0x10FFFF) /* maximum rune value */ + +int runelen(Rune r); +int runetochar(char *s, const Rune *p); + +#endif @@ -39,6 +39,7 @@ #include "text-objects.h" #include "util.h" #include "map.h" +#include "libutf.h" /** global variables */ static Editor *vis; /* global editor instance, keeps track of all windows etc. */ @@ -1037,15 +1038,65 @@ static void prompt_backspace(const Arg *arg) { } static void insert_verbatim(const Arg *arg) { - int value = 0; - for (int i = 0; i < 3; i++) { - Key k = getkey(); - if (k.str[0] < '0' || k.str[0] > '9') + int len = 0, count = 0, base; + Rune rune = 0; + Key key = getkey(); + char buf[4], type = key.str[0]; + switch (type) { + case 'o': + case 'O': + count = 3; + base = 8; + break; + case 'U': + count = 4; + /* fall through */ + case 'u': + count += 4; + base = 16; + break; + case 'x': + case 'X': + count = 2; + base = 16; + break; + default: + if (type < '0' || type > '9') return; - value = value * 10 + k.str[0] - '0'; + rune = type - '0'; + count = 2; + base = 10; + break; + } + + while (count-- > 0) { + key = getkey(); + int v = 0; + if (base == 8 && '0' <= key.str[0] && key.str[0] <= '7') + v = key.str[0] - '0'; + else if ((base == 10 || base == 16) && '0' <= key.str[0] && key.str[0] <= '9') + v = key.str[0] - '0'; + else if (base == 16 && 'a' <= key.str[0] && key.str[0] <= 'f') + v = 10 + key.str[0] - 'a'; + else if (base == 16 && 'A' <= key.str[0] && key.str[0] <= 'F') + v = 10 + key.str[0] - 'A'; + else + break; + rune = rune * base + v; + } + + if (type == 'u' || type == 'U') { + len = runetochar(buf, &rune); + } else { + buf[0] = rune; + len = 1; + } + + if (len > 0) { + size_t pos = view_cursor_get(vis->win->view); + editor_insert(vis, pos, buf, len); + view_cursor_to(vis->win->view, pos + len); } - char v = value; - editor_insert(vis, view_cursor_get(vis->win->view), &v, 1); } static void quit(const Arg *arg) { |
