tvi.c - neatvi - [fork] simple vi-type editor with UTF-8 support | |
git clone git://src.adamsgaard.dk/neatvi | |
Log | |
Files | |
Refs | |
README | |
--- | |
tvi.c (29670B) | |
--- | |
1 /* | |
2 * NEATVI Editor | |
3 * | |
4 * Copyright (C) 2015-2019 Ali Gholami Rudi <ali at rudi dot ir> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for … | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANT… | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE F… | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT … | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 #include <ctype.h> | |
19 #include <fcntl.h> | |
20 #include <stdio.h> | |
21 #include <stdlib.h> | |
22 #include <string.h> | |
23 #include <signal.h> | |
24 #include "vi.h" | |
25 | |
26 static char vi_msg[EXLEN]; /* current message */ | |
27 static char vi_charlast[8]; /* the last character searched via f,… | |
28 static int vi_charcmd; /* the character finding command */ | |
29 static int vi_arg1, vi_arg2; /* the first and second arguments */ | |
30 static int vi_ybuf; /* current yank buffer */ | |
31 static int vi_pcol; /* the column requested by | command … | |
32 static int vi_printed; /* ex_print() calls since the last… | |
33 static int vi_scroll; /* scroll amount for ^f and ^d*/ | |
34 static int vi_soset, vi_so; /* search offset; 1 in "/kw/1" */ | |
35 | |
36 static void vi_wait(void) | |
37 { | |
38 if (vi_printed > 1) { | |
39 free(ex_read("[enter to continue]")); | |
40 vi_msg[0] = '\0'; | |
41 } | |
42 vi_printed = 0; | |
43 } | |
44 | |
45 static void vi_drawmsg(void) | |
46 { | |
47 int oleft = xleft; | |
48 xleft = 0; | |
49 led_printmsg(vi_msg, xrows, "---"); | |
50 vi_msg[0] = '\0'; | |
51 xleft = oleft; | |
52 } | |
53 | |
54 static void vi_drawrow(int row) | |
55 { | |
56 char *s = lbuf_get(xb, row); | |
57 if (xhll && row == xrow) | |
58 syn_context(conf_hlline()); | |
59 led_print(s ? s : (row ? "~" : ""), row - xtop, ex_filetype()); | |
60 syn_context(0); | |
61 } | |
62 | |
63 /* redraw the screen */ | |
64 static void vi_drawagain(int xcol, int lineonly) | |
65 { | |
66 int i; | |
67 term_record(); | |
68 for (i = xtop; i < xtop + xrows; i++) | |
69 if (!lineonly || i == xrow) | |
70 vi_drawrow(i); | |
71 vi_drawmsg(); | |
72 term_pos(xrow, led_pos(lbuf_get(xb, i), xcol)); | |
73 term_commit(); | |
74 } | |
75 | |
76 /* update the screen */ | |
77 static void vi_drawupdate(int xcol, int otop) | |
78 { | |
79 int i = 0; | |
80 if (otop != xtop) { | |
81 term_record(); | |
82 term_pos(0, 0); | |
83 term_room(otop - xtop); | |
84 if (xtop > otop) { | |
85 int n = MIN(xtop - otop, xrows); | |
86 for (i = 0; i < n; i++) | |
87 vi_drawrow(xtop + xrows - n + i); | |
88 } else { | |
89 int n = MIN(otop - xtop, xrows); | |
90 for (i = 0; i < n; i++) | |
91 vi_drawrow(xtop + i); | |
92 } | |
93 term_pos(xrow, led_pos(lbuf_get(xb, i), xcol)); | |
94 term_commit(); | |
95 } | |
96 vi_drawmsg(); | |
97 term_pos(xrow, led_pos(lbuf_get(xb, i), xcol)); | |
98 } | |
99 | |
100 /* update the screen by removing lines r1 to r2 before an input command … | |
101 static void vi_drawrm(int r1, int r2, int newln) | |
102 { | |
103 r1 = MIN(MAX(r1, xtop), xtop + xrows); | |
104 r2 = MIN(MAX(r2, xtop), xtop + xrows); | |
105 term_pos(r1 - xtop, 0); | |
106 term_room(r1 - r2 + newln); | |
107 } | |
108 | |
109 static int vi_buf[128]; | |
110 static int vi_buflen; | |
111 | |
112 static int vi_read(void) | |
113 { | |
114 return vi_buflen ? vi_buf[--vi_buflen] : term_read(); | |
115 } | |
116 | |
117 static void vi_back(int c) | |
118 { | |
119 if (vi_buflen < sizeof(vi_buf)) | |
120 vi_buf[vi_buflen++] = c; | |
121 } | |
122 | |
123 static char *vi_char(void) | |
124 { | |
125 return led_read(&xkmap); | |
126 } | |
127 | |
128 static char *vi_prompt(char *msg, int *kmap) | |
129 { | |
130 char *r, *s; | |
131 term_pos(xrows, led_pos(msg, 0)); | |
132 term_kill(); | |
133 s = led_prompt(msg, "", kmap, "---"); | |
134 if (!s) | |
135 return NULL; | |
136 r = uc_dup(strlen(s) >= strlen(msg) ? s + strlen(msg) : s); | |
137 free(s); | |
138 return r; | |
139 } | |
140 | |
141 /* read an ex input line */ | |
142 char *ex_read(char *msg) | |
143 { | |
144 struct sbuf *sb; | |
145 int c; | |
146 if (xled) { | |
147 int oleft = xleft; | |
148 char *s = led_prompt(msg, "", &xkmap, "---"); | |
149 xleft = oleft; | |
150 if (s) | |
151 term_chr('\n'); | |
152 return s; | |
153 } | |
154 sb = sbuf_make(); | |
155 while ((c = getchar()) != EOF && c != '\n') | |
156 sbuf_chr(sb, c); | |
157 if (c == EOF) { | |
158 sbuf_free(sb); | |
159 return NULL; | |
160 } | |
161 return sbuf_done(sb); | |
162 } | |
163 | |
164 /* show an ex message */ | |
165 void ex_show(char *msg) | |
166 { | |
167 if (xvis) { | |
168 snprintf(vi_msg, sizeof(vi_msg), "%s", msg); | |
169 } else if (xled) { | |
170 led_print(msg, -1, "---"); | |
171 term_chr('\n'); | |
172 } else { | |
173 printf("%s", msg); | |
174 } | |
175 } | |
176 | |
177 /* print an ex output line */ | |
178 void ex_print(char *line) | |
179 { | |
180 if (xvis) { | |
181 vi_printed += line ? 1 : 2; | |
182 if (line) | |
183 snprintf(vi_msg, sizeof(vi_msg), "%s", line); | |
184 if (line) | |
185 led_print(line, -1, ""); | |
186 term_chr('\n'); | |
187 } else { | |
188 if (line) | |
189 ex_show(line); | |
190 } | |
191 } | |
192 | |
193 static int vi_yankbuf(void) | |
194 { | |
195 int c = vi_read(); | |
196 if (c == '"') | |
197 return vi_read(); | |
198 vi_back(c); | |
199 return 0; | |
200 } | |
201 | |
202 static int vi_prefix(void) | |
203 { | |
204 int n = 0; | |
205 int c = vi_read(); | |
206 if ((c >= '1' && c <= '9')) { | |
207 while (isdigit(c)) { | |
208 n = n * 10 + c - '0'; | |
209 c = vi_read(); | |
210 } | |
211 } | |
212 vi_back(c); | |
213 return n; | |
214 } | |
215 | |
216 static int vi_col2off(struct lbuf *lb, int row, int col) | |
217 { | |
218 char *ln = lbuf_get(lb, row); | |
219 return ln ? ren_off(ln, col) : 0; | |
220 } | |
221 | |
222 static int vi_off2col(struct lbuf *lb, int row, int off) | |
223 { | |
224 char *ln = lbuf_get(lb, row); | |
225 return ln ? ren_pos(ln, off) : 0; | |
226 } | |
227 | |
228 static int vi_nextoff(struct lbuf *lb, int dir, int *row, int *off) | |
229 { | |
230 int o = *off + dir; | |
231 if (o < 0 || !lbuf_get(lb, *row) || o >= uc_slen(lbuf_get(lb, *r… | |
232 return 1; | |
233 *off = o; | |
234 return 0; | |
235 } | |
236 | |
237 static int vi_nextcol(struct lbuf *lb, int dir, int *row, int *off) | |
238 { | |
239 char *ln = lbuf_get(lb, *row); | |
240 int col = ln ? ren_pos(ln, *off) : 0; | |
241 int o = ln ? ren_next(ln, col, dir) : -1; | |
242 if (o < 0) | |
243 return -1; | |
244 *off = ren_off(ln, o); | |
245 return 0; | |
246 } | |
247 | |
248 static int vi_findchar(struct lbuf *lb, char *cs, int cmd, int n, int *r… | |
249 { | |
250 if (cs != vi_charlast) | |
251 strcpy(vi_charlast, cs); | |
252 vi_charcmd = cmd; | |
253 return lbuf_findchar(lb, cs, cmd, n, row, off); | |
254 } | |
255 | |
256 static int vi_search(int cmd, int cnt, int *row, int *off) | |
257 { | |
258 char *kwd; | |
259 int r = *row; | |
260 int o = *off; | |
261 char *failed = NULL; | |
262 int len = 0; | |
263 int i, dir; | |
264 if (cmd == '/' || cmd == '?') { | |
265 char sign[4] = {cmd}; | |
266 struct sbuf *sb; | |
267 char *kw = vi_prompt(sign, &xkmap); | |
268 char *re; | |
269 if (!kw) | |
270 return 1; | |
271 sb = sbuf_make(); | |
272 sbuf_chr(sb, cmd); | |
273 sbuf_str(sb, kw); | |
274 free(kw); | |
275 kw = sbuf_buf(sb); | |
276 if ((re = re_read(&kw))) { | |
277 ex_kwdset(re[0] ? re : NULL, cmd == '/' ? +1 : -… | |
278 while (isspace(*kw)) | |
279 kw++; | |
280 vi_soset = !!kw[0]; | |
281 vi_so = atoi(kw); | |
282 free(re); | |
283 } | |
284 sbuf_free(sb); | |
285 } | |
286 if (!lbuf_len(xb) || ex_kwd(&kwd, &dir)) | |
287 return 1; | |
288 dir = cmd == 'N' ? -dir : dir; | |
289 o = *off; | |
290 for (i = 0; i < cnt; i++) { | |
291 if (lbuf_search(xb, kwd, dir, &r, &o, &len)) { | |
292 failed = " not found"; | |
293 break; | |
294 } | |
295 if (i + 1 < cnt && cmd == '/') | |
296 o += len; | |
297 } | |
298 if (!failed) { | |
299 *row = r; | |
300 *off = o; | |
301 if (vi_soset) { | |
302 *off = -1; | |
303 if (*row + vi_so < 0 || *row + vi_so >= lbuf_len… | |
304 failed = " bad offset"; | |
305 else | |
306 *row += vi_so; | |
307 } | |
308 } | |
309 if (failed != NULL) | |
310 snprintf(vi_msg, sizeof(vi_msg), "/%s/%s\n", kwd, failed… | |
311 return failed != NULL; | |
312 } | |
313 | |
314 /* read a line motion */ | |
315 static int vi_motionln(int *row, int cmd) | |
316 { | |
317 int cnt = (vi_arg1 ? vi_arg1 : 1) * (vi_arg2 ? vi_arg2 : 1); | |
318 int c = vi_read(); | |
319 int mark, mark_row, mark_off; | |
320 switch (c) { | |
321 case '\n': | |
322 case '+': | |
323 *row = MIN(*row + cnt, lbuf_len(xb) - 1); | |
324 break; | |
325 case '-': | |
326 *row = MAX(*row - cnt, 0); | |
327 break; | |
328 case '_': | |
329 *row = MIN(*row + cnt - 1, lbuf_len(xb) - 1); | |
330 break; | |
331 case '\'': | |
332 if ((mark = vi_read()) <= 0) | |
333 return -1; | |
334 if (lbuf_jump(xb, mark, &mark_row, &mark_off)) | |
335 return -1; | |
336 *row = mark_row; | |
337 break; | |
338 case 'j': | |
339 *row = MIN(*row + cnt, lbuf_len(xb) - 1); | |
340 break; | |
341 case 'k': | |
342 *row = MAX(*row - cnt, 0); | |
343 break; | |
344 case 'G': | |
345 *row = (vi_arg1 || vi_arg2) ? cnt - 1 : lbuf_len(xb) - 1; | |
346 break; | |
347 case 'H': | |
348 *row = MIN(xtop + cnt - 1, lbuf_len(xb) - 1); | |
349 break; | |
350 case 'L': | |
351 *row = MIN(xtop + xrows - 1 - cnt + 1, lbuf_len(xb) - 1); | |
352 break; | |
353 case 'M': | |
354 *row = MIN(xtop + xrows / 2, lbuf_len(xb) - 1); | |
355 break; | |
356 default: | |
357 if (c == cmd) { | |
358 *row = MIN(*row + cnt - 1, lbuf_len(xb) - 1); | |
359 break; | |
360 } | |
361 if (c == '%' && (vi_arg1 || vi_arg2)) { | |
362 if (cnt > 100) | |
363 return -1; | |
364 *row = MAX(0, lbuf_len(xb) - 1) * cnt / 100; | |
365 break; | |
366 } | |
367 vi_back(c); | |
368 return 0; | |
369 } | |
370 if (*row < 0) | |
371 *row = 0; | |
372 return c; | |
373 } | |
374 | |
375 static char *vi_curword(struct lbuf *lb, int row, int off) | |
376 { | |
377 struct sbuf *sb; | |
378 char *ln = lbuf_get(lb, row); | |
379 char *beg, *end; | |
380 if (!ln) | |
381 return NULL; | |
382 beg = uc_chr(ln, ren_noeol(ln, off)); | |
383 end = beg; | |
384 while (*end && uc_kind(end) == 1) | |
385 end = uc_next(end); | |
386 while (beg > ln && uc_kind(uc_beg(ln, beg - 1)) == 1) | |
387 beg = uc_beg(ln, beg - 1); | |
388 if (beg >= end) | |
389 return NULL; | |
390 sb = sbuf_make(); | |
391 sbuf_str(sb, "\\<"); | |
392 sbuf_mem(sb, beg, end - beg); | |
393 sbuf_str(sb, "\\>"); | |
394 return sbuf_done(sb); | |
395 } | |
396 | |
397 /* read a motion */ | |
398 static int vi_motion(int *row, int *off) | |
399 { | |
400 int cnt = (vi_arg1 ? vi_arg1 : 1) * (vi_arg2 ? vi_arg2 : 1); | |
401 char *ln = lbuf_get(xb, *row); | |
402 int dir = dir_context(ln ? ln : ""); | |
403 int mark, mark_row, mark_off; | |
404 char *cs; | |
405 int mv; | |
406 int i; | |
407 if ((mv = vi_motionln(row, 0))) { | |
408 *off = -1; | |
409 return mv; | |
410 } | |
411 mv = vi_read(); | |
412 switch (mv) { | |
413 case 'f': | |
414 if (!(cs = vi_char())) | |
415 return -1; | |
416 if (vi_findchar(xb, cs, mv, cnt, row, off)) | |
417 return -1; | |
418 break; | |
419 case 'F': | |
420 if (!(cs = vi_char())) | |
421 return -1; | |
422 if (vi_findchar(xb, cs, mv, cnt, row, off)) | |
423 return -1; | |
424 break; | |
425 case ';': | |
426 if (!vi_charlast[0]) | |
427 return -1; | |
428 if (vi_findchar(xb, vi_charlast, vi_charcmd, cnt, row, o… | |
429 return -1; | |
430 break; | |
431 case ',': | |
432 if (!vi_charlast[0]) | |
433 return -1; | |
434 if (vi_findchar(xb, vi_charlast, vi_charcmd, -cnt, row, … | |
435 return -1; | |
436 break; | |
437 case 'h': | |
438 for (i = 0; i < cnt; i++) | |
439 if (vi_nextcol(xb, -1 * dir, row, off)) | |
440 break; | |
441 break; | |
442 case 'l': | |
443 for (i = 0; i < cnt; i++) | |
444 if (vi_nextcol(xb, +1 * dir, row, off)) | |
445 break; | |
446 break; | |
447 case 't': | |
448 if (!(cs = vi_char())) | |
449 return -1; | |
450 if (vi_findchar(xb, cs, mv, cnt, row, off)) | |
451 return -1; | |
452 break; | |
453 case 'T': | |
454 if (!(cs = vi_char())) | |
455 return -1; | |
456 if (vi_findchar(xb, cs, mv, cnt, row, off)) | |
457 return -1; | |
458 break; | |
459 case 'B': | |
460 for (i = 0; i < cnt; i++) | |
461 if (lbuf_wordend(xb, 1, -1, row, off)) | |
462 break; | |
463 break; | |
464 case 'E': | |
465 for (i = 0; i < cnt; i++) | |
466 if (lbuf_wordend(xb, 1, +1, row, off)) | |
467 break; | |
468 break; | |
469 case 'W': | |
470 for (i = 0; i < cnt; i++) | |
471 if (lbuf_wordbeg(xb, 1, +1, row, off)) | |
472 break; | |
473 break; | |
474 case 'b': | |
475 for (i = 0; i < cnt; i++) | |
476 if (lbuf_wordend(xb, 0, -1, row, off)) | |
477 break; | |
478 break; | |
479 case 'e': | |
480 for (i = 0; i < cnt; i++) | |
481 if (lbuf_wordend(xb, 0, +1, row, off)) | |
482 break; | |
483 break; | |
484 case 'w': | |
485 for (i = 0; i < cnt; i++) | |
486 if (lbuf_wordbeg(xb, 0, +1, row, off)) | |
487 break; | |
488 break; | |
489 case '{': | |
490 for (i = 0; i < cnt; i++) | |
491 if (lbuf_paragraphbeg(xb, -1, row, off)) | |
492 break; | |
493 break; | |
494 case '}': | |
495 for (i = 0; i < cnt; i++) | |
496 if (lbuf_paragraphbeg(xb, +1, row, off)) | |
497 break; | |
498 break; | |
499 case '[': | |
500 if (vi_read() != '[') | |
501 return -1; | |
502 for (i = 0; i < cnt; i++) | |
503 if (lbuf_sectionbeg(xb, -1, row, off)) | |
504 break; | |
505 break; | |
506 case ']': | |
507 if (vi_read() != ']') | |
508 return -1; | |
509 for (i = 0; i < cnt; i++) | |
510 if (lbuf_sectionbeg(xb, +1, row, off)) | |
511 break; | |
512 break; | |
513 case '0': | |
514 *off = 0; | |
515 break; | |
516 case '^': | |
517 *off = lbuf_indents(xb, *row); | |
518 break; | |
519 case '$': | |
520 *off = lbuf_eol(xb, *row); | |
521 break; | |
522 case '|': | |
523 *off = vi_col2off(xb, *row, cnt - 1); | |
524 vi_pcol = cnt - 1; | |
525 break; | |
526 case '/': | |
527 if (vi_search(mv, cnt, row, off)) | |
528 return -1; | |
529 break; | |
530 case '?': | |
531 if (vi_search(mv, cnt, row, off)) | |
532 return -1; | |
533 break; | |
534 case 'n': | |
535 if (vi_search(mv, cnt, row, off)) | |
536 return -1; | |
537 break; | |
538 case 'N': | |
539 if (vi_search(mv, cnt, row, off)) | |
540 return -1; | |
541 break; | |
542 case TK_CTL('a'): | |
543 if (!(cs = vi_curword(xb, *row, *off))) | |
544 return -1; | |
545 ex_kwdset(cs, +1); | |
546 vi_soset = 0; | |
547 free(cs); | |
548 if (vi_search('n', cnt, row, off)) | |
549 return -1; | |
550 break; | |
551 case ' ': | |
552 for (i = 0; i < cnt; i++) | |
553 if (vi_nextoff(xb, +1, row, off)) | |
554 break; | |
555 break; | |
556 case 127: | |
557 case TK_CTL('h'): | |
558 for (i = 0; i < cnt; i++) | |
559 if (vi_nextoff(xb, -1, row, off)) | |
560 break; | |
561 break; | |
562 case '`': | |
563 if ((mark = vi_read()) <= 0) | |
564 return -1; | |
565 if (lbuf_jump(xb, mark, &mark_row, &mark_off)) | |
566 return -1; | |
567 *row = mark_row; | |
568 *off = mark_off; | |
569 break; | |
570 case '%': | |
571 if (lbuf_pair(xb, row, off)) | |
572 return -1; | |
573 break; | |
574 default: | |
575 vi_back(mv); | |
576 return 0; | |
577 } | |
578 return mv; | |
579 } | |
580 | |
581 static void swap(int *a, int *b) | |
582 { | |
583 int t = *a; | |
584 *a = *b; | |
585 *b = t; | |
586 } | |
587 | |
588 static char *lbuf_region(struct lbuf *lb, int r1, int o1, int r2, int o2) | |
589 { | |
590 struct sbuf *sb; | |
591 char *s1, *s2, *s3; | |
592 if (r1 == r2) | |
593 return uc_sub(lbuf_get(lb, r1), o1, o2); | |
594 sb = sbuf_make(); | |
595 s1 = uc_sub(lbuf_get(lb, r1), o1, -1); | |
596 s3 = uc_sub(lbuf_get(lb, r2), 0, o2); | |
597 s2 = lbuf_cp(lb, r1 + 1, r2); | |
598 sbuf_str(sb, s1); | |
599 sbuf_str(sb, s2); | |
600 sbuf_str(sb, s3); | |
601 free(s1); | |
602 free(s2); | |
603 free(s3); | |
604 return sbuf_done(sb); | |
605 } | |
606 | |
607 static void vi_yank(int r1, int o1, int r2, int o2, int lnmode) | |
608 { | |
609 char *region; | |
610 region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : … | |
611 reg_put(vi_ybuf, region, lnmode); | |
612 free(region); | |
613 xrow = r1; | |
614 xoff = lnmode ? xoff : o1; | |
615 } | |
616 | |
617 static void vi_delete(int r1, int o1, int r2, int o2, int lnmode) | |
618 { | |
619 char *pref, *post; | |
620 char *region; | |
621 region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : … | |
622 reg_put(vi_ybuf, region, lnmode); | |
623 free(region); | |
624 pref = lnmode ? uc_dup("") : uc_sub(lbuf_get(xb, r1), 0, o1); | |
625 post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), o2, -1); | |
626 if (!lnmode) { | |
627 struct sbuf *sb = sbuf_make(); | |
628 sbuf_str(sb, pref); | |
629 sbuf_str(sb, post); | |
630 lbuf_edit(xb, sbuf_buf(sb), r1, r2 + 1); | |
631 sbuf_free(sb); | |
632 } else { | |
633 lbuf_edit(xb, NULL, r1, r2 + 1); | |
634 } | |
635 xrow = r1; | |
636 xoff = lnmode ? lbuf_indents(xb, xrow) : o1; | |
637 free(pref); | |
638 free(post); | |
639 } | |
640 | |
641 static int linecount(char *s) | |
642 { | |
643 int n; | |
644 for (n = 0; s; n++) | |
645 if ((s = strchr(s, '\n'))) | |
646 s++; | |
647 return n; | |
648 } | |
649 | |
650 static int charcount(char *text, char *post) | |
651 { | |
652 int tlen = strlen(text); | |
653 int plen = strlen(post); | |
654 char *nl = text; | |
655 int i; | |
656 if (tlen < plen) | |
657 return 0; | |
658 for (i = 0; i < tlen - plen; i++) | |
659 if (text[i] == '\n') | |
660 nl = text + i + 1; | |
661 return uc_slen(nl) - uc_slen(post); | |
662 } | |
663 | |
664 static char *vi_input(char *pref, char *post, int *row, int *off) | |
665 { | |
666 char *rep = led_input(pref, post, &xkmap, ex_filetype()); | |
667 if (!rep) | |
668 return NULL; | |
669 *row = linecount(rep) - 1; | |
670 *off = charcount(rep, post) - 1; | |
671 if (*off < 0) | |
672 *off = 0; | |
673 return rep; | |
674 } | |
675 | |
676 static char *vi_indents(char *ln) | |
677 { | |
678 struct sbuf *sb = sbuf_make(); | |
679 while (xai && ln && (*ln == ' ' || *ln == '\t')) | |
680 sbuf_chr(sb, *ln++); | |
681 return sbuf_done(sb); | |
682 } | |
683 | |
684 static void vi_change(int r1, int o1, int r2, int o2, int lnmode) | |
685 { | |
686 char *region; | |
687 int row, off; | |
688 char *rep; | |
689 char *pref, *post; | |
690 region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : … | |
691 reg_put(vi_ybuf, region, lnmode); | |
692 free(region); | |
693 pref = lnmode ? vi_indents(lbuf_get(xb, r1)) : uc_sub(lbuf_get(x… | |
694 post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), o2, -1); | |
695 vi_drawrm(r1, r2, 0); | |
696 rep = vi_input(pref, post, &row, &off); | |
697 if (rep) { | |
698 lbuf_edit(xb, rep, r1, r2 + 1); | |
699 xrow = r1 + row - 1; | |
700 xoff = off; | |
701 free(rep); | |
702 } | |
703 free(pref); | |
704 free(post); | |
705 } | |
706 | |
707 static void vi_case(int r1, int o1, int r2, int o2, int lnmode, int cmd) | |
708 { | |
709 char *pref, *post; | |
710 char *region, *s; | |
711 region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : … | |
712 s = region; | |
713 while (*s) { | |
714 int c = (unsigned char) s[0]; | |
715 if (c <= 0x7f) { | |
716 if (cmd == 'u') | |
717 s[0] = tolower(c); | |
718 if (cmd == 'U') | |
719 s[0] = toupper(c); | |
720 if (cmd == '~') | |
721 s[0] = islower(c) ? toupper(c) : tolower… | |
722 } | |
723 s = uc_next(s); | |
724 } | |
725 pref = lnmode ? uc_dup("") : uc_sub(lbuf_get(xb, r1), 0, o1); | |
726 post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), o2, -1); | |
727 if (!lnmode) { | |
728 struct sbuf *sb = sbuf_make(); | |
729 sbuf_str(sb, pref); | |
730 sbuf_str(sb, region); | |
731 sbuf_str(sb, post); | |
732 lbuf_edit(xb, sbuf_buf(sb), r1, r2 + 1); | |
733 sbuf_free(sb); | |
734 } else { | |
735 lbuf_edit(xb, region, r1, r2 + 1); | |
736 } | |
737 xrow = r2; | |
738 xoff = lnmode ? lbuf_indents(xb, r2) : o2; | |
739 free(region); | |
740 free(pref); | |
741 free(post); | |
742 } | |
743 | |
744 static void vi_pipe(int r1, int r2) | |
745 { | |
746 char *text; | |
747 char *rep; | |
748 int kmap = 0; | |
749 char *cmd = vi_prompt("!", &kmap); | |
750 if (!cmd) | |
751 return; | |
752 text = lbuf_cp(xb, r1, r2 + 1); | |
753 rep = cmd_pipe(cmd, text, 1, 1); | |
754 if (rep) | |
755 lbuf_edit(xb, rep, r1, r2 + 1); | |
756 free(cmd); | |
757 free(text); | |
758 free(rep); | |
759 } | |
760 | |
761 static void vi_shift(int r1, int r2, int dir) | |
762 { | |
763 struct sbuf *sb; | |
764 char *ln; | |
765 int i; | |
766 for (i = r1; i <= r2; i++) { | |
767 if (!(ln = lbuf_get(xb, i))) | |
768 continue; | |
769 sb = sbuf_make(); | |
770 if (dir > 0) | |
771 sbuf_chr(sb, '\t'); | |
772 else | |
773 ln = ln[0] == ' ' || ln[0] == '\t' ? ln + 1 : ln; | |
774 sbuf_str(sb, ln); | |
775 lbuf_edit(xb, sbuf_buf(sb), i, i + 1); | |
776 sbuf_free(sb); | |
777 } | |
778 xrow = r1; | |
779 xoff = lbuf_indents(xb, xrow); | |
780 } | |
781 | |
782 static int vc_motion(int cmd) | |
783 { | |
784 int r1 = xrow, r2 = xrow; /* region rows */ | |
785 int o1 = xoff, o2 = xoff; /* visual region columns */ | |
786 int lnmode = 0; /* line-based region */ | |
787 int mv; | |
788 vi_arg2 = vi_prefix(); | |
789 if (vi_arg2 < 0) | |
790 return 1; | |
791 o1 = ren_noeol(lbuf_get(xb, r1), o1); | |
792 o2 = o1; | |
793 if ((mv = vi_motionln(&r2, cmd))) { | |
794 o2 = -1; | |
795 } else if (!(mv = vi_motion(&r2, &o2))) { | |
796 vi_read(); | |
797 return 1; | |
798 } | |
799 if (mv < 0) | |
800 return 1; | |
801 lnmode = o2 < 0; | |
802 if (lnmode) { | |
803 o1 = 0; | |
804 o2 = lbuf_eol(xb, r2); | |
805 } | |
806 if (r1 > r2) { | |
807 swap(&r1, &r2); | |
808 swap(&o1, &o2); | |
809 } | |
810 if (r1 == r2 && o1 > o2) | |
811 swap(&o1, &o2); | |
812 o1 = ren_noeol(lbuf_get(xb, r1), o1); | |
813 if (!lnmode && strchr("fFtTeE%", mv)) | |
814 if (o2 < lbuf_eol(xb, r2)) | |
815 o2 = ren_noeol(lbuf_get(xb, r2), o2) + 1; | |
816 if (cmd == 'y') | |
817 vi_yank(r1, o1, r2, o2, lnmode); | |
818 if (cmd == 'd') | |
819 vi_delete(r1, o1, r2, o2, lnmode); | |
820 if (cmd == 'c') | |
821 vi_change(r1, o1, r2, o2, lnmode); | |
822 if (cmd == '~' || cmd == 'u' || cmd == 'U') | |
823 vi_case(r1, o1, r2, o2, lnmode, cmd); | |
824 if (cmd == '!') | |
825 vi_pipe(r1, r2); | |
826 if (cmd == '>' || cmd == '<') | |
827 vi_shift(r1, r2, cmd == '>' ? +1 : -1); | |
828 return 0; | |
829 } | |
830 | |
831 static int vc_insert(int cmd) | |
832 { | |
833 char *pref, *post; | |
834 char *ln = lbuf_get(xb, xrow); | |
835 int row, off = 0; | |
836 char *rep; | |
837 if (cmd == 'I') | |
838 xoff = lbuf_indents(xb, xrow); | |
839 if (cmd == 'A') | |
840 xoff = lbuf_eol(xb, xrow); | |
841 xoff = ren_noeol(ln, xoff); | |
842 if (cmd == 'o') | |
843 xrow += 1; | |
844 if (cmd == 'i' || cmd == 'I') | |
845 off = xoff; | |
846 if (cmd == 'a' || cmd == 'A') | |
847 off = xoff + 1; | |
848 if (ln && ln[0] == '\n') | |
849 off = 0; | |
850 pref = ln && cmd != 'o' && cmd != 'O' ? uc_sub(ln, 0, off) : vi_… | |
851 post = ln && cmd != 'o' && cmd != 'O' ? uc_sub(ln, off, -1) : uc… | |
852 vi_drawrm(xrow, xrow, cmd == 'o' || cmd == 'O'); | |
853 rep = vi_input(pref, post, &row, &off); | |
854 if ((cmd == 'o' || cmd == 'O') && !lbuf_len(xb)) | |
855 lbuf_edit(xb, "\n", 0, 0); | |
856 if (rep) { | |
857 lbuf_edit(xb, rep, xrow, xrow + (cmd != 'o' && cmd != 'O… | |
858 xrow += row - 1; | |
859 xoff = off; | |
860 free(rep); | |
861 } | |
862 free(pref); | |
863 free(post); | |
864 return !rep; | |
865 } | |
866 | |
867 static int vc_put(int cmd) | |
868 { | |
869 int cnt = MAX(1, vi_arg1); | |
870 int lnmode; | |
871 char *buf = reg_get(vi_ybuf, &lnmode); | |
872 int i; | |
873 if (!buf) | |
874 snprintf(vi_msg, sizeof(vi_msg), "yank buffer empty\n"); | |
875 if (!buf || !buf[0]) | |
876 return 1; | |
877 if (lnmode) { | |
878 struct sbuf *sb = sbuf_make(); | |
879 for (i = 0; i < cnt; i++) | |
880 sbuf_str(sb, buf); | |
881 if (!lbuf_len(xb)) | |
882 lbuf_edit(xb, "\n", 0, 0); | |
883 if (cmd == 'p') | |
884 xrow++; | |
885 lbuf_edit(xb, sbuf_buf(sb), xrow, xrow); | |
886 xoff = lbuf_indents(xb, xrow); | |
887 sbuf_free(sb); | |
888 } else { | |
889 struct sbuf *sb = sbuf_make(); | |
890 char *ln = xrow < lbuf_len(xb) ? lbuf_get(xb, xrow) : "\… | |
891 int off = ren_noeol(ln, xoff) + (ln[0] != '\n' && cmd ==… | |
892 char *s = uc_sub(ln, 0, off); | |
893 sbuf_str(sb, s); | |
894 free(s); | |
895 for (i = 0; i < cnt; i++) | |
896 sbuf_str(sb, buf); | |
897 s = uc_sub(ln, off, -1); | |
898 sbuf_str(sb, s); | |
899 free(s); | |
900 lbuf_edit(xb, sbuf_buf(sb), xrow, xrow + 1); | |
901 xoff = off + uc_slen(buf) * cnt - 1; | |
902 sbuf_free(sb); | |
903 } | |
904 return 0; | |
905 } | |
906 | |
907 static int join_spaces(char *prev, char *next) | |
908 { | |
909 int prevlen = strlen(prev); | |
910 if (!prev[0]) | |
911 return 0; | |
912 if (prev[prevlen - 1] == ' ' || next[0] == ')') | |
913 return 0; | |
914 return prev[prevlen - 1] == '.' ? 2 : 1; | |
915 } | |
916 | |
917 static int vc_join(void) | |
918 { | |
919 struct sbuf *sb; | |
920 int cnt = vi_arg1 <= 1 ? 2 : vi_arg1; | |
921 int beg = xrow; | |
922 int end = xrow + cnt; | |
923 int off = 0; | |
924 int i; | |
925 if (!lbuf_get(xb, beg) || !lbuf_get(xb, end - 1)) | |
926 return 1; | |
927 sb = sbuf_make(); | |
928 for (i = beg; i < end; i++) { | |
929 char *ln = lbuf_get(xb, i); | |
930 char *lnend = strchr(ln, '\n'); | |
931 int spaces; | |
932 if (i > beg) | |
933 while (ln[0] == ' ' || ln[0] == '\t') | |
934 ln++; | |
935 spaces = i > beg ? join_spaces(sbuf_buf(sb), ln) : 0; | |
936 off = uc_slen(sbuf_buf(sb)); | |
937 while (spaces--) | |
938 sbuf_chr(sb, ' '); | |
939 sbuf_mem(sb, ln, lnend - ln); | |
940 } | |
941 sbuf_chr(sb, '\n'); | |
942 lbuf_edit(xb, sbuf_buf(sb), beg, end); | |
943 xoff = off; | |
944 sbuf_free(sb); | |
945 return 0; | |
946 } | |
947 | |
948 static int vi_scrollforward(int cnt) | |
949 { | |
950 if (xtop >= lbuf_len(xb) - 1) | |
951 return 1; | |
952 xtop = MIN(lbuf_len(xb) - 1, xtop + cnt); | |
953 xrow = MAX(xrow, xtop); | |
954 return 0; | |
955 } | |
956 | |
957 static int vi_scrollbackward(int cnt) | |
958 { | |
959 if (xtop == 0) | |
960 return 1; | |
961 xtop = MAX(0, xtop - cnt); | |
962 xrow = MIN(xrow, xtop + xrows - 1); | |
963 return 0; | |
964 } | |
965 | |
966 static void vc_status(void) | |
967 { | |
968 int col = vi_off2col(xb, xrow, xoff); | |
969 snprintf(vi_msg, sizeof(vi_msg), | |
970 "\"%s\"%c %d lines L%d C%d\n", | |
971 ex_path()[0] ? ex_path() : "unnamed", | |
972 lbuf_modified(xb) ? '*' : ' ', | |
973 lbuf_len(xb), xrow + 1, | |
974 ren_cursor(lbuf_get(xb, xrow), col) + 1); | |
975 } | |
976 | |
977 static void vc_charinfo(void) | |
978 { | |
979 char *c = uc_chr(lbuf_get(xb, xrow), xoff); | |
980 if (c) { | |
981 char cbuf[8] = ""; | |
982 memcpy(cbuf, c, uc_len(c)); | |
983 snprintf(vi_msg, sizeof(vi_msg), "<%s> %04x\n", cbuf, uc… | |
984 } | |
985 } | |
986 | |
987 static int vc_replace(void) | |
988 { | |
989 int cnt = MAX(1, vi_arg1); | |
990 char *cs = vi_char(); | |
991 char *ln = lbuf_get(xb, xrow); | |
992 struct sbuf *sb; | |
993 char *pref, *post; | |
994 char *s; | |
995 int off, i; | |
996 if (!ln || !cs) | |
997 return 1; | |
998 off = ren_noeol(ln, xoff); | |
999 s = uc_chr(ln, off); | |
1000 for (i = 0; s[0] != '\n' && i < cnt; i++) | |
1001 s = uc_next(s); | |
1002 if (i < cnt) | |
1003 return 1; | |
1004 pref = uc_sub(ln, 0, off); | |
1005 post = uc_sub(ln, off + cnt, -1); | |
1006 sb = sbuf_make(); | |
1007 sbuf_str(sb, pref); | |
1008 for (i = 0; i < cnt; i++) | |
1009 sbuf_str(sb, cs); | |
1010 sbuf_str(sb, post); | |
1011 lbuf_edit(xb, sbuf_buf(sb), xrow, xrow + 1); | |
1012 off += cnt - 1; | |
1013 xoff = off; | |
1014 sbuf_free(sb); | |
1015 free(pref); | |
1016 free(post); | |
1017 return 0; | |
1018 } | |
1019 | |
1020 static char rep_cmd[4096]; /* the last command */ | |
1021 static int rep_len; | |
1022 | |
1023 static void vc_repeat(void) | |
1024 { | |
1025 int i; | |
1026 for (i = 0; i < MAX(1, vi_arg1); i++) | |
1027 term_push(rep_cmd, rep_len); | |
1028 } | |
1029 | |
1030 static void vc_execute(void) | |
1031 { | |
1032 static int exec_buf = -1; | |
1033 int lnmode; | |
1034 int c = vi_read(); | |
1035 char *buf = NULL; | |
1036 int i; | |
1037 if (TK_INT(c)) | |
1038 return; | |
1039 if (c == '@') | |
1040 c = exec_buf; | |
1041 exec_buf = c; | |
1042 if (exec_buf >= 0) | |
1043 buf = reg_get(exec_buf, &lnmode); | |
1044 if (buf) | |
1045 for (i = 0; i < MAX(1, vi_arg1); i++) | |
1046 term_push(buf, strlen(buf)); | |
1047 } | |
1048 | |
1049 static void sigwinch(int signo) | |
1050 { | |
1051 vi_back(TK_CTL('l')); | |
1052 vi_back(TK_CTL('c')); | |
1053 } | |
1054 | |
1055 static void vi(void) | |
1056 { | |
1057 int xcol; | |
1058 int mark; | |
1059 char *ln; | |
1060 int kmap = 0; | |
1061 signal(SIGWINCH, sigwinch); | |
1062 xtop = MAX(0, xrow - xrows / 2); | |
1063 xoff = 0; | |
1064 xcol = vi_off2col(xb, xrow, xoff); | |
1065 vi_drawagain(xcol, 0); | |
1066 term_pos(xrow - xtop, led_pos(lbuf_get(xb, xrow), xcol)); | |
1067 while (!xquit) { | |
1068 int mod = 0; /* screen should be redrawn (1: the … | |
1069 int nrow = xrow; | |
1070 int noff = ren_noeol(lbuf_get(xb, xrow), xoff); | |
1071 int otop = xtop; | |
1072 int oleft = xleft; | |
1073 int orow = xrow; | |
1074 int mv, n; | |
1075 term_cmd(&n); | |
1076 vi_arg2 = 0; | |
1077 vi_ybuf = vi_yankbuf(); | |
1078 vi_arg1 = vi_prefix(); | |
1079 if (!vi_ybuf) | |
1080 vi_ybuf = vi_yankbuf(); | |
1081 mv = vi_motion(&nrow, &noff); | |
1082 if (mv > 0) { | |
1083 if (strchr("\'`GHML/?{}[]nN", mv) || | |
1084 (mv == '%' && noff < 0)) { | |
1085 lbuf_mark(xb, '\'', xrow, xoff); | |
1086 lbuf_mark(xb, '`', xrow, xoff); | |
1087 } | |
1088 xrow = nrow; | |
1089 if (noff < 0 && !strchr("jk", mv)) | |
1090 noff = lbuf_indents(xb, xrow); | |
1091 if (strchr("jk", mv)) | |
1092 noff = vi_col2off(xb, xrow, xcol); | |
1093 xoff = ren_noeol(lbuf_get(xb, xrow), noff); | |
1094 if (!strchr("|jk", mv)) | |
1095 xcol = vi_off2col(xb, xrow, xoff); | |
1096 if (mv == '|') | |
1097 xcol = vi_pcol; | |
1098 } else if (mv == 0) { | |
1099 char *cmd; | |
1100 int c = vi_read(); | |
1101 int k = 0; | |
1102 if (c <= 0) | |
1103 continue; | |
1104 lbuf_mark(xb, '*', xrow, xoff); | |
1105 switch (c) { | |
1106 case TK_CTL('b'): | |
1107 if (vi_scrollbackward(MAX(1, vi_arg1) * … | |
1108 break; | |
1109 xoff = lbuf_indents(xb, xrow); | |
1110 mod = 1; | |
1111 break; | |
1112 case TK_CTL('f'): | |
1113 if (vi_scrollforward(MAX(1, vi_arg1) * (… | |
1114 break; | |
1115 xoff = lbuf_indents(xb, xrow); | |
1116 mod = 1; | |
1117 break; | |
1118 case TK_CTL('e'): | |
1119 if (vi_scrollforward(MAX(1, vi_arg1))) | |
1120 break; | |
1121 xoff = vi_col2off(xb, xrow, xcol); | |
1122 break; | |
1123 case TK_CTL('y'): | |
1124 if (vi_scrollbackward(MAX(1, vi_arg1))) | |
1125 break; | |
1126 xoff = vi_col2off(xb, xrow, xcol); | |
1127 break; | |
1128 case TK_CTL('u'): | |
1129 if (xrow == 0) | |
1130 break; | |
1131 if (vi_arg1) | |
1132 vi_scroll = vi_arg1; | |
1133 n = vi_scroll ? vi_scroll : xrows / 2; | |
1134 xrow = MAX(0, xrow - n); | |
1135 if (xtop > 0) | |
1136 xtop = MAX(0, xtop - n); | |
1137 xoff = lbuf_indents(xb, xrow); | |
1138 mod = 1; | |
1139 break; | |
1140 case TK_CTL('d'): | |
1141 if (xrow == lbuf_len(xb) - 1) | |
1142 break; | |
1143 if (vi_arg1) | |
1144 vi_scroll = vi_arg1; | |
1145 n = vi_scroll ? vi_scroll : xrows / 2; | |
1146 xrow = MIN(MAX(0, lbuf_len(xb) - 1), xro… | |
1147 if (xtop < lbuf_len(xb) - xrows) | |
1148 xtop = MIN(lbuf_len(xb) - xrows,… | |
1149 xoff = lbuf_indents(xb, xrow); | |
1150 mod = 1; | |
1151 break; | |
1152 case TK_CTL('z'): | |
1153 term_pos(xrows, 0); | |
1154 term_suspend(); | |
1155 mod = 1; | |
1156 break; | |
1157 case 'u': | |
1158 if (!lbuf_undo(xb)) { | |
1159 lbuf_jump(xb, '*', &xrow, &xoff); | |
1160 mod = 1; | |
1161 } else { | |
1162 snprintf(vi_msg, sizeof(vi_msg),… | |
1163 } | |
1164 break; | |
1165 case TK_CTL('r'): | |
1166 if (!lbuf_redo(xb)) { | |
1167 lbuf_jump(xb, '*', &xrow, &xoff); | |
1168 mod = 1; | |
1169 } else { | |
1170 snprintf(vi_msg, sizeof(vi_msg),… | |
1171 } | |
1172 break; | |
1173 case TK_CTL('g'): | |
1174 vc_status(); | |
1175 break; | |
1176 case TK_CTL('^'): | |
1177 ex_command("e #"); | |
1178 mod = 1; | |
1179 break; | |
1180 case ':': | |
1181 ln = vi_prompt(":", &kmap); | |
1182 if (ln && ln[0]) { | |
1183 ex_command(ln); | |
1184 mod = 1; | |
1185 } | |
1186 free(ln); | |
1187 if (xquit) | |
1188 continue; | |
1189 break; | |
1190 case 'c': | |
1191 case 'd': | |
1192 case 'y': | |
1193 case '!': | |
1194 case '>': | |
1195 case '<': | |
1196 if (!vc_motion(c)) | |
1197 mod = 1; | |
1198 break; | |
1199 case 'i': | |
1200 case 'I': | |
1201 case 'a': | |
1202 case 'A': | |
1203 case 'o': | |
1204 case 'O': | |
1205 if (!vc_insert(c)) | |
1206 mod = 1; | |
1207 break; | |
1208 case 'J': | |
1209 if (!vc_join()) | |
1210 mod = 1; | |
1211 break; | |
1212 case TK_CTL('l'): | |
1213 term_done(); | |
1214 term_init(); | |
1215 mod = 1; | |
1216 break; | |
1217 case 'm': | |
1218 if ((mark = vi_read()) > 0 && islower(ma… | |
1219 lbuf_mark(xb, mark, xrow, xoff); | |
1220 break; | |
1221 case 'p': | |
1222 case 'P': | |
1223 if (!vc_put(c)) | |
1224 mod = 1; | |
1225 break; | |
1226 case 'z': | |
1227 k = vi_read(); | |
1228 switch (k) { | |
1229 case '\n': | |
1230 xtop = vi_arg1 ? vi_arg1 : xrow; | |
1231 break; | |
1232 case '.': | |
1233 n = vi_arg1 ? vi_arg1 : xrow; | |
1234 xtop = MAX(0, n - xrows / 2); | |
1235 break; | |
1236 case '-': | |
1237 n = vi_arg1 ? vi_arg1 : xrow; | |
1238 xtop = MAX(0, n - xrows + 1); | |
1239 break; | |
1240 case 'l': | |
1241 case 'r': | |
1242 xtd = k == 'r' ? -1 : +1; | |
1243 break; | |
1244 case 'L': | |
1245 case 'R': | |
1246 xtd = k == 'R' ? -2 : +2; | |
1247 break; | |
1248 case 'e': | |
1249 case 'f': | |
1250 xkmap = k == 'e' ? 0 : xkmap_alt; | |
1251 break; | |
1252 } | |
1253 mod = 1; | |
1254 break; | |
1255 case 'g': | |
1256 k = vi_read(); | |
1257 if (k == '~' || k == 'u' || k == 'U') | |
1258 if (!vc_motion(k)) | |
1259 mod = 2; | |
1260 if (k == 'a') | |
1261 vc_charinfo(); | |
1262 break; | |
1263 case 'x': | |
1264 vi_back(' '); | |
1265 if (!vc_motion('d')) | |
1266 mod = 2; | |
1267 break; | |
1268 case 'X': | |
1269 vi_back(TK_CTL('h')); | |
1270 if (!vc_motion('d')) | |
1271 mod = 2; | |
1272 break; | |
1273 case 'C': | |
1274 vi_back('$'); | |
1275 if (!vc_motion('c')) | |
1276 mod = 1; | |
1277 break; | |
1278 case 'D': | |
1279 vi_back('$'); | |
1280 if (!vc_motion('d')) | |
1281 mod = 2; | |
1282 break; | |
1283 case 'r': | |
1284 if (!vc_replace()) | |
1285 mod = 2; | |
1286 break; | |
1287 case 's': | |
1288 vi_back(' '); | |
1289 if (!vc_motion('c')) | |
1290 mod = 1; | |
1291 break; | |
1292 case 'S': | |
1293 vi_back('c'); | |
1294 if (!vc_motion('c')) | |
1295 mod = 1; | |
1296 break; | |
1297 case 'Y': | |
1298 vi_back('y'); | |
1299 vc_motion('y'); | |
1300 break; | |
1301 case 'q': | |
1302 k = vi_read(); | |
1303 if (k == 'q') | |
1304 ex_command("q"); | |
1305 break; | |
1306 case 'Z': | |
1307 k = vi_read(); | |
1308 if (k == 'Z') | |
1309 ex_command("x"); | |
1310 break; | |
1311 case '~': | |
1312 vi_back(' '); | |
1313 if (!vc_motion('~')) | |
1314 mod = 2; | |
1315 break; | |
1316 case '.': | |
1317 vc_repeat(); | |
1318 break; | |
1319 case '@': | |
1320 vc_execute(); | |
1321 break; | |
1322 default: | |
1323 continue; | |
1324 } | |
1325 cmd = term_cmd(&n); | |
1326 if (strchr("!<>ACDIJOPRSXYacdioprsxy~", c) || | |
1327 (c == 'g' && strchr("uU~", k))) { | |
1328 if (n < sizeof(rep_cmd)) { | |
1329 memcpy(rep_cmd, cmd, n); | |
1330 rep_len = n; | |
1331 } | |
1332 } | |
1333 } | |
1334 if (xrow < 0 || xrow >= lbuf_len(xb)) | |
1335 xrow = lbuf_len(xb) ? lbuf_len(xb) - 1 : 0; | |
1336 if (xtop > xrow) | |
1337 xtop = xtop - xrows / 2 > xrow ? | |
1338 MAX(0, xrow - xrows / 2) : xrow; | |
1339 if (xtop + xrows <= xrow) | |
1340 xtop = xtop + xrows + xrows / 2 <= xrow ? | |
1341 xrow - xrows / 2 : xrow - xrows … | |
1342 xoff = ren_noeol(lbuf_get(xb, xrow), xoff); | |
1343 if (mod) | |
1344 xcol = vi_off2col(xb, xrow, xoff); | |
1345 if (xcol >= xleft + xcols) | |
1346 xleft = xcol - xcols / 2; | |
1347 if (xcol < xleft) | |
1348 xleft = xcol < xcols ? 0 : xcol - xcols / 2; | |
1349 vi_wait(); | |
1350 if (mod || xleft != oleft) { | |
1351 vi_drawagain(xcol, mod == 2 && xleft == oleft &&… | |
1352 } else { | |
1353 if (xtop != otop) | |
1354 vi_drawupdate(xcol, otop); | |
1355 if (xhll && xrow != orow && orow >= xtop && orow… | |
1356 vi_drawrow(orow); | |
1357 if (xhll && xrow != orow) | |
1358 vi_drawrow(xrow); | |
1359 } | |
1360 if (vi_msg[0]) | |
1361 vi_drawmsg(); | |
1362 term_pos(xrow - xtop, led_pos(lbuf_get(xb, xrow), | |
1363 ren_cursor(lbuf_get(xb, xrow), xcol))); | |
1364 lbuf_modified(xb); | |
1365 } | |
1366 term_pos(xrows, 0); | |
1367 term_kill(); | |
1368 } | |
1369 | |
1370 int main(int argc, char *argv[]) | |
1371 { | |
1372 int i; | |
1373 char *prog = strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : … | |
1374 xvis = strcmp("ex", prog) && strcmp("neatex", prog); | |
1375 for (i = 1; i < argc && argv[i][0] == '-'; i++) { | |
1376 if (argv[i][1] == 's') | |
1377 xled = 0; | |
1378 if (argv[i][1] == 'e') | |
1379 xvis = 0; | |
1380 if (argv[i][1] == 'v') | |
1381 xvis = 1; | |
1382 } | |
1383 dir_init(); | |
1384 syn_init(); | |
1385 if (xled || xvis) | |
1386 term_init(); | |
1387 if (!ex_init(argv + i)) { | |
1388 if (xvis) | |
1389 vi(); | |
1390 else | |
1391 ex(); | |
1392 ex_done(); | |
1393 } | |
1394 if (xled || xvis) | |
1395 term_done(); | |
1396 reg_done(); | |
1397 syn_done(); | |
1398 dir_done(); | |
1399 return 0; | |
1400 } |