4 * Copyright (C) 2015 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
15 static char vi_msg
[EXLEN
]; /* current message */
16 static char vi_charlast
[8]; /* the last character searched via f, t, F, or T */
17 static int vi_charcmd
; /* the character finding command */
18 static int vi_arg1
, vi_arg2
; /* the first and second arguments */
19 static int vi_ybuf
; /* current yank buffer */
20 static char *vi_kmap
; /* current insertion keymap */
21 static int vi_pcol
; /* the column requested by | command */
22 static int vi_printed
; /* ex_print() calls since the last command */
23 static int vi_scroll
; /* scroll amount for ^f and ^d*/
25 static void vi_wait(void)
28 free(ex_read("[enter to continue]"));
34 static void vi_drawmsg(void)
36 led_print(vi_msg
, xrows
);
40 /* redraw the screen */
41 static void vi_draw(int xcol
)
45 for (i
= xtop
; i
< xtop
+ xrows
; i
++) {
46 char *s
= lbuf_get(xb
, i
);
47 led_print(s
? s
: (i
? "~" : ""), i
- xtop
);
50 term_pos(xrow
, led_pos(lbuf_get(xb
, i
), xcol
));
54 /* update the screen by removing lines r1 to r2 before an input command */
55 static void vi_drawrm(int r1
, int r2
, int newln
)
57 r1
= MIN(MAX(r1
, xtop
), xtop
+ xrows
);
58 r2
= MIN(MAX(r2
, xtop
), xtop
+ xrows
);
59 term_pos(r1
- xtop
, 0);
60 term_room(r1
- r2
+ newln
);
63 static int vi_buf
[128];
66 static int vi_read(void)
68 return vi_buflen
? vi_buf
[--vi_buflen
] : term_read();
71 static void vi_back(int c
)
73 if (vi_buflen
< sizeof(vi_buf
))
74 vi_buf
[vi_buflen
++] = c
;
77 static char *vi_char(void)
79 return led_read(&vi_kmap
);
82 static char *vi_prompt(char *msg
, char **kmap
)
84 term_pos(xrows
, led_pos(msg
, 0));
86 return led_prompt(msg
, "", kmap
);
89 /* read an ex input line */
90 char *ex_read(char *msg
)
95 char *s
= led_prompt(msg
, "", &vi_kmap
);
101 while ((c
= getchar()) != EOF
&& c
!= '\n')
107 return sbuf_done(sb
);
110 /* show an ex message */
111 void ex_show(char *msg
)
114 snprintf(vi_msg
, sizeof(vi_msg
), "%s", msg
);
123 /* print an ex output line */
124 void ex_print(char *line
)
127 vi_printed
+= line
? 1 : 2;
129 snprintf(vi_msg
, sizeof(vi_msg
), "%s", line
);
139 static int vi_yankbuf(void)
148 static int vi_prefix(void)
152 if ((c
>= '1' && c
<= '9')) {
154 n
= n
* 10 + c
- '0';
162 static int vi_col2off(struct lbuf
*lb
, int row
, int col
)
164 char *ln
= lbuf_get(lb
, row
);
165 return ln
? ren_off(ln
, col
) : 0;
168 static int vi_off2col(struct lbuf
*lb
, int row
, int off
)
170 char *ln
= lbuf_get(lb
, row
);
171 return ln
? ren_pos(ln
, off
) : 0;
174 static int vi_nextoff(struct lbuf
*lb
, int dir
, int *row
, int *off
)
177 if (o
< 0 || !lbuf_get(lb
, *row
) || o
>= uc_slen(lbuf_get(lb
, *row
)))
183 static int vi_nextcol(struct lbuf
*lb
, int dir
, int *row
, int *off
)
185 char *ln
= lbuf_get(lb
, *row
);
186 int col
= ln
? ren_pos(ln
, *off
) : 0;
187 int o
= ln
? ren_next(ln
, col
, dir
) : -1;
190 *off
= ren_off(ln
, o
);
194 static int vi_findchar(struct lbuf
*lb
, char *cs
, int cmd
, int n
, int *row
, int *off
)
196 strcpy(vi_charlast
, cs
);
198 return lbuf_findchar(lb
, cs
, cmd
, n
, row
, off
);
201 static int vi_search(int cmd
, int cnt
, int *row
, int *off
)
209 if (cmd
== '/' || cmd
== '?') {
210 char sign
[4] = {cmd
};
211 char *kw
= vi_prompt(sign
, &vi_kmap
);
214 xfinddir
= cmd
== '/' ? +1 : -1;
216 snprintf(xfindkwd
, sizeof(xfindkwd
), "%s", kw
);
217 if (strchr(xfindkwd
, cmd
)) {
218 soff
= strchr(xfindkwd
, cmd
) + 1;
219 *strchr(xfindkwd
, cmd
) = '\0';
223 dir
= cmd
== 'N' ? -xfinddir
: xfinddir
;
224 if (!xfindkwd
[0] || !lbuf_len(xb
))
227 for (i
= 0; i
< cnt
; i
++) {
228 if (lbuf_search(xb
, xfindkwd
, dir
, &r
, &o
, &len
)) {
232 if (i
+ 1 < cnt
&& cmd
== '/')
238 while (soff
[0] && isspace((unsigned char) soff
[0]))
242 if (*row
+ atoi(soff
) < 0 || *row
+ atoi(soff
) >= lbuf_len(xb
))
249 snprintf(vi_msg
, sizeof(vi_msg
), "\"%s\" not found\n", xfindkwd
);
253 /* read a line motion */
254 static int vi_motionln(int *row
, int cmd
)
256 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
258 int mark
, mark_row
, mark_off
;
262 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
265 *row
= MAX(*row
- cnt
, 0);
268 *row
= MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1);
271 if ((mark
= vi_read()) <= 0)
273 if (lbuf_jump(xb
, mark
, &mark_row
, &mark_off
))
278 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
281 *row
= MAX(*row
- cnt
, 0);
284 *row
= (vi_arg1
|| vi_arg2
) ? cnt
- 1 : lbuf_len(xb
) - 1;
288 *row
= MIN(xtop
+ cnt
- 1, lbuf_len(xb
) - 1);
294 *row
= MIN(xtop
+ xrows
- 1 - cnt
+ 1, lbuf_len(xb
) - 1);
300 *row
= MIN(xtop
+ xrows
/ 2, lbuf_len(xb
) - 1);
306 *row
= MAX(0, MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1));
309 if (c
== '%' && (vi_arg1
|| vi_arg2
)) {
312 *row
= MAX(0, lbuf_len(xb
) - 1) * cnt
/ 100;
321 static char *vi_curword(struct lbuf
*lb
, int row
, int off
)
324 char *ln
= lbuf_get(lb
, row
);
328 beg
= uc_chr(ln
, ren_noeol(ln
, off
));
330 while (*end
&& uc_kind(end
) == 1)
332 while (beg
> ln
&& uc_kind(uc_beg(ln
, beg
- 1)) == 1)
333 beg
= uc_beg(ln
, beg
- 1);
338 sbuf_mem(sb
, beg
, end
- beg
);
340 return sbuf_done(sb
);
344 static int vi_motion(int *row
, int *off
)
346 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
347 char *ln
= lbuf_get(xb
, *row
);
348 int dir
= dir_context(ln
? ln
: "");
349 int mark
, mark_row
, mark_off
;
353 if ((mv
= vi_motionln(row
, 0))) {
360 if (!(cs
= vi_char()))
362 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
366 if (!(cs
= vi_char()))
368 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
374 if (vi_findchar(xb
, vi_charlast
, vi_charcmd
, cnt
, row
, off
))
380 if (vi_findchar(xb
, vi_charlast
, vi_charcmd
, -cnt
, row
, off
))
384 for (i
= 0; i
< cnt
; i
++)
385 if (vi_nextcol(xb
, -1 * dir
, row
, off
))
389 for (i
= 0; i
< cnt
; i
++)
390 if (vi_nextcol(xb
, +1 * dir
, row
, off
))
394 if (!(cs
= vi_char()))
396 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
400 if (!(cs
= vi_char()))
402 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
406 for (i
= 0; i
< cnt
; i
++)
407 if (lbuf_wordend(xb
, 1, -1, row
, off
))
411 for (i
= 0; i
< cnt
; i
++)
412 if (lbuf_wordend(xb
, 1, +1, row
, off
))
416 for (i
= 0; i
< cnt
; i
++)
417 if (lbuf_wordbeg(xb
, 1, +1, row
, off
))
421 for (i
= 0; i
< cnt
; i
++)
422 if (lbuf_wordend(xb
, 0, -1, row
, off
))
426 for (i
= 0; i
< cnt
; i
++)
427 if (lbuf_wordend(xb
, 0, +1, row
, off
))
431 for (i
= 0; i
< cnt
; i
++)
432 if (lbuf_wordbeg(xb
, 0, +1, row
, off
))
436 for (i
= 0; i
< cnt
; i
++)
437 if (lbuf_paragraphbeg(xb
, -1, row
, off
))
441 for (i
= 0; i
< cnt
; i
++)
442 if (lbuf_paragraphbeg(xb
, +1, row
, off
))
446 if (vi_read() != '[')
448 for (i
= 0; i
< cnt
; i
++)
449 if (lbuf_sectionbeg(xb
, -1, row
, off
))
453 if (vi_read() != ']')
455 for (i
= 0; i
< cnt
; i
++)
456 if (lbuf_sectionbeg(xb
, +1, row
, off
))
463 *off
= lbuf_indents(xb
, *row
);
466 *off
= lbuf_eol(xb
, *row
);
469 *off
= vi_col2off(xb
, *row
, cnt
- 1);
473 if (vi_search(mv
, cnt
, row
, off
))
477 if (vi_search(mv
, cnt
, row
, off
))
481 if (vi_search(mv
, cnt
, row
, off
))
485 if (vi_search(mv
, cnt
, row
, off
))
489 if (!(cs
= vi_curword(xb
, *row
, *off
)))
491 strcpy(xfindkwd
, cs
);
494 if (vi_search('n', cnt
, row
, off
))
498 for (i
= 0; i
< cnt
; i
++)
499 if (vi_nextoff(xb
, +1, row
, off
))
504 for (i
= 0; i
< cnt
; i
++)
505 if (vi_nextoff(xb
, -1, row
, off
))
509 if ((mark
= vi_read()) <= 0)
511 if (lbuf_jump(xb
, mark
, &mark_row
, &mark_off
))
517 if (lbuf_pair(xb
, row
, off
))
527 static void swap(int *a
, int *b
)
534 static char *lbuf_region(struct lbuf
*lb
, int r1
, int o1
, int r2
, int o2
)
539 return uc_sub(lbuf_get(lb
, r1
), o1
, o2
);
541 s1
= uc_sub(lbuf_get(lb
, r1
), o1
, -1);
542 s3
= uc_sub(lbuf_get(lb
, r2
), 0, o2
);
543 s2
= lbuf_cp(lb
, r1
+ 1, r2
);
550 return sbuf_done(sb
);
553 static void vi_yank(int r1
, int o1
, int r2
, int o2
, int lnmode
)
556 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
557 reg_put(vi_ybuf
, region
, lnmode
);
560 xoff
= lnmode
? xoff
: o1
;
563 static void vi_delete(int r1
, int o1
, int r2
, int o2
, int lnmode
)
567 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
568 reg_put(vi_ybuf
, region
, lnmode
);
570 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
571 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
572 lbuf_rm(xb
, r1
, r2
+ 1);
574 struct sbuf
*sb
= sbuf_make();
577 lbuf_put(xb
, r1
, sbuf_buf(sb
));
581 xoff
= lnmode
? lbuf_indents(xb
, xrow
) : o1
;
586 static int linecount(char *s
)
590 if ((s
= strchr(s
, '\n')))
595 static int indentscopy(char *d
, char *s
, int len
)
598 for (i
= 0; i
< len
- 1 && (s
[i
] == ' ' || s
[i
] == '\t'); i
++)
604 static char *vi_input(char *pref
, char *post
, int *row
, int *off
)
611 pref
+= indentscopy(ai
, pref
, sizeof(ai
));
612 rep
= led_input(pref
, post
, ai
, xai
? sizeof(ai
) - 1 : 0, &vi_kmap
);
620 last
= uc_lastline(s
) - s
;
621 *off
= MAX(0, uc_slen(sbuf_buf(sb
) + last
) - 1);
623 while (xai
&& (post
[0] == ' ' || post
[0] == '\t'))
626 *row
= linecount(sbuf_buf(sb
)) - 1;
628 return sbuf_done(sb
);
631 static char *vi_indents(char *ln
)
633 struct sbuf
*sb
= sbuf_make();
634 while (xai
&& ln
&& (*ln
== ' ' || *ln
== '\t'))
636 return sbuf_done(sb
);
639 static void vi_change(int r1
, int o1
, int r2
, int o2
, int lnmode
)
645 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
646 reg_put(vi_ybuf
, region
, lnmode
);
648 pref
= lnmode
? vi_indents(lbuf_get(xb
, r1
)) : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
649 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
650 vi_drawrm(r1
, r2
, 0);
651 rep
= vi_input(pref
, post
, &row
, &off
);
653 lbuf_rm(xb
, r1
, r2
+ 1);
654 lbuf_put(xb
, r1
, rep
);
663 static void vi_case(int r1
, int o1
, int r2
, int o2
, int lnmode
, int cmd
)
667 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
670 int c
= (unsigned char) s
[0];
677 s
[0] = islower(c
) ? toupper(c
) : tolower(c
);
681 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
682 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
683 lbuf_rm(xb
, r1
, r2
+ 1);
685 struct sbuf
*sb
= sbuf_make();
687 sbuf_str(sb
, region
);
689 lbuf_put(xb
, r1
, sbuf_buf(sb
));
692 lbuf_put(xb
, r1
, region
);
695 xoff
= lnmode
? lbuf_indents(xb
, r2
) : o2
;
701 static void vi_pipe(int r1
, int r2
)
706 char *cmd
= vi_prompt("!", &kmap
);
709 text
= lbuf_cp(xb
, r1
, r2
+ 1);
710 rep
= cmd_pipe(cmd
, text
, 1, 1);
712 lbuf_rm(xb
, r1
, r2
+ 1);
713 lbuf_put(xb
, r1
, rep
);
720 static void vi_shift(int r1
, int r2
, int dir
)
725 for (i
= r1
; i
<= r2
; i
++) {
726 if (!(ln
= lbuf_get(xb
, i
)))
732 ln
= ln
[0] == ' ' || ln
[0] == '\t' ? ln
+ 1 : ln
;
734 lbuf_rm(xb
, i
, i
+ 1);
735 lbuf_put(xb
, i
, sbuf_buf(sb
));
739 xoff
= lbuf_indents(xb
, xrow
);
742 static int vc_motion(int cmd
)
744 int r1
= xrow
, r2
= xrow
; /* region rows */
745 int o1
= xoff
, o2
= xoff
; /* visual region columns */
746 int lnmode
= 0; /* line-based region */
748 vi_arg2
= vi_prefix();
751 o1
= ren_noeol(lbuf_get(xb
, r1
), o1
);
753 if ((mv
= vi_motionln(&r2
, cmd
))) {
755 } else if (!(mv
= vi_motion(&r2
, &o2
))) {
764 o2
= lbuf_eol(xb
, r2
);
770 if (r1
== r2
&& o1
> o2
)
772 o1
= ren_noeol(lbuf_get(xb
, r1
), o1
);
773 if (!lnmode
&& strchr("fFtTeE%", mv
))
774 if (o2
< lbuf_eol(xb
, r2
))
775 o2
= ren_noeol(lbuf_get(xb
, r2
), o2
) + 1;
777 vi_yank(r1
, o1
, r2
, o2
, lnmode
);
779 vi_delete(r1
, o1
, r2
, o2
, lnmode
);
781 vi_change(r1
, o1
, r2
, o2
, lnmode
);
782 if (cmd
== '~' || cmd
== 'u' || cmd
== 'U')
783 vi_case(r1
, o1
, r2
, o2
, lnmode
, cmd
);
786 if (cmd
== '>' || cmd
== '<')
787 vi_shift(r1
, r2
, cmd
== '>' ? +1 : -1);
791 static int vc_insert(int cmd
)
794 char *ln
= lbuf_get(xb
, xrow
);
798 xoff
= lbuf_indents(xb
, xrow
);
800 xoff
= lbuf_eol(xb
, xrow
);
801 xoff
= ren_noeol(ln
, xoff
);
804 if (cmd
== 'i' || cmd
== 'I')
806 if (cmd
== 'a' || cmd
== 'A')
808 pref
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, 0, off
) : vi_indents(ln
);
809 post
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, off
, -1) : uc_dup("\n");
810 vi_drawrm(xrow
, xrow
, cmd
== 'o' || cmd
== 'O');
811 rep
= vi_input(pref
, post
, &row
, &off
);
812 if ((cmd
== 'o' || cmd
== 'O') && !lbuf_len(xb
))
813 lbuf_put(xb
, 0, "\n");
815 if (cmd
!= 'o' && cmd
!= 'O')
816 lbuf_rm(xb
, xrow
, xrow
+ 1);
817 lbuf_put(xb
, xrow
, rep
);
827 static int vc_put(int cmd
)
829 int cnt
= MAX(1, vi_arg1
);
831 char *buf
= reg_get(vi_ybuf
, &lnmode
);
834 snprintf(vi_msg
, sizeof(vi_msg
), "yank buffer empty\n");
838 struct sbuf
*sb
= sbuf_make();
839 for (i
= 0; i
< cnt
; i
++)
842 lbuf_put(xb
, 0, "\n");
845 lbuf_put(xb
, xrow
, sbuf_buf(sb
));
846 xoff
= lbuf_indents(xb
, xrow
);
849 struct sbuf
*sb
= sbuf_make();
850 char *ln
= xrow
< lbuf_len(xb
) ? lbuf_get(xb
, xrow
) : "\n";
851 int off
= ren_noeol(ln
, xoff
) + (ln
[0] != '\n' && cmd
== 'p');
852 char *s
= uc_sub(ln
, 0, off
);
855 for (i
= 0; i
< cnt
; i
++)
857 s
= uc_sub(ln
, off
, -1);
860 lbuf_rm(xb
, xrow
, xrow
+ 1);
861 lbuf_put(xb
, xrow
, sbuf_buf(sb
));
862 xoff
= off
+ uc_slen(buf
) * cnt
- 1;
868 static int join_spaces(char *prev
, char *next
)
870 int prevlen
= strlen(prev
);
873 if (prev
[prevlen
- 1] == ' ' || next
[0] == ')')
875 return prev
[prevlen
- 1] == '.' ? 2 : 1;
878 static int vc_join(void)
881 int cnt
= vi_arg1
<= 1 ? 2 : vi_arg1
;
883 int end
= xrow
+ cnt
;
886 if (!lbuf_get(xb
, beg
) || !lbuf_get(xb
, end
- 1))
889 for (i
= beg
; i
< end
; i
++) {
890 char *ln
= lbuf_get(xb
, i
);
891 char *lnend
= strchr(ln
, '\n');
894 while (ln
[0] == ' ' || ln
[0] == '\t')
896 spaces
= i
> beg
? join_spaces(sbuf_buf(sb
), ln
) : 0;
897 off
= uc_slen(sbuf_buf(sb
));
900 sbuf_mem(sb
, ln
, lnend
- ln
);
903 lbuf_rm(xb
, beg
, end
);
904 lbuf_put(xb
, beg
, sbuf_buf(sb
));
910 static int vi_scrollforeward(int cnt
)
912 if (xtop
>= lbuf_len(xb
) - 1)
914 xtop
= MIN(lbuf_len(xb
) - 1, xtop
+ cnt
);
915 xrow
= MAX(xrow
, xtop
);
919 static int vi_scrollbackward(int cnt
)
923 xtop
= MAX(0, xtop
- cnt
);
924 xrow
= MIN(xrow
, xtop
+ xrows
- 1);
928 static void vc_status(void)
930 int col
= vi_off2col(xb
, xrow
, xoff
);
931 snprintf(vi_msg
, sizeof(vi_msg
),
932 "\"%s\"%c %d lines L%d C%d\n",
933 ex_path()[0] ? ex_path() : "unnamed",
934 lbuf_modified(xb
) ? '*' : ' ',
935 lbuf_len(xb
), xrow
+ 1,
936 ren_cursor(lbuf_get(xb
, xrow
), col
) + 1);
939 static int vc_replace(void)
941 int cnt
= MAX(1, vi_arg1
);
942 char *cs
= vi_char();
943 char *ln
= lbuf_get(xb
, xrow
);
950 off
= ren_noeol(ln
, xoff
);
952 for (i
= 0; s
[0] != '\n' && i
< cnt
; i
++)
956 pref
= uc_sub(ln
, 0, off
);
957 post
= uc_sub(ln
, off
+ cnt
, -1);
960 for (i
= 0; i
< cnt
; i
++)
963 lbuf_rm(xb
, xrow
, xrow
+ 1);
964 lbuf_put(xb
, xrow
, sbuf_buf(sb
));
973 static char rep_cmd
[4096]; /* the last command */
976 static void vc_repeat(void)
978 term_push(rep_cmd
, rep_len
);
981 static void vc_execute(void)
992 buf
= reg_get(exec_buf
, &lnmode
);
994 term_push(buf
, strlen(buf
));
1003 xtop
= MAX(0, xrow
- xrows
/ 2);
1005 xcol
= vi_off2col(xb
, xrow
, xoff
);
1007 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
), xcol
));
1011 int noff
= ren_noeol(lbuf_get(xb
, xrow
), xoff
);
1016 vi_ybuf
= vi_yankbuf();
1017 vi_arg1
= vi_prefix();
1019 vi_ybuf
= vi_yankbuf();
1020 mv
= vi_motion(&nrow
, &noff
);
1022 if (strchr("\'`GHML/?{}[]nN", mv
) ||
1023 (mv
== '%' && noff
< 0)) {
1024 lbuf_mark(xb
, '\'', xrow
, xoff
);
1025 lbuf_mark(xb
, '`', xrow
, xoff
);
1028 if (noff
< 0 && !strchr("jk", mv
))
1029 noff
= lbuf_indents(xb
, xrow
);
1030 if (strchr("jk", mv
))
1031 noff
= vi_col2off(xb
, xrow
, xcol
);
1032 xoff
= ren_noeol(lbuf_get(xb
, xrow
), noff
);
1033 if (!strchr("|jk", mv
))
1034 xcol
= vi_off2col(xb
, xrow
, xoff
);
1037 } else if (mv
== 0) {
1043 lbuf_mark(xb
, '*', xrow
, xoff
);
1046 if (vi_scrollbackward(MAX(1, vi_arg1
) * (xrows
- 1)))
1048 xoff
= lbuf_indents(xb
, xrow
);
1052 if (vi_scrollforeward(MAX(1, vi_arg1
) * (xrows
- 1)))
1054 xoff
= lbuf_indents(xb
, xrow
);
1058 if (vi_scrollforeward(MAX(1, vi_arg1
)))
1063 if (vi_scrollbackward(MAX(1, vi_arg1
)))
1071 vi_scroll
= vi_arg1
;
1072 n
= vi_scroll
? vi_scroll
: xrows
/ 2;
1073 xrow
= MAX(0, xrow
- n
);
1075 xtop
= MAX(0, xtop
- n
);
1077 xoff
= lbuf_indents(xb
, xrow
);
1080 if (xrow
== lbuf_len(xb
) - 1)
1083 vi_scroll
= vi_arg1
;
1084 n
= vi_scroll
? vi_scroll
: xrows
/ 2;
1085 xrow
= MIN(MAX(0, lbuf_len(xb
) - 1), xrow
+ n
);
1086 if (xtop
< lbuf_len(xb
) - xrows
)
1087 xtop
= MIN(lbuf_len(xb
) - xrows
, xtop
+ n
);
1089 xoff
= lbuf_indents(xb
, xrow
);
1097 if (!lbuf_undo(xb
)) {
1098 lbuf_jump(xb
, '*', &xrow
, &xoff
);
1101 snprintf(vi_msg
, sizeof(vi_msg
), "undo failed\n");
1105 if (!lbuf_redo(xb
)) {
1106 lbuf_jump(xb
, '*', &xrow
, &xoff
);
1109 snprintf(vi_msg
, sizeof(vi_msg
), "redo failed\n");
1120 ln
= vi_prompt(":", &kmap
);
1152 if ((mark
= vi_read()) > 0 && islower(mark
))
1153 lbuf_mark(xb
, mark
, xrow
, xoff
);
1164 xtop
= vi_arg1
? vi_arg1
: xrow
;
1167 n
= vi_arg1
? vi_arg1
: xrow
;
1168 xtop
= MAX(0, n
- xrows
/ 2);
1171 n
= vi_arg1
? vi_arg1
: xrow
;
1172 xtop
= MAX(0, n
- xrows
+ 1);
1176 xdir
= k
== 'r' ? -1 : +1;
1180 xdir
= k
== 'R' ? -2 : +2;
1187 if (k
== '~' || k
== 'u' || k
== 'U')
1193 if (!vc_motion('d'))
1197 vi_back(TK_CTL('h'));
1198 if (!vc_motion('d'))
1203 if (!vc_motion('c'))
1208 if (!vc_motion('d'))
1217 if (!vc_motion('c'))
1222 if (!vc_motion('c'))
1227 if (!vc_motion('y'))
1237 if (!vc_motion('~'))
1250 if (strchr("!<>ACDIJOPRSXYacdioprsxy~", c
)) {
1251 if (n
< sizeof(rep_cmd
)) {
1252 memcpy(rep_cmd
, cmd
, n
);
1257 if (xrow
< 0 || xrow
>= lbuf_len(xb
))
1258 xrow
= lbuf_len(xb
) ? lbuf_len(xb
) - 1 : 0;
1260 xtop
= xtop
- xrows
/ 2 > xrow
?
1261 MAX(0, xrow
- xrows
/ 2) : xrow
;
1262 if (xtop
+ xrows
<= xrow
)
1263 xtop
= xtop
+ xrows
+ xrows
/ 2 <= xrow
?
1264 xrow
- xrows
/ 2 : xrow
- xrows
+ 1;
1265 xoff
= ren_noeol(lbuf_get(xb
, xrow
), xoff
);
1267 xcol
= vi_off2col(xb
, xrow
, xoff
);
1269 if (redraw
|| xtop
!= otop
)
1273 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
),
1274 ren_cursor(lbuf_get(xb
, xrow
), xcol
)));
1281 int main(int argc
, char *argv
[])
1285 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
1286 if (argv
[i
][1] == 's')
1288 if (argv
[i
][1] == 'e')
1290 if (argv
[i
][1] == 'v')
1297 if (!ex_init(argv
+ i
)) {