Commit Diff


commit - b60507ee6753bf11be13aee78316315edf433587
commit + 6d24bfb3ca185665e8a7fa4e5f88434690f4272d
blob - 196f62dfe357c6603e7b34b29c6bfae0aa17fb56
blob + a5e03b8df279c4a7c853b64d6beaee58b93b6300
--- cmd.c
+++ cmd.c
@@ -22,6 +22,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <grapheme.h>
+
 #include "certs.h"
 #include "cmd.h"
 #include "compl.h"
@@ -111,17 +113,46 @@ cmd_next_line(struct buffer *buffer)
 void
 cmd_backward_char(struct buffer *buffer)
 {
-	if (buffer->cpoff != 0)
-		buffer->cpoff--;
+	struct vline	*vl;
+	char		*text;
+	size_t		 left, off, point = 0;
+
+	if ((vl = buffer->current_line) == NULL)
+		return;
+
+	text = vl->parent->line + vl->from;
+	left = vl->len;
+
+	for (;;) {
+		off = grapheme_next_character_break_utf8(text, left);
+		if (point + off >= buffer->point_offset)
+			break;
+		point += off;
+		text += off;
+		left -= off;
+	}
+
+	buffer->point_offset = point;
 }
 
 void
 cmd_forward_char(struct buffer *buffer)
 {
-	if (buffer->current_line == NULL)
+	struct vline	*vl;
+	char		*text;
+	size_t		 left, off;
+
+	if ((vl = buffer->current_line) == NULL)
 		return;
-	if (buffer->current_line->cplen > buffer->cpoff)
-		buffer->cpoff++;
+
+	text = vl->parent->line + vl->from;
+	left = vl->len;
+
+	text += buffer->point_offset;
+	left -= buffer->point_offset;
+
+	off = grapheme_next_character_break_utf8(text, left);
+	buffer->point_offset += off;
 }
 
 void
@@ -151,7 +182,7 @@ cmd_forward_paragraph(struct buffer *buffer)
 void
 cmd_move_beginning_of_line(struct buffer *buffer)
 {
-	buffer->cpoff = 0;
+	buffer->point_offset = 0;
 }
 
 void
@@ -162,7 +193,7 @@ cmd_move_end_of_line(struct buffer *buffer)
 	vl = buffer->current_line;
 	if (vl == NULL)
 		return;
-	buffer->cpoff = vl->cplen;
+	buffer->point_offset = vl->len;
 }
 
 void
@@ -257,7 +288,7 @@ void
 cmd_beginning_of_buffer(struct buffer *buffer)
 {
 	buffer->current_line = TAILQ_FIRST(&buffer->vhead);
-	buffer->cpoff = 0;
+	buffer->point_offset = 0;
 	buffer->top_line = buffer->current_line;
 	buffer->line_off = 0;
 }
@@ -738,40 +769,50 @@ cmd_olivetti_mode(struct buffer *buffer)
 void
 cmd_mini_delete_char(struct buffer *buffer)
 {
-	char *line, *c, *n;
+	struct vline	*vl;
+	char		*text;
+	size_t		 old_point, gap, rest;
 
 	GUARD_READ_ONLY();
 
-	minibuffer_taint_hist();
-
-	line = buffer->current_line->parent->line + buffer->current_line->from;
-	c = utf8_nth(line, buffer->cpoff);
-	if (*c == '\0')
+	vl = buffer->current_line;
+	old_point = buffer->point_offset;
+	cmd_forward_char(buffer);
+	gap = buffer->point_offset - old_point;
+	if (gap == 0)
 		return;
-	n = utf8_next_cp(c);
 
-	memmove(c, n, strlen(n)+1);
+	minibuffer_taint_hist();
 
+	text = vl->parent->line + vl->from + old_point;
+	rest = vl->len - buffer->point_offset;
+	memmove(text, text + gap, rest);
+	buffer->point_offset = old_point;
+
 	recompute_completions(0);
 }
 
 void
 cmd_mini_delete_backward_char(struct buffer *buffer)
 {
-	char *line, *c, *p;
+	struct vline	*vl;
+	char		*text;
+	size_t		 old_point, gap, rest;
 
 	GUARD_READ_ONLY();
 
-	minibuffer_taint_hist();
-
-	line = buffer->current_line->parent->line + buffer->current_line->from;
-	c = utf8_nth(line, buffer->cpoff);
-	if (c == line)
+	vl = buffer->current_line;
+	old_point = buffer->point_offset;
+	cmd_backward_char(buffer);
+	gap = old_point - buffer->point_offset;
+	if (gap == 0)
 		return;
-	p = utf8_prev_cp(c-1, line);
+
+	minibuffer_taint_hist();
 
-	memmove(p, c, strlen(c)+1);
-	buffer->cpoff--;
+	text = vl->parent->line + vl->from + buffer->point_offset;
+	rest = vl->len - old_point;
+	memmove(text, text + gap, rest);
 
 	recompute_completions(0);
 }
@@ -786,7 +827,7 @@ cmd_mini_kill_line(struct buffer *buffer)
 	minibuffer_taint_hist();
 
 	line = buffer->current_line->parent->line + buffer->current_line->from;
-	c = utf8_nth(line, buffer->cpoff);
+	c = line + buffer->point_offset;
 	*c = '\0';
 
 	recompute_completions(0);
@@ -799,7 +840,7 @@ cmd_mini_kill_whole_line(struct buffer *buffer)
 
 	minibuffer_taint_hist();
 	*buffer->current_line->parent->line = '\0';
-	buffer->cpoff = 0;
+	buffer->point_offset = 0;
 
 	recompute_completions(0);
 }
blob - 84fb3401f3806491824997f7dbf3e61fa9e7b6bd
blob + 39a65d822fa0094de2c922da93c1c315408ff2b9
--- minibuffer.c
+++ minibuffer.c
@@ -26,6 +26,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <grapheme.h>
+
 #include "certs.h"
 #include "cmd.h"
 #include "defaults.h"
@@ -171,7 +173,8 @@ minibuffer_insert_current_candidate(void)
 
 	minibuffer_taint_hist();
 	strlcpy(ministate.buf, vl->parent->line, sizeof(ministate.buf));
-	ministate.buffer.cpoff = ministate.vline.cplen = utf8_cplen(ministate.buf);
+	ministate.buffer.point_offset = strlen(ministate.buf);
+	ministate.vline.len = strlen(ministate.buf);
 
 	return 0;
 }
@@ -227,8 +230,7 @@ minibuffer_taint_hist(void)
 	ministate.editing = 1;
 	strlcpy(ministate.buf, hist_cur(ministate.hist),
 	    sizeof(ministate.buf));
-	ministate.buffer.cpoff = 0;
-	ministate.vline.cplen = utf8_cplen(ministate.buf);
+	ministate.buffer.point_offset = 0;
 	ministate.buffer.current_line->parent->line = ministate.buf;
 }
 
@@ -253,15 +255,17 @@ minibuffer_self_insert(void)
 	if (thiskey.cp == 0)
 		return;
 
-	len = utf8_encode(thiskey.cp, tmp);
-	c = utf8_nth(ministate.buffer.current_line->parent->line,
-	    ministate.buffer.cpoff);
+	len = grapheme_encode_utf8(thiskey.cp, tmp, sizeof(tmp));
+
+	c = ministate.buffer.current_line->parent->line
+	    + ministate.buffer.current_line->from
+	    + ministate.buffer.point_offset;
 	if (c + len > ministate.buf + sizeof(ministate.buf) - 1)
 		return;
 
 	memmove(c + len, c, strlen(c)+1);
 	memcpy(c, tmp, len);
-	ministate.buffer.cpoff++;
+	ministate.buffer.point_offset += len;
 
 	recompute_completions(1);
 }
@@ -599,15 +603,15 @@ enter_minibuffer(struct minibuffer *minibuffer, const 
 	if (ministate.abortfn == NULL)
 		ministate.abortfn = exit_minibuffer;
 
-	ministate.buffer.cpoff = 0;
 	if (minibuffer->input) {
 		strlcpy(ministate.buf, minibuffer->input,
 		    sizeof(ministate.buf));
-		ministate.vline.cplen = utf8_cplen(ministate.buf);
-		ministate.buffer.cpoff = ministate.vline.cplen;
+		ministate.buffer.point_offset = strlen(ministate.buf);
+		ministate.vline.len = strlen(ministate.buf);
 	} else {
 		ministate.buf[0] = '\0';
-		ministate.vline.cplen = ministate.buffer.cpoff = 0;
+		ministate.buffer.point_offset = 0;
+		ministate.vline.len = 0;
 	}
 
 	ministate.buffer.current_line = &ministate.vline;
blob - 3520b8ccfe4a9e44bc7f12180e6c0e5c85bddfdc
blob + 3f7a73e3c48f1a88a5ba2c6846e2c4930cd0f8bc
--- telescope.h
+++ telescope.h
@@ -82,7 +82,6 @@ struct vline {
 	struct line		*parent;
 	size_t			 from;
 	size_t			 len;
-	size_t			 cplen;
 
 #define L_CONTINUATION	0x2
 	int			 flags;
@@ -125,7 +124,7 @@ struct buffer {
 	size_t			 line_max;
 	struct vline		*top_line;
 	struct vline		*current_line;
-	size_t			 cpoff;
+	size_t			 point_offset;
 
 	TAILQ_HEAD(, line)	 head;
 	TAILQ_HEAD(vhead, vline) vhead;
blob - f4317da5b1180f1a70852db4ec5e016213c36217
blob + 81a4a7734f9793f8d8ad1985024d95075580c30e
--- ui.c
+++ ui.c
@@ -200,7 +200,7 @@ save_excursion(struct excursion *place, struct buffer 
 	place->line_off = buffer->line_off;
 	place->top_line = buffer->top_line;
 	place->current_line = buffer->current_line;
-	place->cpoff = buffer->cpoff;
+	place->point_offset = buffer->point_offset;
 }
 
 void
@@ -211,7 +211,7 @@ restore_excursion(struct excursion *place, struct buff
 	buffer->line_off = place->line_off;
 	buffer->top_line = place->top_line;
 	buffer->current_line = place->current_line;
-	buffer->cpoff = place->cpoff;
+	buffer->point_offset = place->point_offset;
 }
 
 static void
@@ -226,13 +226,13 @@ restore_curs_x(struct buffer *buffer)
 
 	vl = buffer->current_line;
 	if (vl == NULL || vl->len == 0 || vl->parent == NULL)
-		buffer->curs_x = buffer->cpoff = 0;
+		buffer->curs_x = buffer->point_offset = 0;
 	else if (vl->parent->data != NULL) {
 		text = vl->parent->data;
-		buffer->curs_x = utf8_snwidth(text + 1, buffer->cpoff) + 1;
+		buffer->curs_x = utf8_snwidth(text, buffer->point_offset);
 	} else {
 		text = vl->parent->line + vl->from;
-		buffer->curs_x = utf8_snwidth(text, buffer->cpoff);
+		buffer->curs_x = utf8_snwidth(text, buffer->point_offset);
 	}
 
 	/* small hack: don't olivetti-mode the download pane */
@@ -969,7 +969,7 @@ do_redraw_minibuffer(void)
 	if (!ministate.editing)
 		start = hist_cur(ministate.hist);
 	line = buffer->current_line->parent->line + buffer->current_line->from;
-	c = utf8_nth(line, buffer->cpoff);
+	c = line + buffer->point_offset;
 	while (utf8_swidth_between(start, c) > (size_t)COLS/2) {
 		start = utf8_next_cp(start);
 	}
blob - 045a2712523fc2f2729b7404174da25a8da3616b
blob + d7061ea4db14f8fe650c8b087523e180da9efec8
--- ui.h
+++ ui.h
@@ -27,7 +27,7 @@ struct excursion {
 	size_t		 line_off;
 	struct vline	*current_line;
 	struct vline	*top_line;
-	size_t		 cpoff;
+	size_t		 point_offset;
 };
 
 enum pairs {
blob - 1433aacce3f0e55b5875538c3ce4bd8fcea4e490
blob + e0e97f5607bfff0056604783be9887e989c3a1bc
--- utf8.c
+++ utf8.c
@@ -166,20 +166,16 @@ utf8_chwidth(uint32_t cp)
 	return wcwidth((wchar_t)cp);
 }
 
-/* NOTE: n is the number of codepoints, NOT the byte length.  In
- * other words, s MUST be NUL-terminated. */
 size_t
-utf8_snwidth(const char *s, size_t n)
+utf8_snwidth(const char *s, size_t off)
 {
 	size_t i, tot;
 	uint32_t cp = 0, state = 0;
 
 	tot = 0;
-	for (i = 0; *s && i < n; ++s)
-		if (!decode(&state, &cp, *s)) {
-			i++;
+	for (i = 0; i < off; ++i)
+		if (!decode(&state, &cp, s[i]))
 			tot += utf8_chwidth(cp);
-		}
 
 	return tot;
 }
blob - 3054f79000e3cbe7f8e905d1994cc436fccd7cf4
blob + b60ff4d9cc3db8f1cb3223f1a45a3768914373de
--- wrap.c
+++ wrap.c
@@ -92,7 +92,6 @@ push_line(struct buffer *buffer, struct line *l, const
 	if (len != 0) {
 		vl->from = buf - l->line;
 		vl->len = len;
-		vl->cplen = utf8_ncplen(buf, vl->len);
 	}
 	vl->flags = flags;