vi: remove autoindent from otherwise empty lines
Lines that have no content apart from automatic indentation should be treated as empty when the user hits return or ESC. The implementation uses the global variable 'indentcol'. Usually this is zero. It can also be -1 to indicate an 'O' (open above) command, replacing the overloading of the tabstop option bit. A value greater than zero indicates that the current line has been autoindented to the given column (or that the autoindent has been adjusted with ctrl-D). Any other change to the line resets 'indentcol' to zero. Replace strspn() with ident_len(). The latter handles the unlikely case that it's called on the last line of a file which doesn't have a terminating newline. function old new delta char_insert 741 912 +171 indent_len - 42 +42 do_cmd 4781 4785 +4 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 217/0) Total: 217 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
16e2fa9049
commit
9659a8db1d
85
editors/vi.c
85
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
|
||||
|
Loading…
Reference in New Issue
Block a user