4 * Copyright (C) 2015-2019 Ali Gholami Rudi <ali at rudi dot ir>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
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 OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 static char vi_msg
[EXLEN
]; /* current message */
26 static char vi_charlast
[8]; /* the last character searched via f, t, F, or T */
27 static int vi_charcmd
; /* the character finding command */
28 static int vi_arg1
, vi_arg2
; /* the first and second arguments */
29 static int vi_ybuf
; /* current yank buffer */
30 static int vi_pcol
; /* the column requested by | command */
31 static int vi_printed
; /* ex_print() calls since the last command */
32 static int vi_scroll
; /* scroll amount for ^f and ^d*/
33 static int vi_soset
, vi_so
; /* search offset; 1 in "/kw/1" */
35 static void vi_wait(void)
38 free(ex_read("[enter to continue]"));
44 static void vi_drawmsg(void)
48 led_printmsg(vi_msg
, xrows
, "---");
53 static void vi_drawrow(int row
)
55 char *s
= lbuf_get(xb
, row
);
56 if (xhll
&& row
== xrow
)
57 syn_context(conf_hlline());
58 led_print(s
? s
: (row
? "~" : ""), row
- xtop
, ex_filetype());
62 /* redraw the screen */
63 static void vi_drawagain(int xcol
, int lineonly
)
67 for (i
= xtop
; i
< xtop
+ xrows
; i
++)
68 if (!lineonly
|| i
== xrow
)
71 term_pos(xrow
, led_pos(lbuf_get(xb
, i
), xcol
));
75 /* update the screen */
76 static void vi_drawupdate(int xcol
, int otop
)
82 term_room(otop
- xtop
);
84 int n
= MIN(xtop
- otop
, xrows
);
85 for (i
= 0; i
< n
; i
++)
86 vi_drawrow(xtop
+ xrows
- n
+ i
);
88 int n
= MIN(otop
- xtop
, xrows
);
89 for (i
= 0; i
< n
; i
++)
92 term_pos(xrow
, led_pos(lbuf_get(xb
, i
), xcol
));
96 term_pos(xrow
, led_pos(lbuf_get(xb
, i
), xcol
));
99 /* update the screen by removing lines r1 to r2 before an input command */
100 static void vi_drawrm(int r1
, int r2
, int newln
)
102 r1
= MIN(MAX(r1
, xtop
), xtop
+ xrows
);
103 r2
= MIN(MAX(r2
, xtop
), xtop
+ xrows
);
104 term_pos(r1
- xtop
, 0);
105 term_room(r1
- r2
+ newln
);
108 static int vi_buf
[128];
109 static int vi_buflen
;
111 static int vi_read(void)
113 return vi_buflen
? vi_buf
[--vi_buflen
] : term_read();
116 static void vi_back(int c
)
118 if (vi_buflen
< sizeof(vi_buf
))
119 vi_buf
[vi_buflen
++] = c
;
122 static char *vi_char(void)
124 return led_read(&xkmap
);
127 static char *vi_prompt(char *msg
, int *kmap
)
130 term_pos(xrows
, led_pos(msg
, 0));
132 s
= led_prompt(msg
, "", kmap
, "---");
135 r
= uc_dup(strlen(s
) >= strlen(msg
) ? s
+ strlen(msg
) : s
);
140 /* read an ex input line */
141 char *ex_read(char *msg
)
147 char *s
= led_prompt(msg
, "", &xkmap
, "---");
154 while ((c
= getchar()) != EOF
&& c
!= '\n')
160 return sbuf_done(sb
);
163 /* show an ex message */
164 void ex_show(char *msg
)
167 snprintf(vi_msg
, sizeof(vi_msg
), "%s", msg
);
169 led_print(msg
, -1, "---");
176 /* print an ex output line */
177 void ex_print(char *line
)
180 vi_printed
+= line
? 1 : 2;
182 snprintf(vi_msg
, sizeof(vi_msg
), "%s", line
);
184 led_print(line
, -1, "");
192 static int vi_yankbuf(void)
201 static int vi_prefix(void)
205 if ((c
>= '1' && c
<= '9')) {
207 n
= n
* 10 + c
- '0';
215 static int vi_col2off(struct lbuf
*lb
, int row
, int col
)
217 char *ln
= lbuf_get(lb
, row
);
218 return ln
? ren_off(ln
, col
) : 0;
221 static int vi_off2col(struct lbuf
*lb
, int row
, int off
)
223 char *ln
= lbuf_get(lb
, row
);
224 return ln
? ren_pos(ln
, off
) : 0;
227 static int vi_nextoff(struct lbuf
*lb
, int dir
, int *row
, int *off
)
230 if (o
< 0 || !lbuf_get(lb
, *row
) || o
>= uc_slen(lbuf_get(lb
, *row
)))
236 static int vi_nextcol(struct lbuf
*lb
, int dir
, int *row
, int *off
)
238 char *ln
= lbuf_get(lb
, *row
);
239 int col
= ln
? ren_pos(ln
, *off
) : 0;
240 int o
= ln
? ren_next(ln
, col
, dir
) : -1;
243 *off
= ren_off(ln
, o
);
247 static int vi_findchar(struct lbuf
*lb
, char *cs
, int cmd
, int n
, int *row
, int *off
)
249 strcpy(vi_charlast
, cs
);
251 return lbuf_findchar(lb
, cs
, cmd
, n
, row
, off
);
254 static int vi_search(int cmd
, int cnt
, int *row
, int *off
)
262 if (cmd
== '/' || cmd
== '?') {
263 char sign
[4] = {cmd
};
265 char *kw
= vi_prompt(sign
, &xkmap
);
274 if ((re
= re_read(&kw
))) {
275 ex_kwdset(re
[0] ? re
: NULL
, cmd
== '/' ? +1 : -1);
284 if (!lbuf_len(xb
) || ex_kwd(&kwd
, &dir
))
286 dir
= cmd
== 'N' ? -dir
: dir
;
288 for (i
= 0; i
< cnt
; i
++) {
289 if (lbuf_search(xb
, kwd
, dir
, &r
, &o
, &len
)) {
293 if (i
+ 1 < cnt
&& cmd
== '/')
301 if (*row
+ vi_so
< 0 || *row
+ vi_so
>= lbuf_len(xb
))
308 snprintf(vi_msg
, sizeof(vi_msg
), "\"%s\" not found\n", kwd
);
312 /* read a line motion */
313 static int vi_motionln(int *row
, int cmd
)
315 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
317 int mark
, mark_row
, mark_off
;
321 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
324 *row
= MAX(*row
- cnt
, 0);
327 *row
= MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1);
330 if ((mark
= vi_read()) <= 0)
332 if (lbuf_jump(xb
, mark
, &mark_row
, &mark_off
))
337 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
340 *row
= MAX(*row
- cnt
, 0);
343 *row
= (vi_arg1
|| vi_arg2
) ? cnt
- 1 : lbuf_len(xb
) - 1;
346 *row
= MIN(xtop
+ cnt
- 1, lbuf_len(xb
) - 1);
349 *row
= MIN(xtop
+ xrows
- 1 - cnt
+ 1, lbuf_len(xb
) - 1);
352 *row
= MIN(xtop
+ xrows
/ 2, lbuf_len(xb
) - 1);
356 *row
= MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1);
359 if (c
== '%' && (vi_arg1
|| vi_arg2
)) {
362 *row
= MAX(0, lbuf_len(xb
) - 1) * cnt
/ 100;
373 static char *vi_curword(struct lbuf
*lb
, int row
, int off
)
376 char *ln
= lbuf_get(lb
, row
);
380 beg
= uc_chr(ln
, ren_noeol(ln
, off
));
382 while (*end
&& uc_kind(end
) == 1)
384 while (beg
> ln
&& uc_kind(uc_beg(ln
, beg
- 1)) == 1)
385 beg
= uc_beg(ln
, beg
- 1);
390 sbuf_mem(sb
, beg
, end
- beg
);
392 return sbuf_done(sb
);
396 static int vi_motion(int *row
, int *off
)
398 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
399 char *ln
= lbuf_get(xb
, *row
);
400 int dir
= dir_context(ln
? ln
: "");
401 int mark
, mark_row
, mark_off
;
405 if ((mv
= vi_motionln(row
, 0))) {
412 if (!(cs
= vi_char()))
414 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
418 if (!(cs
= vi_char()))
420 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
426 if (vi_findchar(xb
, vi_charlast
, vi_charcmd
, cnt
, row
, off
))
432 if (vi_findchar(xb
, vi_charlast
, vi_charcmd
, -cnt
, row
, off
))
436 for (i
= 0; i
< cnt
; i
++)
437 if (vi_nextcol(xb
, -1 * dir
, row
, off
))
441 for (i
= 0; i
< cnt
; i
++)
442 if (vi_nextcol(xb
, +1 * dir
, row
, off
))
446 if (!(cs
= vi_char()))
448 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
452 if (!(cs
= vi_char()))
454 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
458 for (i
= 0; i
< cnt
; i
++)
459 if (lbuf_wordend(xb
, 1, -1, row
, off
))
463 for (i
= 0; i
< cnt
; i
++)
464 if (lbuf_wordend(xb
, 1, +1, row
, off
))
468 for (i
= 0; i
< cnt
; i
++)
469 if (lbuf_wordbeg(xb
, 1, +1, row
, off
))
473 for (i
= 0; i
< cnt
; i
++)
474 if (lbuf_wordend(xb
, 0, -1, row
, off
))
478 for (i
= 0; i
< cnt
; i
++)
479 if (lbuf_wordend(xb
, 0, +1, row
, off
))
483 for (i
= 0; i
< cnt
; i
++)
484 if (lbuf_wordbeg(xb
, 0, +1, row
, off
))
488 for (i
= 0; i
< cnt
; i
++)
489 if (lbuf_paragraphbeg(xb
, -1, row
, off
))
493 for (i
= 0; i
< cnt
; i
++)
494 if (lbuf_paragraphbeg(xb
, +1, row
, off
))
498 if (vi_read() != '[')
500 for (i
= 0; i
< cnt
; i
++)
501 if (lbuf_sectionbeg(xb
, -1, row
, off
))
505 if (vi_read() != ']')
507 for (i
= 0; i
< cnt
; i
++)
508 if (lbuf_sectionbeg(xb
, +1, row
, off
))
515 *off
= lbuf_indents(xb
, *row
);
518 *off
= lbuf_eol(xb
, *row
);
521 *off
= vi_col2off(xb
, *row
, cnt
- 1);
525 if (vi_search(mv
, cnt
, row
, off
))
529 if (vi_search(mv
, cnt
, row
, off
))
533 if (vi_search(mv
, cnt
, row
, off
))
537 if (vi_search(mv
, cnt
, row
, off
))
541 if (!(cs
= vi_curword(xb
, *row
, *off
)))
545 if (vi_search('n', cnt
, row
, off
))
549 for (i
= 0; i
< cnt
; i
++)
550 if (vi_nextoff(xb
, +1, row
, off
))
555 for (i
= 0; i
< cnt
; i
++)
556 if (vi_nextoff(xb
, -1, row
, off
))
560 if ((mark
= vi_read()) <= 0)
562 if (lbuf_jump(xb
, mark
, &mark_row
, &mark_off
))
568 if (lbuf_pair(xb
, row
, off
))
578 static void swap(int *a
, int *b
)
585 static char *lbuf_region(struct lbuf
*lb
, int r1
, int o1
, int r2
, int o2
)
590 return uc_sub(lbuf_get(lb
, r1
), o1
, o2
);
592 s1
= uc_sub(lbuf_get(lb
, r1
), o1
, -1);
593 s3
= uc_sub(lbuf_get(lb
, r2
), 0, o2
);
594 s2
= lbuf_cp(lb
, r1
+ 1, r2
);
601 return sbuf_done(sb
);
604 static void vi_yank(int r1
, int o1
, int r2
, int o2
, int lnmode
)
607 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
608 reg_put(vi_ybuf
, region
, lnmode
);
611 xoff
= lnmode
? xoff
: o1
;
614 static void vi_delete(int r1
, int o1
, int r2
, int o2
, int lnmode
)
618 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
619 reg_put(vi_ybuf
, region
, lnmode
);
621 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
622 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
624 struct sbuf
*sb
= sbuf_make();
627 lbuf_edit(xb
, sbuf_buf(sb
), r1
, r2
+ 1);
630 lbuf_edit(xb
, NULL
, r1
, r2
+ 1);
633 xoff
= lnmode
? lbuf_indents(xb
, xrow
) : o1
;
638 static int linecount(char *s
)
642 if ((s
= strchr(s
, '\n')))
647 static int charcount(char *text
, char *post
)
649 int tlen
= strlen(text
);
650 int plen
= strlen(post
);
655 for (i
= 0; i
< tlen
- plen
; i
++)
658 return uc_slen(nl
) - uc_slen(post
);
661 static char *vi_input(char *pref
, char *post
, int *row
, int *off
)
663 char *rep
= led_input(pref
, post
, &xkmap
, ex_filetype());
666 *row
= linecount(rep
) - 1;
667 *off
= charcount(rep
, post
) - 1;
673 static char *vi_indents(char *ln
)
675 struct sbuf
*sb
= sbuf_make();
676 while (xai
&& ln
&& (*ln
== ' ' || *ln
== '\t'))
678 return sbuf_done(sb
);
681 static void vi_change(int r1
, int o1
, int r2
, int o2
, int lnmode
)
687 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
688 reg_put(vi_ybuf
, region
, lnmode
);
690 pref
= lnmode
? vi_indents(lbuf_get(xb
, r1
)) : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
691 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
692 vi_drawrm(r1
, r2
, 0);
693 rep
= vi_input(pref
, post
, &row
, &off
);
695 lbuf_edit(xb
, rep
, r1
, r2
+ 1);
704 static void vi_case(int r1
, int o1
, int r2
, int o2
, int lnmode
, int cmd
)
708 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
711 int c
= (unsigned char) s
[0];
718 s
[0] = islower(c
) ? toupper(c
) : tolower(c
);
722 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
723 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
725 struct sbuf
*sb
= sbuf_make();
727 sbuf_str(sb
, region
);
729 lbuf_edit(xb
, sbuf_buf(sb
), r1
, r2
+ 1);
732 lbuf_edit(xb
, region
, r1
, r2
+ 1);
735 xoff
= lnmode
? lbuf_indents(xb
, r2
) : o2
;
741 static void vi_pipe(int r1
, int r2
)
746 char *cmd
= vi_prompt("!", &kmap
);
749 text
= lbuf_cp(xb
, r1
, r2
+ 1);
750 rep
= cmd_pipe(cmd
, text
, 1, 1);
752 lbuf_edit(xb
, rep
, r1
, r2
+ 1);
758 static void vi_shift(int r1
, int r2
, int dir
)
763 for (i
= r1
; i
<= r2
; i
++) {
764 if (!(ln
= lbuf_get(xb
, i
)))
770 ln
= ln
[0] == ' ' || ln
[0] == '\t' ? ln
+ 1 : ln
;
772 lbuf_edit(xb
, sbuf_buf(sb
), i
, i
+ 1);
776 xoff
= lbuf_indents(xb
, xrow
);
779 static int vc_motion(int cmd
)
781 int r1
= xrow
, r2
= xrow
; /* region rows */
782 int o1
= xoff
, o2
= xoff
; /* visual region columns */
783 int lnmode
= 0; /* line-based region */
785 vi_arg2
= vi_prefix();
788 o1
= ren_noeol(lbuf_get(xb
, r1
), o1
);
790 if ((mv
= vi_motionln(&r2
, cmd
))) {
792 } else if (!(mv
= vi_motion(&r2
, &o2
))) {
801 o2
= lbuf_eol(xb
, r2
);
807 if (r1
== r2
&& o1
> o2
)
809 o1
= ren_noeol(lbuf_get(xb
, r1
), o1
);
810 if (!lnmode
&& strchr("fFtTeE%", mv
))
811 if (o2
< lbuf_eol(xb
, r2
))
812 o2
= ren_noeol(lbuf_get(xb
, r2
), o2
) + 1;
814 vi_yank(r1
, o1
, r2
, o2
, lnmode
);
816 vi_delete(r1
, o1
, r2
, o2
, lnmode
);
818 vi_change(r1
, o1
, r2
, o2
, lnmode
);
819 if (cmd
== '~' || cmd
== 'u' || cmd
== 'U')
820 vi_case(r1
, o1
, r2
, o2
, lnmode
, cmd
);
823 if (cmd
== '>' || cmd
== '<')
824 vi_shift(r1
, r2
, cmd
== '>' ? +1 : -1);
828 static int vc_insert(int cmd
)
831 char *ln
= lbuf_get(xb
, xrow
);
835 xoff
= lbuf_indents(xb
, xrow
);
837 xoff
= lbuf_eol(xb
, xrow
);
838 xoff
= ren_noeol(ln
, xoff
);
841 if (cmd
== 'i' || cmd
== 'I')
843 if (cmd
== 'a' || cmd
== 'A')
845 if (ln
&& ln
[0] == '\n')
847 pref
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, 0, off
) : vi_indents(ln
);
848 post
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, off
, -1) : uc_dup("\n");
849 vi_drawrm(xrow
, xrow
, cmd
== 'o' || cmd
== 'O');
850 rep
= vi_input(pref
, post
, &row
, &off
);
851 if ((cmd
== 'o' || cmd
== 'O') && !lbuf_len(xb
))
852 lbuf_edit(xb
, "\n", 0, 0);
854 lbuf_edit(xb
, rep
, xrow
, xrow
+ (cmd
!= 'o' && cmd
!= 'O'));
864 static int vc_put(int cmd
)
866 int cnt
= MAX(1, vi_arg1
);
868 char *buf
= reg_get(vi_ybuf
, &lnmode
);
871 snprintf(vi_msg
, sizeof(vi_msg
), "yank buffer empty\n");
875 struct sbuf
*sb
= sbuf_make();
876 for (i
= 0; i
< cnt
; i
++)
879 lbuf_edit(xb
, "\n", 0, 0);
882 lbuf_edit(xb
, sbuf_buf(sb
), xrow
, xrow
);
883 xoff
= lbuf_indents(xb
, xrow
);
886 struct sbuf
*sb
= sbuf_make();
887 char *ln
= xrow
< lbuf_len(xb
) ? lbuf_get(xb
, xrow
) : "\n";
888 int off
= ren_noeol(ln
, xoff
) + (ln
[0] != '\n' && cmd
== 'p');
889 char *s
= uc_sub(ln
, 0, off
);
892 for (i
= 0; i
< cnt
; i
++)
894 s
= uc_sub(ln
, off
, -1);
897 lbuf_edit(xb
, sbuf_buf(sb
), xrow
, xrow
+ 1);
898 xoff
= off
+ uc_slen(buf
) * cnt
- 1;
904 static int join_spaces(char *prev
, char *next
)
906 int prevlen
= strlen(prev
);
909 if (prev
[prevlen
- 1] == ' ' || next
[0] == ')')
911 return prev
[prevlen
- 1] == '.' ? 2 : 1;
914 static int vc_join(void)
917 int cnt
= vi_arg1
<= 1 ? 2 : vi_arg1
;
919 int end
= xrow
+ cnt
;
922 if (!lbuf_get(xb
, beg
) || !lbuf_get(xb
, end
- 1))
925 for (i
= beg
; i
< end
; i
++) {
926 char *ln
= lbuf_get(xb
, i
);
927 char *lnend
= strchr(ln
, '\n');
930 while (ln
[0] == ' ' || ln
[0] == '\t')
932 spaces
= i
> beg
? join_spaces(sbuf_buf(sb
), ln
) : 0;
933 off
= uc_slen(sbuf_buf(sb
));
936 sbuf_mem(sb
, ln
, lnend
- ln
);
939 lbuf_edit(xb
, sbuf_buf(sb
), beg
, end
);
945 static int vi_scrollforeward(int cnt
)
947 if (xtop
>= lbuf_len(xb
) - 1)
949 xtop
= MIN(lbuf_len(xb
) - 1, xtop
+ cnt
);
950 xrow
= MAX(xrow
, xtop
);
954 static int vi_scrollbackward(int cnt
)
958 xtop
= MAX(0, xtop
- cnt
);
959 xrow
= MIN(xrow
, xtop
+ xrows
- 1);
963 static void vc_status(void)
965 int col
= vi_off2col(xb
, xrow
, xoff
);
966 snprintf(vi_msg
, sizeof(vi_msg
),
967 "\"%s\"%c %d lines L%d C%d\n",
968 ex_path()[0] ? ex_path() : "unnamed",
969 lbuf_modified(xb
) ? '*' : ' ',
970 lbuf_len(xb
), xrow
+ 1,
971 ren_cursor(lbuf_get(xb
, xrow
), col
) + 1);
974 static void vc_charinfo(void)
976 char *c
= uc_chr(lbuf_get(xb
, xrow
), xoff
);
979 memcpy(cbuf
, c
, uc_len(c
));
980 snprintf(vi_msg
, sizeof(vi_msg
), "<%s> %04x\n", cbuf
, uc_code(c
));
984 static int vc_replace(void)
986 int cnt
= MAX(1, vi_arg1
);
987 char *cs
= vi_char();
988 char *ln
= lbuf_get(xb
, xrow
);
995 off
= ren_noeol(ln
, xoff
);
997 for (i
= 0; s
[0] != '\n' && i
< cnt
; i
++)
1001 pref
= uc_sub(ln
, 0, off
);
1002 post
= uc_sub(ln
, off
+ cnt
, -1);
1005 for (i
= 0; i
< cnt
; i
++)
1008 lbuf_edit(xb
, sbuf_buf(sb
), xrow
, xrow
+ 1);
1017 static char rep_cmd
[4096]; /* the last command */
1020 static void vc_repeat(void)
1023 for (i
= 0; i
< MAX(1, vi_arg1
); i
++)
1024 term_push(rep_cmd
, rep_len
);
1027 static void vc_execute(void)
1029 static int exec_buf
;
1039 buf
= reg_get(exec_buf
, &lnmode
);
1041 for (i
= 0; i
< MAX(1, vi_arg1
); i
++)
1042 term_push(buf
, strlen(buf
));
1045 static void vi(void)
1051 xtop
= MAX(0, xrow
- xrows
/ 2);
1053 xcol
= vi_off2col(xb
, xrow
, xoff
);
1054 vi_drawagain(xcol
, 0);
1055 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
), xcol
));
1057 int mod
= 0; /* screen should be redrawn (1: the whole screen, 2: the current line) */
1059 int noff
= ren_noeol(lbuf_get(xb
, xrow
), xoff
);
1066 vi_ybuf
= vi_yankbuf();
1067 vi_arg1
= vi_prefix();
1069 vi_ybuf
= vi_yankbuf();
1070 mv
= vi_motion(&nrow
, &noff
);
1072 if (strchr("\'`GHML/?{}[]nN", mv
) ||
1073 (mv
== '%' && noff
< 0)) {
1074 lbuf_mark(xb
, '\'', xrow
, xoff
);
1075 lbuf_mark(xb
, '`', xrow
, xoff
);
1078 if (noff
< 0 && !strchr("jk", mv
))
1079 noff
= lbuf_indents(xb
, xrow
);
1080 if (strchr("jk", mv
))
1081 noff
= vi_col2off(xb
, xrow
, xcol
);
1082 xoff
= ren_noeol(lbuf_get(xb
, xrow
), noff
);
1083 if (!strchr("|jk", mv
))
1084 xcol
= vi_off2col(xb
, xrow
, xoff
);
1087 } else if (mv
== 0) {
1093 lbuf_mark(xb
, '*', xrow
, xoff
);
1096 if (vi_scrollbackward(MAX(1, vi_arg1
) * (xrows
- 1)))
1098 xoff
= lbuf_indents(xb
, xrow
);
1102 if (vi_scrollforeward(MAX(1, vi_arg1
) * (xrows
- 1)))
1104 xoff
= lbuf_indents(xb
, xrow
);
1108 if (vi_scrollforeward(MAX(1, vi_arg1
)))
1112 if (vi_scrollbackward(MAX(1, vi_arg1
)))
1119 vi_scroll
= vi_arg1
;
1120 n
= vi_scroll
? vi_scroll
: xrows
/ 2;
1121 xrow
= MAX(0, xrow
- n
);
1123 xtop
= MAX(0, xtop
- n
);
1124 xoff
= lbuf_indents(xb
, xrow
);
1128 if (xrow
== lbuf_len(xb
) - 1)
1131 vi_scroll
= vi_arg1
;
1132 n
= vi_scroll
? vi_scroll
: xrows
/ 2;
1133 xrow
= MIN(MAX(0, lbuf_len(xb
) - 1), xrow
+ n
);
1134 if (xtop
< lbuf_len(xb
) - xrows
)
1135 xtop
= MIN(lbuf_len(xb
) - xrows
, xtop
+ n
);
1136 xoff
= lbuf_indents(xb
, xrow
);
1145 if (!lbuf_undo(xb
)) {
1146 lbuf_jump(xb
, '*', &xrow
, &xoff
);
1149 snprintf(vi_msg
, sizeof(vi_msg
), "undo failed\n");
1153 if (!lbuf_redo(xb
)) {
1154 lbuf_jump(xb
, '*', &xrow
, &xoff
);
1157 snprintf(vi_msg
, sizeof(vi_msg
), "redo failed\n");
1168 ln
= vi_prompt(":", &kmap
);
1205 if ((mark
= vi_read()) > 0 && islower(mark
))
1206 lbuf_mark(xb
, mark
, xrow
, xoff
);
1217 xtop
= vi_arg1
? vi_arg1
: xrow
;
1220 n
= vi_arg1
? vi_arg1
: xrow
;
1221 xtop
= MAX(0, n
- xrows
/ 2);
1224 n
= vi_arg1
? vi_arg1
: xrow
;
1225 xtop
= MAX(0, n
- xrows
+ 1);
1229 xtd
= k
== 'r' ? -1 : +1;
1233 xtd
= k
== 'R' ? -2 : +2;
1237 xkmap
= k
== 'e' ? 0 : xkmap_alt
;
1244 if (k
== '~' || k
== 'u' || k
== 'U')
1252 if (!vc_motion('d'))
1256 vi_back(TK_CTL('h'));
1257 if (!vc_motion('d'))
1262 if (!vc_motion('c'))
1267 if (!vc_motion('d'))
1276 if (!vc_motion('c'))
1281 if (!vc_motion('c'))
1295 if (!vc_motion('~'))
1308 if (strchr("!<>ACDIJOPRSXYacdioprsxy~", c
) ||
1309 (c
== 'g' && strchr("uU~", k
))) {
1310 if (n
< sizeof(rep_cmd
)) {
1311 memcpy(rep_cmd
, cmd
, n
);
1316 if (xrow
< 0 || xrow
>= lbuf_len(xb
))
1317 xrow
= lbuf_len(xb
) ? lbuf_len(xb
) - 1 : 0;
1319 xtop
= xtop
- xrows
/ 2 > xrow
?
1320 MAX(0, xrow
- xrows
/ 2) : xrow
;
1321 if (xtop
+ xrows
<= xrow
)
1322 xtop
= xtop
+ xrows
+ xrows
/ 2 <= xrow
?
1323 xrow
- xrows
/ 2 : xrow
- xrows
+ 1;
1324 xoff
= ren_noeol(lbuf_get(xb
, xrow
), xoff
);
1326 xcol
= vi_off2col(xb
, xrow
, xoff
);
1327 if (xcol
>= xleft
+ xcols
)
1328 xleft
= xcol
- xcols
/ 2;
1330 xleft
= xcol
< xcols
? 0 : xcol
- xcols
/ 2;
1332 if (mod
|| xleft
!= oleft
) {
1333 vi_drawagain(xcol
, mod
== 2 && xleft
== oleft
&& xrow
== orow
);
1336 vi_drawupdate(xcol
, otop
);
1337 if (xhll
&& xrow
!= orow
&& orow
>= xtop
&& orow
< xtop
+ xrows
)
1339 if (xhll
&& xrow
!= orow
)
1344 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
),
1345 ren_cursor(lbuf_get(xb
, xrow
), xcol
)));
1352 int main(int argc
, char *argv
[])
1355 char *prog
= strchr(argv
[0], '/') ? strrchr(argv
[0], '/') + 1 : argv
[0];
1356 xvis
= strcmp("ex", prog
) && strcmp("neatex", prog
);
1357 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
1358 if (argv
[i
][1] == 's')
1360 if (argv
[i
][1] == 'e')
1362 if (argv
[i
][1] == 'v')
1369 if (!ex_init(argv
+ i
)) {