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 int vi_pcol
; /* the column requested by | command */
21 static int vi_printed
; /* ex_print() calls since the last command */
22 static int vi_scroll
; /* scroll amount for ^f and ^d*/
24 static void vi_wait(void)
27 free(ex_read("[enter to continue]"));
33 static void vi_drawmsg(void)
37 led_print(vi_msg
, xrows
);
42 /* redraw the screen */
43 static void vi_draw(int xcol
)
47 for (i
= xtop
; i
< xtop
+ xrows
; i
++) {
48 char *s
= lbuf_get(xb
, i
);
49 led_print(s
? s
: (i
? "~" : ""), i
- xtop
);
52 term_pos(xrow
, led_pos(lbuf_get(xb
, i
), xcol
));
56 /* update the screen by removing lines r1 to r2 before an input command */
57 static void vi_drawrm(int r1
, int r2
, int newln
)
59 r1
= MIN(MAX(r1
, xtop
), xtop
+ xrows
);
60 r2
= MIN(MAX(r2
, xtop
), xtop
+ xrows
);
61 term_pos(r1
- xtop
, 0);
62 term_room(r1
- r2
+ newln
);
65 static int vi_buf
[128];
68 static int vi_read(void)
70 return vi_buflen
? vi_buf
[--vi_buflen
] : term_read();
73 static void vi_back(int c
)
75 if (vi_buflen
< sizeof(vi_buf
))
76 vi_buf
[vi_buflen
++] = c
;
79 static char *vi_char(void)
81 return led_read(ex_kmap());
84 static char *vi_prompt(char *msg
, char **kmap
)
87 term_pos(xrows
, led_pos(msg
, 0));
89 s
= led_prompt(msg
, "", kmap
);
92 r
= uc_dup(strlen(s
) >= strlen(msg
) ? s
+ strlen(msg
) : s
);
97 /* read an ex input line */
98 char *ex_read(char *msg
)
103 char *s
= led_prompt(msg
, "", ex_kmap());
109 while ((c
= getchar()) != EOF
&& c
!= '\n')
115 return sbuf_done(sb
);
118 /* show an ex message */
119 void ex_show(char *msg
)
122 snprintf(vi_msg
, sizeof(vi_msg
), "%s", msg
);
131 /* print an ex output line */
132 void ex_print(char *line
)
135 vi_printed
+= line
? 1 : 2;
137 snprintf(vi_msg
, sizeof(vi_msg
), "%s", line
);
147 static int vi_yankbuf(void)
156 static int vi_prefix(void)
160 if ((c
>= '1' && c
<= '9')) {
162 n
= n
* 10 + c
- '0';
170 static int vi_col2off(struct lbuf
*lb
, int row
, int col
)
172 char *ln
= lbuf_get(lb
, row
);
173 return ln
? ren_off(ln
, col
) : 0;
176 static int vi_off2col(struct lbuf
*lb
, int row
, int off
)
178 char *ln
= lbuf_get(lb
, row
);
179 return ln
? ren_pos(ln
, off
) : 0;
182 static int vi_nextoff(struct lbuf
*lb
, int dir
, int *row
, int *off
)
185 if (o
< 0 || !lbuf_get(lb
, *row
) || o
>= uc_slen(lbuf_get(lb
, *row
)))
191 static int vi_nextcol(struct lbuf
*lb
, int dir
, int *row
, int *off
)
193 char *ln
= lbuf_get(lb
, *row
);
194 int col
= ln
? ren_pos(ln
, *off
) : 0;
195 int o
= ln
? ren_next(ln
, col
, dir
) : -1;
198 *off
= ren_off(ln
, o
);
202 static int vi_findchar(struct lbuf
*lb
, char *cs
, int cmd
, int n
, int *row
, int *off
)
204 strcpy(vi_charlast
, cs
);
206 return lbuf_findchar(lb
, cs
, cmd
, n
, row
, off
);
209 static int vi_search(int cmd
, int cnt
, int *row
, int *off
)
217 if (cmd
== '/' || cmd
== '?') {
218 char sign
[4] = {cmd
};
219 char *kw
= vi_prompt(sign
, ex_kmap());
222 xfinddir
= cmd
== '/' ? +1 : -1;
224 snprintf(xfindkwd
, sizeof(xfindkwd
), "%s", kw
);
225 if (strchr(xfindkwd
, cmd
)) {
226 soff
= strchr(xfindkwd
, cmd
) + 1;
227 *strchr(xfindkwd
, cmd
) = '\0';
231 dir
= cmd
== 'N' ? -xfinddir
: xfinddir
;
232 if (!xfindkwd
[0] || !lbuf_len(xb
))
235 for (i
= 0; i
< cnt
; i
++) {
236 if (lbuf_search(xb
, xfindkwd
, dir
, &r
, &o
, &len
)) {
240 if (i
+ 1 < cnt
&& cmd
== '/')
246 while (soff
[0] && isspace((unsigned char) soff
[0]))
250 if (*row
+ atoi(soff
) < 0 || *row
+ atoi(soff
) >= lbuf_len(xb
))
257 snprintf(vi_msg
, sizeof(vi_msg
), "\"%s\" not found\n", xfindkwd
);
261 /* read a line motion */
262 static int vi_motionln(int *row
, int cmd
)
264 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
266 int mark
, mark_row
, mark_off
;
270 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
273 *row
= MAX(*row
- cnt
, 0);
276 *row
= MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1);
279 if ((mark
= vi_read()) <= 0)
281 if (lbuf_jump(xb
, mark
, &mark_row
, &mark_off
))
286 *row
= MIN(*row
+ cnt
, lbuf_len(xb
) - 1);
289 *row
= MAX(*row
- cnt
, 0);
292 *row
= (vi_arg1
|| vi_arg2
) ? cnt
- 1 : lbuf_len(xb
) - 1;
296 *row
= MIN(xtop
+ cnt
- 1, lbuf_len(xb
) - 1);
302 *row
= MIN(xtop
+ xrows
- 1 - cnt
+ 1, lbuf_len(xb
) - 1);
308 *row
= MIN(xtop
+ xrows
/ 2, lbuf_len(xb
) - 1);
314 *row
= MAX(0, MIN(*row
+ cnt
- 1, lbuf_len(xb
) - 1));
317 if (c
== '%' && (vi_arg1
|| vi_arg2
)) {
320 *row
= MAX(0, lbuf_len(xb
) - 1) * cnt
/ 100;
329 static char *vi_curword(struct lbuf
*lb
, int row
, int off
)
332 char *ln
= lbuf_get(lb
, row
);
336 beg
= uc_chr(ln
, ren_noeol(ln
, off
));
338 while (*end
&& uc_kind(end
) == 1)
340 while (beg
> ln
&& uc_kind(uc_beg(ln
, beg
- 1)) == 1)
341 beg
= uc_beg(ln
, beg
- 1);
346 sbuf_mem(sb
, beg
, end
- beg
);
348 return sbuf_done(sb
);
352 static int vi_motion(int *row
, int *off
)
354 int cnt
= (vi_arg1
? vi_arg1
: 1) * (vi_arg2
? vi_arg2
: 1);
355 char *ln
= lbuf_get(xb
, *row
);
356 int dir
= dir_context(ln
? ln
: "");
357 int mark
, mark_row
, mark_off
;
361 if ((mv
= vi_motionln(row
, 0))) {
368 if (!(cs
= vi_char()))
370 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
374 if (!(cs
= vi_char()))
376 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
382 if (vi_findchar(xb
, vi_charlast
, vi_charcmd
, cnt
, row
, off
))
388 if (vi_findchar(xb
, vi_charlast
, vi_charcmd
, -cnt
, row
, off
))
392 for (i
= 0; i
< cnt
; i
++)
393 if (vi_nextcol(xb
, -1 * dir
, row
, off
))
397 for (i
= 0; i
< cnt
; i
++)
398 if (vi_nextcol(xb
, +1 * dir
, row
, off
))
402 if (!(cs
= vi_char()))
404 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
408 if (!(cs
= vi_char()))
410 if (vi_findchar(xb
, cs
, mv
, cnt
, row
, off
))
414 for (i
= 0; i
< cnt
; i
++)
415 if (lbuf_wordend(xb
, 1, -1, row
, off
))
419 for (i
= 0; i
< cnt
; i
++)
420 if (lbuf_wordend(xb
, 1, +1, row
, off
))
424 for (i
= 0; i
< cnt
; i
++)
425 if (lbuf_wordbeg(xb
, 1, +1, row
, off
))
429 for (i
= 0; i
< cnt
; i
++)
430 if (lbuf_wordend(xb
, 0, -1, row
, off
))
434 for (i
= 0; i
< cnt
; i
++)
435 if (lbuf_wordend(xb
, 0, +1, row
, off
))
439 for (i
= 0; i
< cnt
; i
++)
440 if (lbuf_wordbeg(xb
, 0, +1, row
, off
))
444 for (i
= 0; i
< cnt
; i
++)
445 if (lbuf_paragraphbeg(xb
, -1, row
, off
))
449 for (i
= 0; i
< cnt
; i
++)
450 if (lbuf_paragraphbeg(xb
, +1, row
, off
))
454 if (vi_read() != '[')
456 for (i
= 0; i
< cnt
; i
++)
457 if (lbuf_sectionbeg(xb
, -1, row
, off
))
461 if (vi_read() != ']')
463 for (i
= 0; i
< cnt
; i
++)
464 if (lbuf_sectionbeg(xb
, +1, row
, off
))
471 *off
= lbuf_indents(xb
, *row
);
474 *off
= lbuf_eol(xb
, *row
);
477 *off
= vi_col2off(xb
, *row
, cnt
- 1);
481 if (vi_search(mv
, cnt
, row
, off
))
485 if (vi_search(mv
, cnt
, row
, off
))
489 if (vi_search(mv
, cnt
, row
, off
))
493 if (vi_search(mv
, cnt
, row
, off
))
497 if (!(cs
= vi_curword(xb
, *row
, *off
)))
499 strcpy(xfindkwd
, cs
);
502 if (vi_search('n', cnt
, row
, off
))
506 for (i
= 0; i
< cnt
; i
++)
507 if (vi_nextoff(xb
, +1, row
, off
))
512 for (i
= 0; i
< cnt
; i
++)
513 if (vi_nextoff(xb
, -1, row
, off
))
517 if ((mark
= vi_read()) <= 0)
519 if (lbuf_jump(xb
, mark
, &mark_row
, &mark_off
))
525 if (lbuf_pair(xb
, row
, off
))
535 static void swap(int *a
, int *b
)
542 static char *lbuf_region(struct lbuf
*lb
, int r1
, int o1
, int r2
, int o2
)
547 return uc_sub(lbuf_get(lb
, r1
), o1
, o2
);
549 s1
= uc_sub(lbuf_get(lb
, r1
), o1
, -1);
550 s3
= uc_sub(lbuf_get(lb
, r2
), 0, o2
);
551 s2
= lbuf_cp(lb
, r1
+ 1, r2
);
558 return sbuf_done(sb
);
561 static void vi_yank(int r1
, int o1
, int r2
, int o2
, int lnmode
)
564 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
565 reg_put(vi_ybuf
, region
, lnmode
);
568 xoff
= lnmode
? xoff
: o1
;
571 static void vi_delete(int r1
, int o1
, int r2
, int o2
, int lnmode
)
575 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
576 reg_put(vi_ybuf
, region
, lnmode
);
578 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
579 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
581 struct sbuf
*sb
= sbuf_make();
584 lbuf_edit(xb
, sbuf_buf(sb
), r1
, r2
+ 1);
587 lbuf_edit(xb
, NULL
, r1
, r2
+ 1);
590 xoff
= lnmode
? lbuf_indents(xb
, xrow
) : o1
;
595 static int linecount(char *s
)
599 if ((s
= strchr(s
, '\n')))
604 static int charcount(char *text
, char *post
)
606 int tlen
= strlen(text
);
607 int plen
= strlen(post
);
612 for (i
= 0; i
< tlen
- plen
; i
++)
615 return uc_slen(nl
) - uc_slen(post
);
618 static char *vi_input(char *pref
, char *post
, int *row
, int *off
)
620 char *rep
= led_input(pref
, post
, ex_kmap());
623 *row
= linecount(rep
) - 1;
624 *off
= charcount(rep
, post
) - 1;
630 static char *vi_indents(char *ln
)
632 struct sbuf
*sb
= sbuf_make();
633 while (xai
&& ln
&& (*ln
== ' ' || *ln
== '\t'))
635 return sbuf_done(sb
);
638 static void vi_change(int r1
, int o1
, int r2
, int o2
, int lnmode
)
644 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
645 reg_put(vi_ybuf
, region
, lnmode
);
647 pref
= lnmode
? vi_indents(lbuf_get(xb
, r1
)) : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
648 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
649 vi_drawrm(r1
, r2
, 0);
650 rep
= vi_input(pref
, post
, &row
, &off
);
652 lbuf_edit(xb
, rep
, r1
, r2
+ 1);
661 static void vi_case(int r1
, int o1
, int r2
, int o2
, int lnmode
, int cmd
)
665 region
= lbuf_region(xb
, r1
, lnmode
? 0 : o1
, r2
, lnmode
? -1 : o2
);
668 int c
= (unsigned char) s
[0];
675 s
[0] = islower(c
) ? toupper(c
) : tolower(c
);
679 pref
= lnmode
? uc_dup("") : uc_sub(lbuf_get(xb
, r1
), 0, o1
);
680 post
= lnmode
? uc_dup("\n") : uc_sub(lbuf_get(xb
, r2
), o2
, -1);
682 struct sbuf
*sb
= sbuf_make();
684 sbuf_str(sb
, region
);
686 lbuf_edit(xb
, sbuf_buf(sb
), r1
, r2
+ 1);
689 lbuf_edit(xb
, region
, r1
, r2
+ 1);
692 xoff
= lnmode
? lbuf_indents(xb
, r2
) : o2
;
698 static void vi_pipe(int r1
, int r2
)
703 char *cmd
= vi_prompt("!", &kmap
);
706 text
= lbuf_cp(xb
, r1
, r2
+ 1);
707 rep
= cmd_pipe(cmd
, text
, 1, 1);
709 lbuf_edit(xb
, rep
, r1
, r2
+ 1);
715 static void vi_shift(int r1
, int r2
, int dir
)
720 for (i
= r1
; i
<= r2
; i
++) {
721 if (!(ln
= lbuf_get(xb
, i
)))
727 ln
= ln
[0] == ' ' || ln
[0] == '\t' ? ln
+ 1 : ln
;
729 lbuf_edit(xb
, sbuf_buf(sb
), i
, i
+ 1);
733 xoff
= lbuf_indents(xb
, xrow
);
736 static int vc_motion(int cmd
)
738 int r1
= xrow
, r2
= xrow
; /* region rows */
739 int o1
= xoff
, o2
= xoff
; /* visual region columns */
740 int lnmode
= 0; /* line-based region */
742 vi_arg2
= vi_prefix();
745 o1
= ren_noeol(lbuf_get(xb
, r1
), o1
);
747 if ((mv
= vi_motionln(&r2
, cmd
))) {
749 } else if (!(mv
= vi_motion(&r2
, &o2
))) {
758 o2
= lbuf_eol(xb
, r2
);
764 if (r1
== r2
&& o1
> o2
)
766 o1
= ren_noeol(lbuf_get(xb
, r1
), o1
);
767 if (!lnmode
&& strchr("fFtTeE%", mv
))
768 if (o2
< lbuf_eol(xb
, r2
))
769 o2
= ren_noeol(lbuf_get(xb
, r2
), o2
) + 1;
771 vi_yank(r1
, o1
, r2
, o2
, lnmode
);
773 vi_delete(r1
, o1
, r2
, o2
, lnmode
);
775 vi_change(r1
, o1
, r2
, o2
, lnmode
);
776 if (cmd
== '~' || cmd
== 'u' || cmd
== 'U')
777 vi_case(r1
, o1
, r2
, o2
, lnmode
, cmd
);
780 if (cmd
== '>' || cmd
== '<')
781 vi_shift(r1
, r2
, cmd
== '>' ? +1 : -1);
785 static int vc_insert(int cmd
)
788 char *ln
= lbuf_get(xb
, xrow
);
792 xoff
= lbuf_indents(xb
, xrow
);
794 xoff
= lbuf_eol(xb
, xrow
);
795 xoff
= ren_noeol(ln
, xoff
);
798 if (cmd
== 'i' || cmd
== 'I')
800 if (cmd
== 'a' || cmd
== 'A')
802 if (ln
&& ln
[0] == '\n')
804 pref
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, 0, off
) : vi_indents(ln
);
805 post
= ln
&& cmd
!= 'o' && cmd
!= 'O' ? uc_sub(ln
, off
, -1) : uc_dup("\n");
806 vi_drawrm(xrow
, xrow
, cmd
== 'o' || cmd
== 'O');
807 rep
= vi_input(pref
, post
, &row
, &off
);
808 if ((cmd
== 'o' || cmd
== 'O') && !lbuf_len(xb
))
809 lbuf_edit(xb
, "\n", 0, 0);
811 lbuf_edit(xb
, rep
, xrow
, xrow
+ (cmd
!= 'o' && cmd
!= 'O'));
821 static int vc_put(int cmd
)
823 int cnt
= MAX(1, vi_arg1
);
825 char *buf
= reg_get(vi_ybuf
, &lnmode
);
828 snprintf(vi_msg
, sizeof(vi_msg
), "yank buffer empty\n");
832 struct sbuf
*sb
= sbuf_make();
833 for (i
= 0; i
< cnt
; i
++)
836 lbuf_edit(xb
, "\n", 0, 0);
839 lbuf_edit(xb
, sbuf_buf(sb
), xrow
, xrow
);
840 xoff
= lbuf_indents(xb
, xrow
);
843 struct sbuf
*sb
= sbuf_make();
844 char *ln
= xrow
< lbuf_len(xb
) ? lbuf_get(xb
, xrow
) : "\n";
845 int off
= ren_noeol(ln
, xoff
) + (ln
[0] != '\n' && cmd
== 'p');
846 char *s
= uc_sub(ln
, 0, off
);
849 for (i
= 0; i
< cnt
; i
++)
851 s
= uc_sub(ln
, off
, -1);
854 lbuf_edit(xb
, sbuf_buf(sb
), xrow
, xrow
+ 1);
855 xoff
= off
+ uc_slen(buf
) * cnt
- 1;
861 static int join_spaces(char *prev
, char *next
)
863 int prevlen
= strlen(prev
);
866 if (prev
[prevlen
- 1] == ' ' || next
[0] == ')')
868 return prev
[prevlen
- 1] == '.' ? 2 : 1;
871 static int vc_join(void)
874 int cnt
= vi_arg1
<= 1 ? 2 : vi_arg1
;
876 int end
= xrow
+ cnt
;
879 if (!lbuf_get(xb
, beg
) || !lbuf_get(xb
, end
- 1))
882 for (i
= beg
; i
< end
; i
++) {
883 char *ln
= lbuf_get(xb
, i
);
884 char *lnend
= strchr(ln
, '\n');
887 while (ln
[0] == ' ' || ln
[0] == '\t')
889 spaces
= i
> beg
? join_spaces(sbuf_buf(sb
), ln
) : 0;
890 off
= uc_slen(sbuf_buf(sb
));
893 sbuf_mem(sb
, ln
, lnend
- ln
);
896 lbuf_edit(xb
, sbuf_buf(sb
), beg
, end
);
902 static int vi_scrollforeward(int cnt
)
904 if (xtop
>= lbuf_len(xb
) - 1)
906 xtop
= MIN(lbuf_len(xb
) - 1, xtop
+ cnt
);
907 xrow
= MAX(xrow
, xtop
);
911 static int vi_scrollbackward(int cnt
)
915 xtop
= MAX(0, xtop
- cnt
);
916 xrow
= MIN(xrow
, xtop
+ xrows
- 1);
920 static void vc_status(void)
922 int col
= vi_off2col(xb
, xrow
, xoff
);
923 snprintf(vi_msg
, sizeof(vi_msg
),
924 "\"%s\"%c %d lines L%d C%d\n",
925 ex_path()[0] ? ex_path() : "unnamed",
926 lbuf_modified(xb
) ? '*' : ' ',
927 lbuf_len(xb
), xrow
+ 1,
928 ren_cursor(lbuf_get(xb
, xrow
), col
) + 1);
931 static int vc_replace(void)
933 int cnt
= MAX(1, vi_arg1
);
934 char *cs
= vi_char();
935 char *ln
= lbuf_get(xb
, xrow
);
942 off
= ren_noeol(ln
, xoff
);
944 for (i
= 0; s
[0] != '\n' && i
< cnt
; i
++)
948 pref
= uc_sub(ln
, 0, off
);
949 post
= uc_sub(ln
, off
+ cnt
, -1);
952 for (i
= 0; i
< cnt
; i
++)
955 lbuf_edit(xb
, sbuf_buf(sb
), xrow
, xrow
+ 1);
964 static char rep_cmd
[4096]; /* the last command */
967 static void vc_repeat(void)
969 term_push(rep_cmd
, rep_len
);
972 static void vc_execute(void)
983 buf
= reg_get(exec_buf
, &lnmode
);
985 term_push(buf
, strlen(buf
));
994 xtop
= MAX(0, xrow
- xrows
/ 2);
996 xcol
= vi_off2col(xb
, xrow
, xoff
);
998 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
), xcol
));
1002 int noff
= ren_noeol(lbuf_get(xb
, xrow
), xoff
);
1008 vi_ybuf
= vi_yankbuf();
1009 vi_arg1
= vi_prefix();
1011 vi_ybuf
= vi_yankbuf();
1012 mv
= vi_motion(&nrow
, &noff
);
1014 if (strchr("\'`GHML/?{}[]nN", mv
) ||
1015 (mv
== '%' && noff
< 0)) {
1016 lbuf_mark(xb
, '\'', xrow
, xoff
);
1017 lbuf_mark(xb
, '`', xrow
, xoff
);
1020 if (noff
< 0 && !strchr("jk", mv
))
1021 noff
= lbuf_indents(xb
, xrow
);
1022 if (strchr("jk", mv
))
1023 noff
= vi_col2off(xb
, xrow
, xcol
);
1024 xoff
= ren_noeol(lbuf_get(xb
, xrow
), noff
);
1025 if (!strchr("|jk", mv
))
1026 xcol
= vi_off2col(xb
, xrow
, xoff
);
1029 } else if (mv
== 0) {
1035 lbuf_mark(xb
, '*', xrow
, xoff
);
1038 if (vi_scrollbackward(MAX(1, vi_arg1
) * (xrows
- 1)))
1040 xoff
= lbuf_indents(xb
, xrow
);
1044 if (vi_scrollforeward(MAX(1, vi_arg1
) * (xrows
- 1)))
1046 xoff
= lbuf_indents(xb
, xrow
);
1050 if (vi_scrollforeward(MAX(1, vi_arg1
)))
1055 if (vi_scrollbackward(MAX(1, vi_arg1
)))
1063 vi_scroll
= vi_arg1
;
1064 n
= vi_scroll
? vi_scroll
: xrows
/ 2;
1065 xrow
= MAX(0, xrow
- n
);
1067 xtop
= MAX(0, xtop
- n
);
1069 xoff
= lbuf_indents(xb
, xrow
);
1072 if (xrow
== lbuf_len(xb
) - 1)
1075 vi_scroll
= vi_arg1
;
1076 n
= vi_scroll
? vi_scroll
: xrows
/ 2;
1077 xrow
= MIN(MAX(0, lbuf_len(xb
) - 1), xrow
+ n
);
1078 if (xtop
< lbuf_len(xb
) - xrows
)
1079 xtop
= MIN(lbuf_len(xb
) - xrows
, xtop
+ n
);
1081 xoff
= lbuf_indents(xb
, xrow
);
1089 if (!lbuf_undo(xb
)) {
1090 lbuf_jump(xb
, '*', &xrow
, &xoff
);
1093 snprintf(vi_msg
, sizeof(vi_msg
), "undo failed\n");
1097 if (!lbuf_redo(xb
)) {
1098 lbuf_jump(xb
, '*', &xrow
, &xoff
);
1101 snprintf(vi_msg
, sizeof(vi_msg
), "redo failed\n");
1112 ln
= vi_prompt(":", &kmap
);
1147 if ((mark
= vi_read()) > 0 && islower(mark
))
1148 lbuf_mark(xb
, mark
, xrow
, xoff
);
1159 xtop
= vi_arg1
? vi_arg1
: xrow
;
1162 n
= vi_arg1
? vi_arg1
: xrow
;
1163 xtop
= MAX(0, n
- xrows
/ 2);
1166 n
= vi_arg1
? vi_arg1
: xrow
;
1167 xtop
= MAX(0, n
- xrows
+ 1);
1171 xdir
= k
== 'r' ? -1 : +1;
1175 xdir
= k
== 'R' ? -2 : +2;
1182 if (k
== '~' || k
== 'u' || k
== 'U')
1188 if (!vc_motion('d'))
1192 vi_back(TK_CTL('h'));
1193 if (!vc_motion('d'))
1198 if (!vc_motion('c'))
1203 if (!vc_motion('d'))
1212 if (!vc_motion('c'))
1217 if (!vc_motion('c'))
1222 if (!vc_motion('y'))
1232 if (!vc_motion('~'))
1245 if (strchr("!<>ACDIJOPRSXYacdioprsxy~", c
)) {
1246 if (n
< sizeof(rep_cmd
)) {
1247 memcpy(rep_cmd
, cmd
, n
);
1252 if (xrow
< 0 || xrow
>= lbuf_len(xb
))
1253 xrow
= lbuf_len(xb
) ? lbuf_len(xb
) - 1 : 0;
1255 xtop
= xtop
- xrows
/ 2 > xrow
?
1256 MAX(0, xrow
- xrows
/ 2) : xrow
;
1257 if (xtop
+ xrows
<= xrow
)
1258 xtop
= xtop
+ xrows
+ xrows
/ 2 <= xrow
?
1259 xrow
- xrows
/ 2 : xrow
- xrows
+ 1;
1260 xoff
= ren_noeol(lbuf_get(xb
, xrow
), xoff
);
1262 xcol
= vi_off2col(xb
, xrow
, xoff
);
1263 if (xcol
>= xleft
+ xcols
)
1264 xleft
= xcol
- xcols
/ 2;
1266 xleft
= xcol
< xcols
? 0 : xcol
- xcols
/ 2;
1268 if (redraw
|| xtop
!= otop
|| xleft
!= oleft
)
1272 term_pos(xrow
- xtop
, led_pos(lbuf_get(xb
, xrow
),
1273 ren_cursor(lbuf_get(xb
, xrow
), xcol
)));
1280 int main(int argc
, char *argv
[])
1284 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
1285 if (argv
[i
][1] == 's')
1287 if (argv
[i
][1] == 'e')
1289 if (argv
[i
][1] == 'v')
1296 if (!ex_init(argv
+ i
)) {