about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2022-03-12 17:52:44 -0500
committerJune McEnroe <june@causal.agency>2022-03-12 17:52:44 -0500
commit186180700c55c224dbf69555debd2a07f52aa19a (patch)
tree1ba9c942d518c057ad95e0e47324478b1b795d24
parentTreat C-v as an emacs key (diff)
downloadcatgirl-186180700c55c224dbf69555debd2a07f52aa19a.tar.gz
catgirl-186180700c55c224dbf69555debd2a07f52aa19a.zip
Implement vi R and r
-rw-r--r--edit.c53
-rw-r--r--edit.h1
2 files changed, 40 insertions, 14 deletions
diff --git a/edit.c b/edit.c
index 25341d1..e7cb62e 100644
--- a/edit.c
+++ b/edit.c
@@ -202,27 +202,37 @@ enum {
 };
 
 static int editViInsert(struct Edit *e, wchar_t ch) {
-	if (e->vi.lnext) {
-		e->vi.lnext = false;
-		return editInsert(e, ch);
-	}
-	switch (ch) {
-		break; case Erase:  return editFn(e, EditDeletePrev);
-		break; case Kill:   return editFn(e, EditDeleteHead);
-		break; case LNext:  e->vi.lnext = true;
-		break; case WErase: return editFn(e, EditDeletePrevWord);
-		break; case Esc: {
-			if (e->pos) e->pos--;
-			e->vi.mode = EditViCommand;
+	if (!e->vi.lnext) {
+		switch (ch) {
+			break; case Erase:  return editFn(e, EditDeletePrev);
+			break; case Kill:   return editFn(e, EditDeleteHead);
+			break; case LNext:  e->vi.lnext = true; return 0;
+			break; case WErase: return editFn(e, EditDeletePrevWord);
+			break; case Esc: {
+				if (e->pos) e->pos--;
+				e->vi.mode = EditViCommand;
+				return 0;
+			}
 		}
-		break; default: return editInsert(e, ch);
+	}
+	e->vi.lnext = false;
+	if (e->vi.verb == 'R' && e->pos < e->len) {
+		e->buf[e->pos] = ch;
+		e->pos++;
+	} else if (e->vi.verb == 'r' && e->pos < e->len) {
+		e->buf[e->pos] = ch;
+		e->vi.mode = EditViCommand;
+	} else {
+		return editInsert(e, ch);
 	}
 	return 0;
 }
 
 static int editViCommand(struct Edit *e, wchar_t ch) {
 	switch (ch) {
-		break; case L'i': e->vi.mode = EditViInsert;
+		break; case L'R': e->vi.verb = 'R'; e->vi.mode = EditViInsert;
+		break; case L'i': e->vi.verb = 'i'; e->vi.mode = EditViInsert;
+		break; case L'r': e->vi.verb = 'r'; e->vi.mode = EditViInsert;
 	}
 	return 0;
 }
@@ -261,6 +271,13 @@ static bool eq(struct Edit *e, const char *str1) {
 }
 
 #define editFn(...) assert(0 == editFn(__VA_ARGS__))
+#define editVi(...) assert(0 == editVi(__VA_ARGS__))
+
+static void vi(struct Edit *e, const char *str) {
+	for (const char *ch = str; *ch; ++ch) {
+		editVi(e, *ch);
+	}
+}
 
 int main(void) {
 	struct Edit cut = {0};
@@ -358,6 +375,14 @@ int main(void) {
 	assert(eq(&e, "foo \33\0"));
 	editVi(&e, Kill);
 	assert(eq(&e, "\0"));
+
+	fix(&e, "foo");
+	vi(&e, "\33rx");
+	assert(e.vi.mode == EditViCommand);
+	assert(eq(&e, "fo\0x"));
+	vi(&e, "Robar\33");
+	assert(e.vi.mode == EditViCommand);
+	assert(eq(&e, "fooba\0r"));
 }
 
 #endif /* TEST */
diff --git a/edit.h b/edit.h
index 8ad382b..382e9d2 100644
--- a/edit.h
+++ b/edit.h
@@ -40,6 +40,7 @@ struct Edit {
 			EditViCommand,
 		} mode;
 		bool lnext;
+		char verb;
 	} vi;
 };