[git commit] vi: correct autoindent for 'O' command

Denys Vlasenko vda.linux at googlemail.com
Thu Apr 15 11:09:12 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=47c3eaa22f7bbdc1d397c3d29beae33139beecde
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Opening a line above the current line with the 'O' command should
use the current, not previous, line to determine how much to
autoindent.

function                                             old     new   delta
char_insert                                          531     563     +32
do_cmd                                              4746    4723     -23
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 32/-23)              Total: 9 bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/vi.c | 41 +++++++++++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 0a82f9e38..b77406967 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -286,6 +286,7 @@ struct globals {
 	int text_size;		// size of the allocated buffer
 
 	// the rest
+#if ENABLE_FEATURE_VI_SETOPTS
 	smallint vi_setops;     // set by setops()
 #define VI_AUTOINDENT (1 << 0)
 #define VI_ERR_METHOD (1 << 1)
@@ -296,6 +297,7 @@ struct globals {
 #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
 #define ignorecase (vi_setops & VI_IGNORECASE)
 #define showmatch  (vi_setops & VI_SHOWMATCH )
+#define openabove  (vi_setops & VI_TABSTOP   )
 // order of constants and strings must match
 #define OPTS_STR \
 		"ai\0""autoindent\0" \
@@ -303,6 +305,15 @@ struct globals {
 		"ic\0""ignorecase\0" \
 		"sm\0""showmatch\0" \
 		"ts\0""tabstop\0"
+#define set_openabove() (vi_setops |= VI_TABSTOP)
+#define clear_openabove() (vi_setops &= ~VI_TABSTOP)
+#else
+#define autoindent (0)
+#define err_method (0)
+#define openabove  (0)
+#define set_openabove() ((void)0)
+#define clear_openabove() ((void)0)
+#endif
 
 #if ENABLE_FEATURE_VI_READONLY
 	smallint readonly_mode;
@@ -2130,8 +2141,13 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
 			showmatching(p - 1);
 		}
 		if (autoindent && c == '\n') {	// auto indent the new line
-			q = prev_line(p);	// use prev line as template
+			// use current/previous line as template
+			q = openabove ? p : prev_line(p);
 			len = strspn(q, " \t"); // space or tab
+			if (openabove) {
+				p--;		// this replaces dot_prev() in do_cmd()
+				q += len;	// template will be shifted by text_hole_make()
+			}
 			if (len) {
 				uintptr_t bias;
 				bias = text_hole_make(p, len);
@@ -2445,6 +2461,7 @@ static void setops(char *args, int flg_no)
 	index = 1 << (index >> 1); // convert to VI_bit
 
 	if (index & VI_TABSTOP) {
+		// don't set this bit in vi_setops, it's reused as 'openabove'
 		int t;
 		if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
 			goto bad;
@@ -3841,19 +3858,19 @@ static void do_cmd(int c)
 			dot = next_line(dot);
 		dot_skip_over_ws();
 		break;
-	case 'O':			// O- open a empty line above
-		//    0i\n ESC -i
-		p = begin_line(dot);
-		if (p[-1] == '\n') {
+	case 'O':			// O- open an empty line above
+		dot_begin();
+		set_openabove();
+		goto dc3;
+	case 'o':			// o- open an empty line below
+		dot_end();
+ dc3:
+		dot = char_insert(dot, '\n', ALLOW_UNDO);
+		if (c == 'O' && !autoindent) {
+			// done in char_insert() for openabove+autoindent
 			dot_prev();
-	case 'o':			// o- open a empty line below; Yes, I know it is in the middle of the "if (..."
-			dot_end();
-			dot = char_insert(dot, '\n', ALLOW_UNDO);
-		} else {
-			dot_begin();	// 0
-			dot = char_insert(dot, '\n', ALLOW_UNDO);	// i\n ESC
-			dot_prev();	// -
 		}
+		clear_openabove();
 		goto dc_i;
 		break;
 	case 'R':			// R- continuous Replace char


More information about the busybox-cvs mailing list