summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2022-03-16 20:18:54 -0400
committerJune McEnroe <june@causal.agency>2022-03-16 20:21:00 -0400
commit714b4bc76a239a7802715f13104cdcafa1020e7c (patch)
treea91f1a69bca57a8aaa12257c64e8b28e8e07cc63
parentDocument using -S to connect over IPv4 or IPv6 (diff)
downloadcatgirl-714b4bc76a239a7802715f13104cdcafa1020e7c.tar.gz
catgirl-714b4bc76a239a7802715f13104cdcafa1020e7c.zip
Skip non-spacing when moving and deleting by "character"
I uh... don't think I can write tests for this, since macOS's wcwidth
is notoriously useless.
-rw-r--r--edit.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/edit.c b/edit.c
index bb92edf..effb623 100644
--- a/edit.c
+++ b/edit.c
@@ -105,13 +105,29 @@ int editDelete(struct Edit *e, bool cut, size_t index, size_t count) {
 	return 0;
 }
 
+static size_t prevSpacing(const struct Edit *e, size_t pos) {
+	if (!pos) return 0;
+	do {
+		pos--;
+	} while (pos && !wcwidth(e->buf[pos]));
+	return pos;
+}
+
+static size_t nextSpacing(const struct Edit *e, size_t pos) {
+	if (pos == e->len) return e->len;
+	do {
+		pos++;
+	} while (pos < e->len && !wcwidth(e->buf[pos]));
+	return pos;
+}
+
 int editFn(struct Edit *e, enum EditFn fn) {
 	int ret = 0;
 	switch (fn) {
 		break; case EditHead: e->pos = 0;
 		break; case EditTail: e->pos = e->len;
-		break; case EditPrev: if (e->pos) e->pos--;
-		break; case EditNext: if (e->pos < e->len) e->pos++;
+		break; case EditPrev: e->pos = prevSpacing(e, e->pos);
+		break; case EditNext: e->pos = nextSpacing(e, e->pos);
 		break; case EditPrevWord: {
 			while (e->pos && !isword(e->buf[e->pos-1])) e->pos--;
 			while (e->pos && isword(e->buf[e->pos-1])) e->pos--;
@@ -129,10 +145,12 @@ int editFn(struct Edit *e, enum EditFn fn) {
 			ret = editDelete(e, true, e->pos, e->len - e->pos);
 		}
 		break; case EditDeletePrev: {
-			if (e->pos) editDelete(e, false, --e->pos, 1);
+			size_t prev = prevSpacing(e, e->pos);
+			editDelete(e, false, prev, e->pos - prev);
+			e->pos = prev;
 		}
 		break; case EditDeleteNext: {
-			editDelete(e, false, e->pos, 1);
+			editDelete(e, false, e->pos, nextSpacing(e, e->pos) - e->pos);
 		}
 		break; case EditDeletePrevWord: {
 			if (!e->pos) break;