From 47c3eaa22f7bbdc1d397c3d29beae33139beecde Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Apr 2021 12:04:22 +0100 Subject: [PATCH] vi: correct autoindent for 'O' command 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 Signed-off-by: Denys Vlasenko --- 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