about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--edit.c43
-rw-r--r--edit.h14
2 files changed, 52 insertions, 5 deletions
diff --git a/edit.c b/edit.c
index bb92edf..0a409a4 100644
--- a/edit.c
+++ b/edit.c
@@ -193,6 +193,39 @@ int editInsert(struct Edit *e, wchar_t ch) {
 	return 0;
 }
 
+enum {
+	Esc = L'\33',
+};
+
+static int editViInsert(struct Edit *e, wchar_t ch) {
+	switch (ch) {
+		break; case Esc: {
+			e->vi.mode = EditViCommand;
+			return 0;
+		}
+		default: return editInsert(e, ch);
+	}
+}
+
+static int editViCommand(struct Edit *e, wchar_t ch) {
+	switch (ch) {
+		break; case L'i': e->vi.mode = EditViInsert;
+	}
+	return 0;
+}
+
+int editVi(struct Edit *e, wchar_t ch) {
+	int error;
+	switch (e->vi.mode) {
+		break; case EditViInsert: error = editViInsert(e, ch);
+		break; case EditViCommand: error = editViCommand(e, ch);
+	}
+	if (e->vi.mode == EditViCommand && e->pos == e->len && e->pos) {
+		e->pos--;
+	}
+	return error;
+}
+
 #ifdef TEST
 #undef NDEBUG
 #include <assert.h>
@@ -291,6 +324,16 @@ int main(void) {
 	fix(&e, "  foo  bar  ");
 	editFn(&e, EditCollapse);
 	assert(eq(&e, "foo bar\0"));
+
+	fix(&e, "foo");
+	assert(e.vi.mode == EditViInsert);
+	editVi(&e, Esc);
+	assert(e.vi.mode == EditViCommand);
+	assert(eq(&e, "fo\0o"));
+	editVi(&e, L'i');
+	assert(e.vi.mode == EditViInsert);
+	editVi(&e, L'b');
+	assert(eq(&e, "fob\0o"));
 }
 
 #endif /* TEST */
diff --git a/edit.h b/edit.h
index db0d416..535b575 100644
--- a/edit.h
+++ b/edit.h
@@ -28,17 +28,18 @@
 #include <stdbool.h>
 #include <stddef.h>
 
-enum EditMode {
-	EditInsert,
-};
-
 struct Edit {
-	enum EditMode mode;
 	wchar_t *buf;
 	size_t pos;
 	size_t len;
 	size_t cap;
 	struct Edit *cut;
+	struct {
+		enum EditViMode {
+			EditViInsert,
+			EditViCommand,
+		} mode;
+	} vi;
 };
 
 enum EditFn {
@@ -63,6 +64,9 @@ enum EditFn {
 // Perform an editing function.
 int editFn(struct Edit *e, enum EditFn fn);
 
+// Perform a vi editing function.
+int editVi(struct Edit *e, wchar_t ch);
+
 // Insert a character at the cursor.
 int editInsert(struct Edit *e, wchar_t ch);