ex: restore the first visible line when switching buffers
[neatvi.git] / ex.c
blob2f598f37b2df20251489b529e1b314dc1ae4b244
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include "vi.h"
10 int xrow, xoff, xtop; /* current row, column, and top row */
11 int xleft; /* the first visible column */
12 int xquit; /* exit if set */
13 int xvis; /* visual mode */
14 int xai = 1; /* autoindent option */
15 int xic = 1; /* ignorecase option */
16 int xaw; /* autowrite option */
17 int xhl = 1; /* syntax highlight option */
18 int xled = 1; /* use the line editor */
19 int xdir = +1; /* current direction context */
20 int xshape = 1; /* perform letter shaping */
21 int xorder = 1; /* change the order of characters */
22 static char xkwd[EXLEN]; /* the last searched keyword */
23 static char xrep[EXLEN]; /* the last replacement */
24 static int xkwddir; /* the last search direction */
25 static char *xkmap = "en"; /* the current keymap */
26 static char xkmap2[8] = "fa"; /* the alternate keymap */
28 static struct buf {
29 char ft[32];
30 char *path;
31 struct lbuf *lb;
32 int row, off, top;
33 long mtime; /* modification time */
34 } bufs[8];
36 static int bufs_find(char *path)
38 int i;
39 for (i = 0; i < LEN(bufs); i++)
40 if (bufs[i].lb && !strcmp(bufs[i].path, path))
41 return i;
42 return -1;
45 static void bufs_free(int idx)
47 if (bufs[idx].lb) {
48 free(bufs[idx].path);
49 lbuf_free(bufs[idx].lb);
50 memset(&bufs[idx], 0, sizeof(bufs[idx]));
54 static long mtime(char *path)
56 struct stat st;
57 if (!stat(path, &st))
58 return st.st_mtime;
59 return -1;
62 static int bufs_open(char *path)
64 int i;
65 for (i = 0; i < LEN(bufs) - 1; i++)
66 if (!bufs[i].lb)
67 break;
68 bufs_free(i);
69 bufs[i].path = uc_dup(path);
70 bufs[i].lb = lbuf_make();
71 bufs[i].row = 0;
72 bufs[i].off = 0;
73 bufs[i].top = 0;
74 bufs[i].mtime = -1;
75 strcpy(bufs[i].ft, syn_filetype(path));
76 return i;
79 static void bufs_swap(int i, int j)
81 struct buf tmp;
82 if (i == j)
83 return;
84 memcpy(&tmp, &bufs[i], sizeof(tmp));
85 memcpy(&bufs[i], &bufs[j], sizeof(tmp));
86 memcpy(&bufs[j], &tmp, sizeof(tmp));
89 static void bufs_switch(int idx)
91 if (idx > 1)
92 bufs_swap(0, 1);
93 bufs_swap(0, idx);
94 xrow = bufs[0].row;
95 xoff = bufs[0].off;
96 xtop = bufs[0].top;
99 char *ex_path(void)
101 return bufs[0].path;
104 struct lbuf *ex_lbuf(void)
106 return bufs[0].lb;
109 char *ex_filetype(void)
111 return xhl ? bufs[0].ft : "";
114 char **ex_kmap(void)
116 return &xkmap;
119 char *ex_kmapalt(void)
121 return xkmap2;
124 /* read ex command location */
125 static char *ex_loc(char *s, char *loc)
127 while (*s == ':' || isspace((unsigned char) *s))
128 s++;
129 while (*s && !isalpha((unsigned char) *s) && *s != '=' && *s != '!') {
130 if (*s == '\'')
131 *loc++ = *s++;
132 if (*s == '/' || *s == '?') {
133 int d = *s;
134 *loc++ = *s++;
135 while (*s && *s != d) {
136 if (*s == '\\' && s[1])
137 *loc++ = *s++;
138 *loc++ = *s++;
141 if (*s)
142 *loc++ = *s++;
144 *loc = '\0';
145 return s;
148 /* read ex command name */
149 static char *ex_cmd(char *s, char *cmd)
151 char *cmd0 = cmd;
152 s = ex_loc(s, cmd);
153 while (isspace((unsigned char) *s))
154 s++;
155 while (isalpha((unsigned char) *s))
156 if ((*cmd++ = *s++) == 'k' && cmd == cmd0 + 1)
157 break;
158 if (*s == '!' || *s == '=')
159 *cmd++ = *s++;
160 *cmd = '\0';
161 return s;
164 /* read ex command argument */
165 static char *ex_arg(char *s, char *arg)
167 s = ex_cmd(s, arg);
168 while (isspace((unsigned char) *s))
169 s++;
170 while (*s && !isspace((unsigned char) *s)) {
171 if (*s == '\\' && s[1])
172 s++;
173 *arg++ = *s++;
175 *arg = '\0';
176 return s;
179 static char *ex_argeol(char *ec)
181 char arg[EXLEN];
182 char *s = ex_cmd(ec, arg);
183 while (isspace((unsigned char) *s))
184 s++;
185 return s;
188 static char *ex_line(char *s, char *ln)
190 while (*s && *s != '|' && *s != '\n')
191 *ln++ = *s++;
192 *ln = '\0';
193 return *s ? s + 1 : s;
196 /* the previous search keyword */
197 int ex_kwd(char **kwd, int *dir)
199 if (kwd)
200 *kwd = xkwd;
201 if (dir)
202 *dir = xkwddir;
203 return xkwddir == 0;
206 /* set the previous search keyword */
207 void ex_kwdset(char *kwd, int dir)
209 if (kwd) {
210 snprintf(xkwd, sizeof(xkwd), "%s", kwd);
211 reg_put('/', kwd, 0);
213 xkwddir = dir;
216 static int ex_search(char *pat)
218 struct sbuf *kw;
219 char *b = pat;
220 char *e = b;
221 char *pats[1];
222 struct rset *re;
223 int dir, row;
224 kw = sbuf_make();
225 while (*++e) {
226 if (*e == *pat)
227 break;
228 sbuf_chr(kw, (unsigned char) *e);
229 if (*e == '\\' && e[1])
230 e++;
232 if (sbuf_len(kw))
233 ex_kwdset(sbuf_buf(kw), *pat == '/' ? 1 : -1);
234 sbuf_free(kw);
235 if (ex_kwd(&pats[0], &dir))
236 return xrow;
237 re = rset_make(1, pats, xic ? RE_ICASE : 0);
238 if (!re)
239 return 1;
240 row = xrow + dir;
241 while (row >= 0 && row < lbuf_len(xb)) {
242 if (rset_find(re, lbuf_get(xb, row), 0, NULL, 0) >= 0)
243 break;
244 row += dir;
246 rset_free(re);
247 return row < 0 || row >= lbuf_len(xb) ? xrow : row;
250 static int ex_lineno(char *num)
252 int n = xrow;
253 if (!num[0] || num[0] == '.')
254 n = xrow;
255 if (isdigit(num[0]))
256 n = atoi(num) - 1;
257 if (num[0] == '$')
258 n = lbuf_len(xb) - 1;
259 if (num[0] == '-')
260 n = xrow - (num[1] ? atoi(num + 1) : 1);
261 if (num[0] == '+')
262 n = xrow + (num[1] ? atoi(num + 1) : 1);
263 if (num[0] == '\'')
264 lbuf_jump(xb, num[1], &n, NULL);
265 if (num[0] == '/' && num[1])
266 n = ex_search(num);
267 if (num[0] == '?' && num[1])
268 n = ex_search(num);
269 return n;
272 /* parse ex command location */
273 static int ex_region(char *loc, int *beg, int *end)
275 int naddr = 0;
276 if (!strcmp("%", loc)) {
277 *beg = 0;
278 *end = MAX(0, lbuf_len(xb));
279 return 0;
281 if (!*loc) {
282 *beg = xrow;
283 *end = xrow == lbuf_len(xb) ? xrow : xrow + 1;
284 return 0;
286 while (*loc) {
287 int end0 = *end;
288 *end = ex_lineno(loc) + 1;
289 *beg = naddr++ ? end0 - 1 : *end - 1;
290 if (!naddr++)
291 *beg = *end - 1;
292 while (*loc && *loc != ';' && *loc != ',')
293 loc++;
294 if (!*loc)
295 break;
296 if (*loc == ';')
297 xrow = *end - 1;
298 loc++;
300 if (*beg < 0 || *beg >= lbuf_len(xb))
301 return 1;
302 if (*end < *beg || *end > lbuf_len(xb))
303 return 1;
304 return 0;
307 static int ec_write(char *ec);
309 static int ex_modifiedbuffer(char *msg)
311 if (!lbuf_modified(xb))
312 return 0;
313 if (xaw && ex_path()[0])
314 return ec_write("w");
315 if (msg)
316 ex_show(msg);
317 return 1;
320 static int ec_quit(char *ec)
322 char cmd[EXLEN];
323 ex_cmd(ec, cmd);
324 if (!strchr(cmd, '!'))
325 if (ex_modifiedbuffer("buffer modified\n"))
326 return 1;
327 xquit = 1;
328 return 0;
331 static int ex_expand(char *d, char *s)
333 while (*s) {
334 int c = (unsigned char) *s++;
335 if (c == '%') {
336 if (!bufs[0].path || !bufs[0].path[0]) {
337 ex_show("\"%\" is unset\n");
338 return 1;
340 strcpy(d, bufs[0].path);
341 d = strchr(d, '\0');
342 continue;
344 if (c == '#') {
345 if (!bufs[1].path || !bufs[1].path[0]) {
346 ex_show("\"#\" is unset\n");
347 return 1;
349 strcpy(d, bufs[1].path);
350 d = strchr(d, '\0');
351 continue;
353 if (c == '\\' && (*s == '%' || *s == '#'))
354 c = *s++;
355 *d++ = c;
357 *d = '\0';
358 return 0;
361 static int ec_edit(char *ec)
363 char msg[128];
364 char arg[EXLEN], cmd[EXLEN];
365 char path[EXLEN];
366 int fd;
367 ex_cmd(ec, cmd);
368 ex_arg(ec, arg);
369 if (!strchr(cmd, '!'))
370 if (xb && ex_modifiedbuffer("buffer modified\n"))
371 return 1;
372 if (ex_expand(path, arg))
373 return 1;
374 bufs[0].row = xrow;
375 bufs[0].off = xoff;
376 bufs[0].top = xtop;
377 if (arg[0] && bufs_find(path) >= 0) {
378 bufs_switch(bufs_find(path));
379 return 0;
381 if (path[0] || !bufs[0].path)
382 bufs_switch(bufs_open(path));
383 fd = open(ex_path(), O_RDONLY);
384 if (fd >= 0) {
385 int rd = lbuf_rd(xb, fd, 0, lbuf_len(xb));
386 close(fd);
387 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
388 ex_path(), lbuf_len(xb));
389 if (rd)
390 ex_show("read failed\n");
391 else
392 ex_show(msg);
394 lbuf_saved(xb, path[0] != '\0');
395 bufs[0].mtime = mtime(ex_path());
396 xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
397 xoff = 0;
398 xtop = MAX(0, MIN(xtop, lbuf_len(xb) - 1));
399 return 0;
402 static int ec_read(char *ec)
404 char arg[EXLEN], loc[EXLEN];
405 char msg[128];
406 int beg, end;
407 char *path;
408 char *obuf;
409 int n = lbuf_len(xb);
410 ex_arg(ec, arg);
411 ex_loc(ec, loc);
412 path = arg[0] ? arg : ex_path();
413 if (ex_region(loc, &beg, &end))
414 return 1;
415 if (arg[0] == '!') {
416 int pos = MIN(xrow + 1, lbuf_len(xb));
417 if (ex_expand(arg, ex_argeol(ec)))
418 return 1;
419 obuf = cmd_pipe(arg + 1, NULL, 0, 1);
420 if (obuf)
421 lbuf_edit(xb, obuf, pos, pos);
422 free(obuf);
423 } else {
424 int fd = open(path, O_RDONLY);
425 int pos = lbuf_len(xb) ? end : 0;
426 if (fd < 0) {
427 ex_show("read failed\n");
428 return 1;
430 if (lbuf_rd(xb, fd, pos, pos)) {
431 ex_show("read failed\n");
432 close(fd);
433 return 1;
435 close(fd);
437 xrow = end + lbuf_len(xb) - n - 1;
438 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
439 path, lbuf_len(xb) - n);
440 ex_show(msg);
441 return 0;
444 static int ec_write(char *ec)
446 char cmd[EXLEN], arg[EXLEN], loc[EXLEN];
447 char msg[128];
448 char *path;
449 char *ibuf;
450 int beg, end;
451 ex_cmd(ec, cmd);
452 ex_arg(ec, arg);
453 ex_loc(ec, loc);
454 path = arg[0] ? arg : ex_path();
455 if (cmd[0] == 'x' && !lbuf_modified(xb))
456 return ec_quit(cmd);
457 if (ex_region(loc, &beg, &end))
458 return 1;
459 if (!loc[0]) {
460 beg = 0;
461 end = lbuf_len(xb);
463 if (arg[0] == '!') {
464 if (ex_expand(arg, ex_argeol(ec)))
465 return 1;
466 ibuf = lbuf_cp(xb, beg, end);
467 ex_print(NULL);
468 cmd_pipe(arg + 1, ibuf, 1, 0);
469 free(ibuf);
470 } else {
471 int fd;
472 if (!strchr(cmd, '!') && bufs[0].path &&
473 !strcmp(bufs[0].path, path) &&
474 mtime(bufs[0].path) > bufs[0].mtime) {
475 ex_show("write failed\n");
476 return 1;
478 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
479 if (fd < 0) {
480 ex_show("write failed\n");
481 return 1;
483 if (lbuf_wr(xb, fd, beg, end)) {
484 ex_show("write failed\n");
485 close(fd);
486 return 1;
488 close(fd);
490 snprintf(msg, sizeof(msg), "\"%s\" %d lines [w]\n",
491 path, end - beg);
492 ex_show(msg);
493 if (!ex_path()[0]) {
494 free(bufs[0].path);
495 bufs[0].path = uc_dup(path);
497 if (!strcmp(ex_path(), path))
498 lbuf_saved(xb, 0);
499 if (!strcmp(ex_path(), path))
500 bufs[0].mtime = mtime(path);
501 if (cmd[0] == 'x' || (cmd[0] == 'w' && cmd[1] == 'q'))
502 ec_quit(cmd);
503 return 0;
506 static int ec_insert(char *ec)
508 char arg[EXLEN], cmd[EXLEN], loc[EXLEN];
509 struct sbuf *sb;
510 char *s;
511 int beg, end;
512 int n;
513 ex_arg(ec, arg);
514 ex_cmd(ec, cmd);
515 ex_loc(ec, loc);
516 if (ex_region(loc, &beg, &end) && (beg != 0 || end != 0))
517 return 1;
518 sb = sbuf_make();
519 while ((s = ex_read(""))) {
520 if (!strcmp(".", s)) {
521 free(s);
522 break;
524 sbuf_str(sb, s);
525 sbuf_chr(sb, '\n');
526 free(s);
528 if (cmd[0] == 'a')
529 if (beg + 1 <= lbuf_len(xb))
530 beg++;
531 if (cmd[0] != 'c')
532 end = beg;
533 n = lbuf_len(xb);
534 lbuf_edit(xb, sbuf_buf(sb), beg, end);
535 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
536 sbuf_free(sb);
537 return 0;
540 static int ec_print(char *ec)
542 char cmd[EXLEN], loc[EXLEN];
543 int beg, end;
544 int i;
545 ex_cmd(ec, cmd);
546 ex_loc(ec, loc);
547 if (!cmd[0] && !loc[0]) {
548 if (xrow >= lbuf_len(xb) - 1)
549 return 1;
550 xrow = xrow + 1;
552 if (ex_region(loc, &beg, &end))
553 return 1;
554 for (i = beg; i < end; i++)
555 ex_print(lbuf_get(xb, i));
556 xrow = end;
557 xoff = 0;
558 return 0;
561 static int ec_null(char *ec)
563 char loc[EXLEN];
564 int beg, end;
565 if (!xvis)
566 return ec_print(ec);
567 ex_loc(ec, loc);
568 if (ex_region(loc, &beg, &end))
569 return 1;
570 xrow = MAX(beg, end - 1);
571 xoff = 0;
572 return 0;
575 static void ex_yank(int reg, int beg, int end)
577 char *buf = lbuf_cp(xb, beg, end);
578 reg_put(reg, buf, 1);
579 free(buf);
582 static int ec_delete(char *ec)
584 char loc[EXLEN];
585 char arg[EXLEN];
586 int beg, end;
587 ex_loc(ec, loc);
588 ex_arg(ec, arg);
589 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
590 return 1;
591 ex_yank(arg[0], beg, end);
592 lbuf_edit(xb, NULL, beg, end);
593 xrow = beg;
594 return 0;
597 static int ec_yank(char *ec)
599 char loc[EXLEN];
600 char arg[EXLEN];
601 int beg, end;
602 ex_loc(ec, loc);
603 ex_arg(ec, arg);
604 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
605 return 1;
606 ex_yank(arg[0], beg, end);
607 return 0;
610 static int ec_put(char *ec)
612 char loc[EXLEN];
613 char arg[EXLEN];
614 int beg, end;
615 int lnmode;
616 char *buf;
617 int n = lbuf_len(xb);
618 ex_loc(ec, loc);
619 ex_arg(ec, arg);
620 buf = reg_get(arg[0], &lnmode);
621 if (!buf || ex_region(loc, &beg, &end))
622 return 1;
623 lbuf_edit(xb, buf, end, end);
624 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
625 return 0;
628 static int ec_lnum(char *ec)
630 char loc[EXLEN];
631 char msg[128];
632 int beg, end;
633 ex_loc(ec, loc);
634 if (ex_region(loc, &beg, &end))
635 return 1;
636 sprintf(msg, "%d\n", end);
637 ex_print(msg);
638 return 0;
641 static int ec_undo(char *ec)
643 return lbuf_undo(xb);
646 static int ec_redo(char *ec)
648 return lbuf_redo(xb);
651 static int ec_mark(char *ec)
653 char loc[EXLEN], arg[EXLEN];
654 int beg, end;
655 ex_arg(ec, arg);
656 ex_loc(ec, loc);
657 if (ex_region(loc, &beg, &end))
658 return 1;
659 lbuf_mark(xb, arg[0], end - 1, 0);
660 return 0;
663 static int ec_substitute(char *ec)
665 char loc[EXLEN];
666 struct rset *re;
667 int offs[32];
668 int beg, end;
669 char *pats[1];
670 char *pat = NULL, *rep = NULL;
671 char *s;
672 int i;
673 ex_loc(ec, loc);
674 if (ex_region(loc, &beg, &end))
675 return 1;
676 s = ex_argeol(ec);
677 pat = re_read(&s);
678 if (pat && pat[0])
679 ex_kwdset(pat, +1);
680 if (pat && *s) {
681 s--;
682 rep = re_read(&s);
684 if (!rep)
685 rep = uc_dup(pat ? "" : xrep);
686 snprintf(xrep, sizeof(xrep), "%s", rep);
687 free(pat);
688 if (ex_kwd(&pats[0], NULL))
689 return 1;
690 re = rset_make(1, pats, xic ? RE_ICASE : 0);
691 if (!re) {
692 free(rep);
693 return 1;
695 for (i = beg; i < end; i++) {
696 char *ln = lbuf_get(xb, i);
697 struct sbuf *r = sbuf_make();
698 while (rset_find(re, ln, LEN(offs) / 2, offs, 0) >= 0) {
699 sbuf_mem(r, ln, offs[0]);
700 sbuf_str(r, rep);
701 ln += offs[1];
702 if (!strchr(s, 'g'))
703 break;
705 sbuf_str(r, ln);
706 lbuf_edit(xb, sbuf_buf(r), i, i + 1);
707 sbuf_free(r);
709 rset_free(re);
710 free(rep);
711 return 0;
714 static int ec_exec(char *ec)
716 char arg[EXLEN];
717 ex_modifiedbuffer(NULL);
718 if (ex_expand(arg, ex_argeol(ec)))
719 return 1;
720 ex_print(NULL);
721 if (cmd_exec(arg))
722 return 1;
723 return 0;
726 static int ec_make(char *ec)
728 char arg[EXLEN];
729 char make[EXLEN];
730 ex_modifiedbuffer(NULL);
731 if (ex_expand(arg, ex_argeol(ec)))
732 return 1;
733 sprintf(make, "make %s", arg);
734 ex_print(NULL);
735 if (cmd_exec(make))
736 return 1;
737 return 0;
740 static int ec_ft(char *ec)
742 char arg[EXLEN];
743 ex_arg(ec, arg);
744 if (arg[0])
745 snprintf(bufs[0].ft, sizeof(bufs[0].ft), arg);
746 else
747 ex_print(ex_filetype());
748 return 0;
751 static int ec_cmap(char *ec)
753 char cmd[EXLEN];
754 char arg[EXLEN];
755 ex_cmd(ec, cmd);
756 ex_arg(ec, arg);
757 if (arg[0])
758 snprintf(xkmap2, sizeof(xkmap2), arg);
759 else
760 ex_print(xkmap);
761 if (arg[0] && !strchr(cmd, '!'))
762 xkmap = xkmap2;
763 return 0;
766 static int ex_exec(char *ln);
768 static int ec_glob(char *ec)
770 char loc[EXLEN], cmd[EXLEN];
771 struct rset *re;
772 int offs[32];
773 int beg, end, not;
774 char *pats[1];
775 char *pat, *s;
776 int i;
777 ex_cmd(ec, cmd);
778 ex_loc(ec, loc);
779 if (ex_region(loc, &beg, &end))
780 return 1;
781 not = strchr(cmd, '!') || cmd[0] == 'v';
782 s = ex_argeol(ec);
783 pat = re_read(&s);
784 if (pat && pat[0])
785 ex_kwdset(pat, +1);
786 free(pat);
787 if (ex_kwd(&pats[0], NULL))
788 return 1;
789 if (!(re = rset_make(1, pats, xic ? RE_ICASE : 0)))
790 return 1;
791 i = beg;
792 while (i < end) {
793 char *ln = lbuf_get(xb, i);
794 if ((rset_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == not) {
795 int len = lbuf_len(xb);
796 xrow = i;
797 ex_exec(s);
798 i += lbuf_len(xb) - len;
799 end += lbuf_len(xb) - len;
801 i++;
803 rset_free(re);
804 return 0;
807 static struct option {
808 char *abbr;
809 char *name;
810 int *var;
811 } options[] = {
812 {"ai", "autoindent", &xai},
813 {"aw", "autowrite", &xaw},
814 {"ic", "ignorecase", &xic},
815 {"td", "textdirection", &xdir},
816 {"shape", "shape", &xshape},
817 {"order", "xorder", &xorder},
818 {"hl", "highlight", &xhl},
821 static char *cutword(char *s, char *d)
823 while (isspace(*s))
824 s++;
825 while (*s && !isspace(*s))
826 *d++ = *s++;
827 while (isspace(*s))
828 s++;
829 *d = '\0';
830 return s;
833 static int ec_set(char *ec)
835 char arg[EXLEN];
836 char tok[EXLEN];
837 char opt[EXLEN];
838 char *s = arg;
839 int val = 0;
840 int i;
841 ex_arg(ec, arg);
842 if (*s) {
843 s = cutword(s, tok);
844 if (tok[0] == 'n' && tok[1] == 'o') {
845 strcpy(opt, tok + 2);
846 val = 0;
847 } else {
848 char *r = strchr(tok, '=');
849 if (r) {
850 *r = '\0';
851 strcpy(opt, tok);
852 val = atoi(r + 1);
853 } else {
854 strcpy(opt, tok);
855 val = 1;
858 for (i = 0; i < LEN(options); i++) {
859 struct option *o = &options[i];
860 if (!strcmp(o->abbr, opt) || !strcmp(o->name, opt)) {
861 *o->var = val;
862 return 0;
865 ex_show("unknown option");
866 return 1;
868 return 0;
871 static struct excmd {
872 char *abbr;
873 char *name;
874 int (*ec)(char *s);
875 } excmds[] = {
876 {"p", "print", ec_print},
877 {"a", "append", ec_insert},
878 {"i", "insert", ec_insert},
879 {"d", "delete", ec_delete},
880 {"c", "change", ec_insert},
881 {"e", "edit", ec_edit},
882 {"e!", "edit!", ec_edit},
883 {"g", "global", ec_glob},
884 {"g!", "global!", ec_glob},
885 {"=", "=", ec_lnum},
886 {"k", "mark", ec_mark},
887 {"pu", "put", ec_put},
888 {"q", "quit", ec_quit},
889 {"q!", "quit!", ec_quit},
890 {"r", "read", ec_read},
891 {"v", "vglobal", ec_glob},
892 {"w", "write", ec_write},
893 {"w!", "write!", ec_write},
894 {"wq", "wq", ec_write},
895 {"wq!", "wq!", ec_write},
896 {"u", "undo", ec_undo},
897 {"r", "redo", ec_redo},
898 {"se", "set", ec_set},
899 {"s", "substitute", ec_substitute},
900 {"x", "xit", ec_write},
901 {"x!", "xit!", ec_write},
902 {"ya", "yank", ec_yank},
903 {"!", "!", ec_exec},
904 {"make", "make", ec_make},
905 {"ft", "filetype", ec_ft},
906 {"cm", "cmap", ec_cmap},
907 {"cm!", "cmap!", ec_cmap},
908 {"", "", ec_null},
911 /* execute a single ex command */
912 static int ex_exec(char *ln)
914 char ec[EXLEN];
915 char cmd[EXLEN];
916 int i;
917 int ret = 0;
918 while (*ln) {
919 ln = ex_line(ln, ec);
920 ex_cmd(ec, cmd);
921 for (i = 0; i < LEN(excmds); i++) {
922 if (!strcmp(excmds[i].abbr, cmd) ||
923 !strcmp(excmds[i].name, cmd)) {
924 ret = excmds[i].ec(ec);
925 break;
928 if (!xvis && !cmd[0])
929 ret = ec_print(ec);
931 return ret;
934 /* execute a single ex command */
935 void ex_command(char *ln)
937 ex_exec(ln);
938 lbuf_modified(xb);
939 reg_put(':', ln, 0);
942 /* ex main loop */
943 void ex(void)
945 while (!xquit) {
946 char *ln = ex_read(":");
947 if (ln)
948 ex_command(ln);
949 free(ln);
953 int ex_init(char **files)
955 char cmd[EXLEN];
956 char *s = cmd;
957 char *r = files[0] ? files[0] : "";
958 *s++ = 'e';
959 *s++ = ' ';
960 while (*r && s + 2 < cmd + sizeof(cmd)) {
961 if (*r == ' ')
962 *s++ = '\\';
963 *s++ = *r++;
965 *s = '\0';
966 if (ec_edit(cmd))
967 return 1;
968 if (getenv("EXINIT"))
969 ex_command(getenv("EXINIT"));
970 return 0;
973 void ex_done(void)
975 int i;
976 for (i = 0; i < LEN(bufs); i++)
977 bufs_free(i);