?? vi.c
字號:
/* vi: set sw=8 ts=8: *//* * tiny vi.c: A small 'vi' clone * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */static const char vi_Version[] = "$Id: vi.c,v 1.19 2002/10/26 10:19:07 andersen Exp $";/* * To compile for standalone use: * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c * or * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features * strip vi *//* * Things To Do: * EXINIT * $HOME/.exrc and ./.exrc * add magic to search /foo.*bar * add :help command * :map macros * how about mode lines: vi: set sw=8 ts=8: * if mark[] values were line numbers rather than pointers * it would be easier to change the mark when add/delete lines * More intelligence in refresh() * ":r !cmd" and "!cmd" to filter text through an external command * A true "undo" facility * An "ex" line oriented mode- maybe using "cmdedit" *///---- Feature -------------- Bytes to immplement#ifdef STANDALONE#define vi_main main#define BB_FEATURE_VI_COLON // 4288#define BB_FEATURE_VI_YANKMARK // 1408#define BB_FEATURE_VI_SEARCH // 1088#define BB_FEATURE_VI_USE_SIGNALS // 1056#define BB_FEATURE_VI_DOT_CMD // 576#define BB_FEATURE_VI_READONLY // 128#define BB_FEATURE_VI_SETOPTS // 576#define BB_FEATURE_VI_SET // 224#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE// To test editor using CRASHME:// vi -C filename// To stop testing, wait until all to text[] is deleted, or// Ctrl-Z and kill -9 %1// while in the editor Ctrl-T will toggle the crashme function on and off.//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute#endif /* STANDALONE */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <time.h>#include <fcntl.h>#include <signal.h>#include <setjmp.h>#include <regex.h>#include <ctype.h>#include <assert.h>#include <errno.h>#include <stdarg.h>#ifndef STANDALONE#include "busybox.h"#endif /* STANDALONE */#ifndef TRUE#define TRUE ((int)1)#define FALSE ((int)0)#endif /* TRUE */#define MAX_SCR_COLS BUFSIZ// Misc. non-Ascii keys that report an escape sequence#define VI_K_UP 128 // cursor key Up#define VI_K_DOWN 129 // cursor key Down#define VI_K_RIGHT 130 // Cursor Key Right#define VI_K_LEFT 131 // cursor key Left#define VI_K_HOME 132 // Cursor Key Home#define VI_K_END 133 // Cursor Key End#define VI_K_INSERT 134 // Cursor Key Insert#define VI_K_PAGEUP 135 // Cursor Key Page Up#define VI_K_PAGEDOWN 136 // Cursor Key Page Down#define VI_K_FUN1 137 // Function Key F1#define VI_K_FUN2 138 // Function Key F2#define VI_K_FUN3 139 // Function Key F3#define VI_K_FUN4 140 // Function Key F4#define VI_K_FUN5 141 // Function Key F5#define VI_K_FUN6 142 // Function Key F6#define VI_K_FUN7 143 // Function Key F7#define VI_K_FUN8 144 // Function Key F8#define VI_K_FUN9 145 // Function Key F9#define VI_K_FUN10 146 // Function Key F10#define VI_K_FUN11 147 // Function Key F11#define VI_K_FUN12 148 // Function Key F12static const int YANKONLY = FALSE;static const int YANKDEL = TRUE;static const int FORWARD = 1; // code depends on "1" for array indexstatic const int BACK = -1; // code depends on "-1" for array indexstatic const int LIMITED = 0; // how much of text[] in char_searchstatic const int FULL = 1; // how much of text[] in char_searchstatic const int S_BEFORE_WS = 1; // used in skip_thing() for moving "dot"static const int S_TO_WS = 2; // used in skip_thing() for moving "dot"static const int S_OVER_WS = 3; // used in skip_thing() for moving "dot"static const int S_END_PUNCT = 4; // used in skip_thing() for moving "dot"static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot"typedef unsigned char Byte;static int editing; // >0 while we are editing a filestatic int cmd_mode; // 0=command 1=insertstatic int file_modified; // buffer contents changedstatic int err_method; // indicate error with beep or flashstatic int fn_start; // index of first cmd line file namestatic int save_argc; // how many file names on cmd linestatic int cmdcnt; // repetition countstatic fd_set rfds; // use select() for small sleepsstatic struct timeval tv; // use select() for small sleepsstatic char erase_char; // the users erase characterstatic int rows, columns; // the terminal screen is this sizestatic int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofsetstatic char *SOs, *SOn; // terminal standout start/normal ESC sequencestatic char *bell; // terminal bell sequencestatic char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequencestatic char *CMrc; // Cursor motion arbitrary destination ESC sequencestatic char *CMup, *CMdown; // Cursor motion up and down ESC sequencestatic Byte *status_buffer; // mesages to the userstatic Byte last_input_char; // last char read from userstatic Byte last_forward_char; // last char searched for with 'f'static Byte *cfn; // previous, current, and next file namestatic Byte *text, *end, *textend; // pointers to the user data in memorystatic Byte *screen; // pointer to the virtual screen bufferstatic int screensize; // and its sizestatic Byte *screenbegin; // index into text[], of top line on the screenstatic Byte *dot; // where all the action takes placestatic int tabstop;static struct termios term_orig, term_vi; // remember what the cooked mode was#ifdef BB_FEATURE_VI_OPTIMIZE_CURSORstatic int last_row; // where the cursor was last moved to#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */#ifdef BB_FEATURE_VI_USE_SIGNALSstatic jmp_buf restart; // catch_sig()#endif /* BB_FEATURE_VI_USE_SIGNALS */#ifdef BB_FEATURE_VI_WIN_RESIZEstatic struct winsize winsize; // remember the window size#endif /* BB_FEATURE_VI_WIN_RESIZE */#ifdef BB_FEATURE_VI_DOT_CMDstatic int adding2q; // are we currently adding user input to qstatic Byte *last_modifying_cmd; // last modifying cmd for "."static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read"#endif /* BB_FEATURE_VI_DOT_CMD */#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK)static Byte *modifying_cmds; // cmds that modify text[]#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */#ifdef BB_FEATURE_VI_READONLYstatic int vi_readonly, readonly;#endif /* BB_FEATURE_VI_READONLY */#ifdef BB_FEATURE_VI_SETOPTSstatic int autoindent;static int showmatch;static int ignorecase;#endif /* BB_FEATURE_VI_SETOPTS */#ifdef BB_FEATURE_VI_YANKMARKstatic Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27static int YDreg, Ureg; // default delete register and orig line for "U"static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context ''static Byte *context_start, *context_end;#endif /* BB_FEATURE_VI_YANKMARK */#ifdef BB_FEATURE_VI_SEARCHstatic Byte *last_search_pattern; // last pattern from a '/' or '?' search#endif /* BB_FEATURE_VI_SEARCH */static void edit_file(Byte *); // edit one filestatic void do_cmd(Byte); // execute a commandstatic void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dotstatic Byte *begin_line(Byte *); // return pointer to cur line B-o-lstatic Byte *end_line(Byte *); // return pointer to cur line E-o-lstatic Byte *dollar_line(Byte *); // return pointer to just before NLstatic Byte *prev_line(Byte *); // return pointer to prev line B-o-lstatic Byte *next_line(Byte *); // return pointer to next line B-o-lstatic Byte *end_screen(void); // get pointer to last char on screenstatic int count_lines(Byte *, Byte *); // count line from start to stopstatic Byte *find_line(int); // find begining of line #listatic Byte *move_to_col(Byte *, int); // move "p" to column lstatic int isblnk(Byte); // is the char a blank or tabstatic void dot_left(void); // move dot left- dont leave linestatic void dot_right(void); // move dot right- dont leave linestatic void dot_begin(void); // move dot to B-o-lstatic void dot_end(void); // move dot to E-o-lstatic void dot_next(void); // move dot to next line B-o-lstatic void dot_prev(void); // move dot to prev line B-o-lstatic void dot_scroll(int, int); // move the screen up or downstatic void dot_skip_over_ws(void); // move dot pat WSstatic void dot_delete(void); // delete the char at 'dot'static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end"static Byte *new_screen(int, int); // malloc virtual screen memorystatic Byte *new_text(int); // malloc memory for text[] bufferstatic Byte *char_insert(Byte *, Byte); // insert the char c at 'p'static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p'static Byte find_range(Byte **, Byte **, Byte); // return pointers for an objectstatic int st_test(Byte *, int, int, Byte *); // helper for skip_thing()static Byte *skip_thing(Byte *, int, int, int); // skip some objectstatic Byte *find_pair(Byte *, Byte); // find matching pair () [] {}static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte holestatic Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte holestatic Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then deletestatic void show_help(void); // display some help infostatic void print_literal(Byte *, Byte *); // copy s to buf, convert unprintablestatic void rawmode(void); // set "raw" mode on ttystatic void cookmode(void); // return to "cooked" mode on ttystatic int mysleep(int); // sleep for 'h' 1/100 secondsstatic Byte readit(void); // read (maybe cursor) key from stdinstatic Byte get_one_char(void); // read 1 char from stdinstatic int file_size(Byte *); // what is the byte size of "fn"static int file_insert(Byte *, Byte *, int);static int file_write(Byte *, Byte *, Byte *);static void place_cursor(int, int, int);static void screen_erase();static void clear_to_eol(void);static void clear_to_eos(void);static void standout_start(void); // send "start reverse video" sequencestatic void standout_end(void); // send "end reverse video" sequencestatic void flash(int); // flash the terminal screenstatic void beep(void); // beep the terminalstatic void indicate_error(char); // use flash or beep to indicate errorstatic void show_status_line(void); // put a message on the bottom linestatic void psb(char *, ...); // Print Status Bufstatic void psbs(char *, ...); // Print Status Buf in standout modestatic void ni(Byte *); // display messagesstatic void edit_status(void); // show file status on status linestatic void redraw(int); // force a full screen refreshstatic void format_line(Byte*, Byte*, int);static void refresh(int); // update the terminal from screen[]#ifdef BB_FEATURE_VI_SEARCHstatic Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at pstatic int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"#endif /* BB_FEATURE_VI_SEARCH */#ifdef BB_FEATURE_VI_COLONstatic void Hit_Return(void);static Byte *get_one_address(Byte *, int *); // get colon addr, if presentstatic Byte *get_address(Byte *, int *, int *); // get two colon addrs, if presentstatic void colon(Byte *); // execute the "colon" mode cmds#endif /* BB_FEATURE_VI_COLON */static Byte *get_input_line(Byte *); // get input line- use "status line"#ifdef BB_FEATURE_VI_USE_SIGNALSstatic void winch_sig(int); // catch window size changesstatic void suspend_sig(int); // catch ctrl-Zstatic void alarm_sig(int); // catch alarm time-outsstatic void catch_sig(int); // catch ctrl-Cstatic void core_sig(int); // catch a core dump signal#endif /* BB_FEATURE_VI_USE_SIGNALS */#ifdef BB_FEATURE_VI_DOT_CMDstatic void start_new_cmd_q(Byte); // new queue for commandstatic void end_cmd_q(); // stop saving input chars#else /* BB_FEATURE_VI_DOT_CMD */#define end_cmd_q()#endif /* BB_FEATURE_VI_DOT_CMD */#ifdef BB_FEATURE_VI_WIN_RESIZEstatic void window_size_get(int); // find out what size the window is#endif /* BB_FEATURE_VI_WIN_RESIZE */#ifdef BB_FEATURE_VI_SETOPTSstatic void showmatching(Byte *); // show the matching pair () [] {}#endif /* BB_FEATURE_VI_SETOPTS */#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)static Byte *string_insert(Byte *, Byte *); // insert the string at 'p'#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */#ifdef BB_FEATURE_VI_YANKMARKstatic Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a registerstatic Byte what_reg(void); // what is letter of current YDregstatic void check_context(Byte); // remember context for '' commandstatic Byte *swap_context(Byte *); // goto new context for '' command#endif /* BB_FEATURE_VI_YANKMARK */#ifdef BB_FEATURE_VI_CRASHMEstatic void crash_dummy();static void crash_test();static int crashme = 0;#endif /* BB_FEATURE_VI_CRASHME */extern int vi_main(int argc, char **argv){ int c;#ifdef BB_FEATURE_VI_YANKMARK int i;#endif /* BB_FEATURE_VI_YANKMARK */ CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence CMup= "\033[A"; // move cursor up one line, same col CMdown="\n"; // move cursor down one line, same col Ceol= "\033[0K"; // Clear from cursor to end of line Ceos= "\033[0J"; // Clear from cursor to end of screen SOs = "\033[7m"; // Terminal standout mode on SOn = "\033[0m"; // Terminal standout mode off bell= "\007"; // Terminal bell sequence#ifdef BB_FEATURE_VI_CRASHME (void) srand((long) getpid());#endif /* BB_FEATURE_VI_CRASHME */ status_buffer = (Byte *) xmalloc(200); // hold messages to user#ifdef BB_FEATURE_VI_READONLY vi_readonly = readonly = FALSE; if (strncmp(argv[0], "view", 4) == 0) { readonly = TRUE; vi_readonly = TRUE; }#endif /* BB_FEATURE_VI_READONLY */#ifdef BB_FEATURE_VI_SETOPTS autoindent = 1; ignorecase = 1; showmatch = 1;#endif /* BB_FEATURE_VI_SETOPTS */#ifdef BB_FEATURE_VI_YANKMARK for (i = 0; i < 28; i++) { reg[i] = 0; } // init the yank regs#endif /* BB_FEATURE_VI_YANKMARK */#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[]#endif /* BB_FEATURE_VI_DOT_CMD */ // 1- process $HOME/.exrc file // 2- process EXINIT variable from environment // 3- process command line args while ((c = getopt(argc, argv, "hCR")) != -1) { switch (c) {#ifdef BB_FEATURE_VI_CRASHME case 'C': crashme = 1; break;#endif /* BB_FEATURE_VI_CRASHME */#ifdef BB_FEATURE_VI_READONLY case 'R': // Read-only flag readonly = TRUE; break;#endif /* BB_FEATURE_VI_READONLY */ //case 'r': // recover flag- ignore- we don't use tmp file //case 'x': // encryption flag- ignore //case 'c': // execute command first //case 'h': // help -- just use default default: show_help(); return 1; } } // The argv array can be used by the ":next" and ":rewind" commands // save optind. fn_start = optind; // remember first file name for :next and :rew save_argc = argc; //----- This is the main file handling loop -------------- if (optind >= argc) { editing = 1; // 0= exit, 1= one file, 2= multiple files edit_file(0); } else { for (; optind < argc; optind++) { editing = 1; // 0=exit, 1=one file, 2+ =many files if (cfn != 0) free(cfn); cfn = (Byte *) strdup(argv[optind]); edit_file(cfn); } } //----------------------------------------------------------- return (0);}static void edit_file(Byte * fn){ char c; int cnt, size, ch;#ifdef BB_FEATURE_VI_USE_SIGNALS char *msg; int sig;#endif /* BB_FEATURE_VI_USE_SIGNALS */#ifdef BB_FEATURE_VI_YANKMARK static Byte *cur_line;#endif /* BB_FEATURE_VI_YANKMARK */ rawmode(); rows = 24; columns = 80; ch= -1;#ifdef BB_FEATURE_VI_WIN_RESIZE window_size_get(0);#endif /* BB_FEATURE_VI_WIN_RESIZE */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -