aboutsummaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
Diffstat (limited to 'editors/vi.c')
-rw-r--r--editors/vi.c201
1 files changed, 70 insertions, 131 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 6fae221ac..821583ec1 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -136,14 +136,6 @@
136//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. 136//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin.
137//config: 137//config:
138//config: This is not clean but helps a lot on serial lines and such. 138//config: This is not clean but helps a lot on serial lines and such.
139//config:
140//config:config FEATURE_VI_OPTIMIZE_CURSOR
141//config: bool "Optimize cursor movement"
142//config: default y
143//config: depends on VI
144//config: help
145//config: This will make the cursor movement faster, but requires more memory
146//config: and it makes the applet a tiny bit larger.
147 139
148//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) 140//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP))
149 141
@@ -154,12 +146,12 @@
154//usage:#define vi_full_usage "\n\n" 146//usage:#define vi_full_usage "\n\n"
155//usage: "Edit FILE\n" 147//usage: "Edit FILE\n"
156//usage: IF_FEATURE_VI_COLON( 148//usage: IF_FEATURE_VI_COLON(
157//usage: "\n -c Initial command to run ($EXINIT also available)" 149//usage: "\n -c CMD Initial command to run ($EXINIT also available)"
158//usage: ) 150//usage: )
159//usage: IF_FEATURE_VI_READONLY( 151//usage: IF_FEATURE_VI_READONLY(
160//usage: "\n -R Read-only" 152//usage: "\n -R Read-only"
161//usage: ) 153//usage: )
162//usage: "\n -H Short help regarding available features" 154//usage: "\n -H List available features"
163 155
164#include "libbb.h" 156#include "libbb.h"
165/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ 157/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */
@@ -202,20 +194,29 @@ enum {
202 MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, 194 MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN,
203}; 195};
204 196
205/* vt102 typical ESC sequence */ 197/* VT102 ESC sequences.
206/* terminal standout start/normal ESC sequence */ 198 * See "Xterm Control Sequences"
207#define SOs "\033[7m" 199 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
208#define SOn "\033[0m" 200 */
209/* terminal bell sequence */ 201/* Inverse/Normal text */
210#define bell "\007" 202#define ESC_BOLD_TEXT "\033[7m"
211/* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 203#define ESC_NORM_TEXT "\033[0m"
212#define Ceol "\033[K" 204/* Bell */
213#define Ceos "\033[J" 205#define ESC_BELL "\007"
214/* Cursor motion arbitrary destination ESC sequence */ 206/* Clear-to-end-of-line */
215#define CMrc "\033[%u;%uH" 207#define ESC_CLEAR2EOL "\033[K"
216/* Cursor motion up and down ESC sequence */ 208/* Clear-to-end-of-screen.
217#define CMup "\033[A" 209 * (We use default param here.
218#define CMdown "\n" 210 * Full sequence is "ESC [ <num> J",
211 * <num> is 0/1/2 = "erase below/above/all".)
212 */
213#define ESC_CLEAR2EOS "\033[J"
214/* Cursor to given coordinate (1,1: top left) */
215#define ESC_SET_CURSOR_POS "\033[%u;%uH"
216//UNUSED
217///* Cursor up and down */
218//#define ESC_CURSOR_UP "\033[A"
219//#define ESC_CURSOR_DOWN "\n"
219 220
220#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 221#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
221// cmds modifying text[] 222// cmds modifying text[]
@@ -303,9 +304,6 @@ struct globals {
303 int lmc_len; // length of last_modifying_cmd 304 int lmc_len; // length of last_modifying_cmd
304 char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 305 char *ioq, *ioq_start; // pointer to string for get_one_char to "read"
305#endif 306#endif
306#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
307 int last_row; // where the cursor was last moved to
308#endif
309#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 307#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
310 int my_pid; 308 int my_pid;
311#endif 309#endif
@@ -389,7 +387,6 @@ struct globals {
389#define lmc_len (G.lmc_len ) 387#define lmc_len (G.lmc_len )
390#define ioq (G.ioq ) 388#define ioq (G.ioq )
391#define ioq_start (G.ioq_start ) 389#define ioq_start (G.ioq_start )
392#define last_row (G.last_row )
393#define my_pid (G.my_pid ) 390#define my_pid (G.my_pid )
394#define last_search_pattern (G.last_search_pattern) 391#define last_search_pattern (G.last_search_pattern)
395 392
@@ -470,10 +467,7 @@ static int file_size(const char *); // what is the byte size of "fn"
470// file_insert might reallocate text[]! 467// file_insert might reallocate text[]!
471static int file_insert(const char *, char *, int); 468static int file_insert(const char *, char *, int);
472static int file_write(char *, char *, char *); 469static int file_write(char *, char *, char *);
473#if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 470static void place_cursor(int, int);
474#define place_cursor(a, b, optimize) place_cursor(a, b)
475#endif
476static void place_cursor(int, int, int);
477static void screen_erase(void); 471static void screen_erase(void);
478static void clear_to_eol(void); 472static void clear_to_eol(void);
479static void clear_to_eos(void); 473static void clear_to_eos(void);
@@ -558,7 +552,8 @@ int vi_main(int argc, char **argv)
558 } 552 }
559#endif 553#endif
560 554
561 vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; 555 // autoindent is not default in vim 7.3
556 vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE;
562 // 1- process $HOME/.exrc file (not inplemented yet) 557 // 1- process $HOME/.exrc file (not inplemented yet)
563 // 2- process EXINIT variable from environment 558 // 2- process EXINIT variable from environment
564 // 3- process command line args 559 // 3- process command line args
@@ -584,7 +579,7 @@ int vi_main(int argc, char **argv)
584#if ENABLE_FEATURE_VI_COLON 579#if ENABLE_FEATURE_VI_COLON
585 case 'c': // cmd line vi command 580 case 'c': // cmd line vi command
586 if (*optarg) 581 if (*optarg)
587 initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN); 582 initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN);
588 break; 583 break;
589#endif 584#endif
590 case 'H': 585 case 'H':
@@ -599,15 +594,19 @@ int vi_main(int argc, char **argv)
599 // The argv array can be used by the ":next" and ":rewind" commands 594 // The argv array can be used by the ":next" and ":rewind" commands
600 argv += optind; 595 argv += optind;
601 argc -= optind; 596 argc -= optind;
602 save_argc = argc;
603 optind = 0;
604 597
605 //----- This is the main file handling loop -------------- 598 //----- This is the main file handling loop --------------
599 save_argc = argc;
600 optind = 0;
601 // "Save cursor, use alternate screen buffer, clear screen"
602 write1("\033[?1049h");
606 while (1) { 603 while (1) {
607 edit_file(argv[optind]); /* param might be NULL */ 604 edit_file(argv[optind]); /* param might be NULL */
608 if (++optind >= argc) 605 if (++optind >= argc)
609 break; 606 break;
610 } 607 }
608 // "Use normal screen buffer, restore cursor"
609 write1("\033[?1049l");
611 //----------------------------------------------------------- 610 //-----------------------------------------------------------
612 611
613 return 0; 612 return 0;
@@ -1191,7 +1190,7 @@ static void colon(char *buf)
1191 char *argp; 1190 char *argp;
1192#endif 1191#endif
1193 i = 0; // offset into args 1192 i = 0; // offset into args
1194 // only blank is regarded as args delmiter. What about tab '\t' ? 1193 // only blank is regarded as args delimiter. What about tab '\t'?
1195 if (!args[0] || strcasecmp(args, "all") == 0) { 1194 if (!args[0] || strcasecmp(args, "all") == 0) {
1196 // print out values of all options 1195 // print out values of all options
1197#if ENABLE_FEATURE_VI_SETOPTS 1196#if ENABLE_FEATURE_VI_SETOPTS
@@ -2176,7 +2175,7 @@ static void show_help(void)
2176 "\n\tPattern searches with / and ?" 2175 "\n\tPattern searches with / and ?"
2177#endif 2176#endif
2178#if ENABLE_FEATURE_VI_DOT_CMD 2177#if ENABLE_FEATURE_VI_DOT_CMD
2179 "\n\tLast command repeat with \'.\'" 2178 "\n\tLast command repeat with ."
2180#endif 2179#endif
2181#if ENABLE_FEATURE_VI_YANKMARK 2180#if ENABLE_FEATURE_VI_YANKMARK
2182 "\n\tLine marking with 'x" 2181 "\n\tLine marking with 'x"
@@ -2187,7 +2186,7 @@ static void show_help(void)
2187 //redundant: usage text says this too: "\n\tReadonly with -R command line arg" 2186 //redundant: usage text says this too: "\n\tReadonly with -R command line arg"
2188#endif 2187#endif
2189#if ENABLE_FEATURE_VI_SET 2188#if ENABLE_FEATURE_VI_SET
2190 "\n\tSome colon mode commands with \':\'" 2189 "\n\tSome colon mode commands with :"
2191#endif 2190#endif
2192#if ENABLE_FEATURE_VI_SETOPTS 2191#if ENABLE_FEATURE_VI_SETOPTS
2193 "\n\tSettable options with \":set\"" 2192 "\n\tSettable options with \":set\""
@@ -2601,107 +2600,56 @@ static int file_write(char *fn, char *first, char *last)
2601// 23,0 ... 23,79 <- status line 2600// 23,0 ... 23,79 <- status line
2602 2601
2603//----- Move the cursor to row x col (count from 0, not 1) ------- 2602//----- Move the cursor to row x col (count from 0, not 1) -------
2604static void place_cursor(int row, int col, int optimize) 2603static void place_cursor(int row, int col)
2605{ 2604{
2606 char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; 2605 char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
2607#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
2608 enum {
2609 SZ_UP = sizeof(CMup),
2610 SZ_DN = sizeof(CMdown),
2611 SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN,
2612 };
2613 char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size
2614#endif
2615 char *cm;
2616 2606
2617 if (row < 0) row = 0; 2607 if (row < 0) row = 0;
2618 if (row >= rows) row = rows - 1; 2608 if (row >= rows) row = rows - 1;
2619 if (col < 0) col = 0; 2609 if (col < 0) col = 0;
2620 if (col >= columns) col = columns - 1; 2610 if (col >= columns) col = columns - 1;
2621 2611
2622 //----- 1. Try the standard terminal ESC sequence 2612 sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
2623 sprintf(cm1, CMrc, row + 1, col + 1); 2613 write1(cm1);
2624 cm = cm1;
2625
2626#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
2627 if (optimize && col < 16) {
2628 char *screenp;
2629 int Rrow = last_row;
2630 int diff = Rrow - row;
2631
2632 if (diff < -5 || diff > 5)
2633 goto skip;
2634
2635 //----- find the minimum # of chars to move cursor -------------
2636 //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
2637 cm2[0] = '\0';
2638
2639 // move to the correct row
2640 while (row < Rrow) {
2641 // the cursor has to move up
2642 strcat(cm2, CMup);
2643 Rrow--;
2644 }
2645 while (row > Rrow) {
2646 // the cursor has to move down
2647 strcat(cm2, CMdown);
2648 Rrow++;
2649 }
2650
2651 // now move to the correct column
2652 strcat(cm2, "\r"); // start at col 0
2653 // just send out orignal source char to get to correct place
2654 screenp = &screen[row * columns]; // start of screen line
2655 strncat(cm2, screenp, col);
2656
2657 // pick the shortest cursor motion to send out
2658 if (strlen(cm2) < strlen(cm)) {
2659 cm = cm2;
2660 }
2661 skip: ;
2662 }
2663 last_row = row;
2664#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
2665 write1(cm);
2666} 2614}
2667 2615
2668//----- Erase from cursor to end of line ----------------------- 2616//----- Erase from cursor to end of line -----------------------
2669static void clear_to_eol(void) 2617static void clear_to_eol(void)
2670{ 2618{
2671 write1(Ceol); // Erase from cursor to end of line 2619 write1(ESC_CLEAR2EOL);
2672} 2620}
2673 2621
2674static void go_bottom_and_clear_to_eol(void) 2622static void go_bottom_and_clear_to_eol(void)
2675{ 2623{
2676 place_cursor(rows - 1, 0, FALSE); // go to bottom of screen 2624 place_cursor(rows - 1, 0);
2677 clear_to_eol(); // erase to end of line 2625 clear_to_eol();
2678} 2626}
2679 2627
2680//----- Erase from cursor to end of screen ----------------------- 2628//----- Erase from cursor to end of screen -----------------------
2681static void clear_to_eos(void) 2629static void clear_to_eos(void)
2682{ 2630{
2683 write1(Ceos); // Erase from cursor to end of screen 2631 write1(ESC_CLEAR2EOS);
2684} 2632}
2685 2633
2686//----- Start standout mode ------------------------------------ 2634//----- Start standout mode ------------------------------------
2687static void standout_start(void) // send "start reverse video" sequence 2635static void standout_start(void)
2688{ 2636{
2689 write1(SOs); // Start reverse video mode 2637 write1(ESC_BOLD_TEXT);
2690} 2638}
2691 2639
2692//----- End standout mode -------------------------------------- 2640//----- End standout mode --------------------------------------
2693static void standout_end(void) // send "end reverse video" sequence 2641static void standout_end(void)
2694{ 2642{
2695 write1(SOn); // End reverse video mode 2643 write1(ESC_NORM_TEXT);
2696} 2644}
2697 2645
2698//----- Flash the screen -------------------------------------- 2646//----- Flash the screen --------------------------------------
2699static void flash(int h) 2647static void flash(int h)
2700{ 2648{
2701 standout_start(); // send "start reverse video" sequence 2649 standout_start();
2702 redraw(TRUE); 2650 redraw(TRUE);
2703 mysleep(h); 2651 mysleep(h);
2704 standout_end(); // send "end reverse video" sequence 2652 standout_end();
2705 redraw(TRUE); 2653 redraw(TRUE);
2706} 2654}
2707 2655
@@ -2712,7 +2660,7 @@ static void Indicate_Error(void)
2712 return; // generate a random command 2660 return; // generate a random command
2713#endif 2661#endif
2714 if (!err_method) { 2662 if (!err_method) {
2715 write1(bell); // send out a bell character 2663 write1(ESC_BELL);
2716 } else { 2664 } else {
2717 flash(10); 2665 flash(10);
2718 } 2666 }
@@ -2758,7 +2706,7 @@ static void show_status_line(void)
2758 } 2706 }
2759 have_status_msg = 0; 2707 have_status_msg = 0;
2760 } 2708 }
2761 place_cursor(crow, ccol, FALSE); // put cursor back in correct place 2709 place_cursor(crow, ccol); // put cursor back in correct place
2762 } 2710 }
2763 fflush_all(); 2711 fflush_all();
2764} 2712}
@@ -2770,12 +2718,12 @@ static void status_line_bold(const char *format, ...)
2770 va_list args; 2718 va_list args;
2771 2719
2772 va_start(args, format); 2720 va_start(args, format);
2773 strcpy(status_buffer, SOs); // Terminal standout mode on 2721 strcpy(status_buffer, ESC_BOLD_TEXT);
2774 vsprintf(status_buffer + sizeof(SOs)-1, format, args); 2722 vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args);
2775 strcat(status_buffer, SOn); // Terminal standout mode off 2723 strcat(status_buffer, ESC_NORM_TEXT);
2776 va_end(args); 2724 va_end(args);
2777 2725
2778 have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2; 2726 have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2;
2779} 2727}
2780 2728
2781// format status buffer 2729// format status buffer
@@ -2807,8 +2755,8 @@ static void print_literal(char *buf, const char *s)
2807 c = *s; 2755 c = *s;
2808 c_is_no_print = (c & 0x80) && !Isprint(c); 2756 c_is_no_print = (c & 0x80) && !Isprint(c);
2809 if (c_is_no_print) { 2757 if (c_is_no_print) {
2810 strcpy(d, SOn); 2758 strcpy(d, ESC_NORM_TEXT);
2811 d += sizeof(SOn)-1; 2759 d += sizeof(ESC_NORM_TEXT)-1;
2812 c = '.'; 2760 c = '.';
2813 } 2761 }
2814 if (c < ' ' || c == 0x7f) { 2762 if (c < ' ' || c == 0x7f) {
@@ -2820,8 +2768,8 @@ static void print_literal(char *buf, const char *s)
2820 *d++ = c; 2768 *d++ = c;
2821 *d = '\0'; 2769 *d = '\0';
2822 if (c_is_no_print) { 2770 if (c_is_no_print) {
2823 strcpy(d, SOs); 2771 strcpy(d, ESC_BOLD_TEXT);
2824 d += sizeof(SOs)-1; 2772 d += sizeof(ESC_BOLD_TEXT)-1;
2825 } 2773 }
2826 if (*s == '\n') { 2774 if (*s == '\n') {
2827 *d++ = '$'; 2775 *d++ = '$';
@@ -2903,8 +2851,8 @@ static int format_edit_status(void)
2903//----- Force refresh of all Lines ----------------------------- 2851//----- Force refresh of all Lines -----------------------------
2904static void redraw(int full_screen) 2852static void redraw(int full_screen)
2905{ 2853{
2906 place_cursor(0, 0, FALSE); // put cursor in correct place 2854 place_cursor(0, 0);
2907 clear_to_eos(); // tell terminal to erase display 2855 clear_to_eos();
2908 screen_erase(); // erase the internal screen buffer 2856 screen_erase(); // erase the internal screen buffer
2909 last_status_cksum = 0; // force status update 2857 last_status_cksum = 0; // force status update
2910 refresh(full_screen); // this will redraw the entire display 2858 refresh(full_screen); // this will redraw the entire display
@@ -3044,22 +2992,13 @@ static void refresh(int full_screen)
3044 if (changed) { 2992 if (changed) {
3045 // copy changed part of buffer to virtual screen 2993 // copy changed part of buffer to virtual screen
3046 memcpy(sp+cs, out_buf+cs, ce-cs+1); 2994 memcpy(sp+cs, out_buf+cs, ce-cs+1);
3047 2995 place_cursor(li, cs);
3048 // move cursor to column of first change
3049 //if (offset != old_offset) {
3050 // // place_cursor is still too stupid
3051 // // to handle offsets correctly
3052 // place_cursor(li, cs, FALSE);
3053 //} else {
3054 place_cursor(li, cs, TRUE);
3055 //}
3056
3057 // write line out to terminal 2996 // write line out to terminal
3058 fwrite(&sp[cs], ce - cs + 1, 1, stdout); 2997 fwrite(&sp[cs], ce - cs + 1, 1, stdout);
3059 } 2998 }
3060 } 2999 }
3061 3000
3062 place_cursor(crow, ccol, TRUE); 3001 place_cursor(crow, ccol);
3063 3002
3064 old_offset = offset; 3003 old_offset = offset;
3065#undef old_offset 3004#undef old_offset
@@ -3229,9 +3168,9 @@ static void do_cmd(int c)
3229 break; 3168 break;
3230 case 12: // ctrl-L force redraw whole screen 3169 case 12: // ctrl-L force redraw whole screen
3231 case 18: // ctrl-R force redraw 3170 case 18: // ctrl-R force redraw
3232 place_cursor(0, 0, FALSE); // put cursor in correct place 3171 place_cursor(0, 0);
3233 clear_to_eos(); // tel terminal to erase display 3172 clear_to_eos();
3234 mysleep(10); 3173 //mysleep(10); // why???
3235 screen_erase(); // erase the internal screen buffer 3174 screen_erase(); // erase the internal screen buffer
3236 last_status_cksum = 0; // force status update 3175 last_status_cksum = 0; // force status update
3237 refresh(TRUE); // this will redraw the entire display 3176 refresh(TRUE); // this will redraw the entire display
@@ -4150,7 +4089,7 @@ static void crash_test()
4150 4089
4151 if (msg[0]) { 4090 if (msg[0]) {
4152 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", 4091 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
4153 totalcmds, last_input_char, msg, SOs, SOn); 4092 totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT);
4154 fflush_all(); 4093 fflush_all();
4155 while (safe_read(STDIN_FILENO, d, 1) > 0) { 4094 while (safe_read(STDIN_FILENO, d, 1) > 0) {
4156 if (d[0] == '\n' || d[0] == '\r') 4095 if (d[0] == '\n' || d[0] == '\r')