diff options
-rw-r--r-- | editors/vi.c | 85 |
1 files changed, 59 insertions, 26 deletions
diff --git a/editors/vi.c b/editors/vi.c index 36116e6..d85cdd9 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -307,7 +307,6 @@ 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" \ @@ -316,15 +315,10 @@ 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 expandtab (0) #define err_method (0) -#define openabove (0) -#define set_openabove() ((void)0) -#define clear_openabove() ((void)0) #endif #if ENABLE_FEATURE_VI_READONLY @@ -380,6 +374,9 @@ struct globals { #if ENABLE_FEATURE_VI_SEARCH char *last_search_pattern; // last pattern from a '/' or '?' search #endif +#if ENABLE_FEATURE_VI_SETOPTS + int indentcol; // column of recently autoindent, 0 or -1 +#endif // former statics #if ENABLE_FEATURE_VI_YANKMARK @@ -503,6 +500,7 @@ struct globals { #define ioq_start (G.ioq_start ) #define dotcnt (G.dotcnt ) #define last_search_pattern (G.last_search_pattern) +#define indentcol (G.indentcol ) #define edit_file__cur_line (G.edit_file__cur_line) #define refresh__old_offset (G.refresh__old_offset) @@ -2103,16 +2101,26 @@ static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at return bias; } +// find number of characters in indent, p must be at beginning of line +static size_t indent_len(char *p) +{ + char *r = p; + + while (r < (end - 1) && isblank(*r)) + r++; + return r - p; +} + #if !ENABLE_FEATURE_VI_UNDO #define char_insert(a,b,c) char_insert(a,b) #endif static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' { #if ENABLE_FEATURE_VI_SETOPTS - char *q; size_t len; int col, ntab, nspc; #endif + char *bol = begin_line(p); if (c == 22) { // Is this an ctrl-V? p += stupid_insert(p, '^'); // use ^ to indicate literal next @@ -2134,22 +2142,33 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' if ((p[-1] != '\n') && (dot > text)) { p--; } - } else if (c == 4) { // ctrl-D reduces indentation - int prev; - char *r, *bol; - bol = begin_line(p); - for (r = bol; r < end_line(p); ++r) { - if (!isblank(*r)) - break; +#if ENABLE_FEATURE_VI_SETOPTS + if (autoindent) { + len = indent_len(bol); + if (len && get_column(bol + len) == indentcol) { + // remove autoindent from otherwise empty line + text_hole_delete(bol, bol + len - 1, undo); + p = bol; + } } - - prev = prev_tabstop(get_column(r)); +#endif + } else if (c == 4) { // ctrl-D reduces indentation + char *r = bol + indent_len(bol); + int prev = prev_tabstop(get_column(r)); while (r > bol && get_column(r) > prev) { if (p > bol) p--; r--; r = text_hole_delete(r, r, ALLOW_UNDO_QUEUED); } + +#if ENABLE_FEATURE_VI_SETOPTS + if (autoindent && indentcol && r == end_line(p)) { + // record changed size of autoindent + indentcol = get_column(p); + return p; + } +#endif #if ENABLE_FEATURE_VI_SETOPTS } else if (c == '\t' && expandtab) { // expand tab col = get_column(p); @@ -2188,12 +2207,23 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' } if (autoindent && c == '\n') { // auto indent the new line // use indent of current/previous line - q = openabove ? p : prev_line(p); - len = strspn(q, " \t"); // space or tab - if (openabove) - p--; // indent goes before newly inserted NL + bol = indentcol < 0 ? p : prev_line(p); + len = indent_len(bol); + col = get_column(bol + len); + + if (len && col == indentcol) { + // previous line was empty except for autoindent + // move the indent to the current line + memmove(bol + 1, bol, len); + *bol = '\n'; + return p; + } + + if (indentcol < 0) + p--; // open above, indent before newly inserted NL + if (len) { - col = get_column(q + len); + indentcol = col; if (expandtab) { ntab = 0; nspc = col; @@ -2208,11 +2238,14 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' memset(p, '\t', ntab); p += ntab; memset(p, ' ', nspc); - p += nspc; + return p + nspc; } } #endif } +#if ENABLE_FEATURE_VI_SETOPTS + indentcol = 0; +#endif return p; } @@ -2587,7 +2620,6 @@ 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; @@ -4050,17 +4082,18 @@ static void do_cmd(int c) break; case 'O': // O- open an empty line above dot_begin(); - set_openabove(); +#if ENABLE_FEATURE_VI_SETOPTS + indentcol = -1; +#endif 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 + // done in char_insert() for 'O'+autoindent dot_prev(); } - clear_openabove(); goto dc_i; break; case 'R': // R- continuous Replace char |