oksh-noxz

[fork] Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
git clone https://noxz.tech/git/oksh-noxz.git
oksh-noxz

commit: 38a023f241e3c8a7dbc070c6a7415aad37a24b76
parent: 8cd753b4aa2caad09bce7697dbc5709ab9ff1dd6
author: Chris Noxz <chris@noxz.tech>
date:   Wed, 26 Jun 2024 19:14:17 +0200
Visually indicate the current vi mode
Mvi.c64++++++++++++++++----
1 file changed, 51 insertions(+), 13 deletions(-)
diff --git a/vi.c b/vi.c
@@ -41,6 +41,10 @@ struct edstate {
 	int	cursor;		/* byte# in cbuf having the cursor */
 };
 
+static const char vprompt_normal[] = "\\[\x1b[1;31m\\]cmd\\[\x1b[0m\\]";
+static const char vprompt_insert[] = "\\[\x1b[1;32m\\]ins\\[\x1b[0m\\]";
+static const char vprompt_replace[] = "\\[\x1b[1;33m\\]rep\\[\x1b[0m\\]";
+static void set_insert(int);
 
 static int	vi_hook(int);
 static void	vi_reset(char *, size_t);
@@ -779,21 +783,21 @@ vi_cmd(int argcnt, const char *cmd)
 			if (es->linelen != 0)
 				while (isu8cont(es->cbuf[++es->cursor]))
 					continue;
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'A':
 			modified = 1; hnum = hlast;
 			del_range(0, 0);
 			es->cursor = es->linelen;
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'S':
 			es->cursor = domove(1, "^", 1);
 			del_range(es->cursor, es->linelen);
 			modified = 1; hnum = hlast;
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'Y':
@@ -836,7 +840,7 @@ vi_cmd(int argcnt, const char *cmd)
 			}
 			if (*cmd == 'c') {
 				modified = 1; hnum = hlast;
-				insert = INSERT;
+				set_insert(INSERT);
 			}
 			break;
 
@@ -866,7 +870,7 @@ vi_cmd(int argcnt, const char *cmd)
 		case 'C':
 			modified = 1; hnum = hlast;
 			del_range(es->cursor, es->linelen);
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'D':
@@ -895,13 +899,13 @@ vi_cmd(int argcnt, const char *cmd)
 
 		case 'i':
 			modified = 1; hnum = hlast;
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'I':
 			modified = 1; hnum = hlast;
 			es->cursor = domove(1, "^", 1);
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'j':
@@ -968,7 +972,7 @@ vi_cmd(int argcnt, const char *cmd)
 					if (argcnt-- == 0)
 						break;
 			del_range(es->cursor, cur);
-			insert = INSERT;
+			set_insert(INSERT);
 			break;
 
 		case 'v':
@@ -1112,7 +1116,7 @@ vi_cmd(int argcnt, const char *cmd)
 					es->cursor--;
 				return -1;
 			}
-			insert = INSERT;
+			set_insert(INSERT);
 			}
 			break;
 
@@ -1322,7 +1326,7 @@ redo_insert(int count)
 	if (es->cursor > 0)
 		while (isu8cont(es->cbuf[--es->cursor]))
 			continue;
-	insert = 0;
+	set_insert(0);
 	return 0;
 }
 
@@ -2071,7 +2075,7 @@ expand_word(int command)
 	if (rval == 0 && i > 0)
 		es->cursor += i;
 	modified = 1; hnum = hlast;
-	insert = INSERT;
+	set_insert(INSERT);
 	lastac = 0;
 	refresh_line(0);
 	return rval;
@@ -2175,7 +2179,7 @@ complete_word(int command, int count)
 	x_free_words(nwords, words);
 
 	modified = 1; hnum = hlast;
-	insert = INSERT;
+	set_insert(INSERT);
 	lastac = 0;	 /* prevent this from being redone... */
 	refresh_line(0);
 
@@ -2237,10 +2241,44 @@ x_vi_zotc(int c)
 	x_putc(c);
 }
 
+static void
+set_insert(int nmode)
+{
+	int update = nmode != insert;
+	insert = nmode;
+
+	if (update)
+		ed_mov_opt(0, wbuf[1 - win]);
+}
+
 static void
 vi_pprompt(int full)
 {
-	pprompt(prompt + (full ? 0 : prompt_skip), prompt_trunc);
+	const char *prefix = (insert == 0       ? vprompt_normal :
+	                      insert == REPLACE ? vprompt_replace:
+	                                          vprompt_insert);
+	char *nprompt = calloc(strlen(prefix) + strlen(prompt) + 1, sizeof(char));
+	int start_index = 0, stop_index = 0, length = 0;
+	char *start, *stop;
+
+	if ((start = strchr(prompt, '[')) && (stop = strchr(prompt, ']'))) {
+		start_index = (int)(start - prompt);
+		stop_index  = (int)(stop - prompt);
+		length      = (int)(stop_index - start_index - 1);
+	}
+
+	if (promptlen(vprompt_insert, NULL) == length &&
+	    promptlen(vprompt_normal, NULL) == length &&
+	    promptlen(vprompt_replace, NULL) == length) {
+		strncpy(nprompt, prompt, start_index + 1);
+		strcat(nprompt, prefix);
+		strncat(nprompt, prompt + stop_index, strlen(prompt) - stop_index);
+	} else {
+		strcat(nprompt, prompt);
+	}
+
+	pprompt(nprompt + (full ? 0 : prompt_skip), prompt_trunc);
+	free(nprompt);
 }
 
 static void