vi: improvements to range selection
Rewrite find_range(), pushing quite a bit of code from do_cmd() down into it. - The commands 'y', 'd', 'c', '<' and '>' can be given twice to specify a whole-line range. BusyBox vi actually accepted any second character from that group, e.g. 'dc' or '<y', with the latter being accepted even if yank was disabled. Require the two characters to match. - '<' and '>' commands followed by ESC incorrectly issued an alert. - Allow search commands and a marker (specified as "y'a", for example) to define a range for those operators that support it. function old new delta find_range 518 707 +189 .rodata 105119 105133 +14 get_motion_char 68 - -68 do_cmd 4860 4695 -165 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/1 up/down: 203/-233) Total: -30 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
7ce0e75c1f
commit
b7b1119d9f
83
editors/vi.c
83
editors/vi.c
@ -3079,22 +3079,38 @@ static int at_eof(const char *s)
|
|||||||
return ((s == end - 2 && s[1] == '\n') || s == end - 1);
|
return ((s == end - 2 && s[1] == '\n') || s == end - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_range(char **start, char **stop, char c)
|
static int find_range(char **start, char **stop, int cmd)
|
||||||
{
|
{
|
||||||
char *save_dot, *p, *q, *t;
|
char *save_dot, *p, *q, *t;
|
||||||
int buftype = -1;
|
int buftype = -1;
|
||||||
|
int c;
|
||||||
|
|
||||||
save_dot = dot;
|
save_dot = dot;
|
||||||
p = q = dot;
|
p = q = dot;
|
||||||
|
|
||||||
if (strchr("cdy><", c)) {
|
#if ENABLE_FEATURE_VI_YANKMARK
|
||||||
|
if (cmd == 'Y') {
|
||||||
|
c = 'y';
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
c = get_motion_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_VI_YANKMARK
|
||||||
|
if ((cmd == 'Y' || cmd == c) && strchr("cdy><", c)) {
|
||||||
|
#else
|
||||||
|
if (cmd == c && strchr("cd><", c)) {
|
||||||
|
#endif
|
||||||
// these cmds operate on whole lines
|
// these cmds operate on whole lines
|
||||||
buftype = WHOLE;
|
buftype = WHOLE;
|
||||||
if (--cmdcnt > 0)
|
if (--cmdcnt > 0)
|
||||||
do_cmd('j');
|
do_cmd('j');
|
||||||
} else if (strchr("^%$0bBeEfFtTh|{}\b\177", c)) {
|
} else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) {
|
||||||
// These cmds operate on char positions
|
// Most operate on char positions within a line. Of those that
|
||||||
buftype = PARTIAL;
|
// don't '%' needs no special treatment, search commands are
|
||||||
|
// marked as MULTI and "{}" are handled below.
|
||||||
|
buftype = strchr("nN/?", c) ? MULTI : PARTIAL;
|
||||||
do_cmd(c); // execute movement cmd
|
do_cmd(c); // execute movement cmd
|
||||||
if (p == dot) // no movement is an error
|
if (p == dot) // no movement is an error
|
||||||
buftype = -1;
|
buftype = -1;
|
||||||
@ -3104,7 +3120,16 @@ static int find_range(char **start, char **stop, char c)
|
|||||||
// step back one char, but not if we're at end of file
|
// step back one char, but not if we're at end of file
|
||||||
if (dot > p && !at_eof(dot))
|
if (dot > p && !at_eof(dot))
|
||||||
dot--;
|
dot--;
|
||||||
} else if (strchr("GHL+-jk\r\n", c)) {
|
t = dot;
|
||||||
|
// don't include trailing WS as part of word
|
||||||
|
while (dot > p && isspace(*dot)) {
|
||||||
|
if (*dot-- == '\n')
|
||||||
|
t = dot;
|
||||||
|
}
|
||||||
|
// for non-change operations WS after NL is not part of word
|
||||||
|
if (cmd != 'c' && dot != p && *dot != '\n')
|
||||||
|
dot = t;
|
||||||
|
} else if (strchr("GHL+-jk'\r\n", c)) {
|
||||||
// these operate on whole lines
|
// these operate on whole lines
|
||||||
buftype = WHOLE;
|
buftype = WHOLE;
|
||||||
do_cmd(c); // execute movement cmd
|
do_cmd(c); // execute movement cmd
|
||||||
@ -3119,8 +3144,11 @@ static int find_range(char **start, char **stop, char c)
|
|||||||
dot--;
|
dot--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buftype == -1)
|
if (buftype == -1) {
|
||||||
|
if (c != 27)
|
||||||
|
indicate_error();
|
||||||
return buftype;
|
return buftype;
|
||||||
|
}
|
||||||
|
|
||||||
q = dot;
|
q = dot;
|
||||||
if (q < p) {
|
if (q < p) {
|
||||||
@ -3131,7 +3159,7 @@ static int find_range(char **start, char **stop, char c)
|
|||||||
|
|
||||||
// movements which don't include end of range
|
// movements which don't include end of range
|
||||||
if (q > p) {
|
if (q > p) {
|
||||||
if (strchr("^0bBFTh|\b\177", c)) {
|
if (strchr("^0bBFThnN/?|\b\177", c)) {
|
||||||
q--;
|
q--;
|
||||||
} else if (strchr("{}", c)) {
|
} else if (strchr("{}", c)) {
|
||||||
buftype = (p == begin_line(p) && (*q == '\n' || at_eof(q))) ?
|
buftype = (p == begin_line(p) && (*q == '\n' || at_eof(q))) ?
|
||||||
@ -3144,7 +3172,7 @@ static int find_range(char **start, char **stop, char c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buftype == WHOLE) {
|
if (buftype == WHOLE || cmd == '<' || cmd == '>') {
|
||||||
p = begin_line(p);
|
p = begin_line(p);
|
||||||
q = end_line(q);
|
q = end_line(q);
|
||||||
}
|
}
|
||||||
@ -3582,14 +3610,9 @@ static void do_cmd(int c)
|
|||||||
case '<': // <- Left shift something
|
case '<': // <- Left shift something
|
||||||
case '>': // >- Right shift something
|
case '>': // >- Right shift something
|
||||||
cnt = count_lines(text, dot); // remember what line we are on
|
cnt = count_lines(text, dot); // remember what line we are on
|
||||||
c1 = get_motion_char(); // get the type of thing to operate on
|
if (find_range(&p, &q, c) == -1)
|
||||||
if (find_range(&p, &q, c1) == -1) {
|
|
||||||
indicate_error();
|
|
||||||
goto dc6;
|
goto dc6;
|
||||||
}
|
|
||||||
yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change
|
yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change
|
||||||
p = begin_line(p);
|
|
||||||
q = end_line(q);
|
|
||||||
i = count_lines(p, q); // # of lines we are shifting
|
i = count_lines(p, q); // # of lines we are shifting
|
||||||
for ( ; i > 0; i--, p = next_line(p)) {
|
for ( ; i > 0; i--, p = next_line(p)) {
|
||||||
if (c == '<') {
|
if (c == '<') {
|
||||||
@ -3820,39 +3843,17 @@ static void do_cmd(int c)
|
|||||||
case 'Y': // Y- Yank a line
|
case 'Y': // Y- Yank a line
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
int yf = YANKDEL; // assume either "c" or "d"
|
||||||
|
int buftype;
|
||||||
#if ENABLE_FEATURE_VI_YANKMARK
|
#if ENABLE_FEATURE_VI_YANKMARK
|
||||||
char *savereg = reg[YDreg];
|
char *savereg = reg[YDreg];
|
||||||
#endif
|
|
||||||
int yf, buftype = 0;
|
|
||||||
yf = YANKDEL; // assume either "c" or "d"
|
|
||||||
#if ENABLE_FEATURE_VI_YANKMARK
|
|
||||||
if (c == 'y' || c == 'Y')
|
if (c == 'y' || c == 'Y')
|
||||||
yf = YANKONLY;
|
yf = YANKONLY;
|
||||||
#endif
|
#endif
|
||||||
c1 = 'y';
|
|
||||||
if (c != 'Y') {
|
|
||||||
c1 = get_motion_char(); // get the type of thing to operate on
|
|
||||||
if (c1 == 27) // ESC- user changed mind and wants out
|
|
||||||
goto dc6;
|
|
||||||
}
|
|
||||||
// determine range, and whether it spans lines
|
// determine range, and whether it spans lines
|
||||||
buftype = find_range(&p, &q, c1);
|
buftype = find_range(&p, &q, c);
|
||||||
place_cursor(0, 0);
|
if (buftype == -1) // invalid range
|
||||||
if (buftype == -1) { // invalid range
|
|
||||||
indicate_error();
|
|
||||||
goto dc6;
|
goto dc6;
|
||||||
}
|
|
||||||
if (c1 == 'w' || c1 == 'W') {
|
|
||||||
char *q0 = q;
|
|
||||||
// don't include trailing WS as part of word
|
|
||||||
while (q > p && isspace(*q)) {
|
|
||||||
if (*q-- == '\n')
|
|
||||||
q0 = q;
|
|
||||||
}
|
|
||||||
// for non-change operations WS after NL is not part of word
|
|
||||||
if (c != 'c' && q != p && *q != '\n')
|
|
||||||
q = q0;
|
|
||||||
}
|
|
||||||
dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word
|
dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word
|
||||||
if (buftype == WHOLE) {
|
if (buftype == WHOLE) {
|
||||||
if (c == 'c') {
|
if (c == 'c') {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user