4 * Copyright (C) 2015 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
15 char vi_msg
[512]; /* current message */
16 static char vi_findlast
[256]; /* the last searched keyword */
17 static int vi_finddir
; /* the last search direction */
18 static char vi_charlast
[8]; /* the last character searched via f, t, F, or T */
19 static int vi_charcmd
; /* the character finding command */
20 static int vi_arg1
, vi_arg2
; /* the first and second arguments */
21 static int vi_ybuf
; /* current yank buffer */
23 static void vi_drawmsg(void)
25 led_print(vi_msg
, xrows
);
29 static void vi_draw(void)
33 for (i
= xtop
; i
< xtop
+ xrows
; i
++) {
34 char *s
= lbuf_get(xb
, i
);
35 led_print(s
? s
: (i
? "~" : ""), i
- xtop
);
38 term_pos(xrow
, led_pos(lbuf_get(xb
, i
), xcol
));
42 static int vi_buf
[128];
45 static int vi_read(void)
47 return vi_buflen
? vi_buf
[--vi_buflen
] : term_read(1000);
50 static void vi_back(int c
)
52 if (vi_buflen
< sizeof(vi_buf
))
53 vi_buf
[vi_buflen
++] = c
;
56 static char *vi_char(void)
59 return TK_INT(key
) ? NULL
: led_keymap(key
);
62 static char *vi_prompt(char *msg
)
64 term_pos(xrows
, led_pos(msg
, 0));
66 return led_prompt(msg
, "");
69 char *ex_read(char *msg
)
74 char *s
= led_prompt(msg
, "");
80 while ((c
= getchar()) != EOF
&& c
!= '\n')
89 void ex_show(char *msg
)
92 snprintf(vi_msg
, sizeof(vi_msg
), "%s", msg
);
101 static int vi_yankbuf(void)
110 static int vi_prefix(void)
114 if ((c
>= '1' && c
<= '9')) {
116 n
= n
* 10 + c
- '0';
124 static int lbuf_lnnext(struct lbuf
*lb
, int *r
, int *c
, int dir
)
126 char *ln
= lbuf_get(lb
, *r
);
127 int col
= ln
? ren_next(ln
, *c
, dir
) : -1;
134 static void lbuf_eol(struct lbuf
*lb
, int *r
, int *c
, int dir
)
136 char *ln
= lbuf_get(lb
, *r
);
137 *c
= dir
< 0 ? 0 : MAX(0, ren_wid(ln
? ln
: "") - 1);
140 static int lbuf_next(struct lbuf
*lb
, int *r
, int *c
, int dir
)
142 if (dir
< 0 && *r
>= lbuf_len(lb
))
143 *r
= MAX(0, lbuf_len(lb
) - 1);
144 if (lbuf_lnnext(lb
, r
, c
, dir
)) {
145 if (!lbuf_get(lb
, *r
+ dir
))
148 lbuf_eol(lb
, r
, c
, -dir
);
154 /* return a pointer to the character at visual position c of line r */
155 static char *lbuf_chr(struct lbuf
*lb
, int r
, int c
)
157 char *ln
= lbuf_get(lb
, r
);
158 return ln
? uc_chr(ln
, ren_off(ln
, c
)) : "";
161 static void lbuf_postindents(struct lbuf
*lb
, int *r
, int *c
)
163 lbuf_eol(lb
, r
, c
, -1);
164 while (uc_isspace(lbuf_chr(lb
, *r
, *c
)))
165 if (lbuf_lnnext(lb
, r
, c
, +1))
169 static int lbuf_findchar(struct lbuf
*lb
, int *row
, int *col
, char *cs
, int cmd
, int n
)
171 int dir
= (cmd
== 'f' || cmd
== 't') ? +1 : -1;
177 strcpy(vi_charlast
, cs
);
179 while (n
> 0 && !lbuf_lnnext(lb
, row
, &c
, dir
))
180 if (uc_code(lbuf_chr(lb
, *row
, c
)) == uc_code(cs
))
184 if (!n
&& (cmd
== 't' || cmd
== 'T'))
185 lbuf_lnnext(lb
, row
, col
, -dir
);
189 static int lbuf_search(struct lbuf
*lb
, char *kw
, int dir
, int *r
, int *c
, int *len
)
193 int row
= *r
, col
= *c
;
195 struct rset
*re
= rset_make(1, &kw
, xic
? RE_ICASE
: 0);
198 for (i
= row
; !found
&& i
>= 0 && i
< lbuf_len(lb
); i
+= dir
) {
199 char *s
= lbuf_get(lb
, i
);
200 int off
= dir
> 0 && row
== i
? uc_chr(s
, col
+ 1) - s
: 0;
201 int flg
= off
? RE_NOTBOL
: 0;
202 while (rset_find(re
, s
+ off
, 1, offs
, flg
) >= 0) {
203 if (dir
< 0 && row
== i
&& off
+ offs
[0] >= col
)
206 *c
= uc_off(s
, off
+ offs
[0]);
208 *len
= offs
[1] - offs
[0];
218 static int vi_search(int cmd
, int cnt
, int *row
, int *col
)
226 if (cmd
== '/' || cmd
== '?') {
227 char sign
[4] = {cmd
};
228 char *kw
= vi_prompt(sign
);
231 vi_finddir
= cmd
== '/' ? +1 : -1;
233 snprintf(vi_findlast
, sizeof(vi_findlast
), "%s", kw
);
234 if (strchr(vi_findlast
, cmd
)) {
235 off
= strchr(vi_findlast
, cmd
) + 1;
236 *strchr(vi_findlast
, cmd
) = '\0';
240 dir
= cmd
== 'N' ? -vi_finddir
: vi_finddir
;
241 if (!vi_findlast
[0] || !lbuf_len(xb
))
243 c
= ren_off(lbuf_get(xb
, *row
), *col
);
244 for (i
= 0; i
< cnt
; i
++) {
245 if (lbuf_search(xb
, vi_findlast
, dir
, &r
, &c
, &len
)) {
249 if (i
+ 1 < cnt
&& cmd
== '/')
254 *col
= ren_pos(lbuf_get(xb
, r
), c
);
255 while (off
[0] && isspace((unsigned char) off
[0]))
259 if (*row
+ atoi(off
) < 0 || *row
+ atoi(off
) >= lbuf_len(xb
))
266 snprintf(vi_msg
, sizeof(vi_msg
), "\"%s\" not found\n", vi_findlast
);
270 /* move to the last character of the word */
271 static int lbuf_wordlast(struct lbuf
*lb
, int *row
, int *col
, int kind
, int dir
)
273 if (!kind
|| !(uc_kind(lbuf_chr(lb
, *row
, *col
)) & kind
))
275 while (uc_kind(lbuf_chr(lb
, *row
, *col
)) & kind
)
276 if (lbuf_next(lb
, row
, col
, dir
))
278 if (!(uc_kind(lbuf_chr(lb
, *row
, *col
)) & kind
))
279 lbuf_next(lb
, row
, col
, -dir
);
283 static int lbuf_wordbeg(struct lbuf
*lb
, int *row
, int *col
, int big
, int dir
)
286 lbuf_wordlast(lb
, row
, col
, big
? 3 : uc_kind(lbuf_chr(lb
, *row
, *col
)), dir
);
287 if (lbuf_next(lb
, row
, col
, dir
))
289 while (uc_isspace(lbuf_chr(lb
, *row
, *col
))) {
290 nl
= uc_code(lbuf_chr(lb
, *row
, *col
)) == '\n' ? nl
+ 1 : 0;
293 if (lbuf_next(lb
, row
, col
, dir
))
299 static int lbuf_wordend(struct lbuf
*lb
, int *row
, int *col
, int big
, int dir
)
301 int nl
= uc_code(lbuf_chr(lb
, *row
, *col
)) == '\n' ? -1 : 0;
302 if (!uc_isspace(lbuf_chr(lb
, *row
, *col
)))
303 if (lbuf_next(lb
, row
, col
, dir
))
305 while (uc_isspace(lbuf_chr(lb
, *row
, *col
))) {
306 nl
= uc_code(lbuf_chr(lb
, *row
, *col
)) == '\n' ? nl
+ 1 : 0;
309 lbuf_next(lb
, row
, col
, -dir
);
312 if (lbuf_next(lb
, row
, col
, dir
))
315 if (lbuf_wordlast(lb
, row
, col
, big
? 3 : uc_kind(lbuf_chr(lb
, *row
, *col
)), dir
))
320 static int lbuf_paragraphbeg(struct lbuf
*lb
, int *row
, int *col
, int dir
)
322 while (*row
>= 0 && *row
< lbuf_len(lb
) && !strcmp("\n", lbuf_get(lb
, *row
)))
324 while (*row
>= 0 && *row
< lbuf_len(lb
) && strcmp("\n", lbuf_get(lb
, *row
)))
326 *row
= MAX(0, MIN(*row
, lbuf_len(lb
) - 1));
327 lbuf_eol(lb
, row
, col
, -1);
331 static int lbuf_sectionbeg(struct lbuf
*lb
, int *row
, int *col
, int dir
)
334 while (*row
>= 0 && *row
< lbuf_len(lb
) && lbuf_get(lb
, *row
)[0] != '{')
336 *row
= MAX(0, MIN(*row
, lbuf_len(lb
) - 1));
337 lbuf_eol(lb
, row
, col
, -1);
341 /* read a line motion */
342 static int vi_motionln(int *row
, int cmd
)
344 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
350 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
353 *row
= MAX(*row
- cnt
, 0);
356 *row
= MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1);
359 if ((mark
= vi_read()) > 0 && (isalpha(mark
) || mark
== '\''))
360 if (lbuf_markpos(xb
, mark
) >= 0)
361 *row
= lbuf_markpos(xb
, mark
);
364 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
367 *row
= MAX(*row
- cnt
, 0);
370 *row
= (vi_arg1
|| vi_arg2
) ? cnt
- 1 : lbuf_len(xb
) - 1;
374 *row
= MIN(xtop
+ cnt
- 1, lbuf_len(xb
) - 1);
380 *row
= MIN(xtop
+ xrows
- 1 - cnt
+ 1, lbuf_len(xb
) - 1);
386 *row
= MIN(xtop
+ xrows
/ 2, lbuf_len(xb
) - 1);
392 *row
= MAX(0, MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1));
402 static int vi_motion(int *row
, int *col
)
404 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
405 char *ln
= lbuf_get(xb
, *row
);
406 int dir
= dir_context(ln
? ln
: "");
410 if ((mv
= vi_motionln(row
, 0))) {
417 for (i
= 0; i
< cnt
; i
++)
418 if (lbuf_lnnext(xb
, row
, col
, 1))
422 if (!(cs
= vi_char()))
424 if (lbuf_findchar(xb
, row
, col
, cs
, mv
, cnt
))
428 if (!(cs
= vi_char()))
430 if (lbuf_findchar(xb
, row
, col
, cs
, mv
, cnt
))
436 if (lbuf_findchar(xb
, row
, col
, vi_charlast
, vi_charcmd
, cnt
))
442 if (lbuf_findchar(xb
, row
, col
, vi_charlast
, vi_charcmd
, -cnt
))
446 for (i
= 0; i
< cnt
; i
++)
447 if (lbuf_lnnext(xb
, row
, col
, -1 * dir
))
451 for (i
= 0; i
< cnt
; i
++)
452 if (lbuf_lnnext(xb
, row
, col
, +1 * dir
))
456 if (!(cs
= vi_char()))
458 if (lbuf_findchar(xb
, row
, col
, cs
, mv
, cnt
))
462 if (!(cs
= vi_char()))
464 if (lbuf_findchar(xb
, row
, col
, cs
, mv
, cnt
))
468 for (i
= 0; i
< cnt
; i
++)
469 if (lbuf_wordend(xb
, row
, col
, 1, -1))
473 for (i
= 0; i
< cnt
; i
++)
474 if (lbuf_wordend(xb
, row
, col
, 1, +1))
478 for (i
= 0; i
< cnt
; i
++)
479 if (lbuf_wordbeg(xb
, row
, col
, 1, +1))
483 for (i
= 0; i
< cnt
; i
++)
484 if (lbuf_wordend(xb
, row
, col
, 0, -1))
488 for (i
= 0; i
< cnt
; i
++)
489 if (lbuf_wordend(xb
, row
, col
, 0, +1))
493 for (i
= 0; i
< cnt
; i
++)
494 if (lbuf_wordbeg(xb
, row
, col
, 0, +1))
498 for (i
= 0; i
< cnt
; i
++)
499 if (lbuf_paragraphbeg(xb
, row
, col
, -1))
503 for (i
= 0; i
< cnt
; i
++)
504 if (lbuf_paragraphbeg(xb
, row
, col
, +1))
508 if (vi_read() != '[')
510 for (i
= 0; i
< cnt
; i
++)
511 if (lbuf_sectionbeg(xb
, row
, col
, -1))
515 if (vi_read() != ']')
517 for (i
= 0; i
< cnt
; i
++)
518 if (lbuf_sectionbeg(xb
, row
, col
, +1))
522 lbuf_eol(xb
, row
, col
, -1);
525 lbuf_postindents(xb
, row
, col
);
534 if (vi_search(mv
, cnt
, row
, col
))
538 if (vi_search(mv
, cnt
, row
, col
))
542 if (vi_search(mv
, cnt
, row
, col
))
546 if (vi_search(mv
, cnt
, row
, col
))
551 for (i
= 0; i
< cnt
; i
++)
552 if (lbuf_lnnext(xb
, row
, col
, -1))
562 static void swap(int *a
, int *b
)
569 static char *lbuf_region(struct lbuf
*lb
, int r1
, int l1
, int r2
, int l2
)
574 return uc_sub(lbuf_get(lb
, r1
), l1
, l2
);
576 s1
= uc_sub(lbuf_get(lb
, r1
), l1
, -1);
577 s3
= uc_sub(lbuf_get(lb
, r2
), 0, l2
);
578 s2
= lbuf_cp(lb
, r1
+ 1, r2
);
585 return sbuf_done(sb
);
588 /* insertion offset before or after the given visual position */
589 static int vi_insertionoffset(char *s
, int c1
, int before
)
595 return before
|| s
[l
] == '\n' ? l
: l
+ 1;
598 static void vi_commandregion(int *r1
, int *r2
, int *c1
, int *c2
, int *l1
, int *l2
, int closed
)
600 if (*r2
< *r1
|| (*r2
== *r1
&& *c2
< *c1
)) {
604 *l1
= vi_insertionoffset(lbuf_get(xb
, *r1
), *c1
, 1);
605 *l2
= vi_insertionoffset(lbuf_get(xb
, *r2
), *c2
, !closed
);
606 if (*r1
== *r2
&& lbuf_get(xb
, *r1
))
607 ren_region(lbuf_get(xb
, *r1
), *c1
, *c2
, l1
, l2
, closed
);
608 if (*r1
== *r2
&& *l2
< *l1
)
612 static void vi_yank(int r1
, int c1
, int r2
, int c2
, int lnmode
, int closed
)
616 vi_commandregion(&r1
, &r2
, &c1
, &c2
, &l1
, &l2
, closed
);
617 region
= lbuf_region(xb
, r1
, lnmode
? 0 : l1
, r2
, lnmode
? -1 : l2
);
618 reg_put(vi_ybuf
, region
, lnmode
);
621 xcol
= lnmode
? xcol
: c1
;
624 static void vi_delete(int r1
, int c1
, int r2
, int c2
, int lnmode
, int closed
)
629 vi_commandregion(&r1
, &r2
, &c1
, &c2
, &l1
, &l2
, closed
);
630 region
= lbuf_region(xb
, r1
, lnmode
? 0 : l1
, r2
, lnmode
? -1 : l2
);
631 reg_put(vi_ybuf
, region
, lnmode
);
633 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, l1
);
634 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), l2
, -1);
635 lbuf_rm(xb
, r1
, r2
+ 1);
637 struct sbuf
*sb
= sbuf_make();
640 lbuf_put(xb
, r1
, sbuf_buf(sb
));
646 lbuf_postindents(xb
, &xrow
, &xcol
);
651 static int lastline(char *str
)
657 s
= strchr(s
+ 1, '\n');
662 static int linecount(char *s
)
666 if ((s
= strchr(s
, '\n')))
671 static int indentscopy(char *d
, char *s
, int len
)
674 for (i
= 0; i
< len
- 1 && (s
[i
] == ' ' || s
[i
] == '\t'); i
++)
680 static char *vi_input(char *pref
, char *post
, int *row
, int *col
)
687 pref
+= indentscopy(ai
, pref
, sizeof(ai
));
688 rep
= led_input(pref
, post
, ai
, xai
? sizeof(ai
) - 1 : 0);
695 last
= lastline(sbuf_buf(sb
));
696 off
= uc_slen(sbuf_buf(sb
) + last
);
698 while (xai
&& (post
[0] == ' ' || post
[0] == '\t'))
701 *row
= linecount(sbuf_buf(sb
)) - 1;
702 *col
= ren_pos(sbuf_buf(sb
) + last
, MAX(0, off
- 1));
704 return sbuf_done(sb
);
707 static char *vi_indents(char *ln
)
709 struct sbuf
*sb
= sbuf_make();
710 while (xai
&& ln
&& (*ln
== ' ' || *ln
== '\t'))
712 return sbuf_done(sb
);
715 static void vi_change(int r1
, int c1
, int r2
, int c2
, int lnmode
, int closed
)
722 vi_commandregion(&r1
, &r2
, &c1
, &c2
, &l1
, &l2
, closed
);
723 region
= lbuf_region(xb
, r1
, lnmode
? 0 : l1
, r2
, lnmode
? -1 : l2
);
724 reg_put(vi_ybuf
, region
, lnmode
);
726 pref
= lnmode
? vi_indents(lbuf_get(xb
, r1
)) : uc_sub(lbuf_get(xb
, r1
), 0, l1
);
727 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), l2
, -1);
728 rep
= vi_input(pref
, post
, &row
, &col
);
730 lbuf_rm(xb
, r1
, r2
+ 1);
731 lbuf_put(xb
, r1
, rep
);
740 static void vi_pipe(int r1
, int r2
)
744 char *cmd
= vi_prompt("!");
749 text
= lbuf_cp(xb
, r1
, r2
+ 1);
750 rep
= cmd_pipe(cmd
, text
);
752 lbuf_rm(xb
, r1
, r2
+ 1);
753 lbuf_put(xb
, r1
, rep
);
760 static void vi_shift(int r1
, int r2
, int dir
)
767 for (i
= r1
; i
<= r2
; i
++) {
768 if (!(ln
= lbuf_get(xb
, i
)))
774 ln
= ln
[0] == ' ' || ln
[0] == '\t' ? ln
+ 1 : ln
;
776 lbuf_rm(xb
, i
, i
+ 1);
777 lbuf_put(xb
, i
, sbuf_buf(sb
));
781 lbuf_postindents(xb
, &xrow
, &xcol
);
784 static int vc_motion(int cmd
)
786 int r1
= xrow
, r2
= xrow
; /* region rows */
787 int c1
= xcol
, c2
= xcol
; /* visual region columns */
788 int lnmode
= 0; /* line-based region */
789 int closed
= 1; /* include the last character */
791 vi_arg2
= vi_prefix();
794 c1
= ren_noeol(lbuf_get(xb
, r1
), xcol
);
796 if ((mv
= vi_motionln(&r2
, cmd
))) {
798 } else if (!(mv
= vi_motion(&r2
, &c2
))) {
804 if (!strchr("fFtTeE", mv
))
808 lbuf_eol(xb
, &r1
, &c1
, -1);
809 lbuf_eol(xb
, &r2
, &c2
, +1);
812 vi_yank(r1
, c1
, r2
, c2
, lnmode
, closed
);
814 vi_delete(r1
, c1
, r2
, c2
, lnmode
, closed
);
816 vi_change(r1
, c1
, r2
, c2
, lnmode
, closed
);
819 if (cmd
== '>' || cmd
== '<')
820 vi_shift(r1
, r2
, cmd
== '>' ? +1 : -1);
824 static int vc_insert(int cmd
)
827 char *ln
= lbuf_get(xb
, xrow
);
828 int row
, col
, off
= 0;
831 lbuf_postindents(xb
, &xrow
, &xcol
);
833 lbuf_eol(xb
, &xrow
, &xcol
, +1);
834 lbuf_lnnext(xb
, &xrow
, &xcol
, -1);
836 xcol
= ren_noeol(ln
, xcol
);
839 if (cmd
== 'i' || cmd
== 'I')
840 off
= vi_insertionoffset(ln
, xcol
, 1);
841 if (cmd
== 'a' || cmd
== 'A')
842 off
= vi_insertionoffset(ln
, xcol
, 0);
843 pref
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, 0, off
) : vi_indents(ln
);
844 post
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, off
, -1) : uc_dup("\n");
845 rep
= vi_input(pref
, post
, &row
, &col
);
846 if ((cmd
== 'o' || cmd
== 'O') && !lbuf_len(xb
))
847 lbuf_put(xb
, 0, "\n");
849 if (cmd
!= 'o' && cmd
!= 'O')
850 lbuf_rm(xb
, xrow
, xrow
+ 1);
851 lbuf_put(xb
, xrow
, rep
);
861 static int vc_put(int cmd
)
863 int cnt
= MAX(1, vi_arg1
);
866 char *buf
= reg_get(vi_ybuf
, &lnmode
);
872 ln
= lnmode
? NULL
: lbuf_get(xb
, xrow
);
873 off
= vi_insertionoffset(ln
, xcol
, cmd
== 'P');
874 if (cmd
== 'p' && !ln
)
878 char *s
= uc_sub(ln
, 0, off
);
882 for (i
= 0; i
< cnt
; i
++)
885 char *s
= uc_sub(ln
, off
, -1);
889 if (!ln
&& !lbuf_len(xb
))
890 lbuf_put(xb
, 0, "\n");
892 lbuf_rm(xb
, xrow
, xrow
+ 1);
893 lbuf_put(xb
, xrow
, sbuf_buf(sb
));
895 xcol
= ren_pos(lbuf_get(xb
, xrow
), off
+ uc_slen(buf
) * cnt
- 1);
897 lbuf_postindents(xb
, &xrow
, &xcol
);
902 static int join_spaces(char *prev
, char *next
)
904 int prevlen
= strlen(prev
);
907 if (prev
[prevlen
- 1] == ' ' || next
[0] == ')')
909 return prev
[prevlen
- 1] == '.' ? 2 : 1;
912 static int vc_join(void)
915 int cnt
= vi_arg1
<= 1 ? 2 : vi_arg1
;
917 int end
= xrow
+ cnt
;
920 if (!lbuf_get(xb
, beg
) || !lbuf_get(xb
, end
- 1))
923 for (i
= beg
; i
< end
; i
++) {
924 char *ln
= lbuf_get(xb
, i
);
925 char *lnend
= strchr(ln
, '\n');
928 while (ln
[0] == ' ' || ln
[0] == '\t')
930 spaces
= i
> beg
? join_spaces(sbuf_buf(sb
), ln
) : 0;
931 off
= uc_slen(sbuf_buf(sb
));
934 sbuf_mem(sb
, ln
, lnend
- ln
);
937 lbuf_rm(xb
, beg
, end
);
938 lbuf_put(xb
, beg
, sbuf_buf(sb
));
939 xcol
= ren_pos(sbuf_buf(sb
), off
);
944 static int vi_scrollforeward(int cnt
)
946 if (xtop
>= lbuf_len(xb
) - 1)
948 xtop
= MIN(lbuf_len(xb
) - 1, xtop
+ cnt
);
949 xrow
= MAX(xrow
, xtop
);
953 static int vi_scrollbackward(int cnt
)
957 xtop
= MAX(0, xtop
- cnt
);
958 xrow
= MIN(xrow
, xtop
+ xrows
- 1);
962 static void vc_status(void)
964 int pos
= ren_noeol(lbuf_get(xb
, xrow
), xcol
);
965 snprintf(vi_msg
, sizeof(vi_msg
), "\"%s\" line %d of %d, col %d\n",
966 xpath
[0] ? xpath
: "unnamed", xrow
+ 1, lbuf_len(xb
),
967 ren_cursor(lbuf_get(xb
, xrow
), pos
) + 1);
970 static int vc_replace(void)
972 int cnt
= MAX(1, vi_arg1
);
973 char *cs
= vi_char();
974 char *ln
= lbuf_get(xb
, xrow
);
981 off
= ren_off(ln
, xcol
);
983 for (i
= 0; s
[0] != '\n' && i
< cnt
; i
++)
987 pref
= uc_sub(ln
, 0, off
);
988 post
= uc_sub(ln
, off
+ cnt
, -1);
991 for (i
= 0; i
< cnt
; i
++)
994 lbuf_rm(xb
, xrow
, xrow
+ 1);
995 lbuf_put(xb
, xrow
, sbuf_buf(sb
));
997 xcol
= ren_pos(sbuf_buf(sb
), off
);
1004 static void vi(void)
1011 lbuf_eol(xb
, &xrow
, &xcol
, -1);
1013 term_pos(xrow
, led_pos(lbuf_get(xb
, xrow
), xcol
));
1017 int ncol
= ren_noeol(lbuf_get(xb
, xrow
), xcol
);
1021 vi_ybuf
= vi_yankbuf();
1022 vi_arg1
= vi_prefix();
1024 vi_ybuf
= vi_yankbuf();
1025 mv
= vi_motion(&nrow
, &ncol
);
1027 if (strchr("\'GHML/?{}[]", mv
))
1028 lbuf_mark(xb
, '\'', xrow
);
1031 if (!strchr("jk", mv
))
1032 lbuf_postindents(xb
, &xrow
, &xcol
);
1034 if (strchr("|$", mv
))
1037 xcol
= ren_noeol(lbuf_get(xb
, xrow
), ncol
);
1039 } else if (mv
== 0) {
1046 if (vi_scrollbackward(MAX(1, vi_arg1
) * (xrows
- 1)))
1048 lbuf_postindents(xb
, &xrow
, &xcol
);
1052 if (vi_scrollforeward(MAX(1, vi_arg1
) * (xrows
- 1)))
1054 lbuf_postindents(xb
, &xrow
, &xcol
);
1058 if (vi_scrollforeward(MAX(1, vi_arg1
)))
1063 if (vi_scrollbackward(MAX(1, vi_arg1
)))
1083 ln
= vi_prompt(":");
1115 if ((mark
= vi_read()) > 0 && isalpha(mark
))
1116 lbuf_mark(xb
, mark
, xrow
);
1127 xtop
= vi_arg1
? vi_arg1
: xrow
;
1130 n
= vi_arg1
? vi_arg1
: xrow
;
1131 xtop
= MAX(0, n
- xrows
/ 2);
1134 n
= vi_arg1
? vi_arg1
: xrow
;
1135 xtop
= MAX(0, n
- xrows
+ 1);
1139 xdir
= z
== 'r' ? -1 : +1;
1143 xdir
= z
== 'R' ? -2 : +2;
1150 if (!vc_motion('d'))
1154 vi_back(TK_CTL('h'));
1155 if (!vc_motion('d'))
1160 if (!vc_motion('c'))
1165 if (!vc_motion('d'))
1174 if (!vc_motion('c'))
1179 if (!vc_motion('c'))
1184 if (!vc_motion('y'))
1191 if (xrow
< 0 || xrow
>= lbuf_len(xb
))
1192 xrow
= lbuf_len(xb
) ? lbuf_len(xb
) - 1 : 0;
1194 xtop
= xtop
- xrows
/ 2 > xrow
?
1195 MAX(0, xrow
- xrows
/ 2) : xrow
;
1196 if (xtop
+ xrows
<= xrow
)
1197 xtop
= xtop
+ xrows
+ xrows
/ 2 <= xrow
?
1198 xrow
- xrows
/ 2 : xrow
- xrows
+ 1;
1199 if (redraw
|| xtop
!= otop
)
1203 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
),
1204 ren_cursor(lbuf_get(xb
, xrow
), xcol
)));
1212 int main(int argc
, char *argv
[])
1218 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
1219 if (argv
[i
][1] == 's')
1221 if (argv
[i
][1] == 'e')
1223 if (argv
[i
][1] == 'v')
1228 snprintf(ecmd
, PATHLEN
, "e %s", argv
[i
]);