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 */
33 long mtime
; /* modification time */
36 static int bufs_find(char *path
)
39 for (i
= 0; i
< LEN(bufs
); i
++)
40 if (bufs
[i
].lb
&& !strcmp(bufs
[i
].path
, path
))
45 static void bufs_free(int idx
)
49 lbuf_free(bufs
[idx
].lb
);
50 memset(&bufs
[idx
], 0, sizeof(bufs
[idx
]));
54 static long mtime(char *path
)
62 static int bufs_open(char *path
)
65 for (i
= 0; i
< LEN(bufs
) - 1; i
++)
69 bufs
[i
].path
= uc_dup(path
);
70 bufs
[i
].lb
= lbuf_make();
75 strcpy(bufs
[i
].ft
, syn_filetype(path
));
79 static void bufs_swap(int i
, int j
)
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
)
104 struct lbuf
*ex_lbuf(void)
109 char *ex_filetype(void)
111 return xhl
? bufs
[0].ft
: "";
119 char *ex_kmapalt(void)
124 /* read ex command location */
125 static char *ex_loc(char *s
, char *loc
)
127 while (*s
== ':' || isspace((unsigned char) *s
))
129 while (*s
&& !isalpha((unsigned char) *s
) && *s
!= '=' && *s
!= '!') {
132 if (*s
== '/' || *s
== '?') {
135 while (*s
&& *s
!= d
) {
136 if (*s
== '\\' && s
[1])
148 /* read ex command name */
149 static char *ex_cmd(char *s
, char *cmd
)
153 while (isspace((unsigned char) *s
))
155 while (isalpha((unsigned char) *s
))
156 if ((*cmd
++ = *s
++) == 'k' && cmd
== cmd0
+ 1)
158 if (*s
== '!' || *s
== '=')
164 /* read ex command argument */
165 static char *ex_arg(char *s
, char *arg
)
168 while (isspace((unsigned char) *s
))
170 while (*s
&& !isspace((unsigned char) *s
)) {
171 if (*s
== '\\' && s
[1])
179 static char *ex_argeol(char *ec
)
182 char *s
= ex_cmd(ec
, arg
);
183 while (isspace((unsigned char) *s
))
188 static char *ex_line(char *s
, char *ln
)
190 while (*s
&& *s
!= '|' && *s
!= '\n')
193 return *s
? s
+ 1 : s
;
196 /* the previous search keyword */
197 int ex_kwd(char **kwd
, int *dir
)
206 /* set the previous search keyword */
207 void ex_kwdset(char *kwd
, int dir
)
210 snprintf(xkwd
, sizeof(xkwd
), "%s", kwd
);
211 reg_put('/', kwd
, 0);
216 static int ex_search(char *pat
)
228 sbuf_chr(kw
, (unsigned char) *e
);
229 if (*e
== '\\' && e
[1])
233 ex_kwdset(sbuf_buf(kw
), *pat
== '/' ? 1 : -1);
235 if (ex_kwd(&pats
[0], &dir
))
237 re
= rset_make(1, pats
, xic
? RE_ICASE
: 0);
241 while (row
>= 0 && row
< lbuf_len(xb
)) {
242 if (rset_find(re
, lbuf_get(xb
, row
), 0, NULL
, 0) >= 0)
247 return row
< 0 || row
>= lbuf_len(xb
) ? xrow
: row
;
250 static int ex_lineno(char *num
)
253 if (!num
[0] || num
[0] == '.')
258 n
= lbuf_len(xb
) - 1;
260 n
= xrow
- (num
[1] ? atoi(num
+ 1) : 1);
262 n
= xrow
+ (num
[1] ? atoi(num
+ 1) : 1);
264 lbuf_jump(xb
, num
[1], &n
, NULL
);
265 if (num
[0] == '/' && num
[1])
267 if (num
[0] == '?' && num
[1])
272 /* parse ex command location */
273 static int ex_region(char *loc
, int *beg
, int *end
)
276 if (!strcmp("%", loc
)) {
278 *end
= MAX(0, lbuf_len(xb
));
283 *end
= xrow
== lbuf_len(xb
) ? xrow
: xrow
+ 1;
288 *end
= ex_lineno(loc
) + 1;
289 *beg
= naddr
++ ? end0
- 1 : *end
- 1;
292 while (*loc
&& *loc
!= ';' && *loc
!= ',')
300 if (*beg
< 0 || *beg
>= lbuf_len(xb
))
302 if (*end
< *beg
|| *end
> lbuf_len(xb
))
307 static int ec_write(char *ec
);
309 static int ex_modifiedbuffer(char *msg
)
311 if (!lbuf_modified(xb
))
313 if (xaw
&& ex_path()[0])
314 return ec_write("w");
320 static int ec_quit(char *ec
)
324 if (!strchr(cmd
, '!'))
325 if (ex_modifiedbuffer("buffer modified\n"))
331 static int ex_expand(char *d
, char *s
)
334 int c
= (unsigned char) *s
++;
336 if (!bufs
[0].path
|| !bufs
[0].path
[0]) {
337 ex_show("\"%\" is unset\n");
340 strcpy(d
, bufs
[0].path
);
345 if (!bufs
[1].path
|| !bufs
[1].path
[0]) {
346 ex_show("\"#\" is unset\n");
349 strcpy(d
, bufs
[1].path
);
353 if (c
== '\\' && (*s
== '%' || *s
== '#'))
361 static int ec_edit(char *ec
)
364 char arg
[EXLEN
], cmd
[EXLEN
];
369 if (!strchr(cmd
, '!'))
370 if (xb
&& ex_modifiedbuffer("buffer modified\n"))
372 if (ex_expand(path
, arg
))
377 if (arg
[0] && bufs_find(path
) >= 0) {
378 bufs_switch(bufs_find(path
));
381 if (path
[0] || !bufs
[0].path
)
382 bufs_switch(bufs_open(path
));
383 fd
= open(ex_path(), O_RDONLY
);
385 int rd
= lbuf_rd(xb
, fd
, 0, lbuf_len(xb
));
387 snprintf(msg
, sizeof(msg
), "\"%s\" %d lines [r]\n",
388 ex_path(), lbuf_len(xb
));
390 ex_show("read failed\n");
394 lbuf_saved(xb
, path
[0] != '\0');
395 bufs
[0].mtime
= mtime(ex_path());
396 xrow
= MAX(0, MIN(xrow
, lbuf_len(xb
) - 1));
398 xtop
= MAX(0, MIN(xtop
, lbuf_len(xb
) - 1));
402 static int ec_read(char *ec
)
404 char arg
[EXLEN
], loc
[EXLEN
];
409 int n
= lbuf_len(xb
);
412 path
= arg
[0] ? arg
: ex_path();
413 if (ex_region(loc
, &beg
, &end
))
416 int pos
= MIN(xrow
+ 1, lbuf_len(xb
));
417 if (ex_expand(arg
, ex_argeol(ec
)))
419 obuf
= cmd_pipe(arg
+ 1, NULL
, 0, 1);
421 lbuf_edit(xb
, obuf
, pos
, pos
);
424 int fd
= open(path
, O_RDONLY
);
425 int pos
= lbuf_len(xb
) ? end
: 0;
427 ex_show("read failed\n");
430 if (lbuf_rd(xb
, fd
, pos
, pos
)) {
431 ex_show("read failed\n");
437 xrow
= end
+ lbuf_len(xb
) - n
- 1;
438 snprintf(msg
, sizeof(msg
), "\"%s\" %d lines [r]\n",
439 path
, lbuf_len(xb
) - n
);
444 static int ec_write(char *ec
)
446 char cmd
[EXLEN
], arg
[EXLEN
], loc
[EXLEN
];
454 path
= arg
[0] ? arg
: ex_path();
455 if (cmd
[0] == 'x' && !lbuf_modified(xb
))
457 if (ex_region(loc
, &beg
, &end
))
464 if (ex_expand(arg
, ex_argeol(ec
)))
466 ibuf
= lbuf_cp(xb
, beg
, end
);
468 cmd_pipe(arg
+ 1, ibuf
, 1, 0);
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");
478 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
480 ex_show("write failed\n");
483 if (lbuf_wr(xb
, fd
, beg
, end
)) {
484 ex_show("write failed\n");
490 snprintf(msg
, sizeof(msg
), "\"%s\" %d lines [w]\n",
495 bufs
[0].path
= uc_dup(path
);
497 if (!strcmp(ex_path(), path
))
499 if (!strcmp(ex_path(), path
))
500 bufs
[0].mtime
= mtime(path
);
501 if (cmd
[0] == 'x' || (cmd
[0] == 'w' && cmd
[1] == 'q'))
506 static int ec_insert(char *ec
)
508 char arg
[EXLEN
], cmd
[EXLEN
], loc
[EXLEN
];
516 if (ex_region(loc
, &beg
, &end
) && (beg
!= 0 || end
!= 0))
519 while ((s
= ex_read(""))) {
520 if (!strcmp(".", s
)) {
529 if (beg
+ 1 <= 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);
540 static int ec_print(char *ec
)
542 char cmd
[EXLEN
], loc
[EXLEN
];
547 if (!cmd
[0] && !loc
[0]) {
548 if (xrow
>= lbuf_len(xb
) - 1)
552 if (ex_region(loc
, &beg
, &end
))
554 for (i
= beg
; i
< end
; i
++)
555 ex_print(lbuf_get(xb
, i
));
561 static int ec_null(char *ec
)
568 if (ex_region(loc
, &beg
, &end
))
570 xrow
= MAX(beg
, end
- 1);
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);
582 static int ec_delete(char *ec
)
589 if (ex_region(loc
, &beg
, &end
) || !lbuf_len(xb
))
591 ex_yank(arg
[0], beg
, end
);
592 lbuf_edit(xb
, NULL
, beg
, end
);
597 static int ec_yank(char *ec
)
604 if (ex_region(loc
, &beg
, &end
) || !lbuf_len(xb
))
606 ex_yank(arg
[0], beg
, end
);
610 static int ec_put(char *ec
)
617 int n
= lbuf_len(xb
);
620 buf
= reg_get(arg
[0], &lnmode
);
621 if (!buf
|| ex_region(loc
, &beg
, &end
))
623 lbuf_edit(xb
, buf
, end
, end
);
624 xrow
= MIN(lbuf_len(xb
) - 1, end
+ lbuf_len(xb
) - n
- 1);
628 static int ec_lnum(char *ec
)
634 if (ex_region(loc
, &beg
, &end
))
636 sprintf(msg
, "%d\n", end
);
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
];
657 if (ex_region(loc
, &beg
, &end
))
659 lbuf_mark(xb
, arg
[0], end
- 1, 0);
663 static int ec_substitute(char *ec
)
670 char *pat
= NULL
, *rep
= NULL
;
674 if (ex_region(loc
, &beg
, &end
))
685 rep
= uc_dup(pat
? "" : xrep
);
686 snprintf(xrep
, sizeof(xrep
), "%s", rep
);
688 if (ex_kwd(&pats
[0], NULL
))
690 re
= rset_make(1, pats
, xic
? RE_ICASE
: 0);
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]);
706 lbuf_edit(xb
, sbuf_buf(r
), i
, i
+ 1);
714 static int ec_exec(char *ec
)
717 ex_modifiedbuffer(NULL
);
718 if (ex_expand(arg
, ex_argeol(ec
)))
726 static int ec_make(char *ec
)
730 ex_modifiedbuffer(NULL
);
731 if (ex_expand(arg
, ex_argeol(ec
)))
733 sprintf(make
, "make %s", arg
);
740 static int ec_ft(char *ec
)
745 snprintf(bufs
[0].ft
, sizeof(bufs
[0].ft
), arg
);
747 ex_print(ex_filetype());
751 static int ec_cmap(char *ec
)
758 snprintf(xkmap2
, sizeof(xkmap2
), arg
);
761 if (arg
[0] && !strchr(cmd
, '!'))
766 static int ex_exec(char *ln
);
768 static int ec_glob(char *ec
)
770 char loc
[EXLEN
], cmd
[EXLEN
];
779 if (ex_region(loc
, &beg
, &end
))
781 not = strchr(cmd
, '!') || cmd
[0] == 'v';
787 if (ex_kwd(&pats
[0], NULL
))
789 if (!(re
= rset_make(1, pats
, xic
? RE_ICASE
: 0)))
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
);
798 i
+= lbuf_len(xb
) - len
;
799 end
+= lbuf_len(xb
) - len
;
807 static struct option
{
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
)
825 while (*s
&& !isspace(*s
))
833 static int ec_set(char *ec
)
844 if (tok
[0] == 'n' && tok
[1] == 'o') {
845 strcpy(opt
, tok
+ 2);
848 char *r
= strchr(tok
, '=');
858 for (i
= 0; i
< LEN(options
); i
++) {
859 struct option
*o
= &options
[i
];
860 if (!strcmp(o
->abbr
, opt
) || !strcmp(o
->name
, opt
)) {
865 ex_show("unknown option");
871 static struct excmd
{
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
},
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
},
904 {"make", "make", ec_make
},
905 {"ft", "filetype", ec_ft
},
906 {"cm", "cmap", ec_cmap
},
907 {"cm!", "cmap!", ec_cmap
},
911 /* execute a single ex command */
912 static int ex_exec(char *ln
)
919 ln
= ex_line(ln
, ec
);
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
);
928 if (!xvis
&& !cmd
[0])
934 /* execute a single ex command */
935 void ex_command(char *ln
)
946 char *ln
= ex_read(":");
953 int ex_init(char **files
)
957 char *r
= files
[0] ? files
[0] : "";
960 while (*r
&& s
+ 2 < cmd
+ sizeof(cmd
)) {
968 if (getenv("EXINIT"))
969 ex_command(getenv("EXINIT"));
976 for (i
= 0; i
< LEN(bufs
); i
++)