Introduction
Introduction Statistics Contact Development Disclaimer Help
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 }
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.