10 int xrow
, xoff
, xtop
; /* current row, column, and top row */
11 int xquit
; /* exit if set */
12 int xvis
; /* visual mode */
13 int xai
= 1; /* autoindent option */
14 int xic
= 1; /* ignorecase option */
15 int xaw
; /* autowrite option */
16 int xhl
= 1; /* syntax highlight option */
17 int xled
= 1; /* use the line editor */
18 int xdir
= +1; /* current direction context */
19 int xshape
= 1; /* perform letter shaping */
20 int xorder
= 1; /* change the order of characters */
21 char xfindkwd
[EXLEN
]; /* the last searched keyword */
22 int xfinddir
= +1; /* the last search direction */
31 static int bufs_find(char *path
)
34 for (i
= 0; i
< LEN(bufs
); i
++)
35 if (bufs
[i
].lb
&& !strcmp(bufs
[i
].path
, path
))
40 static void bufs_free(int idx
)
44 lbuf_free(bufs
[idx
].lb
);
45 memset(&bufs
[idx
], 0, sizeof(bufs
[idx
]));
49 static int bufs_open(char *path
)
52 for (i
= 0; i
< LEN(bufs
) - 1; i
++)
56 bufs
[i
].path
= uc_dup(path
);
57 bufs
[i
].lb
= lbuf_make();
60 strcpy(bufs
[i
].ft
, syn_filetype(path
));
64 static void bufs_swap(int i
, int j
)
69 memcpy(&tmp
, &bufs
[i
], sizeof(tmp
));
70 memcpy(&bufs
[i
], &bufs
[j
], sizeof(tmp
));
71 memcpy(&bufs
[j
], &tmp
, sizeof(tmp
));
74 static void bufs_switch(int idx
)
88 struct lbuf
*ex_lbuf(void)
93 char *ex_filetype(void)
95 return xhl
? bufs
[0].ft
: "";
98 /* read ex command location */
99 static char *ex_loc(char *s
, char *loc
)
101 while (*s
== ':' || isspace((unsigned char) *s
))
103 while (*s
&& !isalpha((unsigned char) *s
) && *s
!= '=' && *s
!= '!') {
106 if (*s
== '/' || *s
== '?') {
109 while (*s
&& *s
!= d
) {
110 if (*s
== '\\' && s
[1])
122 /* read ex command name */
123 static char *ex_cmd(char *s
, char *cmd
)
127 while (isspace((unsigned char) *s
))
129 while (isalpha((unsigned char) *s
))
130 if ((*cmd
++ = *s
++) == 'k' && cmd
== cmd0
+ 1)
132 if (*s
== '!' || *s
== '=')
138 /* read ex command argument */
139 static char *ex_arg(char *s
, char *arg
)
142 while (isspace((unsigned char) *s
))
144 while (*s
&& !isspace((unsigned char) *s
))
150 static char *ex_argeol(char *ec
)
153 char *s
= ex_cmd(ec
, arg
);
154 while (isspace((unsigned char) *s
))
159 static char *ex_line(char *s
, char *ln
)
161 while (*s
&& *s
!= '|' && *s
!= '\n')
164 return *s
? s
+ 1 : s
;
167 static int ex_search(char *pat
)
170 int dir
= *pat
== '/' ? 1 : -1;
180 sbuf_chr(kw
, (unsigned char) *e
);
181 if (*e
== '\\' && e
[1])
185 snprintf(xfindkwd
, sizeof(xfindkwd
), "%s", sbuf_buf(kw
));
191 re
= rset_make(1, pats
, xic
? RE_ICASE
: 0);
195 while (row
>= 0 && row
< lbuf_len(xb
)) {
196 if (rset_find(re
, lbuf_get(xb
, row
), 0, NULL
, 0) >= 0)
201 return row
< 0 || row
>= lbuf_len(xb
) ? xrow
: row
;
204 static int ex_lineno(char *num
)
207 if (!num
[0] || num
[0] == '.')
212 n
= lbuf_len(xb
) - 1;
214 n
= xrow
- (num
[1] ? ex_lineno(num
+ 1) : 1);
216 n
= xrow
+ (num
[1] ? ex_lineno(num
+ 1) : 1);
218 lbuf_jump(xb
, num
[1], &n
, NULL
);
219 if (num
[0] == '/' && num
[1])
221 if (num
[0] == '?' && num
[1])
226 /* parse ex command location */
227 static int ex_region(char *loc
, int *beg
, int *end
)
230 if (!strcmp("%", loc
)) {
232 *end
= MAX(0, lbuf_len(xb
));
237 *end
= xrow
== lbuf_len(xb
) ? xrow
: xrow
+ 1;
242 *end
= ex_lineno(loc
) + 1;
243 *beg
= naddr
++ ? end0
- 1 : *end
- 1;
246 while (*loc
&& *loc
!= ';' && *loc
!= ',')
254 if (*beg
< 0 || *beg
>= lbuf_len(xb
))
256 if (*end
< *beg
|| *end
> lbuf_len(xb
))
261 static int ec_write(char *ec
);
263 static int ex_modifiedbuffer(char *msg
)
265 if (!lbuf_modified(xb
))
267 if (xaw
&& ex_path()[0])
268 return ec_write("w");
274 static int ec_quit(char *ec
)
278 if (!strchr(cmd
, '!'))
279 if (ex_modifiedbuffer("buffer modified\n"))
285 static int ex_expand(char *d
, char *s
)
288 int c
= (unsigned char) *s
++;
290 if (!bufs
[0].path
|| !bufs
[0].path
[0]) {
291 ex_show("\"%\" is unset\n");
294 strcpy(d
, bufs
[0].path
);
299 if (!bufs
[1].path
|| !bufs
[1].path
[0]) {
300 ex_show("\"#\" is unset\n");
303 strcpy(d
, bufs
[1].path
);
307 if (c
== '\\' && (*s
== '%' || *s
== '#'))
315 static int ec_edit(char *ec
)
318 char arg
[EXLEN
], cmd
[EXLEN
];
323 if (!strchr(cmd
, '!'))
324 if (xb
&& ex_modifiedbuffer("buffer modified\n"))
326 if (ex_expand(path
, arg
))
330 if (arg
[0] && bufs_find(path
) >= 0) {
331 bufs_switch(bufs_find(path
));
334 if (path
[0] || !bufs
[0].path
)
335 bufs_switch(bufs_open(path
));
336 fd
= open(ex_path(), O_RDONLY
);
338 lbuf_rm(xb
, 0, lbuf_len(xb
));
341 snprintf(msg
, sizeof(msg
), "\"%s\" %d lines [r]\n",
342 ex_path(), lbuf_len(xb
));
345 xrow
= xvis
? 0 : MAX(0, MIN(xrow
, lbuf_len(xb
) - 1));
346 lbuf_saved(xb
, path
[0] != '\0');
350 static int ec_read(char *ec
)
352 char arg
[EXLEN
], loc
[EXLEN
];
357 int n
= lbuf_len(xb
);
360 path
= arg
[0] ? arg
: ex_path();
361 if (ex_region(loc
, &beg
, &end
))
364 if (ex_expand(arg
, ex_argeol(ec
)))
366 obuf
= cmd_pipe(arg
+ 1, NULL
, 0, 1);
368 lbuf_put(xb
, MIN(xrow
+ 1, lbuf_len(xb
)), obuf
);
371 int fd
= open(path
, O_RDONLY
);
373 ex_show("read failed\n");
376 lbuf_rd(xb
, fd
, lbuf_len(xb
) ? end
: 0);
379 xrow
= end
+ lbuf_len(xb
) - n
- 1;
380 snprintf(msg
, sizeof(msg
), "\"%s\" %d lines [r]\n",
381 path
, lbuf_len(xb
) - n
);
386 static int ec_write(char *ec
)
388 char cmd
[EXLEN
], arg
[EXLEN
], loc
[EXLEN
];
396 path
= arg
[0] ? arg
: ex_path();
397 if (cmd
[0] == 'x' && !lbuf_modified(xb
))
399 if (ex_region(loc
, &beg
, &end
))
406 if (ex_expand(arg
, ex_argeol(ec
)))
408 ibuf
= lbuf_cp(xb
, beg
, end
);
410 cmd_pipe(arg
+ 1, ibuf
, 1, 0);
413 int fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
415 ex_show("write failed\n");
418 lbuf_wr(xb
, fd
, beg
, end
);
421 snprintf(msg
, sizeof(msg
), "\"%s\" %d lines [w]\n",
426 bufs
[0].path
= uc_dup(path
);
428 if (!strcmp(ex_path(), path
))
430 if (cmd
[0] == 'x' || (cmd
[0] == 'w' && cmd
[1] == 'q'))
435 static int ec_insert(char *ec
)
437 char arg
[EXLEN
], cmd
[EXLEN
], loc
[EXLEN
];
445 if (ex_region(loc
, &beg
, &end
) && (beg
!= 0 || end
!= 0))
449 lbuf_rm(xb
, beg
, end
);
453 while ((s
= ex_read(""))) {
454 if (!strcmp(".", s
)) {
463 if (end
> lbuf_len(xb
))
466 lbuf_put(xb
, end
, sbuf_buf(sb
));
467 xrow
= MIN(lbuf_len(xb
) - 1, end
+ lbuf_len(xb
) - n
- 1);
472 static int ec_print(char *ec
)
474 char cmd
[EXLEN
], loc
[EXLEN
];
479 if (!cmd
[0] && !loc
[0]) {
480 if (xrow
>= lbuf_len(xb
) - 1)
484 if (ex_region(loc
, &beg
, &end
))
486 for (i
= beg
; i
< end
; i
++)
487 ex_print(lbuf_get(xb
, i
));
493 static int ec_null(char *ec
)
500 if (ex_region(loc
, &beg
, &end
))
502 xrow
= MAX(beg
, end
- 1);
507 static void ex_yank(int reg
, int beg
, int end
)
509 char *buf
= lbuf_cp(xb
, beg
, end
);
510 reg_put(reg
, buf
, 1);
514 static int ec_delete(char *ec
)
521 if (ex_region(loc
, &beg
, &end
) || !lbuf_len(xb
))
523 ex_yank(arg
[0], beg
, end
);
524 lbuf_rm(xb
, beg
, end
);
529 static int ec_yank(char *ec
)
536 if (ex_region(loc
, &beg
, &end
) || !lbuf_len(xb
))
538 ex_yank(arg
[0], beg
, end
);
542 static int ec_put(char *ec
)
549 int n
= lbuf_len(xb
);
552 buf
= reg_get(arg
[0], &lnmode
);
553 if (!buf
|| ex_region(loc
, &beg
, &end
))
555 lbuf_put(xb
, end
, buf
);
556 xrow
= MIN(lbuf_len(xb
) - 1, end
+ lbuf_len(xb
) - n
- 1);
560 static int ec_lnum(char *ec
)
566 if (ex_region(loc
, &beg
, &end
))
568 sprintf(msg
, "%d\n", end
);
573 static int ec_undo(char *ec
)
575 return lbuf_undo(xb
);
578 static int ec_redo(char *ec
)
580 return lbuf_redo(xb
);
583 static int ec_mark(char *ec
)
585 char loc
[EXLEN
], arg
[EXLEN
];
589 if (ex_region(loc
, &beg
, &end
))
591 lbuf_mark(xb
, arg
[0], end
- 1, 0);
595 static char *readuntil(char **src
, int delim
)
597 struct sbuf
*sbuf
= sbuf_make();
599 /* reading the pattern */
600 while (*s
&& *s
!= delim
) {
601 if (s
[0] == '\\' && s
[1])
602 sbuf_chr(sbuf
, (unsigned char) *s
++);
603 sbuf_chr(sbuf
, (unsigned char) *s
++);
605 if (*s
) /* skipping the delimiter */
608 return sbuf_done(sbuf
);
611 static int ec_substitute(char *ec
)
623 if (ex_region(loc
, &beg
, &end
))
626 delim
= (unsigned char) *s
++;
627 pat
= readuntil(&s
, delim
);
628 rep
= readuntil(&s
, delim
);
630 snprintf(xfindkwd
, sizeof(xfindkwd
), "%s", pat
);
633 re
= rset_make(1, pats
, xic
? RE_ICASE
: 0);
638 for (i
= beg
; i
< end
; i
++) {
639 char *ln
= lbuf_get(xb
, i
);
640 struct sbuf
*r
= sbuf_make();
641 while (rset_find(re
, ln
, LEN(offs
) / 2, offs
, 0) >= 0) {
642 sbuf_mem(r
, ln
, offs
[0]);
649 lbuf_rm(xb
, i
, i
+ 1);
650 lbuf_put(xb
, i
, sbuf_buf(r
));
658 static int ec_exec(char *ec
)
661 ex_modifiedbuffer(NULL
);
662 if (ex_expand(arg
, ex_argeol(ec
)))
670 static int ec_make(char *ec
)
674 ex_modifiedbuffer(NULL
);
675 if (ex_expand(arg
, ex_argeol(ec
)))
677 sprintf(make
, "make %s", arg
);
684 static struct option
{
689 {"ai", "autoindent", &xai
},
690 {"aw", "autowrite", &xaw
},
691 {"ic", "ignorecase", &xic
},
692 {"td", "textdirection", &xdir
},
693 {"shape", "shape", &xshape
},
694 {"order", "xorder", &xorder
},
695 {"hl", "highlight", &xhl
},
698 static char *cutword(char *s
, char *d
)
702 while (*s
&& !isspace(*s
))
710 static int ec_set(char *ec
)
721 if (tok
[0] == 'n' && tok
[1] == 'o') {
722 strcpy(opt
, tok
+ 2);
725 char *r
= strchr(tok
, '=');
735 for (i
= 0; i
< LEN(options
); i
++) {
736 struct option
*o
= &options
[i
];
737 if (!strcmp(o
->abbr
, opt
) || !strcmp(o
->name
, opt
)) {
742 ex_show("unknown option");
748 static struct excmd
{
753 {"p", "print", ec_print
},
754 {"a", "append", ec_insert
},
755 {"i", "insert", ec_insert
},
756 {"d", "delete", ec_delete
},
757 {"c", "change", ec_insert
},
758 {"e", "edit", ec_edit
},
759 {"e!", "edit!", ec_edit
},
761 {"k", "mark", ec_mark
},
762 {"pu", "put", ec_put
},
763 {"q", "quit", ec_quit
},
764 {"q!", "quit!", ec_quit
},
765 {"r", "read", ec_read
},
766 {"w", "write", ec_write
},
767 {"wq", "wq", ec_write
},
768 {"u", "undo", ec_undo
},
769 {"r", "redo", ec_redo
},
770 {"se", "set", ec_set
},
771 {"s", "substitute", ec_substitute
},
772 {"x", "xit", ec_write
},
773 {"x!", "xit!", ec_write
},
774 {"ya", "yank", ec_yank
},
776 {"make", "make", ec_make
},
780 /* execute a single ex command */
781 void ex_command(char *ln
)
787 ln
= ex_line(ln
, ec
);
789 for (i
= 0; i
< LEN(excmds
); i
++) {
790 if (!strcmp(excmds
[i
].abbr
, cmd
) ||
791 !strcmp(excmds
[i
].name
, cmd
)) {
796 if (!xvis
&& !cmd
[0])
806 char *ln
= ex_read(":");
813 int ex_init(char **files
)
816 snprintf(cmd
, sizeof(cmd
), "e %s", files
[0] ? files
[0] : "");
819 if (getenv("EXINIT"))
820 ex_command(getenv("EXINIT"));
827 for (i
= 0; i
< LEN(bufs
); i
++)