diff options
-rw-r--r-- | editors/vi.c | 518 |
1 files changed, 258 insertions, 260 deletions
diff --git a/editors/vi.c b/editors/vi.c index 9bdee5928..406119371 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -483,7 +483,6 @@ struct globals { } while (0) -static void edit_file(char *); // edit one file static void do_cmd(int); // execute a command static int next_tabstop(int); static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot @@ -527,7 +526,6 @@ static uintptr_t text_hole_make(char *, int); // at "p", make a 'size' byte hole #define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d) #endif static char *yank_delete(char *, char *, int, int, int); // yank text[] into register then delete -static void show_help(void); // display some help info static void rawmode(void); // set "raw" mode on tty static void cookmode(void); // return to "cooked" mode on tty // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) @@ -610,94 +608,42 @@ static void crash_test(); static int crashme = 0; #endif -static void write1(const char *out) -{ - fputs(out, stdout); -} - -int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int vi_main(int argc, char **argv) +static void show_help(void) { - int c; - - INIT_G(); - -#if ENABLE_FEATURE_VI_UNDO - /* undo_stack_tail = NULL; - already is */ -#if ENABLE_FEATURE_VI_UNDO_QUEUE - undo_queue_state = UNDO_EMPTY; - /* undo_q = 0; - already is */ + puts("These features are available:" +#if ENABLE_FEATURE_VI_SEARCH + "\n\tPattern searches with / and ?" #endif +#if ENABLE_FEATURE_VI_DOT_CMD + "\n\tLast command repeat with ." #endif - -#if ENABLE_FEATURE_VI_CRASHME - srand((long) getpid()); +#if ENABLE_FEATURE_VI_YANKMARK + "\n\tLine marking with 'x" + "\n\tNamed buffers with \"x" #endif -#ifdef NO_SUCH_APPLET_YET - // if we aren't "vi", we are "view" - if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) { - SET_READONLY_MODE(readonly_mode); - } +#if ENABLE_FEATURE_VI_READONLY + //not implemented: "\n\tReadonly if vi is called as \"view\"" + //redundant: usage text says this too: "\n\tReadonly with -R command line arg" #endif - - // autoindent is not default in vim 7.3 - vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE; - // 1- process $HOME/.exrc file (not inplemented yet) - // 2- process EXINIT variable from environment - // 3- process command line args -#if ENABLE_FEATURE_VI_COLON - { - char *p = getenv("EXINIT"); - if (p && *p) - initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); - } +#if ENABLE_FEATURE_VI_SET + "\n\tSome colon mode commands with :" #endif - while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) { - switch (c) { -#if ENABLE_FEATURE_VI_CRASHME - case 'C': - crashme = 1; - break; +#if ENABLE_FEATURE_VI_SETOPTS + "\n\tSettable options with \":set\"" #endif -#if ENABLE_FEATURE_VI_READONLY - case 'R': // Read-only flag - SET_READONLY_MODE(readonly_mode); - break; +#if ENABLE_FEATURE_VI_USE_SIGNALS + "\n\tSignal catching- ^C" + "\n\tJob suspend and resume with ^Z" #endif -#if ENABLE_FEATURE_VI_COLON - case 'c': // cmd line vi command - if (*optarg) - initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); - break; +#if ENABLE_FEATURE_VI_WIN_RESIZE + "\n\tAdapt to window re-sizes" #endif - case 'H': - show_help(); - // fall through - default: - bb_show_usage(); - return 1; - } - } - - // The argv array can be used by the ":next" and ":rewind" commands - argv += optind; - argc -= optind; - - //----- This is the main file handling loop -------------- - save_argc = argc; - optind = 0; - // "Save cursor, use alternate screen buffer, clear screen" - write1(ESC"[?1049h"); - while (1) { - edit_file(argv[optind]); // param might be NULL - if (++optind >= argc) - break; - } - // "Use normal screen buffer, restore cursor" - write1(ESC"[?1049l"); - //----------------------------------------------------------- + ); +} - return 0; +static void write1(const char *out) +{ + fputs(out, stdout); } /* read text from file or create an empty buf */ @@ -748,153 +694,6 @@ static ALWAYS_INLINE int query_screen_dimensions(void) } #endif -static void edit_file(char *fn) -{ -#if ENABLE_FEATURE_VI_YANKMARK -#define cur_line edit_file__cur_line -#endif - int c; -#if ENABLE_FEATURE_VI_USE_SIGNALS - int sig; -#endif - - editing = 1; // 0 = exit, 1 = one file, 2 = multiple files - rawmode(); - rows = 24; - columns = 80; - IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); -#if ENABLE_FEATURE_VI_ASK_TERMINAL - if (G.get_rowcol_error /* TODO? && no input on stdin */) { - uint64_t k; - write1(ESC"[999;999H" ESC"[6n"); - fflush_all(); - k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); - if ((int32_t)k == KEYCODE_CURSOR_POS) { - uint32_t rc = (k >> 32); - columns = (rc & 0x7fff); - if (columns > MAX_SCR_COLS) - columns = MAX_SCR_COLS; - rows = ((rc >> 16) & 0x7fff); - if (rows > MAX_SCR_ROWS) - rows = MAX_SCR_ROWS; - } - } -#endif - new_screen(rows, columns); // get memory for virtual screen - init_text_buffer(fn); - -#if ENABLE_FEATURE_VI_YANKMARK - YDreg = 26; // default Yank/Delete reg -// Ureg = 27; - const // hold orig line for "U" cmd - mark[26] = mark[27] = text; // init "previous context" -#endif - - last_forward_char = last_input_char = '\0'; - crow = 0; - ccol = 0; - -#if ENABLE_FEATURE_VI_USE_SIGNALS - signal(SIGWINCH, winch_handler); - signal(SIGTSTP, tstp_handler); - sig = sigsetjmp(restart, 1); - if (sig != 0) { - screenbegin = dot = text; - } - // int_handler() can jump to "restart", - // must install handler *after* initializing "restart" - signal(SIGINT, int_handler); -#endif - - cmd_mode = 0; // 0=command 1=insert 2='R'eplace - cmdcnt = 0; - tabstop = 8; - offset = 0; // no horizontal offset - c = '\0'; -#if ENABLE_FEATURE_VI_DOT_CMD - free(ioq_start); - ioq = ioq_start = NULL; - lmc_len = 0; - adding2q = 0; -#endif - -#if ENABLE_FEATURE_VI_COLON - { - char *p, *q; - int n = 0; - - while ((p = initial_cmds[n]) != NULL) { - do { - q = p; - p = strchr(q, '\n'); - if (p) - while (*p == '\n') - *p++ = '\0'; - if (*q) - colon(q); - } while (p); - free(initial_cmds[n]); - initial_cmds[n] = NULL; - n++; - } - } -#endif - redraw(FALSE); // dont force every col re-draw - //------This is the main Vi cmd handling loop ----------------------- - while (editing > 0) { -#if ENABLE_FEATURE_VI_CRASHME - if (crashme > 0) { - if ((end - text) > 1) { - crash_dummy(); // generate a random command - } else { - crashme = 0; - string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n", NO_UNDO); // insert the string - dot = text; - refresh(FALSE); - } - } -#endif - last_input_char = c = get_one_char(); // get a cmd from user -#if ENABLE_FEATURE_VI_YANKMARK - // save a copy of the current line- for the 'U" command - if (begin_line(dot) != cur_line) { - cur_line = begin_line(dot); - text_yank(begin_line(dot), end_line(dot), Ureg); - } -#endif -#if ENABLE_FEATURE_VI_DOT_CMD - // These are commands that change text[]. - // Remember the input for the "." command - if (!adding2q && ioq_start == NULL - && cmd_mode == 0 // command mode - && c > '\0' // exclude NUL and non-ASCII chars - && c < 0x7f // (Unicode and such) - && strchr(modifying_cmds, c) - ) { - start_new_cmd_q(c); - } -#endif - do_cmd(c); // execute the user command - - // poll to see if there is input already waiting. if we are - // not able to display output fast enough to keep up, skip - // the display update until we catch up with input. - if (!readbuffer[0] && mysleep(0) == 0) { - // no input pending - so update output - refresh(FALSE); - show_status_line(); - } -#if ENABLE_FEATURE_VI_CRASHME - if (crashme > 0) - crash_test(); // test editor variables -#endif - } - //------------------------------------------------------------------- - - go_bottom_and_clear_to_eol(); - cookmode(); -#undef cur_line -} - //----- The Colon commands ------------------------------------- #if ENABLE_FEATURE_VI_COLON static char *get_one_address(char *p, int *addr) // get colon addr, if present @@ -2589,39 +2388,6 @@ static char *yank_delete(char *start, char *stop, int dist, int yf, int undo) return p; } -static void show_help(void) -{ - puts("These features are available:" -#if ENABLE_FEATURE_VI_SEARCH - "\n\tPattern searches with / and ?" -#endif -#if ENABLE_FEATURE_VI_DOT_CMD - "\n\tLast command repeat with ." -#endif -#if ENABLE_FEATURE_VI_YANKMARK - "\n\tLine marking with 'x" - "\n\tNamed buffers with \"x" -#endif -#if ENABLE_FEATURE_VI_READONLY - //not implemented: "\n\tReadonly if vi is called as \"view\"" - //redundant: usage text says this too: "\n\tReadonly with -R command line arg" -#endif -#if ENABLE_FEATURE_VI_SET - "\n\tSome colon mode commands with :" -#endif -#if ENABLE_FEATURE_VI_SETOPTS - "\n\tSettable options with \":set\"" -#endif -#if ENABLE_FEATURE_VI_USE_SIGNALS - "\n\tSignal catching- ^C" - "\n\tJob suspend and resume with ^Z" -#endif -#if ENABLE_FEATURE_VI_WIN_RESIZE - "\n\tAdapt to window re-sizes" -#endif - ); -} - #if ENABLE_FEATURE_VI_DOT_CMD static void start_new_cmd_q(char c) { @@ -4495,3 +4261,235 @@ static void crash_test() } } #endif + +static void edit_file(char *fn) +{ +#if ENABLE_FEATURE_VI_YANKMARK +#define cur_line edit_file__cur_line +#endif + int c; +#if ENABLE_FEATURE_VI_USE_SIGNALS + int sig; +#endif + + editing = 1; // 0 = exit, 1 = one file, 2 = multiple files + rawmode(); + rows = 24; + columns = 80; + IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); +#if ENABLE_FEATURE_VI_ASK_TERMINAL + if (G.get_rowcol_error /* TODO? && no input on stdin */) { + uint64_t k; + write1(ESC"[999;999H" ESC"[6n"); + fflush_all(); + k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); + if ((int32_t)k == KEYCODE_CURSOR_POS) { + uint32_t rc = (k >> 32); + columns = (rc & 0x7fff); + if (columns > MAX_SCR_COLS) + columns = MAX_SCR_COLS; + rows = ((rc >> 16) & 0x7fff); + if (rows > MAX_SCR_ROWS) + rows = MAX_SCR_ROWS; + } + } +#endif + new_screen(rows, columns); // get memory for virtual screen + init_text_buffer(fn); + +#if ENABLE_FEATURE_VI_YANKMARK + YDreg = 26; // default Yank/Delete reg +// Ureg = 27; - const // hold orig line for "U" cmd + mark[26] = mark[27] = text; // init "previous context" +#endif + + last_forward_char = last_input_char = '\0'; + crow = 0; + ccol = 0; + +#if ENABLE_FEATURE_VI_USE_SIGNALS + signal(SIGWINCH, winch_handler); + signal(SIGTSTP, tstp_handler); + sig = sigsetjmp(restart, 1); + if (sig != 0) { + screenbegin = dot = text; + } + // int_handler() can jump to "restart", + // must install handler *after* initializing "restart" + signal(SIGINT, int_handler); +#endif + + cmd_mode = 0; // 0=command 1=insert 2='R'eplace + cmdcnt = 0; + tabstop = 8; + offset = 0; // no horizontal offset + c = '\0'; +#if ENABLE_FEATURE_VI_DOT_CMD + free(ioq_start); + ioq = ioq_start = NULL; + lmc_len = 0; + adding2q = 0; +#endif + +#if ENABLE_FEATURE_VI_COLON + { + char *p, *q; + int n = 0; + + while ((p = initial_cmds[n]) != NULL) { + do { + q = p; + p = strchr(q, '\n'); + if (p) + while (*p == '\n') + *p++ = '\0'; + if (*q) + colon(q); + } while (p); + free(initial_cmds[n]); + initial_cmds[n] = NULL; + n++; + } + } +#endif + redraw(FALSE); // dont force every col re-draw + //------This is the main Vi cmd handling loop ----------------------- + while (editing > 0) { +#if ENABLE_FEATURE_VI_CRASHME + if (crashme > 0) { + if ((end - text) > 1) { + crash_dummy(); // generate a random command + } else { + crashme = 0; + string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n", NO_UNDO); // insert the string + dot = text; + refresh(FALSE); + } + } +#endif + last_input_char = c = get_one_char(); // get a cmd from user +#if ENABLE_FEATURE_VI_YANKMARK + // save a copy of the current line- for the 'U" command + if (begin_line(dot) != cur_line) { + cur_line = begin_line(dot); + text_yank(begin_line(dot), end_line(dot), Ureg); + } +#endif +#if ENABLE_FEATURE_VI_DOT_CMD + // These are commands that change text[]. + // Remember the input for the "." command + if (!adding2q && ioq_start == NULL + && cmd_mode == 0 // command mode + && c > '\0' // exclude NUL and non-ASCII chars + && c < 0x7f // (Unicode and such) + && strchr(modifying_cmds, c) + ) { + start_new_cmd_q(c); + } +#endif + do_cmd(c); // execute the user command + + // poll to see if there is input already waiting. if we are + // not able to display output fast enough to keep up, skip + // the display update until we catch up with input. + if (!readbuffer[0] && mysleep(0) == 0) { + // no input pending - so update output + refresh(FALSE); + show_status_line(); + } +#if ENABLE_FEATURE_VI_CRASHME + if (crashme > 0) + crash_test(); // test editor variables +#endif + } + //------------------------------------------------------------------- + + go_bottom_and_clear_to_eol(); + cookmode(); +#undef cur_line +} + +int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int vi_main(int argc, char **argv) +{ + int c; + + INIT_G(); + +#if ENABLE_FEATURE_VI_UNDO + /* undo_stack_tail = NULL; - already is */ +#if ENABLE_FEATURE_VI_UNDO_QUEUE + undo_queue_state = UNDO_EMPTY; + /* undo_q = 0; - already is */ +#endif +#endif + +#if ENABLE_FEATURE_VI_CRASHME + srand((long) getpid()); +#endif +#ifdef NO_SUCH_APPLET_YET + // if we aren't "vi", we are "view" + if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) { + SET_READONLY_MODE(readonly_mode); + } +#endif + + // autoindent is not default in vim 7.3 + vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE; + // 1- process $HOME/.exrc file (not inplemented yet) + // 2- process EXINIT variable from environment + // 3- process command line args +#if ENABLE_FEATURE_VI_COLON + { + char *p = getenv("EXINIT"); + if (p && *p) + initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); + } +#endif + while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) { + switch (c) { +#if ENABLE_FEATURE_VI_CRASHME + case 'C': + crashme = 1; + break; +#endif +#if ENABLE_FEATURE_VI_READONLY + case 'R': // Read-only flag + SET_READONLY_MODE(readonly_mode); + break; +#endif +#if ENABLE_FEATURE_VI_COLON + case 'c': // cmd line vi command + if (*optarg) + initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); + break; +#endif + case 'H': + show_help(); + // fall through + default: + bb_show_usage(); + return 1; + } + } + + // The argv array can be used by the ":next" and ":rewind" commands + argv += optind; + argc -= optind; + + //----- This is the main file handling loop -------------- + save_argc = argc; + optind = 0; + // "Save cursor, use alternate screen buffer, clear screen" + write1(ESC"[?1049h"); + while (1) { + edit_file(argv[optind]); // param might be NULL + if (++optind >= argc) + break; + } + // "Use normal screen buffer, restore cursor" + write1(ESC"[?1049l"); + //----------------------------------------------------------- + + return 0; +} |