diff options
author | Ron Yorston <rmy@pobox.com> | 2021-06-28 07:46:32 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-06-28 07:46:32 +0100 |
commit | e1ad66c0b8fd58a7158d40771175a7dab224202d (patch) | |
tree | 959d687eee9637151ad5798322586174de331141 /editors/vi.c | |
parent | 0fdf99bee07b6c38795eb5415b5e337ab82cfba8 (diff) | |
parent | 5dbbd0a6f52befe6bc57baf97d39168e595197f1 (diff) | |
download | busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.tar.gz busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.tar.bz2 busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'editors/vi.c')
-rw-r--r-- | editors/vi.c | 144 |
1 files changed, 88 insertions, 56 deletions
diff --git a/editors/vi.c b/editors/vi.c index a4d6b21b4..89c567f10 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -181,7 +181,7 @@ | |||
181 | //kbuild:lib-$(CONFIG_VI) += vi.o | 181 | //kbuild:lib-$(CONFIG_VI) += vi.o |
182 | 182 | ||
183 | //usage:#define vi_trivial_usage | 183 | //usage:#define vi_trivial_usage |
184 | //usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[FILE]..." | 184 | //usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..." |
185 | //usage:#define vi_full_usage "\n\n" | 185 | //usage:#define vi_full_usage "\n\n" |
186 | //usage: "Edit FILE\n" | 186 | //usage: "Edit FILE\n" |
187 | //usage: IF_FEATURE_VI_COLON( | 187 | //usage: IF_FEATURE_VI_COLON( |
@@ -191,6 +191,7 @@ | |||
191 | //usage: "\n -R Read-only" | 191 | //usage: "\n -R Read-only" |
192 | //usage: ) | 192 | //usage: ) |
193 | //usage: "\n -H List available features" | 193 | //usage: "\n -H List available features" |
194 | // note: non-standard, "vim -H" is Hebrew mode (bidi support) | ||
194 | 195 | ||
195 | #include "libbb.h" | 196 | #include "libbb.h" |
196 | // Should be after libbb.h: on some systems regex.h needs sys/types.h: | 197 | // Should be after libbb.h: on some systems regex.h needs sys/types.h: |
@@ -377,6 +378,7 @@ struct globals { | |||
377 | #if ENABLE_FEATURE_VI_SETOPTS | 378 | #if ENABLE_FEATURE_VI_SETOPTS |
378 | int indentcol; // column of recently autoindent, 0 or -1 | 379 | int indentcol; // column of recently autoindent, 0 or -1 |
379 | #endif | 380 | #endif |
381 | smallint cmd_error; | ||
380 | 382 | ||
381 | // former statics | 383 | // former statics |
382 | #if ENABLE_FEATURE_VI_YANKMARK | 384 | #if ENABLE_FEATURE_VI_YANKMARK |
@@ -503,6 +505,7 @@ struct globals { | |||
503 | #define dotcnt (G.dotcnt ) | 505 | #define dotcnt (G.dotcnt ) |
504 | #define last_search_pattern (G.last_search_pattern) | 506 | #define last_search_pattern (G.last_search_pattern) |
505 | #define indentcol (G.indentcol ) | 507 | #define indentcol (G.indentcol ) |
508 | #define cmd_error (G.cmd_error ) | ||
506 | 509 | ||
507 | #define edit_file__cur_line (G.edit_file__cur_line) | 510 | #define edit_file__cur_line (G.edit_file__cur_line) |
508 | #define refresh__old_offset (G.refresh__old_offset) | 511 | #define refresh__old_offset (G.refresh__old_offset) |
@@ -537,6 +540,7 @@ struct globals { | |||
537 | last_modified_count = -1; \ | 540 | last_modified_count = -1; \ |
538 | /* "" but has space for 2 chars: */ \ | 541 | /* "" but has space for 2 chars: */ \ |
539 | IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ | 542 | IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ |
543 | tabstop = 8; \ | ||
540 | } while (0) | 544 | } while (0) |
541 | 545 | ||
542 | #if ENABLE_FEATURE_VI_CRASHME | 546 | #if ENABLE_FEATURE_VI_CRASHME |
@@ -1122,6 +1126,7 @@ static void indicate_error(void) | |||
1122 | if (crashme > 0) | 1126 | if (crashme > 0) |
1123 | return; | 1127 | return; |
1124 | #endif | 1128 | #endif |
1129 | cmd_error = TRUE; | ||
1125 | if (!err_method) { | 1130 | if (!err_method) { |
1126 | write1(ESC_BELL); | 1131 | write1(ESC_BELL); |
1127 | } else { | 1132 | } else { |
@@ -2191,13 +2196,13 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2191 | cmdcnt = 0; | 2196 | cmdcnt = 0; |
2192 | end_cmd_q(); // stop adding to q | 2197 | end_cmd_q(); // stop adding to q |
2193 | last_status_cksum = 0; // force status update | 2198 | last_status_cksum = 0; // force status update |
2194 | if ((p[-1] != '\n') && (dot > text)) { | 2199 | if ((dot > text) && (p[-1] != '\n')) { |
2195 | p--; | 2200 | p--; |
2196 | } | 2201 | } |
2197 | #if ENABLE_FEATURE_VI_SETOPTS | 2202 | #if ENABLE_FEATURE_VI_SETOPTS |
2198 | if (autoindent) { | 2203 | if (autoindent) { |
2199 | len = indent_len(bol); | 2204 | len = indent_len(bol); |
2200 | if (len && get_column(bol + len) == indentcol) { | 2205 | if (len && get_column(bol + len) == indentcol && bol[len] == '\n') { |
2201 | // remove autoindent from otherwise empty line | 2206 | // remove autoindent from otherwise empty line |
2202 | text_hole_delete(bol, bol + len - 1, undo); | 2207 | text_hole_delete(bol, bol + len - 1, undo); |
2203 | p = bol; | 2208 | p = bol; |
@@ -2437,9 +2442,7 @@ static char *char_search(char *p, const char *pat, int dir_and_range) | |||
2437 | struct re_pattern_buffer preg; | 2442 | struct re_pattern_buffer preg; |
2438 | const char *err; | 2443 | const char *err; |
2439 | char *q; | 2444 | char *q; |
2440 | int i; | 2445 | int i, size, range, start; |
2441 | int size; | ||
2442 | int range; | ||
2443 | 2446 | ||
2444 | re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; | 2447 | re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; |
2445 | if (ignorecase) | 2448 | if (ignorecase) |
@@ -2464,31 +2467,26 @@ static char *char_search(char *p, const char *pat, int dir_and_range) | |||
2464 | 2467 | ||
2465 | // RANGE could be negative if we are searching backwards | 2468 | // RANGE could be negative if we are searching backwards |
2466 | range = q - p; | 2469 | range = q - p; |
2467 | q = p; | ||
2468 | size = range; | ||
2469 | if (range < 0) { | 2470 | if (range < 0) { |
2470 | size = -size; | 2471 | size = -range; |
2471 | q = p - size; | 2472 | start = size; |
2472 | if (q < text) | 2473 | } else { |
2473 | q = text; | 2474 | size = range; |
2475 | start = 0; | ||
2474 | } | 2476 | } |
2477 | q = p - start; | ||
2478 | if (q < text) | ||
2479 | q = text; | ||
2475 | // search for the compiled pattern, preg, in p[] | 2480 | // search for the compiled pattern, preg, in p[] |
2476 | // range < 0: search backward | 2481 | // range < 0, start == size: search backward |
2477 | // range > 0: search forward | 2482 | // range > 0, start == 0: search forward |
2478 | // 0 < start < size | ||
2479 | // re_search() < 0: not found or error | 2483 | // re_search() < 0: not found or error |
2480 | // re_search() >= 0: index of found pattern | 2484 | // re_search() >= 0: index of found pattern |
2481 | // struct pattern char int int int struct reg | 2485 | // struct pattern char int int int struct reg |
2482 | // re_search(*pattern_buffer, *string, size, start, range, *regs) | 2486 | // re_search(*pattern_buffer, *string, size, start, range, *regs) |
2483 | i = re_search(&preg, q, size, /*start:*/ 0, range, /*struct re_registers*:*/ NULL); | 2487 | i = re_search(&preg, q, size, start, range, /*struct re_registers*:*/ NULL); |
2484 | regfree(&preg); | 2488 | regfree(&preg); |
2485 | if (i < 0) | 2489 | return i < 0 ? NULL : q + i; |
2486 | return NULL; | ||
2487 | if (dir_and_range > 0) // FORWARD? | ||
2488 | p = p + i; | ||
2489 | else | ||
2490 | p = p - i; | ||
2491 | return p; | ||
2492 | } | 2490 | } |
2493 | # else | 2491 | # else |
2494 | # if ENABLE_FEATURE_VI_SETOPTS | 2492 | # if ENABLE_FEATURE_VI_SETOPTS |
@@ -3063,12 +3061,10 @@ static void colon(char *buf) | |||
3063 | status_line_bold("No current filename"); | 3061 | status_line_bold("No current filename"); |
3064 | goto ret; | 3062 | goto ret; |
3065 | } | 3063 | } |
3066 | if (e < 0) { // no addr given- read after current line | 3064 | if (e == 0) { // user said ":0r foo" |
3067 | q = begin_line(dot); | ||
3068 | } else if (e == 0) { // user said ":0r foo" | ||
3069 | q = text; | 3065 | q = text; |
3070 | } else { // addr given- read after that line | 3066 | } else { // read after given line or current line if none given |
3071 | q = next_line(find_line(e)); | 3067 | q = next_line(e > 0 ? find_line(e) : dot); |
3072 | // read after last line | 3068 | // read after last line |
3073 | if (q == end-1) | 3069 | if (q == end-1) |
3074 | ++q; | 3070 | ++q; |
@@ -3170,6 +3166,18 @@ static void colon(char *buf) | |||
3170 | } | 3166 | } |
3171 | len_R = strlen(R); | 3167 | len_R = strlen(R); |
3172 | 3168 | ||
3169 | if (len_F) { // save "find" as last search pattern | ||
3170 | free(last_search_pattern); | ||
3171 | last_search_pattern = xstrdup(F - 1); | ||
3172 | last_search_pattern[0] = '/'; | ||
3173 | } else if (last_search_pattern[1] == '\0') { | ||
3174 | status_line_bold("No previous search"); | ||
3175 | goto ret; | ||
3176 | } else { | ||
3177 | F = last_search_pattern + 1; | ||
3178 | len_F = strlen(F); | ||
3179 | } | ||
3180 | |||
3173 | if (e < 0) { // no addr given | 3181 | if (e < 0) { // no addr given |
3174 | q = begin_line(dot); // start with cur line | 3182 | q = begin_line(dot); // start with cur line |
3175 | r = end_line(dot); | 3183 | r = end_line(dot); |
@@ -3465,8 +3473,11 @@ static int find_range(char **start, char **stop, int cmd) | |||
3465 | #endif | 3473 | #endif |
3466 | // these cmds operate on whole lines | 3474 | // these cmds operate on whole lines |
3467 | buftype = WHOLE; | 3475 | buftype = WHOLE; |
3468 | if (--cmdcnt > 0) | 3476 | if (--cmdcnt > 0) { |
3469 | do_cmd('j'); | 3477 | do_cmd('j'); |
3478 | if (cmd_error) | ||
3479 | buftype = -1; | ||
3480 | } | ||
3470 | } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) { | 3481 | } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) { |
3471 | // Most operate on char positions within a line. Of those that | 3482 | // Most operate on char positions within a line. Of those that |
3472 | // don't '%' needs no special treatment, search commands are | 3483 | // don't '%' needs no special treatment, search commands are |
@@ -3496,6 +3507,8 @@ static int find_range(char **start, char **stop, int cmd) | |||
3496 | // these operate on whole lines | 3507 | // these operate on whole lines |
3497 | buftype = WHOLE; | 3508 | buftype = WHOLE; |
3498 | do_cmd(c); // execute movement cmd | 3509 | do_cmd(c); // execute movement cmd |
3510 | if (cmd_error) | ||
3511 | buftype = -1; | ||
3499 | } else if (c == ' ' || c == 'l') { | 3512 | } else if (c == ' ' || c == 'l') { |
3500 | // forward motion by character | 3513 | // forward motion by character |
3501 | int tmpcnt = (cmdcnt ?: 1); | 3514 | int tmpcnt = (cmdcnt ?: 1); |
@@ -3581,6 +3594,7 @@ static void do_cmd(int c) | |||
3581 | // p = q = save_dot = buf; // quiet the compiler | 3594 | // p = q = save_dot = buf; // quiet the compiler |
3582 | memset(buf, '\0', sizeof(buf)); | 3595 | memset(buf, '\0', sizeof(buf)); |
3583 | keep_index = FALSE; | 3596 | keep_index = FALSE; |
3597 | cmd_error = FALSE; | ||
3584 | 3598 | ||
3585 | show_status_line(); | 3599 | show_status_line(); |
3586 | 3600 | ||
@@ -3701,24 +3715,30 @@ static void do_cmd(int c) | |||
3701 | case 10: // Newline ^J | 3715 | case 10: // Newline ^J |
3702 | case 'j': // j- goto next line, same col | 3716 | case 'j': // j- goto next line, same col |
3703 | case KEYCODE_DOWN: // cursor key Down | 3717 | case KEYCODE_DOWN: // cursor key Down |
3718 | case 13: // Carriage Return ^M | ||
3719 | case '+': // +- goto next line | ||
3720 | q = dot; | ||
3704 | do { | 3721 | do { |
3705 | dot_next(); // go to next B-o-l | 3722 | p = next_line(q); |
3723 | if (p == end_line(q)) { | ||
3724 | indicate_error(); | ||
3725 | goto dc1; | ||
3726 | } | ||
3727 | q = p; | ||
3706 | } while (--cmdcnt > 0); | 3728 | } while (--cmdcnt > 0); |
3707 | // try to stay in saved column | 3729 | dot = q; |
3708 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | 3730 | if (c == 13 || c == '+') { |
3709 | keep_index = TRUE; | 3731 | dot_skip_over_ws(); |
3732 | } else { | ||
3733 | // try to stay in saved column | ||
3734 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | ||
3735 | keep_index = TRUE; | ||
3736 | } | ||
3710 | break; | 3737 | break; |
3711 | case 12: // ctrl-L force redraw whole screen | 3738 | case 12: // ctrl-L force redraw whole screen |
3712 | case 18: // ctrl-R force redraw | 3739 | case 18: // ctrl-R force redraw |
3713 | redraw(TRUE); // this will redraw the entire display | 3740 | redraw(TRUE); // this will redraw the entire display |
3714 | break; | 3741 | break; |
3715 | case 13: // Carriage Return ^M | ||
3716 | case '+': // +- goto next line | ||
3717 | do { | ||
3718 | dot_next(); | ||
3719 | } while (--cmdcnt > 0); | ||
3720 | dot_skip_over_ws(); | ||
3721 | break; | ||
3722 | case 21: // ctrl-U scroll up half screen | 3742 | case 21: // ctrl-U scroll up half screen |
3723 | dot_scroll((rows - 2) / 2, -1); | 3743 | dot_scroll((rows - 2) / 2, -1); |
3724 | break; | 3744 | break; |
@@ -3759,6 +3779,8 @@ static void do_cmd(int c) | |||
3759 | dot = q; | 3779 | dot = q; |
3760 | dot_begin(); // go to B-o-l | 3780 | dot_begin(); // go to B-o-l |
3761 | dot_skip_over_ws(); | 3781 | dot_skip_over_ws(); |
3782 | } else { | ||
3783 | indicate_error(); | ||
3762 | } | 3784 | } |
3763 | } else if (c1 == '\'') { // goto previous context | 3785 | } else if (c1 == '\'') { // goto previous context |
3764 | dot = swap_context(dot); // swap current and previous context | 3786 | dot = swap_context(dot); // swap current and previous context |
@@ -3884,12 +3906,6 @@ static void do_cmd(int c) | |||
3884 | case ',': // ,- repeat latest search in opposite direction | 3906 | case ',': // ,- repeat latest search in opposite direction |
3885 | dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20); | 3907 | dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20); |
3886 | break; | 3908 | break; |
3887 | case '-': // -- goto prev line | ||
3888 | do { | ||
3889 | dot_prev(); | ||
3890 | } while (--cmdcnt > 0); | ||
3891 | dot_skip_over_ws(); | ||
3892 | break; | ||
3893 | #if ENABLE_FEATURE_VI_DOT_CMD | 3909 | #if ENABLE_FEATURE_VI_DOT_CMD |
3894 | case '.': // .- repeat the last modifying command | 3910 | case '.': // .- repeat the last modifying command |
3895 | // Stuff the last_modifying_cmd back into stdin | 3911 | // Stuff the last_modifying_cmd back into stdin |
@@ -4095,9 +4111,10 @@ static void do_cmd(int c) | |||
4095 | if (cmdcnt > (rows - 1)) { | 4111 | if (cmdcnt > (rows - 1)) { |
4096 | cmdcnt = (rows - 1); | 4112 | cmdcnt = (rows - 1); |
4097 | } | 4113 | } |
4098 | if (--cmdcnt > 0) { | 4114 | while (--cmdcnt > 0) { |
4099 | do_cmd('+'); | 4115 | dot_next(); |
4100 | } | 4116 | } |
4117 | dot_begin(); | ||
4101 | dot_skip_over_ws(); | 4118 | dot_skip_over_ws(); |
4102 | break; | 4119 | break; |
4103 | case 'I': // I- insert before first non-blank | 4120 | case 'I': // I- insert before first non-blank |
@@ -4134,8 +4151,8 @@ static void do_cmd(int c) | |||
4134 | if (cmdcnt > (rows - 1)) { | 4151 | if (cmdcnt > (rows - 1)) { |
4135 | cmdcnt = (rows - 1); | 4152 | cmdcnt = (rows - 1); |
4136 | } | 4153 | } |
4137 | if (--cmdcnt > 0) { | 4154 | while (--cmdcnt > 0) { |
4138 | do_cmd('-'); | 4155 | dot_prev(); |
4139 | } | 4156 | } |
4140 | dot_begin(); | 4157 | dot_begin(); |
4141 | dot_skip_over_ws(); | 4158 | dot_skip_over_ws(); |
@@ -4300,12 +4317,24 @@ static void do_cmd(int c) | |||
4300 | } | 4317 | } |
4301 | case 'k': // k- goto prev line, same col | 4318 | case 'k': // k- goto prev line, same col |
4302 | case KEYCODE_UP: // cursor key Up | 4319 | case KEYCODE_UP: // cursor key Up |
4320 | case '-': // -- goto prev line | ||
4321 | q = dot; | ||
4303 | do { | 4322 | do { |
4304 | dot_prev(); | 4323 | p = prev_line(q); |
4324 | if (p == begin_line(q)) { | ||
4325 | indicate_error(); | ||
4326 | goto dc1; | ||
4327 | } | ||
4328 | q = p; | ||
4305 | } while (--cmdcnt > 0); | 4329 | } while (--cmdcnt > 0); |
4306 | // try to stay in saved column | 4330 | dot = q; |
4307 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | 4331 | if (c == '-') { |
4308 | keep_index = TRUE; | 4332 | dot_skip_over_ws(); |
4333 | } else { | ||
4334 | // try to stay in saved column | ||
4335 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | ||
4336 | keep_index = TRUE; | ||
4337 | } | ||
4309 | break; | 4338 | break; |
4310 | case 'r': // r- replace the current char with user input | 4339 | case 'r': // r- replace the current char with user input |
4311 | c1 = get_one_char(); // get the replacement char | 4340 | c1 = get_one_char(); // get the replacement char |
@@ -4686,7 +4715,6 @@ static void edit_file(char *fn) | |||
4686 | 4715 | ||
4687 | cmd_mode = 0; // 0=command 1=insert 2='R'eplace | 4716 | cmd_mode = 0; // 0=command 1=insert 2='R'eplace |
4688 | cmdcnt = 0; | 4717 | cmdcnt = 0; |
4689 | tabstop = 8; | ||
4690 | offset = 0; // no horizontal offset | 4718 | offset = 0; // no horizontal offset |
4691 | c = '\0'; | 4719 | c = '\0'; |
4692 | #if ENABLE_FEATURE_VI_DOT_CMD | 4720 | #if ENABLE_FEATURE_VI_DOT_CMD |
@@ -4814,7 +4842,11 @@ int vi_main(int argc, char **argv) | |||
4814 | initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); | 4842 | initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); |
4815 | } | 4843 | } |
4816 | #endif | 4844 | #endif |
4817 | while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) { | 4845 | while ((c = getopt(argc, argv, |
4846 | #if ENABLE_FEATURE_VI_CRASHME | ||
4847 | "C" | ||
4848 | #endif | ||
4849 | "RHh" IF_FEATURE_VI_COLON("c:"))) != -1) { | ||
4818 | switch (c) { | 4850 | switch (c) { |
4819 | #if ENABLE_FEATURE_VI_CRASHME | 4851 | #if ENABLE_FEATURE_VI_CRASHME |
4820 | case 'C': | 4852 | case 'C': |