vi: make de-indentation with ctrl-D more like vim

Commit ac6495f6f (vi: allow ctrl-D to reduce indentation) treated
ctrl-D during autoindent as a backspace.  This was adequate for
indentation using tabs but doesn't work well with the expandtab
option.  In the latter case it's necessary to backspace over all
the spaces.

Make ctrl-D work correctly when spaces are present in the indent.

Also, make it behave more like vim:

- ctrl-D is independent of autoindent;
- indentation is reduced even when the cursor isn't positioned at
  the end of the indent.

function                                             old     new   delta
char_insert                                          679     717     +38
get_column                                             -      37     +37
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 75/0)               Total: 75 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Ron Yorston 2021-04-17 09:25:47 +01:00 committed by Denys Vlasenko
parent 310ef23280
commit f277c9eebb

View File

@ -763,6 +763,11 @@ static int next_tabstop(int col)
return col + ((tabstop - 1) - (col % tabstop)); return col + ((tabstop - 1) - (col % tabstop));
} }
static int prev_tabstop(int col)
{
return col - ((col % tabstop) ?: tabstop);
}
static int next_column(char c, int co) static int next_column(char c, int co)
{ {
if (c == '\t') if (c == '\t')
@ -772,7 +777,6 @@ static int next_column(char c, int co)
return co + 1; return co + 1;
} }
#if ENABLE_FEATURE_VI_SETOPTS
static int get_column(char *p) static int get_column(char *p)
{ {
const char *r; const char *r;
@ -782,7 +786,6 @@ static int get_column(char *p)
co = next_column(*r, co); co = next_column(*r, co);
return co; return co;
} }
#endif
//----- Erase the Screen[] memory ------------------------------ //----- Erase the Screen[] memory ------------------------------
static void screen_erase(void) static void screen_erase(void)
@ -2113,14 +2116,23 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
if ((p[-1] != '\n') && (dot > text)) { if ((p[-1] != '\n') && (dot > text)) {
p--; p--;
} }
#if ENABLE_FEATURE_VI_SETOPTS } else if (c == 4) { // ctrl-D reduces indentation
} else if (c == 4 && autoindent) { // ctrl-D reduces indentation int prev;
q = begin_line(p); char *r, *bol;
len = strspn(q, " \t"); bol = begin_line(p);
if (len && q + len == p) { for (r = bol; r < end_line(p); ++r) {
p--; if (!isblank(*r))
p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); break;
} }
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
} else if (c == '\t' && expandtab) { // expand tab } else if (c == '\t' && expandtab) { // expand tab
int col = get_column(p); int col = get_column(p);
col = next_tabstop(col) - col + 1; col = next_tabstop(col) - col + 1;