Commit Diff


commit - 8947c1f29122ab2e506b2bb723a4fc92bd9d3a59
commit + 17e5106b8ecac061d8558f1d73f284c5516347cd
blob - 404312ec0aba8b3eca9ca668466fb8ffe6e5b933
blob + 17dd7e40516f85b94911879c02fb06aa540ab44a
--- telescope.h
+++ telescope.h
@@ -256,16 +256,21 @@ void		 ui_end(void);
 
 /* utf.8 */
 uint32_t	 utf8_decode(uint32_t*restrict, uint32_t*restrict, uint8_t);
-void		 utf8_encode(uint32_t, char*);
+size_t		 utf8_encode(uint32_t, char*);
 char		*utf8_nth(char*, size_t);
 size_t		 utf8_cplen(char*);
 size_t		 utf8_chwidth(uint32_t);
 size_t		 utf8_snwidth(const char*, size_t);
 size_t		 utf8_swidth(const char*);
+size_t		 utf8_swidth_between(const char*, const char*);
+char		*utf8_next_cp(char*);
+char		*utf8_prev_cp(char*, char*);
 
 /* util.c */
 int		 mark_nonblock(int);
 int		 has_prefix(const char*, const char*);
+int		 unicode_isspace(uint32_t);
+int		 unicode_isgraph(uint32_t);
 void		 dispatch_imsg(struct imsgbuf*, imsg_handlerfn**, size_t);
 
 /* wrap.c */
blob - ac2a27eb58345f3820fc77fe3e629e65c662714e
blob + ec6035aa0bce147c1c8b077104d6202d950a643b
--- ui.c
+++ ui.c
@@ -36,7 +36,6 @@
 
 #include <telescope.h>
 
-#include <ctype.h>
 #include <curses.h>
 #include <event.h>
 #include <locale.h>
@@ -168,14 +167,15 @@ static struct {
 	char	*curmesg;
 
 	char	 buf[1025];
-	size_t	 off, len;
+	char	*curs;
+	size_t	 cpoff;
 	char	 prompt[32];
 	void	 (*donefn)(void);
 	void	 (*abortfn)(void);
 
 	struct histhead	*history;
 	struct hist	*hist_cur;
-	size_t			 hist_off;
+	size_t		 hist_off;
 } ministate;
 
 struct lineprefix {
@@ -766,8 +766,7 @@ cmd_load_current_url(struct tab *tab)
 	    &lu_history);
 	strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt));
 	strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf));
-	ministate.off = strlen(tab->hist_cur->h);
-	ministate.len = ministate.off;
+	ministate.curs = strchr(ministate.buf, '\0');
 }
 
 static void
@@ -776,8 +775,7 @@ cmd_bookmark_page(struct tab *tab)
 	enter_minibuffer(lu_self_insert, bp_select, exit_minibuffer, NULL);
 	strlcpy(ministate.prompt, "Bookmark URL: ", sizeof(ministate.prompt));
 	strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf));
-	ministate.off = strlen(tab->hist_cur->h);
-	ministate.len = ministate.off;
+	ministate.curs = strchr(ministate.buf, '\0');
 }
 
 static void
@@ -795,75 +793,72 @@ global_key_unbound(void)
 static void
 cmd_mini_delete_char(struct tab *tab)
 {
+	char *n;
+
 	minibuffer_taint_hist();
 
-	if (ministate.len == 0 || ministate.off == ministate.len)
+	if (*(n = utf8_next_cp(ministate.curs)) == '\0')
 		return;
 
-	memmove(&ministate.buf[ministate.off],
-	    &ministate.buf[ministate.off+1],
-	    ministate.len - ministate.off + 1);
-	ministate.len--;
+	memmove(ministate.curs, n, strlen(n)+1);
 }
 
 static void
 cmd_mini_delete_backward_char(struct tab *tab)
 {
+	char *p;
+
 	minibuffer_taint_hist();
 
-	if (ministate.len == 0 || ministate.off == 0)
+	if ((p = utf8_prev_cp(ministate.curs, ministate.buf)) == ministate.buf)
 		return;
 
-	memmove(&ministate.buf[ministate.off-1],
-	    &ministate.buf[ministate.off],
-	    ministate.len - ministate.off + 1);
-	ministate.off--;
-	ministate.len--;
+	memmove(p, ministate.curs, strlen(ministate.curs)+1);
 }
 
 static void
 cmd_mini_forward_char(struct tab *tab)
 {
-	if (ministate.off == ministate.len)
+	if (*ministate.curs == '\0')
 		return;
-	ministate.off++;
+	ministate.curs = utf8_next_cp(ministate.curs);
+	ministate.cpoff++;
 }
 
 static void
 cmd_mini_backward_char(struct tab *tab)
 {
-	if (ministate.off == 0)
+	if (ministate.cpoff == 0)
 		return;
-	ministate.off--;
+	ministate.cpoff--;
+	ministate.curs = utf8_prev_cp(ministate.curs-1, ministate.buf);
 }
 
 static void
 cmd_mini_move_end_of_line(struct tab *tab)
 {
-	ministate.off = ministate.len;
+	ministate.curs = strchr(ministate.buf, '\0');
+	ministate.cpoff = utf8_cplen(ministate.buf);
 }
 
 static void
 cmd_mini_move_beginning_of_line(struct tab *tab)
 {
-	ministate.off = 0;
+	ministate.curs = ministate.buf;
+	ministate.cpoff = 0;
 }
 
 static void
 cmd_mini_kill_line(struct tab *tab)
 {
 	minibuffer_taint_hist();
-
-        if (ministate.off == ministate.len)
-		return;
-	ministate.buf[ministate.off] = '\0';
-	ministate.len -= ministate.off;
+	*ministate.curs = '\0';
 }
 
 static void
 cmd_mini_abort(struct tab *tab)
 {
-        ministate.abortfn();
+	ministate.abortfn();
 }
 
 static void
@@ -891,10 +886,8 @@ cmd_mini_previous_history_element(struct tab *tab)
 		ministate.hist_off--;
 	}
 
-	if (ministate.hist_cur != NULL) {
-		ministate.off = 0;
-		ministate.len = strlen(ministate.hist_cur->h);
-	}
+	if (ministate.hist_cur != NULL)
+		ministate.curs = ministate.hist_cur->h;
 }
 
 static void
@@ -915,10 +908,8 @@ cmd_mini_next_history_element(struct tab *tab)
 		ministate.hist_off++;
 	}
 
-	if (ministate.hist_cur != NULL) {
-		ministate.off = 0;
-		ministate.len = strlen(ministate.hist_cur->h);
-	}
+	if (ministate.hist_cur != NULL)
+		ministate.curs = ministate.hist_cur->h;
 }
 
 static void
@@ -959,26 +950,29 @@ minibuffer_taint_hist(void)
 static void
 minibuffer_self_insert(void)
 {
+	char	tmp[5] = {0};
+	size_t	len;
+
 	minibuffer_taint_hist();
 
-	if (ministate.len == sizeof(ministate.buf) -1)
+	if (thiskey.cp == 0)
 		return;
 
-	/* TODO: utf8 handling! */
+	len = utf8_encode(thiskey.cp, tmp);
+	if (ministate.curs + len > ministate.buf + sizeof(ministate.buf) - 1)
+		return;
 
-	memmove(&ministate.buf[ministate.off+1],
-	    &ministate.buf[ministate.off],
-	    ministate.len - ministate.off + 1);
-	ministate.buf[ministate.off] = thiskey.key;
-	ministate.off++;
-	ministate.len++;
+	memmove(ministate.curs + len, ministate.curs, strlen(ministate.curs)+1);
+	memcpy(ministate.curs, tmp, len);
+	ministate.curs = utf8_next_cp(ministate.curs);
+	ministate.cpoff++;
 }
 
 static void
 eecmd_self_insert(void)
 {
-	if (thiskey.meta || isspace(thiskey.key) ||
-	    !isgraph(thiskey.key)) {
+	if (thiskey.meta || unicode_isspace(thiskey.cp) ||
+	    !unicode_isgraph(thiskey.cp)) {
 		global_key_unbound();
 		return;
 	}
@@ -1022,8 +1016,8 @@ ir_select(void)
 static void
 lu_self_insert(void)
 {
-	if (thiskey.meta || isspace(thiskey.key) ||
-	    !isgraph(thiskey.key)) {
+	if (thiskey.meta || unicode_isspace(thiskey.key) ||
+	    !unicode_isgraph(thiskey.key)) {
 		global_key_unbound();
 		return;
 	}
@@ -1426,10 +1420,12 @@ redraw_modeline(struct tab *tab)
 static void
 redraw_minibuffer(void)
 {
-	size_t skip = 0, off_x = 0, off_y = 0;
 	struct tab *tab;
+	size_t off_y, off_x = 0;
+	char *start;
 
 	werase(minibuf);
+
 	if (in_minibuffer) {
 		mvwprintw(minibuf, 0, 0, "%s", ministate.prompt);
 		if (ministate.hist_cur != NULL)
@@ -1439,37 +1435,33 @@ redraw_minibuffer(void)
 
 		getyx(minibuf, off_y, off_x);
 
-		while (ministate.off - skip > (size_t)COLS / 2) {
-			skip += MIN(ministate.off/4, 1);
+		start = ministate.hist_cur != NULL
+			? ministate.hist_cur->h
+			: ministate.buf;
+		while (utf8_swidth_between(start, ministate.curs) > (size_t)COLS/2) {
+			start = utf8_next_cp(start);
 		}
 
-		if (ministate.hist_cur != NULL)
-			wprintw(minibuf, "%s", ministate.hist_cur->h + skip);
-		else
-			wprintw(minibuf, "%s", ministate.buf + skip);
+		waddstr(minibuf, start);
 	}
 
-	if (ministate.curmesg != NULL) {
-		if (in_minibuffer)
-			wprintw(minibuf, "  [%s]", ministate.curmesg);
-		else
-			wprintw(minibuf, "%s", ministate.curmesg);
-	}
+	if (ministate.curmesg != NULL)
+                wprintw(minibuf, in_minibuffer ? "  [%s]" : "%s",
+		    ministate.curmesg);
 
 	if (!in_minibuffer && ministate.curmesg == NULL)
-		wprintw(minibuf, "%s", keybuf);
+		waddstr(minibuf, keybuf);
 
 	/* If nothing else, show the URL at point */
 	if (!in_minibuffer && ministate.curmesg == NULL && *keybuf == '\0') {
 		tab = current_tab();
 		if (tab->s.current_line != NULL &&
 		    tab->s.current_line->parent->type == LINE_LINK)
-			wprintw(minibuf, "%s",
-			    tab->s.current_line->parent->alt);
+			waddstr(minibuf, tab->s.current_line->parent->alt);
 	}
 
 	if (in_minibuffer)
-		wmove(minibuf, 0, off_x + ministate.off - skip);
+		wmove(minibuf, 0, off_x + utf8_swidth_between(start, ministate.curs));
 }
 
 static void
@@ -1625,8 +1617,8 @@ enter_minibuffer(void (*self_insert_fn)(void), void (*
 	ministate.donefn = donefn;
 	ministate.abortfn = abortfn;
 	memset(ministate.buf, 0, sizeof(ministate.buf));
-        ministate.off = 0;
-	ministate.len = 0;
+	ministate.curs = ministate.buf;
+	ministate.cpoff = 0;
 	strlcpy(ministate.buf, "", sizeof(ministate.prompt));
 
 	ministate.history = hist;
blob - 127fbb5153f75ff8a6135564ac27df0b9d7ae17c
blob + 98aa6ca7aa2f966abcac792d28ef44e1c84b3624
--- utf8.c
+++ utf8.c
@@ -64,25 +64,31 @@ utf8_decode(uint32_t* restrict state, uint32_t* restri
 /* end of the converter, utility functions ahead */
 
 /* encode cp in s.  s must be at least 4 bytes wide */
-void
+size_t
 utf8_encode(uint32_t cp, char *s)
 {
 	if (cp <= 0x7F) {
                 *s = (uint8_t)cp;
+		return 1;
 	} else if (cp <= 0x7FF) {
                 s[1] = (uint8_t)(( cp        & 0x3F ) + 0x80);
 		s[0] = (uint8_t)(((cp >>  6) & 0x1F) + 0xC0);
+		return 2;
 	} else if (cp <= 0xFFFF) {
                 s[2] = (uint8_t)(( cp        & 0x3F) + 0x80);
 		s[1] = (uint8_t)(((cp >>  6) & 0x3F) + 0x80);
 		s[0] = (uint8_t)(((cp >> 12) & 0x0F) + 0xE0);
+		return 3;
 	} else if (cp <= 0x10FFFF) {
                 s[3] = (uint8_t)(( cp        & 0x3F) + 0x80);
 		s[2] = (uint8_t)(((cp >>  6) & 0x3F) + 0x80);
 		s[1] = (uint8_t)(((cp >> 12) & 0x3F) + 0x80);
 		s[0] = (uint8_t)(((cp >> 18) & 0x07) + 0xF0);
-	} else
-                s[0] = '\0';
+		return 4;
+	} else {
+		s[0] = '\0';
+		return 0;
+	}
 }
 
 char *
@@ -159,3 +165,41 @@ utf8_swidth(const char *s)
 
 	return tot;
 }
+
+size_t
+utf8_swidth_between(const char *str, const char *end)
+{
+	size_t tot;
+	uint32_t cp = 0, state = 0;
+
+	tot = 0;
+	for (; *str && str < end; ++str)
+		if (!utf8_decode(&state, &cp, *str))
+			tot += utf8_chwidth(cp);
+	return tot;
+}
+
+char *
+utf8_next_cp(char *s)
+{
+	uint32_t cp = 0, state = 0;
+
+	for (; *s; ++s)
+		if (!utf8_decode(&state, &cp, *s))
+			break;
+	return s+1;
+}
+
+char *
+utf8_prev_cp(char *start, char *base)
+{
+	uint8_t c;
+
+	for (; start > base; start--) {
+		c = *start;
+                if ((c & 0xC0) != 0x80)
+			return start;
+	}
+
+	return base;
+}
blob - 88a155f7dac24ee2cba73a819c8ed0e2fd51ae35
blob + 5d0267624c08d1c1f99cedfe2af9e7b944e563d8
--- util.c
+++ util.c
@@ -16,6 +16,7 @@
 
 #include "telescope.h"
 
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
@@ -44,6 +45,22 @@ has_prefix(const char *str, const char *prfx)
 	return prfx[i] == '\0';
 }
 
+int
+unicode_isspace(uint32_t cp)
+{
+	if (cp < INT8_MAX)
+		return isspace(cp);
+	return 0;
+}
+
+int
+unicode_isgraph(uint32_t cp)
+{
+	if (cp < INT8_MAX)
+		return isgraph(cp);
+	return 1;
+}
+
 void
 dispatch_imsg(struct imsgbuf *ibuf, imsg_handlerfn **handlers, size_t size)
 {