diff options
Diffstat (limited to 'editors/vi.c')
-rw-r--r-- | editors/vi.c | 97 |
1 files changed, 57 insertions, 40 deletions
diff --git a/editors/vi.c b/editors/vi.c index d6d926e35..6fae221ac 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -278,7 +278,6 @@ struct globals { | |||
278 | smallint cmd_mode; // 0=command 1=insert 2=replace | 278 | smallint cmd_mode; // 0=command 1=insert 2=replace |
279 | int file_modified; // buffer contents changed (counter, not flag!) | 279 | int file_modified; // buffer contents changed (counter, not flag!) |
280 | int last_file_modified; // = -1; | 280 | int last_file_modified; // = -1; |
281 | int fn_start; // index of first cmd line file name | ||
282 | int save_argc; // how many file names on cmd line | 281 | int save_argc; // how many file names on cmd line |
283 | int cmdcnt; // repetition count | 282 | int cmdcnt; // repetition count |
284 | unsigned rows, columns; // the terminal screen is this size | 283 | unsigned rows, columns; // the terminal screen is this size |
@@ -363,7 +362,6 @@ struct globals { | |||
363 | #define cmd_mode (G.cmd_mode ) | 362 | #define cmd_mode (G.cmd_mode ) |
364 | #define file_modified (G.file_modified ) | 363 | #define file_modified (G.file_modified ) |
365 | #define last_file_modified (G.last_file_modified ) | 364 | #define last_file_modified (G.last_file_modified ) |
366 | #define fn_start (G.fn_start ) | ||
367 | #define save_argc (G.save_argc ) | 365 | #define save_argc (G.save_argc ) |
368 | #define cmdcnt (G.cmdcnt ) | 366 | #define cmdcnt (G.cmdcnt ) |
369 | #define rows (G.rows ) | 367 | #define rows (G.rows ) |
@@ -599,9 +597,10 @@ int vi_main(int argc, char **argv) | |||
599 | } | 597 | } |
600 | 598 | ||
601 | // The argv array can be used by the ":next" and ":rewind" commands | 599 | // The argv array can be used by the ":next" and ":rewind" commands |
602 | // save optind. | 600 | argv += optind; |
603 | fn_start = optind; // remember first file name for :next and :rew | 601 | argc -= optind; |
604 | save_argc = argc; | 602 | save_argc = argc; |
603 | optind = 0; | ||
605 | 604 | ||
606 | //----- This is the main file handling loop -------------- | 605 | //----- This is the main file handling loop -------------- |
607 | while (1) { | 606 | while (1) { |
@@ -1021,7 +1020,7 @@ static void colon(char *buf) | |||
1021 | } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file | 1020 | } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file |
1022 | // don't edit, if the current file has been modified | 1021 | // don't edit, if the current file has been modified |
1023 | if (file_modified && !useforce) { | 1022 | if (file_modified && !useforce) { |
1024 | status_line_bold("No write since last change (:edit! overrides)"); | 1023 | status_line_bold("No write since last change (:%s! overrides)", cmd); |
1025 | goto ret; | 1024 | goto ret; |
1026 | } | 1025 | } |
1027 | if (args[0]) { | 1026 | if (args[0]) { |
@@ -1040,13 +1039,13 @@ static void colon(char *buf) | |||
1040 | goto ret; | 1039 | goto ret; |
1041 | 1040 | ||
1042 | #if ENABLE_FEATURE_VI_YANKMARK | 1041 | #if ENABLE_FEATURE_VI_YANKMARK |
1043 | if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { | 1042 | if (Ureg >= 0 && Ureg < 28) { |
1044 | free(reg[Ureg]); // free orig line reg- for 'U' | 1043 | free(reg[Ureg]); // free orig line reg- for 'U' |
1045 | reg[Ureg]= 0; | 1044 | reg[Ureg] = NULL; |
1046 | } | 1045 | } |
1047 | if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { | 1046 | if (YDreg >= 0 && YDreg < 28) { |
1048 | free(reg[YDreg]); // free default yank/delete register | 1047 | free(reg[YDreg]); // free default yank/delete register |
1049 | reg[YDreg]= 0; | 1048 | reg[YDreg] = NULL; |
1050 | } | 1049 | } |
1051 | #endif | 1050 | #endif |
1052 | // how many lines in text[]? | 1051 | // how many lines in text[]? |
@@ -1111,11 +1110,12 @@ static void colon(char *buf) | |||
1111 | Hit_Return(); | 1110 | Hit_Return(); |
1112 | } else if (strncmp(cmd, "quit", i) == 0 // quit | 1111 | } else if (strncmp(cmd, "quit", i) == 0 // quit |
1113 | || strncmp(cmd, "next", i) == 0 // edit next file | 1112 | || strncmp(cmd, "next", i) == 0 // edit next file |
1113 | || strncmp(cmd, "prev", i) == 0 // edit previous file | ||
1114 | ) { | 1114 | ) { |
1115 | int n; | 1115 | int n; |
1116 | if (useforce) { | 1116 | if (useforce) { |
1117 | // force end of argv list | ||
1118 | if (*cmd == 'q') { | 1117 | if (*cmd == 'q') { |
1118 | // force end of argv list | ||
1119 | optind = save_argc; | 1119 | optind = save_argc; |
1120 | } | 1120 | } |
1121 | editing = 0; | 1121 | editing = 0; |
@@ -1123,8 +1123,7 @@ static void colon(char *buf) | |||
1123 | } | 1123 | } |
1124 | // don't exit if the file been modified | 1124 | // don't exit if the file been modified |
1125 | if (file_modified) { | 1125 | if (file_modified) { |
1126 | status_line_bold("No write since last change (:%s! overrides)", | 1126 | status_line_bold("No write since last change (:%s! overrides)", cmd); |
1127 | (*cmd == 'q' ? "quit" : "next")); | ||
1128 | goto ret; | 1127 | goto ret; |
1129 | } | 1128 | } |
1130 | // are there other file to edit | 1129 | // are there other file to edit |
@@ -1137,6 +1136,14 @@ static void colon(char *buf) | |||
1137 | status_line_bold("No more files to edit"); | 1136 | status_line_bold("No more files to edit"); |
1138 | goto ret; | 1137 | goto ret; |
1139 | } | 1138 | } |
1139 | if (*cmd == 'p') { | ||
1140 | // are there previous files to edit | ||
1141 | if (optind < 1) { | ||
1142 | status_line_bold("No previous files to edit"); | ||
1143 | goto ret; | ||
1144 | } | ||
1145 | optind -= 2; | ||
1146 | } | ||
1140 | editing = 0; | 1147 | editing = 0; |
1141 | } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] | 1148 | } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] |
1142 | fn = args; | 1149 | fn = args; |
@@ -1172,10 +1179,10 @@ static void colon(char *buf) | |||
1172 | } | 1179 | } |
1173 | } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args | 1180 | } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args |
1174 | if (file_modified && !useforce) { | 1181 | if (file_modified && !useforce) { |
1175 | status_line_bold("No write since last change (:rewind! overrides)"); | 1182 | status_line_bold("No write since last change (:%s! overrides)", cmd); |
1176 | } else { | 1183 | } else { |
1177 | // reset the filenames to edit | 1184 | // reset the filenames to edit |
1178 | optind = fn_start - 1; | 1185 | optind = -1; /* start from 0th file */ |
1179 | editing = 0; | 1186 | editing = 0; |
1180 | } | 1187 | } |
1181 | #if ENABLE_FEATURE_VI_SET | 1188 | #if ENABLE_FEATURE_VI_SET |
@@ -1225,51 +1232,53 @@ static void colon(char *buf) | |||
1225 | #endif /* FEATURE_VI_SET */ | 1232 | #endif /* FEATURE_VI_SET */ |
1226 | #if ENABLE_FEATURE_VI_SEARCH | 1233 | #if ENABLE_FEATURE_VI_SEARCH |
1227 | } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern | 1234 | } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern |
1228 | char *ls, *F, *R; | 1235 | char *F, *R, *flags; |
1229 | int gflag; | 1236 | size_t len_F, len_R; |
1237 | int gflag; // global replace flag | ||
1230 | 1238 | ||
1231 | // F points to the "find" pattern | 1239 | // F points to the "find" pattern |
1232 | // R points to the "replace" pattern | 1240 | // R points to the "replace" pattern |
1233 | // replace the cmd line delimiters "/" with NULLs | 1241 | // replace the cmd line delimiters "/" with NULs |
1234 | gflag = 0; // global replace flag | ||
1235 | c = orig_buf[1]; // what is the delimiter | 1242 | c = orig_buf[1]; // what is the delimiter |
1236 | F = orig_buf + 2; // start of "find" | 1243 | F = orig_buf + 2; // start of "find" |
1237 | R = strchr(F, c); // middle delimiter | 1244 | R = strchr(F, c); // middle delimiter |
1238 | if (!R) | 1245 | if (!R) |
1239 | goto colon_s_fail; | 1246 | goto colon_s_fail; |
1247 | len_F = R - F; | ||
1240 | *R++ = '\0'; // terminate "find" | 1248 | *R++ = '\0'; // terminate "find" |
1241 | buf1 = strchr(R, c); | 1249 | flags = strchr(R, c); |
1242 | if (!buf1) | 1250 | if (!flags) |
1243 | goto colon_s_fail; | 1251 | goto colon_s_fail; |
1244 | *buf1++ = '\0'; // terminate "replace" | 1252 | len_R = flags - R; |
1245 | if (*buf1 == 'g') { // :s/foo/bar/g | 1253 | *flags++ = '\0'; // terminate "replace" |
1246 | buf1++; | 1254 | gflag = *flags; |
1247 | gflag++; // turn on gflag | 1255 | |
1248 | } | ||
1249 | q = begin_line(q); | 1256 | q = begin_line(q); |
1250 | if (b < 0) { // maybe :s/foo/bar/ | 1257 | if (b < 0) { // maybe :s/foo/bar/ |
1251 | q = begin_line(dot); // start with cur line | 1258 | q = begin_line(dot); // start with cur line |
1252 | b = count_lines(text, q); // cur line number | 1259 | b = count_lines(text, q); // cur line number |
1253 | } | 1260 | } |
1254 | if (e < 0) | 1261 | if (e < 0) |
1255 | e = b; // maybe :.s/foo/bar/ | 1262 | e = b; // maybe :.s/foo/bar/ |
1263 | |||
1256 | for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 | 1264 | for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 |
1257 | ls = q; // orig line start | 1265 | char *ls = q; // orig line start |
1266 | char *found; | ||
1258 | vc4: | 1267 | vc4: |
1259 | buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" | 1268 | found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" |
1260 | if (buf1) { | 1269 | if (found) { |
1261 | uintptr_t bias; | 1270 | uintptr_t bias; |
1262 | // we found the "find" pattern - delete it | 1271 | // we found the "find" pattern - delete it |
1263 | text_hole_delete(buf1, buf1 + strlen(F) - 1); | 1272 | text_hole_delete(found, found + len_F - 1); |
1264 | // inset the "replace" patern | 1273 | // inset the "replace" patern |
1265 | bias = string_insert(buf1, R); // insert the string | 1274 | bias = string_insert(found, R); // insert the string |
1266 | buf1 += bias; | 1275 | found += bias; |
1267 | ls += bias; | 1276 | ls += bias; |
1268 | /*q += bias; - recalculated anyway */ | 1277 | /*q += bias; - recalculated anyway */ |
1269 | // check for "global" :s/foo/bar/g | 1278 | // check for "global" :s/foo/bar/g |
1270 | if (gflag == 1) { | 1279 | if (gflag == 'g') { |
1271 | if ((buf1 + strlen(R)) < end_line(ls)) { | 1280 | if ((found + len_R) < end_line(ls)) { |
1272 | q = buf1 + strlen(R); | 1281 | q = found + len_R; |
1273 | goto vc4; // don't let q move past cur line | 1282 | goto vc4; // don't let q move past cur line |
1274 | } | 1283 | } |
1275 | } | 1284 | } |
@@ -2073,6 +2082,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte | |||
2073 | dot += bias; | 2082 | dot += bias; |
2074 | end += bias; | 2083 | end += bias; |
2075 | p += bias; | 2084 | p += bias; |
2085 | #if ENABLE_FEATURE_VI_YANKMARK | ||
2086 | { | ||
2087 | int i; | ||
2088 | for (i = 0; i < ARRAY_SIZE(mark); i++) | ||
2089 | if (mark[i]) | ||
2090 | mark[i] += bias; | ||
2091 | } | ||
2092 | #endif | ||
2076 | text = new_text; | 2093 | text = new_text; |
2077 | } | 2094 | } |
2078 | memmove(p + size, p, end - size - p); | 2095 | memmove(p + size, p, end - size - p); |
@@ -2304,7 +2321,7 @@ static void rawmode(void) | |||
2304 | { | 2321 | { |
2305 | tcgetattr(0, &term_orig); | 2322 | tcgetattr(0, &term_orig); |
2306 | term_vi = term_orig; | 2323 | term_vi = term_orig; |
2307 | term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's | 2324 | term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's |
2308 | term_vi.c_iflag &= (~IXON & ~ICRNL); | 2325 | term_vi.c_iflag &= (~IXON & ~ICRNL); |
2309 | term_vi.c_oflag &= (~ONLCR); | 2326 | term_vi.c_oflag &= (~ONLCR); |
2310 | term_vi.c_cc[VMIN] = 1; | 2327 | term_vi.c_cc[VMIN] = 1; |
@@ -3314,7 +3331,7 @@ static void do_cmd(int c) | |||
3314 | end_cmd_q(); // stop adding to q | 3331 | end_cmd_q(); // stop adding to q |
3315 | break; | 3332 | break; |
3316 | case 'U': // U- Undo; replace current line with original version | 3333 | case 'U': // U- Undo; replace current line with original version |
3317 | if (reg[Ureg] != 0) { | 3334 | if (reg[Ureg] != NULL) { |
3318 | p = begin_line(dot); | 3335 | p = begin_line(dot); |
3319 | q = end_line(dot); | 3336 | q = end_line(dot); |
3320 | p = text_hole_delete(p, q); // delete cur line | 3337 | p = text_hole_delete(p, q); // delete cur line |
@@ -3328,7 +3345,7 @@ static void do_cmd(int c) | |||
3328 | case KEYCODE_END: // Cursor Key End | 3345 | case KEYCODE_END: // Cursor Key End |
3329 | for (;;) { | 3346 | for (;;) { |
3330 | dot = end_line(dot); | 3347 | dot = end_line(dot); |
3331 | if (--cmdcnt > 0) | 3348 | if (--cmdcnt <= 0) |
3332 | break; | 3349 | break; |
3333 | dot_next(); | 3350 | dot_next(); |
3334 | } | 3351 | } |
@@ -3506,7 +3523,7 @@ static void do_cmd(int c) | |||
3506 | || strncmp(p, "q!", cnt) == 0 // delete lines | 3523 | || strncmp(p, "q!", cnt) == 0 // delete lines |
3507 | ) { | 3524 | ) { |
3508 | if (file_modified && p[1] != '!') { | 3525 | if (file_modified && p[1] != '!') { |
3509 | status_line_bold("No write since last change (:quit! overrides)"); | 3526 | status_line_bold("No write since last change (:%s! overrides)", p); |
3510 | } else { | 3527 | } else { |
3511 | editing = 0; | 3528 | editing = 0; |
3512 | } | 3529 | } |