aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-04-06 13:40:23 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2021-04-11 00:18:55 +0200
commitb7b1119d9f95cc956eb0161a59ee21a1daca8f52 (patch)
tree230b99719a414b668601bc75b083c54da413ef2a
parent7ce0e75c1f26d9cb3061c64aeab3204f62a5b55c (diff)
downloadbusybox-w32-b7b1119d9f95cc956eb0161a59ee21a1daca8f52.tar.gz
busybox-w32-b7b1119d9f95cc956eb0161a59ee21a1daca8f52.tar.bz2
busybox-w32-b7b1119d9f95cc956eb0161a59ee21a1daca8f52.zip
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>
-rw-r--r--editors/vi.c83
1 files changed, 42 insertions, 41 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 5dc14f1ba..9a17f6527 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3079,22 +3079,38 @@ static int at_eof(const char *s)
3079 return ((s == end - 2 && s[1] == '\n') || s == end - 1); 3079 return ((s == end - 2 && s[1] == '\n') || s == end - 1);
3080} 3080}
3081 3081
3082static int find_range(char **start, char **stop, char c) 3082static int find_range(char **start, char **stop, int cmd)
3083{ 3083{
3084 char *save_dot, *p, *q, *t; 3084 char *save_dot, *p, *q, *t;
3085 int buftype = -1; 3085 int buftype = -1;
3086 int c;
3086 3087
3087 save_dot = dot; 3088 save_dot = dot;
3088 p = q = dot; 3089 p = q = dot;
3089 3090
3090 if (strchr("cdy><", c)) { 3091#if ENABLE_FEATURE_VI_YANKMARK
3092 if (cmd == 'Y') {
3093 c = 'y';
3094 } else
3095#endif
3096 {
3097 c = get_motion_char();
3098 }
3099
3100#if ENABLE_FEATURE_VI_YANKMARK
3101 if ((cmd == 'Y' || cmd == c) && strchr("cdy><", c)) {
3102#else
3103 if (cmd == c && strchr("cd><", c)) {
3104#endif
3091 // these cmds operate on whole lines 3105 // these cmds operate on whole lines
3092 buftype = WHOLE; 3106 buftype = WHOLE;
3093 if (--cmdcnt > 0) 3107 if (--cmdcnt > 0)
3094 do_cmd('j'); 3108 do_cmd('j');
3095 } else if (strchr("^%$0bBeEfFtTh|{}\b\177", c)) { 3109 } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) {
3096 // These cmds operate on char positions 3110 // Most operate on char positions within a line. Of those that
3097 buftype = PARTIAL; 3111 // don't '%' needs no special treatment, search commands are
3112 // marked as MULTI and "{}" are handled below.
3113 buftype = strchr("nN/?", c) ? MULTI : PARTIAL;
3098 do_cmd(c); // execute movement cmd 3114 do_cmd(c); // execute movement cmd
3099 if (p == dot) // no movement is an error 3115 if (p == dot) // no movement is an error
3100 buftype = -1; 3116 buftype = -1;
@@ -3104,7 +3120,16 @@ static int find_range(char **start, char **stop, char c)
3104 // step back one char, but not if we're at end of file 3120 // step back one char, but not if we're at end of file
3105 if (dot > p && !at_eof(dot)) 3121 if (dot > p && !at_eof(dot))
3106 dot--; 3122 dot--;
3107 } else if (strchr("GHL+-jk\r\n", c)) { 3123 t = dot;
3124 // don't include trailing WS as part of word
3125 while (dot > p && isspace(*dot)) {
3126 if (*dot-- == '\n')
3127 t = dot;
3128 }
3129 // for non-change operations WS after NL is not part of word
3130 if (cmd != 'c' && dot != p && *dot != '\n')
3131 dot = t;
3132 } else if (strchr("GHL+-jk'\r\n", c)) {
3108 // these operate on whole lines 3133 // these operate on whole lines
3109 buftype = WHOLE; 3134 buftype = WHOLE;
3110 do_cmd(c); // execute movement cmd 3135 do_cmd(c); // execute movement cmd
@@ -3119,8 +3144,11 @@ static int find_range(char **start, char **stop, char c)
3119 dot--; 3144 dot--;
3120 } 3145 }
3121 3146
3122 if (buftype == -1) 3147 if (buftype == -1) {
3148 if (c != 27)
3149 indicate_error();
3123 return buftype; 3150 return buftype;
3151 }
3124 3152
3125 q = dot; 3153 q = dot;
3126 if (q < p) { 3154 if (q < p) {
@@ -3131,7 +3159,7 @@ static int find_range(char **start, char **stop, char c)
3131 3159
3132 // movements which don't include end of range 3160 // movements which don't include end of range
3133 if (q > p) { 3161 if (q > p) {
3134 if (strchr("^0bBFTh|\b\177", c)) { 3162 if (strchr("^0bBFThnN/?|\b\177", c)) {
3135 q--; 3163 q--;
3136 } else if (strchr("{}", c)) { 3164 } else if (strchr("{}", c)) {
3137 buftype = (p == begin_line(p) && (*q == '\n' || at_eof(q))) ? 3165 buftype = (p == begin_line(p) && (*q == '\n' || at_eof(q))) ?
@@ -3144,7 +3172,7 @@ static int find_range(char **start, char **stop, char c)
3144 } 3172 }
3145 } 3173 }
3146 3174
3147 if (buftype == WHOLE) { 3175 if (buftype == WHOLE || cmd == '<' || cmd == '>') {
3148 p = begin_line(p); 3176 p = begin_line(p);
3149 q = end_line(q); 3177 q = end_line(q);
3150 } 3178 }
@@ -3582,14 +3610,9 @@ static void do_cmd(int c)
3582 case '<': // <- Left shift something 3610 case '<': // <- Left shift something
3583 case '>': // >- Right shift something 3611 case '>': // >- Right shift something
3584 cnt = count_lines(text, dot); // remember what line we are on 3612 cnt = count_lines(text, dot); // remember what line we are on
3585 c1 = get_motion_char(); // get the type of thing to operate on 3613 if (find_range(&p, &q, c) == -1)
3586 if (find_range(&p, &q, c1) == -1) {
3587 indicate_error();
3588 goto dc6; 3614 goto dc6;
3589 }
3590 yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change 3615 yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change
3591 p = begin_line(p);
3592 q = end_line(q);
3593 i = count_lines(p, q); // # of lines we are shifting 3616 i = count_lines(p, q); // # of lines we are shifting
3594 for ( ; i > 0; i--, p = next_line(p)) { 3617 for ( ; i > 0; i--, p = next_line(p)) {
3595 if (c == '<') { 3618 if (c == '<') {
@@ -3820,39 +3843,17 @@ static void do_cmd(int c)
3820 case 'Y': // Y- Yank a line 3843 case 'Y': // Y- Yank a line
3821#endif 3844#endif
3822 { 3845 {
3846 int yf = YANKDEL; // assume either "c" or "d"
3847 int buftype;
3823#if ENABLE_FEATURE_VI_YANKMARK 3848#if ENABLE_FEATURE_VI_YANKMARK
3824 char *savereg = reg[YDreg]; 3849 char *savereg = reg[YDreg];
3825#endif
3826 int yf, buftype = 0;
3827 yf = YANKDEL; // assume either "c" or "d"
3828#if ENABLE_FEATURE_VI_YANKMARK
3829 if (c == 'y' || c == 'Y') 3850 if (c == 'y' || c == 'Y')
3830 yf = YANKONLY; 3851 yf = YANKONLY;
3831#endif 3852#endif
3832 c1 = 'y';
3833 if (c != 'Y') {
3834 c1 = get_motion_char(); // get the type of thing to operate on
3835 if (c1 == 27) // ESC- user changed mind and wants out
3836 goto dc6;
3837 }
3838 // determine range, and whether it spans lines 3853 // determine range, and whether it spans lines
3839 buftype = find_range(&p, &q, c1); 3854 buftype = find_range(&p, &q, c);
3840 place_cursor(0, 0); 3855 if (buftype == -1) // invalid range
3841 if (buftype == -1) { // invalid range
3842 indicate_error();
3843 goto dc6; 3856 goto dc6;
3844 }
3845 if (c1 == 'w' || c1 == 'W') {
3846 char *q0 = q;
3847 // don't include trailing WS as part of word
3848 while (q > p && isspace(*q)) {
3849 if (*q-- == '\n')
3850 q0 = q;
3851 }
3852 // for non-change operations WS after NL is not part of word
3853 if (c != 'c' && q != p && *q != '\n')
3854 q = q0;
3855 }
3856 dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word 3857 dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word
3857 if (buftype == WHOLE) { 3858 if (buftype == WHOLE) {
3858 if (c == 'c') { 3859 if (c == 'c') {