diff --git a/led.c b/led.c
index 7a124730..0bd9deee 100644
--- a/led.c
+++ b/led.c
@@ -281,7 +281,7 @@ static int led_lastword(char *s)
 }
 
 static void led_printparts(sbuf *sb, int pre, int ps,
-	char *post, int postn, int ai_max)
+	char *post, int postn, int ai_max, int print)
 {
 	if (!xled) {
 		sbuf_set(sb, '\0', 4)
@@ -309,8 +309,10 @@ static void led_printparts(sbuf *sb, int pre, int ps,
 	}
 	if (pos >= xleft + xcols || pos < xleft)
 		xleft = pos < xcols ? 0 : pos - xcols / 2;
-	syn_blockhl = -1;
-	led_crender(r->s, -1, vi_lncol, xleft, xleft + xcols - vi_lncol);
+	if (print) {
+		syn_blockhl = -1;
+		led_crender(sb->s+ps, -1, vi_lncol, xleft, xleft + xcols - vi_lncol);
+	}
 	term_pos(-1, led_pos(r->s, pos) + vi_lncol);
 	sbufn_cut(sb, psn)
 	rstate -= 2;
@@ -416,7 +418,8 @@ static void led_line(sbuf *sb, int ps, int pre, char *post, int postn,
 	int c, i, lsug = 0, sug_pt = -1;
 	char *cs, *sug = NULL, *_sug = NULL;
 	while (1) {
-		led_printparts(sb, pre, ps, post, postn, ai_max);
+		led_printparts(sb, pre, ps, post, postn, ai_max, !memchr("ABCD", vi_insmov, 4));
+		vi_insmov = -1;
 		len = sb->s_n;
 		c = term_read();
 		switch (c) {
@@ -608,6 +611,20 @@ static void led_line(sbuf *sb, int ps, int pre, char *post, int postn,
 			else
 				led_redraw(sb->s, 0, orow, lsh);
 			continue;
+		case '\033':;	/* Arrow keys */
+			char cbuf[1];
+			cbuf[0] = '\0';
+			int fl = fcntl(STDIN_FILENO, F_GETFL);
+			fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK);
+			read(STDIN_FILENO, cbuf, 1);
+			if (*cbuf == '[') {
+				read(STDIN_FILENO, cbuf, 1);
+				vi_insmov = *cbuf;
+				fcntl(STDIN_FILENO, F_SETFL, fl);
+				goto _leave;
+			}
+			fcntl(STDIN_FILENO, F_SETFL, fl);
+			goto leave;
 		case TK_CTL('o'):;
 			led_modeswap();
 			continue;
@@ -623,6 +640,7 @@ static void led_line(sbuf *sb, int ps, int pre, char *post, int postn,
 	}
 leave:
 	vi_insmov = c;
+_leave:
 	*key = c;
 }
 
@@ -656,7 +674,7 @@ void led_input(sbuf *sb, char **post, int postn, int row, int lsh)
 			return;
 		}
 		sbuf_chr(sb, key)
-		led_printparts(sb, -1, ps, "", 0, 0);
+		led_printparts(sb, -1, ps, "", 0, 0, 1);
 		term_chr('\n');
 		term_room(1);
 		xrow++;
diff --git a/vi.c b/vi.c
index b83a1df9..67d21331 100644
--- a/vi.c
+++ b/vi.c
@@ -821,6 +821,8 @@ static void vi_indents(char *ln, int *l)
 	*l = ln - pln;
 }
 
+static int lmodified;
+
 static void vi_change(int r1, int o1, int r2, int o2, int lnmode)
 {
 	char *post, *_post, *ln = lbuf_get(xb, r1);
@@ -853,6 +855,7 @@ static void vi_change(int r1, int o1, int r2, int o2, int lnmode)
 		lbuf_edit(xb, sb->s, r1, r2 + 1, o1, xoff);
 	free(sb->s);
 	free(_post);
+	lmodified = 1;
 }
 
 static void vi_case(int r1, int o1, int r2, int o2, int lnmode, int cmd)
@@ -1022,7 +1025,9 @@ static void vc_insert(int cmd)
 	if (sb->s_n != l1 || cmdo || !ln) {
 		sbufn_str(sb, post)
 		lbuf_edit(xb, sb->s, row, row + !cmdo, off, xoff);
-	}
+		lmodified = 1;
+	} else
+		lmodified = 0;
 	free(sb->s);
 }
 
@@ -1489,6 +1494,37 @@ void vi(int init)
 				vc_insert(c);
 				ins:
 				vi_mod |= !xpac && xrow == orow ? 8 : 1;
+				switch (vi_insmov) {
+				case 'A':	/* ↑ */
+					term_back(!lmodified ? c : 'i');
+					if (lmodified)
+						vi_col = vi_off2col(xb, xrow, xoff);
+					xrow--;
+					xrow = xrow < 0 ? 0 : xrow;
+					xoff = vi_col2off(xb, xrow, vi_col);
+					lmodified = 0;
+					goto _break;
+				case 'B':	/* ↓ */
+					term_back(!lmodified ? c : 'i');
+					if (lmodified)
+						vi_col = vi_off2col(xb, xrow, xoff);
+					xrow++;
+					xoff = vi_col2off(xb, xrow, vi_col);
+					lmodified = 0;
+					goto _break;
+				case 'D':	/* ← */
+					term_back('i');
+					xoff--;
+					xoff = xoff < 0 ? 0 : xoff;
+					vi_col = vi_off2col(xb, xrow, xoff);
+					goto _break;
+				case 'C':	/* → */
+					term_back(*uc_chr(lbuf_get(xb, xrow), xoff+2) ? 'i' : 'A');
+					xoff++;
+					if (*uc_chr(lbuf_get(xb, xrow), xoff))
+						vi_col = vi_off2col(xb, xrow, xoff);
+					goto _break;
+				}
 				if (vi_insmov == 127) {
 					if (xrow && !(xoff > 0 && lbuf_eol(xb, xrow, 1))) {
 						xrow--;
@@ -1501,6 +1537,9 @@ void vi(int init)
 				if (c != 'A' && c != 'C')
 					xoff--;
 				break;
+				_break:
+				vi_mod = 0;
+				break;
 			case 'J':
 				vc_join(vi_joinmode, vi_arg <= 1 ? 2 : vi_arg);
 				break;
