aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libutf.c52
-rw-r--r--libutf.h34
-rw-r--r--vis.c65
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
diff --git a/vis.c b/vis.c
index ffe45ce..339bfb0 100644
--- a/vis.c
+++ b/vis.c
@@ -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) {