Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/editors/vi.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/editors/vi.c
r2725 r3232 15 15 * :map macros 16 16 * if mark[] values were line numbers rather than pointers 17 * 17 * it would be easier to change the mark when add/delete lines 18 18 * More intelligence in refresh() 19 19 * ":r !cmd" and "!cmd" to filter text through an external command … … 22 22 */ 23 23 24 //config:config VI 25 //config: bool "vi" 26 //config: default y 27 //config: help 28 //config: 'vi' is a text editor. More specifically, it is the One True 29 //config: text editor <grin>. It does, however, have a rather steep 30 //config: learning curve. If you are not already comfortable with 'vi' 31 //config: you may wish to use something else. 32 //config: 33 //config:config FEATURE_VI_MAX_LEN 34 //config: int "Maximum screen width in vi" 35 //config: range 256 16384 36 //config: default 4096 37 //config: depends on VI 38 //config: help 39 //config: Contrary to what you may think, this is not eating much. 40 //config: Make it smaller than 4k only if you are very limited on memory. 41 //config: 42 //config:config FEATURE_VI_8BIT 43 //config: bool "Allow vi to display 8-bit chars (otherwise shows dots)" 44 //config: default n 45 //config: depends on VI 46 //config: help 47 //config: If your terminal can display characters with high bit set, 48 //config: you may want to enable this. Note: vi is not Unicode-capable. 49 //config: If your terminal combines several 8-bit bytes into one character 50 //config: (as in Unicode mode), this will not work properly. 51 //config: 52 //config:config FEATURE_VI_COLON 53 //config: bool "Enable \":\" colon commands (no \"ex\" mode)" 54 //config: default y 55 //config: depends on VI 56 //config: help 57 //config: Enable a limited set of colon commands for vi. This does not 58 //config: provide an "ex" mode. 59 //config: 60 //config:config FEATURE_VI_YANKMARK 61 //config: bool "Enable yank/put commands and mark cmds" 62 //config: default y 63 //config: depends on VI 64 //config: help 65 //config: This will enable you to use yank and put, as well as mark in 66 //config: busybox vi. 67 //config: 68 //config:config FEATURE_VI_SEARCH 69 //config: bool "Enable search and replace cmds" 70 //config: default y 71 //config: depends on VI 72 //config: help 73 //config: Select this if you wish to be able to do search and replace in 74 //config: busybox vi. 75 //config: 76 //config:config FEATURE_VI_REGEX_SEARCH 77 //config: bool "Enable regex in search and replace" 78 //config: default n # Uses GNU regex, which may be unavailable. FIXME 79 //config: depends on FEATURE_VI_SEARCH 80 //config: help 81 //config: Use extended regex search. 82 //config: 83 //config:config FEATURE_VI_USE_SIGNALS 84 //config: bool "Catch signals" 85 //config: default y 86 //config: depends on VI 87 //config: help 88 //config: Selecting this option will make busybox vi signal aware. This will 89 //config: make busybox vi support SIGWINCH to deal with Window Changes, catch 90 //config: Ctrl-Z and Ctrl-C and alarms. 91 //config: 92 //config:config FEATURE_VI_DOT_CMD 93 //config: bool "Remember previous cmd and \".\" cmd" 94 //config: default y 95 //config: depends on VI 96 //config: help 97 //config: Make busybox vi remember the last command and be able to repeat it. 98 //config: 99 //config:config FEATURE_VI_READONLY 100 //config: bool "Enable -R option and \"view\" mode" 101 //config: default y 102 //config: depends on VI 103 //config: help 104 //config: Enable the read-only command line option, which allows the user to 105 //config: open a file in read-only mode. 106 //config: 107 //config:config FEATURE_VI_SETOPTS 108 //config: bool "Enable set-able options, ai ic showmatch" 109 //config: default y 110 //config: depends on VI 111 //config: help 112 //config: Enable the editor to set some (ai, ic, showmatch) options. 113 //config: 114 //config:config FEATURE_VI_SET 115 //config: bool "Support for :set" 116 //config: default y 117 //config: depends on VI 118 //config: help 119 //config: Support for ":set". 120 //config: 121 //config:config FEATURE_VI_WIN_RESIZE 122 //config: bool "Handle window resize" 123 //config: default y 124 //config: depends on VI 125 //config: help 126 //config: Make busybox vi behave nicely with terminals that get resized. 127 //config: 128 //config:config FEATURE_VI_ASK_TERMINAL 129 //config: bool "Use 'tell me cursor position' ESC sequence to measure window" 130 //config: default y 131 //config: depends on VI 132 //config: help 133 //config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, 134 //config: this option makes vi perform a last-ditch effort to find it: 135 //config: position cursor to 999,999 and ask terminal to report real 136 //config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. 137 //config: 138 //config: This is not clean but helps a lot on serial lines and such. 139 140 //applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) 141 142 //kbuild:lib-$(CONFIG_VI) += vi.o 143 144 //usage:#define vi_trivial_usage 145 //usage: "[OPTIONS] [FILE]..." 146 //usage:#define vi_full_usage "\n\n" 147 //usage: "Edit FILE\n" 148 //usage: IF_FEATURE_VI_COLON( 149 //usage: "\n -c CMD Initial command to run ($EXINIT also available)" 150 //usage: ) 151 //usage: IF_FEATURE_VI_READONLY( 152 //usage: "\n -R Read-only" 153 //usage: ) 154 //usage: "\n -H List available features" 155 24 156 #include "libbb.h" 157 /* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ 158 #if ENABLE_FEATURE_VI_REGEX_SEARCH 159 # include <regex.h> 160 #endif 25 161 26 162 /* the CRASHME code is unmaintained, and doesn't currently build */ … … 41 177 /* 0x9b is Meta-ESC */ 42 178 #if ENABLE_FEATURE_VI_8BIT 43 # define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b)179 # define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) 44 180 #else 45 # define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f)181 # define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) 46 182 #endif 47 183 … … 59 195 }; 60 196 61 /* vt102 typical ESC sequence */ 62 /* terminal standout start/normal ESC sequence */ 63 #define SOs "\033[7m" 64 #define SOn "\033[0m" 65 /* terminal bell sequence */ 66 #define bell "\007" 67 /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 68 #define Ceol "\033[K" 69 #define Ceos "\033[J" 70 /* Cursor motion arbitrary destination ESC sequence */ 71 #define CMrc "\033[%u;%uH" 72 /* Cursor motion up and down ESC sequence */ 73 #define CMup "\033[A" 74 #define CMdown "\n" 197 /* VT102 ESC sequences. 198 * See "Xterm Control Sequences" 199 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 200 */ 201 /* Inverse/Normal text */ 202 #define ESC_BOLD_TEXT "\033[7m" 203 #define ESC_NORM_TEXT "\033[0m" 204 /* Bell */ 205 #define ESC_BELL "\007" 206 /* Clear-to-end-of-line */ 207 #define ESC_CLEAR2EOL "\033[K" 208 /* Clear-to-end-of-screen. 209 * (We use default param here. 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" 75 220 76 221 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK … … 135 280 int file_modified; // buffer contents changed (counter, not flag!) 136 281 int last_file_modified; // = -1; 137 int fn_start; // index of first cmd line file name138 282 int save_argc; // how many file names on cmd line 139 283 int cmdcnt; // repetition count … … 161 305 char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 162 306 #endif 163 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR164 int last_row; // where the cursor was last moved to165 #endif166 307 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 167 308 int my_pid; … … 220 361 #define file_modified (G.file_modified ) 221 362 #define last_file_modified (G.last_file_modified ) 222 #define fn_start (G.fn_start )223 363 #define save_argc (G.save_argc ) 224 364 #define cmdcnt (G.cmdcnt ) … … 248 388 #define ioq (G.ioq ) 249 389 #define ioq_start (G.ioq_start ) 250 #define last_row (G.last_row )251 390 #define my_pid (G.my_pid ) 252 391 #define last_search_pattern (G.last_search_pattern) … … 329 468 static int file_insert(const char *, char *, int); 330 469 static int file_write(char *, char *, char *); 331 #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 332 #define place_cursor(a, b, optimize) place_cursor(a, b) 333 #endif 334 static void place_cursor(int, int, int); 470 static void place_cursor(int, int); 335 471 static void screen_erase(void); 336 472 static void clear_to_eol(void); … … 355 491 #if ENABLE_FEATURE_VI_SEARCH 356 492 static char *char_search(char *, const char *, int, int); // search for pattern starting at p 357 static int mycmp(const char *, const char *, int); // string cmp based in "ignorecase"358 493 #endif 359 494 #if ENABLE_FEATURE_VI_COLON … … 418 553 #endif 419 554 420 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; 421 557 // 1- process $HOME/.exrc file (not inplemented yet) 422 558 // 2- process EXINIT variable from environment … … 444 580 case 'c': // cmd line vi command 445 581 if (*optarg) 446 initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN);582 initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); 447 583 break; 448 584 #endif … … 457 593 458 594 // The argv array can be used by the ":next" and ":rewind" commands 459 // save optind. 460 fn_start = optind; // remember first file name for :next and :rew 595 argv += optind; 596 argc -= optind; 597 598 //----- This is the main file handling loop -------------- 461 599 save_argc = argc; 462 463 //----- This is the main file handling loop -------------- 600 optind = 0; 601 // "Save cursor, use alternate screen buffer, clear screen" 602 write1("\033[?1049h"); 464 603 while (1) { 465 604 edit_file(argv[optind]); /* param might be NULL */ … … 467 606 break; 468 607 } 608 // "Use normal screen buffer, restore cursor" 609 write1("\033[?1049l"); 469 610 //----------------------------------------------------------- 470 611 … … 524 665 #endif 525 666 int c; 526 int size;527 667 #if ENABLE_FEATURE_VI_USE_SIGNALS 528 668 int sig; … … 533 673 rows = 24; 534 674 columns = 80; 535 size = 0;536 675 IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); 537 676 #if ENABLE_FEATURE_VI_ASK_TERMINAL … … 881 1020 // don't edit, if the current file has been modified 882 1021 if (file_modified && !useforce) { 883 status_line_bold("No write since last change (: edit! overrides)");1022 status_line_bold("No write since last change (:%s! overrides)", cmd); 884 1023 goto ret; 885 1024 } … … 900 1039 901 1040 #if ENABLE_FEATURE_VI_YANKMARK 902 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {1041 if (Ureg >= 0 && Ureg < 28) { 903 1042 free(reg[Ureg]); // free orig line reg- for 'U' 904 reg[Ureg] = 0;905 } 906 if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {1043 reg[Ureg] = NULL; 1044 } 1045 if (YDreg >= 0 && YDreg < 28) { 907 1046 free(reg[YDreg]); // free default yank/delete register 908 reg[YDreg] = 0;1047 reg[YDreg] = NULL; 909 1048 } 910 1049 #endif … … 971 1110 } else if (strncmp(cmd, "quit", i) == 0 // quit 972 1111 || strncmp(cmd, "next", i) == 0 // edit next file 1112 || strncmp(cmd, "prev", i) == 0 // edit previous file 973 1113 ) { 974 1114 int n; 975 1115 if (useforce) { 976 // force end of argv list977 1116 if (*cmd == 'q') { 1117 // force end of argv list 978 1118 optind = save_argc; 979 1119 } … … 983 1123 // don't exit if the file been modified 984 1124 if (file_modified) { 985 status_line_bold("No write since last change (:%s! overrides)", 986 (*cmd == 'q' ? "quit" : "next")); 1125 status_line_bold("No write since last change (:%s! overrides)", cmd); 987 1126 goto ret; 988 1127 } … … 996 1135 status_line_bold("No more files to edit"); 997 1136 goto ret; 1137 } 1138 if (*cmd == 'p') { 1139 // are there previous files to edit 1140 if (optind < 1) { 1141 status_line_bold("No previous files to edit"); 1142 goto ret; 1143 } 1144 optind -= 2; 998 1145 } 999 1146 editing = 0; … … 1032 1179 } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args 1033 1180 if (file_modified && !useforce) { 1034 status_line_bold("No write since last change (: rewind! overrides)");1181 status_line_bold("No write since last change (:%s! overrides)", cmd); 1035 1182 } else { 1036 1183 // reset the filenames to edit 1037 optind = fn_start - 1;1184 optind = -1; /* start from 0th file */ 1038 1185 editing = 0; 1039 1186 } … … 1044 1191 #endif 1045 1192 i = 0; // offset into args 1046 // only blank is regarded as args del miter. What about tab '\t'?1193 // only blank is regarded as args delimiter. What about tab '\t'? 1047 1194 if (!args[0] || strcasecmp(args, "all") == 0) { 1048 1195 // print out values of all options … … 1085 1232 #if ENABLE_FEATURE_VI_SEARCH 1086 1233 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern 1087 char *ls, *F, *R; 1088 int gflag; 1234 char *F, *R, *flags; 1235 size_t len_F, len_R; 1236 int gflag; // global replace flag 1089 1237 1090 1238 // F points to the "find" pattern 1091 1239 // R points to the "replace" pattern 1092 // replace the cmd line delimiters "/" with NULLs 1093 gflag = 0; // global replace flag 1240 // replace the cmd line delimiters "/" with NULs 1094 1241 c = orig_buf[1]; // what is the delimiter 1095 1242 F = orig_buf + 2; // start of "find" … … 1097 1244 if (!R) 1098 1245 goto colon_s_fail; 1246 len_F = R - F; 1099 1247 *R++ = '\0'; // terminate "find" 1100 buf1= strchr(R, c);1101 if (! buf1)1248 flags = strchr(R, c); 1249 if (!flags) 1102 1250 goto colon_s_fail; 1103 *buf1++ = '\0'; // terminate "replace" 1104 if (*buf1 == 'g') { // :s/foo/bar/g 1105 buf1++; 1106 gflag++; // turn on gflag 1107 } 1251 len_R = flags - R; 1252 *flags++ = '\0'; // terminate "replace" 1253 gflag = *flags; 1254 1108 1255 q = begin_line(q); 1109 1256 if (b < 0) { // maybe :s/foo/bar/ 1110 q = begin_line(dot); 1111 b = count_lines(text, q); 1257 q = begin_line(dot); // start with cur line 1258 b = count_lines(text, q); // cur line number 1112 1259 } 1113 1260 if (e < 0) 1114 1261 e = b; // maybe :.s/foo/bar/ 1262 1115 1263 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 1116 ls = q; // orig line start 1264 char *ls = q; // orig line start 1265 char *found; 1117 1266 vc4: 1118 buf1= char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"1119 if ( buf1) {1267 found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" 1268 if (found) { 1120 1269 uintptr_t bias; 1121 1270 // we found the "find" pattern - delete it 1122 text_hole_delete( buf1, buf1 + strlen(F)- 1);1271 text_hole_delete(found, found + len_F - 1); 1123 1272 // inset the "replace" patern 1124 bias = string_insert( buf1, R); // insert the string1125 buf1+= bias;1273 bias = string_insert(found, R); // insert the string 1274 found += bias; 1126 1275 ls += bias; 1127 1276 /*q += bias; - recalculated anyway */ 1128 1277 // check for "global" :s/foo/bar/g 1129 if (gflag == 1) {1130 if (( buf1 + strlen(R)) < end_line(ls)) {1131 q = buf1 + strlen(R);1278 if (gflag == 'g') { 1279 if ((found + len_R) < end_line(ls)) { 1280 q = found + len_R; 1132 1281 goto vc4; // don't let q move past cur line 1133 1282 } … … 1552 1701 1553 1702 #if ENABLE_FEATURE_VI_SEARCH 1554 static int mycmp(const char *s1, const char *s2, int len) 1555 { 1556 if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { 1557 return strncasecmp(s1, s2, len); 1558 } 1559 return strncmp(s1, s2, len); 1560 } 1703 1704 # if ENABLE_FEATURE_VI_REGEX_SEARCH 1561 1705 1562 1706 // search for pattern starting at p 1563 1707 static char *char_search(char *p, const char *pat, int dir, int range) 1564 1708 { 1565 #ifndef REGEX_SEARCH1566 char *start, *stop;1567 int len;1568 1569 len = strlen(pat);1570 if (dir == FORWARD) {1571 stop = end - 1; // assume range is p - end-11572 if (range == LIMITED)1573 stop = next_line(p); // range is to next line1574 for (start = p; start < stop; start++) {1575 if (mycmp(start, pat, len) == 0) {1576 return start;1577 }1578 }1579 } else if (dir == BACK) {1580 stop = text; // assume range is text - p1581 if (range == LIMITED)1582 stop = prev_line(p); // range is to prev line1583 for (start = p - len; start >= stop; start--) {1584 if (mycmp(start, pat, len) == 0) {1585 return start;1586 }1587 }1588 }1589 // pattern not found1590 return NULL;1591 #else /* REGEX_SEARCH */1592 1709 char *q; 1593 1710 struct re_pattern_buffer preg; 1594 1711 int i; 1595 int size , range;1712 int size; 1596 1713 1597 1714 re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; … … 1616 1733 range = q - p; 1617 1734 1618 q = re_compile_pattern(pat, strlen(pat),&preg);1735 q = (char *)re_compile_pattern(pat, strlen(pat), (struct re_pattern_buffer *)&preg); 1619 1736 if (q != 0) { 1620 1737 // The pattern was not compiled … … 1650 1767 } 1651 1768 return p; 1652 #endif /* REGEX_SEARCH */ 1653 } 1769 } 1770 1771 # else 1772 1773 # if ENABLE_FEATURE_VI_SETOPTS 1774 static int mycmp(const char *s1, const char *s2, int len) 1775 { 1776 if (ignorecase) { 1777 return strncasecmp(s1, s2, len); 1778 } 1779 return strncmp(s1, s2, len); 1780 } 1781 # else 1782 # define mycmp strncmp 1783 # endif 1784 1785 static char *char_search(char *p, const char *pat, int dir, int range) 1786 { 1787 char *start, *stop; 1788 int len; 1789 1790 len = strlen(pat); 1791 if (dir == FORWARD) { 1792 stop = end - 1; // assume range is p - end-1 1793 if (range == LIMITED) 1794 stop = next_line(p); // range is to next line 1795 for (start = p; start < stop; start++) { 1796 if (mycmp(start, pat, len) == 0) { 1797 return start; 1798 } 1799 } 1800 } else if (dir == BACK) { 1801 stop = text; // assume range is text - p 1802 if (range == LIMITED) 1803 stop = prev_line(p); // range is to prev line 1804 for (start = p - len; start >= stop; start--) { 1805 if (mycmp(start, pat, len) == 0) { 1806 return start; 1807 } 1808 } 1809 } 1810 // pattern not found 1811 return NULL; 1812 } 1813 1814 # endif 1815 1654 1816 #endif /* FEATURE_VI_SEARCH */ 1655 1817 … … 1678 1840 } 1679 1841 } else { 1842 #if ENABLE_FEATURE_VI_SETOPTS 1680 1843 // insert a char into text[] 1681 1844 char *sp; // "save p" 1845 #endif 1682 1846 1683 1847 if (c == 13) 1684 1848 c = '\n'; // translate \r to \n 1849 #if ENABLE_FEATURE_VI_SETOPTS 1685 1850 sp = p; // remember addr of insert 1851 #endif 1686 1852 p += 1 + stupid_insert(p, c); // insert the char 1687 1853 #if ENABLE_FEATURE_VI_SETOPTS … … 1764 1930 q = dot; 1765 1931 } else { 1766 1767 1768 1769 1770 1932 // nothing -- this causes any other values of c to 1933 // represent the one-character range under the 1934 // cursor. this is correct for ' ' and 'l', but 1935 // perhaps no others. 1936 // 1771 1937 } 1772 1938 if (q < p) { … … 1916 2082 end += bias; 1917 2083 p += bias; 2084 #if ENABLE_FEATURE_VI_YANKMARK 2085 { 2086 int i; 2087 for (i = 0; i < ARRAY_SIZE(mark); i++) 2088 if (mark[i]) 2089 mark[i] += bias; 2090 } 2091 #endif 1918 2092 text = new_text; 1919 2093 } … … 2002 2176 #endif 2003 2177 #if ENABLE_FEATURE_VI_DOT_CMD 2004 "\n\tLast command repeat with \'.\'"2178 "\n\tLast command repeat with ." 2005 2179 #endif 2006 2180 #if ENABLE_FEATURE_VI_YANKMARK … … 2009 2183 #endif 2010 2184 #if ENABLE_FEATURE_VI_READONLY 2011 "\n\tReadonly if vi is called as \"view\""2012 "\n\tReadonly with -R command line arg"2185 //not implemented: "\n\tReadonly if vi is called as \"view\"" 2186 //redundant: usage text says this too: "\n\tReadonly with -R command line arg" 2013 2187 #endif 2014 2188 #if ENABLE_FEATURE_VI_SET 2015 "\n\tSome colon mode commands with \':\'"2189 "\n\tSome colon mode commands with :" 2016 2190 #endif 2017 2191 #if ENABLE_FEATURE_VI_SETOPTS … … 2147 2321 tcgetattr(0, &term_orig); 2148 2322 term_vi = term_orig; 2149 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's2323 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's 2150 2324 term_vi.c_iflag &= (~IXON & ~ICRNL); 2151 2325 term_vi.c_oflag &= (~ONLCR); … … 2418 2592 2419 2593 //----- Move the cursor to row x col (count from 0, not 1) ------- 2420 static void place_cursor(int row, int col, int optimize) 2421 { 2422 char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; 2423 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2424 enum { 2425 SZ_UP = sizeof(CMup), 2426 SZ_DN = sizeof(CMdown), 2427 SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN, 2428 }; 2429 char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size 2430 #endif 2431 char *cm; 2594 static void place_cursor(int row, int col) 2595 { 2596 char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2]; 2432 2597 2433 2598 if (row < 0) row = 0; … … 2436 2601 if (col >= columns) col = columns - 1; 2437 2602 2438 //----- 1. Try the standard terminal ESC sequence 2439 sprintf(cm1, CMrc, row + 1, col + 1); 2440 cm = cm1; 2441 2442 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2443 if (optimize && col < 16) { 2444 char *screenp; 2445 int Rrow = last_row; 2446 int diff = Rrow - row; 2447 2448 if (diff < -5 || diff > 5) 2449 goto skip; 2450 2451 //----- find the minimum # of chars to move cursor ------------- 2452 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 2453 cm2[0] = '\0'; 2454 2455 // move to the correct row 2456 while (row < Rrow) { 2457 // the cursor has to move up 2458 strcat(cm2, CMup); 2459 Rrow--; 2460 } 2461 while (row > Rrow) { 2462 // the cursor has to move down 2463 strcat(cm2, CMdown); 2464 Rrow++; 2465 } 2466 2467 // now move to the correct column 2468 strcat(cm2, "\r"); // start at col 0 2469 // just send out orignal source char to get to correct place 2470 screenp = &screen[row * columns]; // start of screen line 2471 strncat(cm2, screenp, col); 2472 2473 // pick the shortest cursor motion to send out 2474 if (strlen(cm2) < strlen(cm)) { 2475 cm = cm2; 2476 } 2477 skip: ; 2478 } 2479 last_row = row; 2480 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2481 write1(cm); 2603 sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1); 2604 write1(cm1); 2482 2605 } 2483 2606 … … 2485 2608 static void clear_to_eol(void) 2486 2609 { 2487 write1( Ceol); // Erase from cursor to end of line2610 write1(ESC_CLEAR2EOL); 2488 2611 } 2489 2612 2490 2613 static void go_bottom_and_clear_to_eol(void) 2491 2614 { 2492 place_cursor(rows - 1, 0 , FALSE); // go to bottom of screen2493 clear_to_eol(); // erase to end of line2615 place_cursor(rows - 1, 0); 2616 clear_to_eol(); 2494 2617 } 2495 2618 … … 2497 2620 static void clear_to_eos(void) 2498 2621 { 2499 write1( Ceos); // Erase from cursor to end of screen2622 write1(ESC_CLEAR2EOS); 2500 2623 } 2501 2624 2502 2625 //----- Start standout mode ------------------------------------ 2503 static void standout_start(void) // send "start reverse video" sequence2504 { 2505 write1( SOs); // Start reverse video mode2626 static void standout_start(void) 2627 { 2628 write1(ESC_BOLD_TEXT); 2506 2629 } 2507 2630 2508 2631 //----- End standout mode -------------------------------------- 2509 static void standout_end(void) // send "end reverse video" sequence2510 { 2511 write1( SOn); // End reverse video mode2632 static void standout_end(void) 2633 { 2634 write1(ESC_NORM_TEXT); 2512 2635 } 2513 2636 … … 2515 2638 static void flash(int h) 2516 2639 { 2517 standout_start(); // send "start reverse video" sequence2640 standout_start(); 2518 2641 redraw(TRUE); 2519 2642 mysleep(h); 2520 standout_end(); // send "end reverse video" sequence2643 standout_end(); 2521 2644 redraw(TRUE); 2522 2645 } … … 2529 2652 #endif 2530 2653 if (!err_method) { 2531 write1( bell); // send out a bell character2654 write1(ESC_BELL); 2532 2655 } else { 2533 2656 flash(10); … … 2575 2698 have_status_msg = 0; 2576 2699 } 2577 place_cursor(crow, ccol , FALSE);// put cursor back in correct place2700 place_cursor(crow, ccol); // put cursor back in correct place 2578 2701 } 2579 2702 fflush_all(); … … 2587 2710 2588 2711 va_start(args, format); 2589 strcpy(status_buffer, SOs); // Terminal standout mode on2590 vsprintf(status_buffer + sizeof( SOs)-1, format, args);2591 strcat(status_buffer, SOn); // Terminal standout mode off2712 strcpy(status_buffer, ESC_BOLD_TEXT); 2713 vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args); 2714 strcat(status_buffer, ESC_NORM_TEXT); 2592 2715 va_end(args); 2593 2716 2594 have_status_msg = 1 + sizeof( SOs) + sizeof(SOn) - 2;2717 have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; 2595 2718 } 2596 2719 … … 2624 2747 c_is_no_print = (c & 0x80) && !Isprint(c); 2625 2748 if (c_is_no_print) { 2626 strcpy(d, SOn);2627 d += sizeof( SOn)-1;2749 strcpy(d, ESC_NORM_TEXT); 2750 d += sizeof(ESC_NORM_TEXT)-1; 2628 2751 c = '.'; 2629 2752 } … … 2637 2760 *d = '\0'; 2638 2761 if (c_is_no_print) { 2639 strcpy(d, SOs);2640 d += sizeof( SOs)-1;2762 strcpy(d, ESC_BOLD_TEXT); 2763 d += sizeof(ESC_BOLD_TEXT)-1; 2641 2764 } 2642 2765 if (*s == '\n') { … … 2720 2843 static void redraw(int full_screen) 2721 2844 { 2722 place_cursor(0, 0 , FALSE); // put cursor in correct place2723 clear_to_eos(); // tell terminal to erase display2845 place_cursor(0, 0); 2846 clear_to_eos(); 2724 2847 screen_erase(); // erase the internal screen buffer 2725 2848 last_status_cksum = 0; // force status update … … 2861 2984 // copy changed part of buffer to virtual screen 2862 2985 memcpy(sp+cs, out_buf+cs, ce-cs+1); 2863 2864 // move cursor to column of first change 2865 //if (offset != old_offset) { 2866 // // place_cursor is still too stupid 2867 // // to handle offsets correctly 2868 // place_cursor(li, cs, FALSE); 2869 //} else { 2870 place_cursor(li, cs, TRUE); 2871 //} 2872 2986 place_cursor(li, cs); 2873 2987 // write line out to terminal 2874 2988 fwrite(&sp[cs], ce - cs + 1, 1, stdout); … … 2876 2990 } 2877 2991 2878 place_cursor(crow, ccol , TRUE);2992 place_cursor(crow, ccol); 2879 2993 2880 2994 old_offset = offset; … … 2906 3020 static void do_cmd(int c) 2907 3021 { 2908 const char *msg = msg; // for compiler2909 3022 char *p, *q, *save_dot; 2910 3023 char buf[12]; … … 2915 3028 // c1 = c; // quiet the compiler 2916 3029 // cnt = yf = 0; // quiet the compiler 2917 // msg =p = q = save_dot = buf; // quiet the compiler2918 memset(buf, '\0', 12);3030 // p = q = save_dot = buf; // quiet the compiler 3031 memset(buf, '\0', sizeof(buf)); 2919 3032 2920 3033 show_status_line(); … … 3032 3145 case 8: // ctrl-H- move left (This may be ERASE char) 3033 3146 case 0x7f: // DEL- move left (This may be ERASE char) 3034 if (--cmdcnt > 0) { 3035 do_cmd(c); 3036 } 3037 dot_left(); 3147 do { 3148 dot_left(); 3149 } while (--cmdcnt > 0); 3038 3150 break; 3039 3151 case 10: // Newline ^J 3040 3152 case 'j': // j- goto next line, same col 3041 3153 case KEYCODE_DOWN: // cursor key Down 3042 if (--cmdcnt > 0){3043 do _cmd(c);3044 }3045 dot_next(); // go to next B-o-l3046 dot = move_to_col(dot, ccol + offset); // try stay in same col3154 do { 3155 dot_next(); // go to next B-o-l 3156 // try stay in same col 3157 dot = move_to_col(dot, ccol + offset); 3158 } while (--cmdcnt > 0); 3047 3159 break; 3048 3160 case 12: // ctrl-L force redraw whole screen 3049 3161 case 18: // ctrl-R force redraw 3050 place_cursor(0, 0 , FALSE); // put cursor in correct place3051 clear_to_eos(); // tel terminal to erase display3052 mysleep(10);3162 place_cursor(0, 0); 3163 clear_to_eos(); 3164 //mysleep(10); // why??? 3053 3165 screen_erase(); // erase the internal screen buffer 3054 3166 last_status_cksum = 0; // force status update … … 3057 3169 case 13: // Carriage Return ^M 3058 3170 case '+': // +- goto next line 3059 if (--cmdcnt > 0) { 3060 do_cmd(c); 3061 } 3062 dot_next(); 3063 dot_skip_over_ws(); 3171 do { 3172 dot_next(); 3173 dot_skip_over_ws(); 3174 } while (--cmdcnt > 0); 3064 3175 break; 3065 3176 case 21: // ctrl-U scroll up half screen … … 3079 3190 case 'l': // move right 3080 3191 case KEYCODE_RIGHT: // Cursor Key Right 3081 if (--cmdcnt > 0) { 3082 do_cmd(c); 3083 } 3084 dot_right(); 3192 do { 3193 dot_right(); 3194 } while (--cmdcnt > 0); 3085 3195 break; 3086 3196 #if ENABLE_FEATURE_VI_YANKMARK … … 3152 3262 break; 3153 3263 case 'U': // U- Undo; replace current line with original version 3154 if (reg[Ureg] != 0) {3264 if (reg[Ureg] != NULL) { 3155 3265 p = begin_line(dot); 3156 3266 q = end_line(dot); … … 3164 3274 case '$': // $- goto end of line 3165 3275 case KEYCODE_END: // Cursor Key End 3166 if (--cmdcnt > 0) { 3276 for (;;) { 3277 dot = end_line(dot); 3278 if (--cmdcnt <= 0) 3279 break; 3167 3280 dot_next(); 3168 do_cmd(c); 3169 } 3170 dot = end_line(dot); 3281 } 3171 3282 break; 3172 3283 case '%': // %- find matching char of pair () [] {} … … 3193 3304 //**** fall through to ... ';' 3194 3305 case ';': // ;- look at rest of line for last forward char 3195 if (--cmdcnt > 0) { 3196 do_cmd(';'); 3197 } 3306 do { 3307 if (last_forward_char == 0) 3308 break; 3309 q = dot + 1; 3310 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 3311 q++; 3312 } 3313 if (*q == last_forward_char) 3314 dot = q; 3315 } while (--cmdcnt > 0); 3316 break; 3317 case ',': // repeat latest 'f' in opposite direction 3198 3318 if (last_forward_char == 0) 3199 3319 break; 3200 q = dot + 1; 3201 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 3202 q++; 3203 } 3204 if (*q == last_forward_char) 3205 dot = q; 3206 break; 3207 case ',': // repeat latest 'f' in opposite direction 3208 if (--cmdcnt > 0) { 3209 do_cmd(','); 3210 } 3211 if (last_forward_char == 0) 3212 break; 3213 q = dot - 1; 3214 while (q >= text && *q != '\n' && *q != last_forward_char) { 3215 q--; 3216 } 3217 if (q >= text && *q == last_forward_char) 3218 dot = q; 3320 do { 3321 q = dot - 1; 3322 while (q >= text && *q != '\n' && *q != last_forward_char) { 3323 q--; 3324 } 3325 if (q >= text && *q == last_forward_char) 3326 dot = q; 3327 } while (--cmdcnt > 0); 3219 3328 break; 3220 3329 3221 3330 case '-': // -- goto prev line 3222 if (--cmdcnt > 0) { 3223 do_cmd(c); 3224 } 3225 dot_prev(); 3226 dot_skip_over_ws(); 3331 do { 3332 dot_prev(); 3333 dot_skip_over_ws(); 3334 } while (--cmdcnt > 0); 3227 3335 break; 3228 3336 #if ENABLE_FEATURE_VI_DOT_CMD … … 3256 3364 break; 3257 3365 case 'N': // N- backward search for last pattern 3258 if (--cmdcnt > 0) {3259 do_cmd(c);3260 }3261 3366 dir = BACK; // assume BACKWARD search 3262 3367 p = dot - 1; … … 3270 3375 // search rest of text[] starting at next char 3271 3376 // if search fails return orignal "p" not the "p+1" address 3272 if (--cmdcnt > 0) { 3273 do_cmd(c); 3274 } 3377 do { 3378 const char *msg; 3275 3379 dc3: 3276 dir = FORWARD; // assume FORWARD search3277 p = dot + 1;3278 if (last_search_pattern[0] == '?') {3279 dir = BACK;3280 p = dot - 1;3281 }3380 dir = FORWARD; // assume FORWARD search 3381 p = dot + 1; 3382 if (last_search_pattern[0] == '?') { 3383 dir = BACK; 3384 p = dot - 1; 3385 } 3282 3386 dc4: 3283 q = char_search(p, last_search_pattern + 1, dir, FULL); 3284 if (q != NULL) { 3285 dot = q; // good search, update "dot" 3286 msg = ""; 3287 goto dc2; 3288 } 3289 // no pattern found between "dot" and "end"- continue at top 3290 p = text; 3291 if (dir == BACK) { 3292 p = end - 1; 3293 } 3294 q = char_search(p, last_search_pattern + 1, dir, FULL); 3295 if (q != NULL) { // found something 3296 dot = q; // found new pattern- goto it 3297 msg = "search hit BOTTOM, continuing at TOP"; 3387 q = char_search(p, last_search_pattern + 1, dir, FULL); 3388 if (q != NULL) { 3389 dot = q; // good search, update "dot" 3390 msg = NULL; 3391 goto dc2; 3392 } 3393 // no pattern found between "dot" and "end"- continue at top 3394 p = text; 3298 3395 if (dir == BACK) { 3299 msg = "search hit TOP, continuing at BOTTOM"; 3300 } 3301 } else { 3302 msg = "Pattern not found"; 3303 } 3396 p = end - 1; 3397 } 3398 q = char_search(p, last_search_pattern + 1, dir, FULL); 3399 if (q != NULL) { // found something 3400 dot = q; // found new pattern- goto it 3401 msg = "search hit BOTTOM, continuing at TOP"; 3402 if (dir == BACK) { 3403 msg = "search hit TOP, continuing at BOTTOM"; 3404 } 3405 } else { 3406 msg = "Pattern not found"; 3407 } 3304 3408 dc2: 3305 if (*msg) 3306 status_line_bold("%s", msg); 3409 if (msg) 3410 status_line_bold("%s", msg); 3411 } while (--cmdcnt > 0); 3307 3412 break; 3308 3413 case '{': // {- move backward paragraph … … 3349 3454 ) { 3350 3455 if (file_modified && p[1] != '!') { 3351 status_line_bold("No write since last change (: quit! overrides)");3456 status_line_bold("No write since last change (:%s! overrides)", p); 3352 3457 } else { 3353 3458 editing = 0; … … 3423 3528 case 'E': // E- end of a blank-delimited word 3424 3529 case 'W': // W- forward a blank-delimited word 3425 if (--cmdcnt > 0) {3426 do_cmd(c);3427 }3428 3530 dir = FORWARD; 3429 3531 if (c == 'B') 3430 3532 dir = BACK; 3431 if (c == 'W' || isspace(dot[dir])) { 3432 dot = skip_thing(dot, 1, dir, S_TO_WS); 3433 dot = skip_thing(dot, 2, dir, S_OVER_WS); 3434 } 3435 if (c != 'W') 3436 dot = skip_thing(dot, 1, dir, S_BEFORE_WS); 3533 do { 3534 if (c == 'W' || isspace(dot[dir])) { 3535 dot = skip_thing(dot, 1, dir, S_TO_WS); 3536 dot = skip_thing(dot, 2, dir, S_OVER_WS); 3537 } 3538 if (c != 'W') 3539 dot = skip_thing(dot, 1, dir, S_BEFORE_WS); 3540 } while (--cmdcnt > 0); 3437 3541 break; 3438 3542 case 'C': // C- Change to e-o-l … … 3485 3589 case KEYCODE_INSERT: // Cursor Key Insert 3486 3590 dc_i: 3487 cmd_mode = 1; // start ins rting3591 cmd_mode = 1; // start inserting 3488 3592 break; 3489 3593 case 'J': // J- join current and next lines together 3490 if (--cmdcnt > 1) { 3491 do_cmd(c); 3492 } 3493 dot_end(); // move to NL 3494 if (dot < end - 1) { // make sure not last char in text[] 3495 *dot++ = ' '; // replace NL with space 3496 file_modified++; 3497 while (isblank(*dot)) { // delete leading WS 3498 dot_delete(); 3499 } 3500 } 3594 do { 3595 dot_end(); // move to NL 3596 if (dot < end - 1) { // make sure not last char in text[] 3597 *dot++ = ' '; // replace NL with space 3598 file_modified++; 3599 while (isblank(*dot)) { // delete leading WS 3600 dot_delete(); 3601 } 3602 } 3603 } while (--cmdcnt > 0); 3501 3604 end_cmd_q(); // stop adding to q 3502 3605 break; … … 3542 3645 case 'x': // x- delete the current char 3543 3646 case 's': // s- substitute the current char 3544 if (--cmdcnt > 0) {3545 do_cmd(c);3546 }3547 3647 dir = 0; 3548 3648 if (c == 'X') 3549 3649 dir = -1; 3550 if (dot[dir] != '\n') { 3551 if (c == 'X') 3552 dot--; // delete prev char 3553 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char 3554 } 3650 do { 3651 if (dot[dir] != '\n') { 3652 if (c == 'X') 3653 dot--; // delete prev char 3654 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char 3655 } 3656 } while (--cmdcnt > 0); 3657 end_cmd_q(); // stop adding to q 3555 3658 if (c == 's') 3556 goto dc_i; // start insrting 3557 end_cmd_q(); // stop adding to q 3659 goto dc_i; // start inserting 3558 3660 break; 3559 3661 case 'Z': // Z- if modified, {write}; exit … … 3586 3688 case 'b': // b- back a word 3587 3689 case 'e': // e- end of word 3588 if (--cmdcnt > 0) {3589 do_cmd(c);3590 }3591 3690 dir = FORWARD; 3592 3691 if (c == 'b') 3593 3692 dir = BACK; 3594 if ((dot + dir) < text || (dot + dir) > end - 1) 3595 break; 3596 dot += dir; 3597 if (isspace(*dot)) { 3598 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); 3599 } 3600 if (isalnum(*dot) || *dot == '_') { 3601 dot = skip_thing(dot, 1, dir, S_END_ALNUM); 3602 } else if (ispunct(*dot)) { 3603 dot = skip_thing(dot, 1, dir, S_END_PUNCT); 3604 } 3693 do { 3694 if ((dot + dir) < text || (dot + dir) > end - 1) 3695 break; 3696 dot += dir; 3697 if (isspace(*dot)) { 3698 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); 3699 } 3700 if (isalnum(*dot) || *dot == '_') { 3701 dot = skip_thing(dot, 1, dir, S_END_ALNUM); 3702 } else if (ispunct(*dot)) { 3703 dot = skip_thing(dot, 1, dir, S_END_PUNCT); 3704 } 3705 } while (--cmdcnt > 0); 3605 3706 break; 3606 3707 case 'c': // c- change something … … 3687 3788 case 'k': // k- goto prev line, same col 3688 3789 case KEYCODE_UP: // cursor key Up 3689 if (--cmdcnt > 0) { 3690 do_cmd(c); 3691 } 3692 dot_prev(); 3693 dot = move_to_col(dot, ccol + offset); // try stay in same col 3790 do { 3791 dot_prev(); 3792 dot = move_to_col(dot, ccol + offset); // try stay in same col 3793 } while (--cmdcnt > 0); 3694 3794 break; 3695 3795 case 'r': // r- replace the current char with user input … … 3709 3809 break; 3710 3810 case 'w': // w- forward a word 3711 if (--cmdcnt > 0) { 3712 do_cmd(c); 3713 } 3714 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3715 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); 3716 } else if (ispunct(*dot)) { // we are on PUNCT 3717 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); 3718 } 3719 if (dot < end - 1) 3720 dot++; // move over word 3721 if (isspace(*dot)) { 3722 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); 3723 } 3811 do { 3812 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3813 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); 3814 } else if (ispunct(*dot)) { // we are on PUNCT 3815 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); 3816 } 3817 if (dot < end - 1) 3818 dot++; // move over word 3819 if (isspace(*dot)) { 3820 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); 3821 } 3822 } while (--cmdcnt > 0); 3724 3823 break; 3725 3824 case 'z': // z- … … 3737 3836 break; 3738 3837 case '~': // ~- flip the case of letters a-z -> A-Z 3739 if (--cmdcnt > 0) { 3740 do_cmd(c); 3741 } 3742 if (islower(*dot)) { 3743 *dot = toupper(*dot); 3744 file_modified++; 3745 } else if (isupper(*dot)) { 3746 *dot = tolower(*dot); 3747 file_modified++; 3748 } 3749 dot_right(); 3838 do { 3839 if (islower(*dot)) { 3840 *dot = toupper(*dot); 3841 file_modified++; 3842 } else if (isupper(*dot)) { 3843 *dot = tolower(*dot); 3844 file_modified++; 3845 } 3846 dot_right(); 3847 } while (--cmdcnt > 0); 3750 3848 end_cmd_q(); // stop adding to q 3751 3849 break; … … 3983 4081 if (msg[0]) { 3984 4082 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", 3985 totalcmds, last_input_char, msg, SOs, SOn);4083 totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT); 3986 4084 fflush_all(); 3987 4085 while (safe_read(STDIN_FILENO, d, 1) > 0) {
Note:
See TracChangeset
for help on using the changeset viewer.