1 /* $OpenBSD: vi.c,v 1.26 2009/06/29 22:50:19 martynas Exp $ */
5 * written by John Rochester (initially for nsh)
6 * bludgeoned to fit pdksh by Larry Bouzane, Jeff Sparkes & Eric Gisin
14 #include <sys/stat.h> /* completion */
18 #define Ctrl(c) (c&0x1f)
19 #define is_wordch(c) (letnum(c))
30 static int vi_hook(int);
31 static void vi_reset(char *, size_t);
32 static int nextstate(int);
33 static int vi_insert(int);
34 static int vi_cmd(int, const char *);
35 static int domove(int, const char *, int);
36 static int redo_insert(int);
37 static void yank_range(int, int);
38 static int bracktype(int);
39 static void save_cbuf(void);
40 static void restore_cbuf(void);
41 static void edit_reset(char *, size_t);
42 static int putbuf(const char *, int, int);
43 static void del_range(int, int);
44 static int findch(int, int, int, int);
45 static int forwword(int);
46 static int backword(int);
47 static int endword(int);
48 static int Forwword(int);
49 static int Backword(int);
50 static int Endword(int);
51 static int grabhist(int, int);
52 static int grabsearch(int, int, int, char *);
53 static void redraw_line(int);
54 static void refresh(int);
55 static int outofwin(void);
56 static void rewindow(void);
57 static int newcol(int, int);
58 static void display(char *, char *, int);
59 static void ed_mov_opt(int, char *);
60 static int expand_word(int);
61 static int complete_word(int, int);
62 static int print_expansions(struct edstate
*, int);
63 static int char_len(int);
64 static void x_vi_zotc(int);
65 static void vi_pprompt(int);
66 static void vi_error(void);
67 static void vi_macro_reset(void);
68 static int x_vi_putbuf(const char *, size_t);
70 #define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */
71 #define M_ 0x2 /* movement command (h, l, etc.) */
72 #define E_ 0x4 /* extended command (c, d, y) */
73 #define X_ 0x8 /* long command (@, f, F, t, T, etc.) */
74 #define U_ 0x10 /* an UN-undoable command (that isn't a M_) */
75 #define B_ 0x20 /* bad command (^@) */
76 #define Z_ 0x40 /* repeat count defaults to 0 (not 1) */
77 #define S_ 0x80 /* search (/, ?) */
79 #define is_bad(c) (classify[(c)&0x7f]&B_)
80 #define is_cmd(c) (classify[(c)&0x7f]&(M_|E_|C_|U_))
81 #define is_move(c) (classify[(c)&0x7f]&M_)
82 #define is_extend(c) (classify[(c)&0x7f]&E_)
83 #define is_long(c) (classify[(c)&0x7f]&X_)
84 #define is_undoable(c) (!(classify[(c)&0x7f]&U_))
85 #define is_srch(c) (classify[(c)&0x7f]&S_)
86 #define is_zerocount(c) (classify[(c)&0x7f]&Z_)
88 const unsigned char classify
[128] = {
90 /* 0 ^@ ^A ^B ^C ^D ^E ^F ^G */
91 B_
, 0, 0, 0, 0, C_
|U_
, C_
|Z_
, 0,
92 /* 01 ^H ^I ^J ^K ^L ^M ^N ^O */
93 M_
, C_
|Z_
, 0, 0, C_
|U_
, 0, C_
, 0,
94 /* 02 ^P ^Q ^R ^S ^T ^U ^V ^W */
95 C_
, 0, C_
|U_
, 0, 0, 0, C_
, 0,
96 /* 03 ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
97 C_
, 0, 0, C_
|Z_
, 0, 0, 0, 0,
98 /* 04 <space> ! " # $ % & ' */
99 M_
, 0, 0, C_
, M_
, M_
, 0, 0,
100 /* 05 ( ) * + , - . / */
101 0, 0, C_
, C_
, M_
, C_
, 0, C_
|S_
,
102 /* 06 0 1 2 3 4 5 6 7 */
103 M_
, 0, 0, 0, 0, 0, 0, 0,
104 /* 07 8 9 : ; < = > ? */
105 0, 0, 0, M_
, 0, C_
, 0, C_
|S_
,
106 /* 010 @ A B C D E F G */
107 C_
|X_
, C_
, M_
, C_
, C_
, M_
, M_
|X_
, C_
|U_
|Z_
,
108 /* 011 H I J K L M N O */
109 0, C_
, 0, 0, 0, 0, C_
|U_
, 0,
110 /* 012 P Q R S T U V W */
111 C_
, 0, C_
, C_
, M_
|X_
, C_
, 0, M_
,
112 /* 013 X Y Z [ \ ] ^ _ */
113 C_
, C_
|U_
, 0, 0, C_
|Z_
, 0, M_
, C_
|Z_
,
114 /* 014 ` a b c d e f g */
115 0, C_
, M_
, E_
, E_
, M_
, M_
|X_
, C_
|Z_
,
116 /* 015 h i j k l m n o */
117 M_
, C_
, C_
|U_
, C_
|U_
, M_
, 0, C_
|U_
, 0,
118 /* 016 p q r s t u v w */
119 C_
, 0, X_
, C_
, M_
|X_
, C_
|U_
, C_
|U_
|Z_
,M_
,
120 /* 017 x y z { | } ~ ^? */
121 C_
, E_
|U_
, 0, 0, M_
|Z_
, 0, C_
, 0
130 #define VNORMAL 0 /* command, insert or replace mode */
131 #define VARG1 1 /* digit prefix (first, eg, 5l) */
132 #define VEXTCMD 2 /* cmd + movement (eg, cl) */
133 #define VARG2 3 /* digit prefix (second, eg, 2c3l) */
134 #define VXCH 4 /* f, F, t, T, @ */
135 #define VFAIL 5 /* bad command */
136 #define VCMD 6 /* single char command (eg, X) */
137 #define VREDO 7 /* . */
138 #define VLIT 8 /* ^V */
139 #define VSEARCH 9 /* /, ? */
140 #define VVERSION 10 /* <ESC> ^V */
142 static char undocbuf
[CMDLEN
];
144 static struct edstate
*save_edstate(struct edstate
*old
);
145 static void restore_edstate(struct edstate
*old
, struct edstate
*new);
146 static void free_edstate(struct edstate
*old
);
148 static struct edstate ebuf
;
149 static struct edstate undobuf
= { 0, undocbuf
, CMDLEN
, 0, 0 };
151 static struct edstate
*es
; /* current editor state */
152 static struct edstate
*undo
;
154 static char ibuf
[CMDLEN
]; /* input buffer */
155 static int first_insert
; /* set when starting in insert mode */
156 static int saved_inslen
; /* saved inslen for first insert */
157 static int inslen
; /* length of input buffer */
158 static int srchlen
; /* length of current search pattern */
159 static char ybuf
[CMDLEN
]; /* yank buffer */
160 static int yanklen
; /* length of yank buffer */
161 static int fsavecmd
= ' '; /* last find command */
162 static int fsavech
; /* character to find */
163 static char lastcmd
[MAXVICMD
]; /* last non-move command */
164 static int lastac
; /* argcnt for lastcmd */
165 static int lastsearch
= ' '; /* last search command */
166 static char srchpat
[SRCHLEN
]; /* last search pattern */
167 static int insert
; /* non-zero in insert mode */
168 static int hnum
; /* position in history */
169 static int ohnum
; /* history line copied (after mod) */
170 static int hlast
; /* 1 past last position in history */
171 static int modified
; /* buffer has been "modified" */
174 /* Information for keeping track of macros that are being expanded.
175 * The format of buf is the alias contents followed by a null byte followed
176 * by the name (letter) of the alias. The end of the buffer is marked by
177 * a double null. The name of the alias is stored so recursive macros can
181 unsigned char *p
; /* current position in buf */
182 unsigned char *buf
; /* pointer to macro(s) being expanded */
183 int len
; /* how much data in buffer */
185 static struct macro_state macro
;
187 enum expand_mode
{ NONE
, EXPAND
, COMPLETE
, PRINT
};
188 static enum expand_mode expanded
= NONE
;/* last input was expanded */
191 x_vi(char *buf
, size_t len
)
195 vi_reset(buf
, len
> CMDLEN
? CMDLEN
: len
);
201 /* end of current macro? */
203 /* more macros left to finish? */
206 /* must be the end of all the macros */
216 if (c
== edchars
.intr
|| c
== edchars
.quit
) {
217 /* pretend we got an interrupt */
220 trapsig(c
== edchars
.intr
? SIGINT
: SIGQUIT
);
223 } else if (c
== edchars
.eof
&& state
!= VVERSION
) {
224 if (es
->linelen
== 0) {
225 x_vi_zotc(edchars
.eof
);
237 x_putc('\r'); x_putc('\n'); x_flush();
239 if (c
== -1 || len
<= es
->linelen
)
243 memmove(buf
, es
->cbuf
, es
->linelen
);
245 buf
[es
->linelen
++] = '\n';
253 static char curcmd
[MAXVICMD
], locpat
[SRCHLEN
];
254 static int cmdlen
, argc1
, argc2
;
260 if (ch
== Ctrl('v')) {
264 switch (vi_insert(ch
)) {
274 refresh(insert
!= 0);
280 if (ch
== '\r' || ch
== '\n')
284 if (ch
>= '1' && ch
<= '9') {
288 curcmd
[cmdlen
++] = ch
;
289 state
= nextstate(ch
);
290 if (state
== VSEARCH
) {
295 if (putbuf("/", 1, 0) != 0)
297 } else if (putbuf("?", 1, 0) != 0)
301 if (state
== VVERSION
) {
305 putbuf(ksh_version
+ 4,
306 strlen(ksh_version
+ 4), 0);
315 del_range(es
->cursor
, es
->cursor
+ 1);
318 es
->cbuf
[es
->cursor
++] = ch
;
331 argc1
= argc1
* 10 + ch
- '0';
333 curcmd
[cmdlen
++] = ch
;
334 state
= nextstate(ch
);
340 if (ch
>= '1' && ch
<= '9') {
345 curcmd
[cmdlen
++] = ch
;
348 else if (is_move(ch
))
349 state
= nextstate(ch
);
357 argc2
= argc2
* 10 + ch
- '0';
363 curcmd
[cmdlen
++] = ch
;
366 else if (is_move(ch
))
367 state
= nextstate(ch
);
377 curcmd
[cmdlen
++] = ch
;
383 if (ch
== '\r' || ch
== '\n' /*|| ch == Ctrl('[')*/ ) {
385 /* Repeat last search? */
394 locpat
[srchlen
] = '\0';
395 (void) strlcpy(srchpat
, locpat
, sizeof srchpat
);
398 } else if (ch
== edchars
.erase
|| ch
== Ctrl('h')) {
401 es
->linelen
-= char_len((unsigned char)locpat
[srchlen
]);
402 es
->cursor
= es
->linelen
;
409 } else if (ch
== edchars
.kill
) {
415 } else if (ch
== edchars
.werase
) {
416 struct edstate new_es
, *save_es
;
421 new_es
.cbuf
= locpat
;
428 for (i
= srchlen
; --i
>= n
; )
429 es
->linelen
-= char_len((unsigned char)locpat
[i
]);
431 es
->cursor
= es
->linelen
;
435 if (srchlen
== SRCHLEN
- 1)
438 locpat
[srchlen
++] = ch
;
439 if ((ch
& 0x80) && Flag(FVISHOW8
)) {
440 if (es
->linelen
+ 2 > es
->cbufsize
)
442 es
->cbuf
[es
->linelen
++] = 'M';
443 es
->cbuf
[es
->linelen
++] = '-';
446 if (ch
< ' ' || ch
== 0x7f) {
447 if (es
->linelen
+ 2 > es
->cbufsize
)
449 es
->cbuf
[es
->linelen
++] = '^';
450 es
->cbuf
[es
->linelen
++] = ch
^ '@';
452 if (es
->linelen
>= es
->cbufsize
)
454 es
->cbuf
[es
->linelen
++] = ch
;
456 es
->cursor
= es
->linelen
;
467 switch (vi_cmd(argc1
, curcmd
)) {
475 refresh(insert
!= 0);
481 /* back from a 'v' command - don't redraw the screen */
490 switch (vi_cmd(lastac
, lastcmd
)) {
497 if (lastcmd
[0] == 's' || lastcmd
[0] == 'c' ||
499 if (redo_insert(1) != 0)
502 if (redo_insert(lastac
) != 0)
512 /* back from a 'v' command - can't happen */
526 vi_reset(char *buf
, size_t len
)
529 ohnum
= hnum
= hlast
= histnum(-1) + 1;
531 saved_inslen
= inslen
;
536 edit_reset(buf
, len
);
544 else if (is_srch(ch
))
546 else if (is_long(ch
))
550 else if (ch
== Ctrl('v'))
563 if (ch
== edchars
.erase
|| ch
== Ctrl('h')) {
564 if (insert
== REPLACE
) {
565 if (es
->cursor
== undo
->cursor
) {
572 if (es
->cursor
>= undo
->linelen
)
575 es
->cbuf
[es
->cursor
] = undo
->cbuf
[es
->cursor
];
577 if (es
->cursor
== 0) {
578 /* x_putc(BEL); no annoying bell here */
585 memmove(&es
->cbuf
[es
->cursor
], &es
->cbuf
[es
->cursor
+1],
586 es
->linelen
- es
->cursor
+ 1);
591 if (ch
== edchars
.kill
) {
592 if (es
->cursor
!= 0) {
594 memmove(es
->cbuf
, &es
->cbuf
[es
->cursor
],
595 es
->linelen
- es
->cursor
);
596 es
->linelen
-= es
->cursor
;
602 if (ch
== edchars
.werase
) {
603 if (es
->cursor
!= 0) {
604 tcursor
= backword(1);
605 memmove(&es
->cbuf
[tcursor
], &es
->cbuf
[es
->cursor
],
606 es
->linelen
- es
->cursor
);
607 es
->linelen
-= es
->cursor
- tcursor
;
608 if (inslen
< es
->cursor
- tcursor
)
611 inslen
-= es
->cursor
- tcursor
;
612 es
->cursor
= tcursor
;
617 /* If any chars are entered before escape, trash the saved insert
618 * buffer (if user inserts & deletes char, ibuf gets trashed and
619 * we don't want to use it)
621 if (first_insert
&& ch
!= Ctrl('['))
636 inslen
= saved_inslen
;
637 return redo_insert(0);
642 if (lastcmd
[0] == 's' || lastcmd
[0] == 'c' ||
644 return redo_insert(0);
646 return redo_insert(lastac
- 1);
648 /* { Begin nonstandard vi commands */
658 print_expansions(es
, 0);
662 if (Flag(FVITABCOMPLETE
)) {
667 /* End nonstandard vi commands } */
670 if (es
->linelen
>= es
->cbufsize
- 1)
673 if (insert
== INSERT
) {
674 memmove(&es
->cbuf
[es
->cursor
+1], &es
->cbuf
[es
->cursor
],
675 es
->linelen
- es
->cursor
);
678 es
->cbuf
[es
->cursor
++] = ch
;
679 if (insert
== REPLACE
&& es
->cursor
> es
->linelen
)
687 vi_cmd(int argcnt
, const char *cmd
)
690 int cur
, c1
, c2
, c3
= 0;
694 if (argcnt
== 0 && !is_zerocount(*cmd
))
698 if ((cur
= domove(argcnt
, cmd
, 0)) >= 0) {
699 if (cur
== es
->linelen
&& cur
!= 0)
705 /* Don't save state in middle of macro.. */
706 if (is_undoable(*cmd
) && !macro
.p
) {
707 undo
->winleft
= es
->winleft
;
708 memmove(undo
->cbuf
, es
->cbuf
, es
->linelen
);
709 undo
->linelen
= es
->linelen
;
710 undo
->cursor
= es
->cursor
;
712 memmove(lastcmd
, cmd
, MAXVICMD
);
723 static char alias
[] = "_\0";
728 /* lookup letter in alias list... */
730 ap
= ktsearch(&aliases
, alias
, hash(alias
));
731 if (!cmd
[1] || !ap
|| !(ap
->flag
& ISSET
))
733 /* check if this is a recursive call... */
734 if ((p
= (char *) macro
.p
))
735 while ((p
= strchr(p
, '\0')) && p
[1])
738 /* insert alias into macro buffer */
739 nlen
= strlen(ap
->val
.s
) + 1;
740 olen
= !macro
.p
? 2 :
741 macro
.len
- (macro
.p
- macro
.buf
);
742 nbuf
= alloc(nlen
+ 1 + olen
, APERM
);
743 memcpy(nbuf
, ap
->val
.s
, nlen
);
744 nbuf
[nlen
++] = cmd
[1];
746 memcpy(nbuf
+ nlen
, macro
.p
, olen
);
747 afree(macro
.buf
, APERM
);
753 macro
.p
= macro
.buf
= (unsigned char *) nbuf
;
759 modified
= 1; hnum
= hlast
;
760 if (es
->linelen
!= 0)
766 modified
= 1; hnum
= hlast
;
768 es
->cursor
= es
->linelen
;
773 es
->cursor
= domove(1, "^", 1);
774 del_range(es
->cursor
, es
->linelen
);
775 modified
= 1; hnum
= hlast
;
785 if (*cmd
== cmd
[1]) {
786 c1
= *cmd
== 'c' ? domove(1, "^", 1) : 0;
788 } else if (!is_move(cmd
[1]))
791 if ((ncursor
= domove(argcnt
, &cmd
[1], 1)) < 0)
794 (cmd
[1]=='w' || cmd
[1]=='W') &&
795 !isspace(es
->cbuf
[es
->cursor
])) {
796 while (isspace(es
->cbuf
[--ncursor
]))
800 if (ncursor
> es
->cursor
) {
810 if (*cmd
!= 'c' && c1
!= c2
)
817 modified
= 1; hnum
= hlast
;
823 modified
= 1; hnum
= hlast
;
824 if (es
->linelen
!= 0)
826 while (putbuf(ybuf
, yanklen
, 0) == 0 && --argcnt
> 0)
835 modified
= 1; hnum
= hlast
;
837 while (putbuf(ybuf
, yanklen
, 0) == 0 && --argcnt
> 0)
839 if (any
&& es
->cursor
!= 0)
846 modified
= 1; hnum
= hlast
;
847 del_range(es
->cursor
, es
->linelen
);
852 yank_range(es
->cursor
, es
->linelen
);
853 del_range(es
->cursor
, es
->linelen
);
866 argcnt
= hlast
- (source
->line
- argcnt
);
867 if (grabhist(modified
, argcnt
- 1) < 0)
876 modified
= 1; hnum
= hlast
;
881 modified
= 1; hnum
= hlast
;
882 es
->cursor
= domove(1, "^", 1);
889 if (grabhist(modified
, hnum
+ argcnt
) < 0)
900 if (grabhist(modified
, hnum
- argcnt
) < 0)
909 if (es
->linelen
== 0)
911 modified
= 1; hnum
= hlast
;
917 if (es
->cursor
+ argcnt
> es
->linelen
)
919 for (n
= 0; n
< argcnt
; ++n
)
920 es
->cbuf
[es
->cursor
+ n
] = cmd
[1];
926 modified
= 1; hnum
= hlast
;
931 if (es
->linelen
== 0)
933 modified
= 1; hnum
= hlast
;
934 if (es
->cursor
+ argcnt
> es
->linelen
)
935 argcnt
= es
->linelen
- es
->cursor
;
936 del_range(es
->cursor
, es
->cursor
+ argcnt
);
941 if (es
->linelen
== 0 && argcnt
== 0)
945 es
->cbuf
[es
->linelen
] = '\0';
947 histsave(source
->line
, es
->cbuf
, 1);
949 argcnt
= source
->line
+ 1
952 shf_snprintf(es
->cbuf
, es
->cbufsize
,
953 argcnt
? "%s %d" : "%s",
954 "fc -e ${VISUAL:-${EDITOR:-vi}} --",
956 es
->linelen
= strlen(es
->cbuf
);
960 if (es
->linelen
== 0)
962 modified
= 1; hnum
= hlast
;
963 if (es
->cursor
+ argcnt
> es
->linelen
)
964 argcnt
= es
->linelen
- es
->cursor
;
965 yank_range(es
->cursor
, es
->cursor
+ argcnt
);
966 del_range(es
->cursor
, es
->cursor
+ argcnt
);
970 if (es
->cursor
> 0) {
971 modified
= 1; hnum
= hlast
;
972 if (es
->cursor
< argcnt
)
974 yank_range(es
->cursor
- argcnt
, es
->cursor
);
975 del_range(es
->cursor
- argcnt
, es
->cursor
);
976 es
->cursor
-= argcnt
;
990 if (grabhist(modified
, ohnum
) < 0)
1007 if (lastsearch
== ' ')
1009 if (lastsearch
== '?')
1015 if ((c2
= grabsearch(modified
, hnum
,
1016 c1
, srchpat
)) < 0) {
1032 if (histnum(-1) < 0)
1035 #define issp(c) (isspace((c)) || (c) == '\n')
1037 while (*p
&& issp(*p
))
1039 while (*p
&& --argcnt
) {
1040 while (*p
&& !issp(*p
))
1042 while (*p
&& issp(*p
))
1062 modified
= 1; hnum
= hlast
;
1063 if (es
->cursor
!= es
->linelen
)
1065 while (*p
&& !issp(*p
)) {
1069 if (putbuf(space
, 1, 0) != 0)
1071 else if (putbuf(sp
, argcnt
, 0) != 0)
1074 if (es
->cursor
!= 0)
1086 if (es
->linelen
== 0)
1088 for (i
= 0; i
< argcnt
; i
++) {
1089 p
= &es
->cbuf
[es
->cursor
];
1091 modified
= 1; hnum
= hlast
;
1093 } else if (isupper(*p
)) {
1094 modified
= 1; hnum
= hlast
;
1097 if (es
->cursor
< es
->linelen
- 1)
1105 int ret
= x_do_comment(es
->cbuf
, es
->cbufsize
,
1112 case '=': /* at&t ksh */
1113 case Ctrl('e'): /* Nonstandard vi/ksh */
1114 print_expansions(es
, 1);
1118 case Ctrl('i'): /* Nonstandard vi/ksh */
1119 if (!Flag(FVITABCOMPLETE
))
1121 complete_word(1, argcnt
);
1124 case Ctrl('['): /* some annoying at&t ksh's */
1125 if (!Flag(FVIESCCOMPLETE
))
1127 case '\\': /* at&t ksh */
1128 case Ctrl('f'): /* Nonstandard vi/ksh */
1129 complete_word(1, argcnt
);
1133 case '*': /* at&t ksh */
1134 case Ctrl('x'): /* Nonstandard vi/ksh */
1138 if (insert
== 0 && es
->cursor
!= 0 && es
->cursor
>= es
->linelen
)
1145 domove(int argcnt
, const char *cmd
, int sub
)
1147 int bcount
, i
= 0, t
;
1153 if (!sub
&& es
->cursor
== 0)
1155 ncursor
= backword(argcnt
);
1159 if (!sub
&& es
->cursor
== 0)
1161 ncursor
= Backword(argcnt
);
1165 if (!sub
&& es
->cursor
+ 1 >= es
->linelen
)
1167 ncursor
= endword(argcnt
);
1168 if (sub
&& ncursor
< es
->linelen
)
1173 if (!sub
&& es
->cursor
+ 1 >= es
->linelen
)
1175 ncursor
= Endword(argcnt
);
1176 if (sub
&& ncursor
< es
->linelen
)
1190 if (fsavecmd
== ' ')
1192 i
= fsavecmd
== 'f' || fsavecmd
== 'F';
1196 if ((ncursor
= findch(fsavech
, argcnt
, t
, i
)) < 0)
1204 if (!sub
&& es
->cursor
== 0)
1206 ncursor
= es
->cursor
- argcnt
;
1213 if (!sub
&& es
->cursor
+ 1 >= es
->linelen
)
1215 if (es
->linelen
!= 0) {
1216 ncursor
= es
->cursor
+ argcnt
;
1217 if (ncursor
> es
->linelen
)
1218 ncursor
= es
->linelen
;
1223 if (!sub
&& es
->cursor
+ 1 >= es
->linelen
)
1225 ncursor
= forwword(argcnt
);
1229 if (!sub
&& es
->cursor
+ 1 >= es
->linelen
)
1231 ncursor
= Forwword(argcnt
);
1240 while (ncursor
< es
->linelen
- 1 && isspace(es
->cbuf
[ncursor
]))
1246 if (ncursor
> es
->linelen
)
1247 ncursor
= es
->linelen
;
1253 if (es
->linelen
!= 0)
1254 ncursor
= es
->linelen
;
1260 ncursor
= es
->cursor
;
1261 while (ncursor
< es
->linelen
&&
1262 (i
= bracktype(es
->cbuf
[ncursor
])) == 0)
1264 if (ncursor
== es
->linelen
)
1269 if (++ncursor
>= es
->linelen
)
1275 t
= bracktype(es
->cbuf
[ncursor
]);
1280 } while (bcount
!= 0);
1292 redo_insert(int count
)
1295 if (putbuf(ibuf
, inslen
, insert
==REPLACE
) != 0)
1304 yank_range(int a
, int b
)
1308 memmove(ybuf
, &es
->cbuf
[a
], yanklen
);
1340 * Non user interface editor routines below here
1343 static int cur_col
; /* current column on line */
1344 static int pwidth
; /* width of prompt */
1345 static int prompt_trunc
; /* how much of prompt to truncate */
1346 static int prompt_skip
; /* how much of prompt to skip */
1347 static int winwidth
; /* width of window */
1348 static char *wbuf
[2]; /* window buffers */
1349 static int wbuf_len
; /* length of window buffers (x_cols-3)*/
1350 static int win
; /* window buffer in use */
1351 static char morec
; /* more character at right of window */
1352 static int lastref
; /* argument to last refresh() */
1353 static char holdbuf
[CMDLEN
]; /* place to hold last edit buffer */
1354 static int holdlen
; /* length of holdbuf */
1359 memmove(holdbuf
, es
->cbuf
, es
->linelen
);
1360 holdlen
= es
->linelen
;
1361 holdbuf
[holdlen
] = '\0';
1368 es
->linelen
= holdlen
;
1369 memmove(es
->cbuf
, holdbuf
, holdlen
);
1372 /* return a new edstate */
1373 static struct edstate
*
1374 save_edstate(struct edstate
*old
)
1376 struct edstate
*new;
1378 new = (struct edstate
*)alloc(sizeof(struct edstate
), APERM
);
1379 new->cbuf
= alloc(old
->cbufsize
, APERM
);
1380 memcpy(new->cbuf
, old
->cbuf
, old
->linelen
);
1381 new->cbufsize
= old
->cbufsize
;
1382 new->linelen
= old
->linelen
;
1383 new->cursor
= old
->cursor
;
1384 new->winleft
= old
->winleft
;
1389 restore_edstate(struct edstate
*new, struct edstate
*old
)
1391 memcpy(new->cbuf
, old
->cbuf
, old
->linelen
);
1392 new->linelen
= old
->linelen
;
1393 new->cursor
= old
->cursor
;
1394 new->winleft
= old
->winleft
;
1399 free_edstate(struct edstate
*old
)
1401 afree(old
->cbuf
, APERM
);
1402 afree((char *)old
, APERM
);
1408 edit_reset(char *buf
, size_t len
)
1416 undo
->cbufsize
= len
;
1418 es
->linelen
= undo
->linelen
= 0;
1419 es
->cursor
= undo
->cursor
= 0;
1420 es
->winleft
= undo
->winleft
= 0;
1422 cur_col
= pwidth
= promptlen(prompt
, &p
);
1423 prompt_skip
= p
- prompt
;
1424 if (pwidth
> x_cols
- 3 - MIN_EDIT_SPACE
) {
1425 cur_col
= x_cols
- 3 - MIN_EDIT_SPACE
;
1426 prompt_trunc
= pwidth
- cur_col
;
1427 pwidth
-= prompt_trunc
;
1430 if (!wbuf_len
|| wbuf_len
!= x_cols
- 3) {
1431 wbuf_len
= x_cols
- 3;
1432 wbuf
[0] = aresize(wbuf
[0], wbuf_len
, APERM
);
1433 wbuf
[1] = aresize(wbuf
[1], wbuf_len
, APERM
);
1435 (void) memset(wbuf
[0], ' ', wbuf_len
);
1436 (void) memset(wbuf
[1], ' ', wbuf_len
);
1437 winwidth
= x_cols
- pwidth
- 3;
1445 * this is used for calling x_escape() in complete_word()
1448 x_vi_putbuf(const char *s
, size_t len
)
1450 return putbuf(s
, len
, 0);
1454 putbuf(const char *buf
, int len
, int repl
)
1459 if (es
->cursor
+ len
>= es
->cbufsize
)
1461 if (es
->cursor
+ len
> es
->linelen
)
1462 es
->linelen
= es
->cursor
+ len
;
1464 if (es
->linelen
+ len
>= es
->cbufsize
)
1466 memmove(&es
->cbuf
[es
->cursor
+ len
], &es
->cbuf
[es
->cursor
],
1467 es
->linelen
- es
->cursor
);
1470 memmove(&es
->cbuf
[es
->cursor
], buf
, len
);
1476 del_range(int a
, int b
)
1478 if (es
->linelen
!= b
)
1479 memmove(&es
->cbuf
[a
], &es
->cbuf
[b
], es
->linelen
- b
);
1480 es
->linelen
-= b
- a
;
1484 findch(int ch
, int cnt
, int forw
, int incl
)
1488 if (es
->linelen
== 0)
1490 ncursor
= es
->cursor
;
1494 if (++ncursor
== es
->linelen
)
1500 } while (es
->cbuf
[ncursor
] != ch
);
1512 forwword(int argcnt
)
1516 ncursor
= es
->cursor
;
1517 while (ncursor
< es
->linelen
&& argcnt
--) {
1518 if (is_wordch(es
->cbuf
[ncursor
]))
1519 while (is_wordch(es
->cbuf
[ncursor
]) &&
1520 ncursor
< es
->linelen
)
1522 else if (!isspace(es
->cbuf
[ncursor
]))
1523 while (!is_wordch(es
->cbuf
[ncursor
]) &&
1524 !isspace(es
->cbuf
[ncursor
]) &&
1525 ncursor
< es
->linelen
)
1527 while (isspace(es
->cbuf
[ncursor
]) && ncursor
< es
->linelen
)
1534 backword(int argcnt
)
1538 ncursor
= es
->cursor
;
1539 while (ncursor
> 0 && argcnt
--) {
1540 while (--ncursor
> 0 && isspace(es
->cbuf
[ncursor
]))
1543 if (is_wordch(es
->cbuf
[ncursor
]))
1544 while (--ncursor
>= 0 &&
1545 is_wordch(es
->cbuf
[ncursor
]))
1548 while (--ncursor
>= 0 &&
1549 !is_wordch(es
->cbuf
[ncursor
]) &&
1550 !isspace(es
->cbuf
[ncursor
]))
1563 ncursor
= es
->cursor
;
1564 while (ncursor
< es
->linelen
&& argcnt
--) {
1565 while (++ncursor
< es
->linelen
- 1 &&
1566 isspace(es
->cbuf
[ncursor
]))
1568 if (ncursor
< es
->linelen
- 1) {
1569 if (is_wordch(es
->cbuf
[ncursor
]))
1570 while (++ncursor
< es
->linelen
&&
1571 is_wordch(es
->cbuf
[ncursor
]))
1574 while (++ncursor
< es
->linelen
&&
1575 !is_wordch(es
->cbuf
[ncursor
]) &&
1576 !isspace(es
->cbuf
[ncursor
]))
1585 Forwword(int argcnt
)
1589 ncursor
= es
->cursor
;
1590 while (ncursor
< es
->linelen
&& argcnt
--) {
1591 while (!isspace(es
->cbuf
[ncursor
]) && ncursor
< es
->linelen
)
1593 while (isspace(es
->cbuf
[ncursor
]) && ncursor
< es
->linelen
)
1600 Backword(int argcnt
)
1604 ncursor
= es
->cursor
;
1605 while (ncursor
> 0 && argcnt
--) {
1606 while (--ncursor
>= 0 && isspace(es
->cbuf
[ncursor
]))
1608 while (ncursor
>= 0 && !isspace(es
->cbuf
[ncursor
]))
1620 ncursor
= es
->cursor
;
1621 while (ncursor
< es
->linelen
- 1 && argcnt
--) {
1622 while (++ncursor
< es
->linelen
- 1 &&
1623 isspace(es
->cbuf
[ncursor
]))
1625 if (ncursor
< es
->linelen
- 1) {
1626 while (++ncursor
< es
->linelen
&&
1627 !isspace(es
->cbuf
[ncursor
]))
1636 grabhist(int save
, int n
)
1640 if (n
< 0 || n
> hlast
)
1648 if ((hptr
= *histpos()) == NULL
) {
1649 internal_errorf(0, "grabhist: bad history array");
1654 if ((es
->linelen
= strlen(hptr
)) >= es
->cbufsize
)
1655 es
->linelen
= es
->cbufsize
- 1;
1656 memmove(es
->cbuf
, hptr
, es
->linelen
);
1663 grabsearch(int save
, int start
, int fwd
, char *pat
)
1669 if ((start
== 0 && fwd
== 0) || (start
>= hlast
-1 && fwd
== 1))
1675 anchored
= *pat
== '^' ? (++pat
, 1) : 0;
1676 if ((hist
= findhist(start
, fwd
, pat
, anchored
)) < 0) {
1677 /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
1678 /* XXX should strcmp be strncmp? */
1679 if (start
!= 0 && fwd
&& strcmp(holdbuf
, pat
) >= 0) {
1689 if ((es
->linelen
= strlen(hptr
)) >= es
->cbufsize
)
1690 es
->linelen
= es
->cbufsize
- 1;
1691 memmove(es
->cbuf
, hptr
, es
->linelen
);
1697 redraw_line(int newline
)
1699 (void) memset(wbuf
[win
], ' ', wbuf_len
);
1710 refresh(int leftside
)
1718 display(wbuf
[1 - win
], wbuf
[win
], leftside
);
1727 if (es
->cursor
< es
->winleft
)
1731 while (cur
< es
->cursor
)
1732 col
= newcol((unsigned char) es
->cbuf
[cur
++], col
);
1733 if (col
>= winwidth
)
1742 int holdcur1
, holdcol1
;
1743 int holdcur2
, holdcol2
;
1745 holdcur1
= holdcur2
= tcur
= 0;
1746 holdcol1
= holdcol2
= tcol
= 0;
1747 while (tcur
< es
->cursor
) {
1748 if (tcol
- holdcol2
> winwidth
/ 2) {
1749 holdcur1
= holdcur2
;
1750 holdcol1
= holdcol2
;
1754 tcol
= newcol((unsigned char) es
->cbuf
[tcur
++], tcol
);
1756 while (tcol
- holdcol1
> winwidth
/ 2)
1757 holdcol1
= newcol((unsigned char) es
->cbuf
[holdcur1
++],
1759 es
->winleft
= holdcur1
;
1763 newcol(int ch
, int col
)
1766 return (col
| 7) + 1;
1767 return col
+ char_len(ch
);
1771 display(char *wb1
, char *wb2
, int leftside
)
1774 char *twb1
, *twb2
, mc
;
1783 while (col
< winwidth
&& cur
< es
->linelen
) {
1784 if (cur
== es
->cursor
&& leftside
)
1785 ncol
= col
+ pwidth
;
1786 if ((ch
= es
->cbuf
[cur
]) == '\t') {
1789 } while (++col
< winwidth
&& (col
& 7) != 0);
1791 if ((ch
& 0x80) && Flag(FVISHOW8
)) {
1793 if (++col
< winwidth
) {
1799 if (col
< winwidth
) {
1800 if (ch
< ' ' || ch
== 0x7f) {
1802 if (++col
< winwidth
) {
1812 if (cur
== es
->cursor
&& !leftside
)
1813 ncol
= col
+ pwidth
- 1;
1816 if (cur
== es
->cursor
)
1817 ncol
= col
+ pwidth
;
1818 if (col
< winwidth
) {
1819 while (col
< winwidth
) {
1832 if (*twb1
!= *twb2
) {
1834 ed_mov_opt(col
, wb1
);
1842 if (es
->winleft
> 0 && moreright
)
1843 /* POSIX says to use * for this but that is a globbing
1844 * character and may confuse people; + is more innocuous
1847 else if (es
->winleft
> 0)
1854 ed_mov_opt(pwidth
+ winwidth
+ 1, wb1
);
1859 if (cur_col
!= ncol
)
1860 ed_mov_opt(ncol
, wb1
);
1864 ed_mov_opt(int col
, char *wb
)
1866 if (col
< cur_col
) {
1867 if (col
+ 1 < cur_col
- col
) {
1871 while (cur_col
++ < col
)
1874 while (cur_col
-- > col
)
1878 wb
= &wb
[cur_col
- pwidth
];
1879 while (cur_col
++ < col
)
1886 /* replace word with all expansions (ie, expand word*) */
1888 expand_word(int command
)
1890 static struct edstate
*buf
;
1897 /* Undo previous expansion */
1898 if (command
== 0 && expanded
== EXPAND
&& buf
) {
1899 restore_edstate(es
, buf
);
1909 nwords
= x_cf_glob(XCF_COMMAND_FILE
|XCF_FULLPATH
,
1910 es
->cbuf
, es
->linelen
, es
->cursor
,
1911 &start
, &end
, &words
, (int *) 0);
1917 buf
= save_edstate(es
);
1919 del_range(start
, end
);
1921 for (i
= 0; i
< nwords
; ) {
1922 if (x_escape(words
[i
], strlen(words
[i
]), x_vi_putbuf
) != 0) {
1926 if (++i
< nwords
&& putbuf(space
, 1, 0) != 0) {
1931 i
= buf
->cursor
- end
;
1932 if (rval
== 0 && i
> 0)
1934 modified
= 1; hnum
= hlast
;
1942 complete_word(int command
, int count
)
1944 static struct edstate
*buf
;
1954 /* Undo previous completion */
1955 if (command
== 0 && expanded
== COMPLETE
&& buf
) {
1956 print_expansions(buf
, 0);
1960 if (command
== 0 && expanded
== PRINT
&& buf
) {
1961 restore_edstate(es
, buf
);
1971 /* XCF_FULLPATH for count 'cause the menu printed by print_expansions()
1972 * was done this way.
1974 nwords
= x_cf_glob(XCF_COMMAND_FILE
| (count
? XCF_FULLPATH
: 0),
1975 es
->cbuf
, es
->linelen
, es
->cursor
,
1976 &start
, &end
, &words
, &is_command
);
1985 if (count
>= nwords
) {
1987 x_print_expansions(nwords
, words
, is_command
);
1988 x_free_words(nwords
, words
);
1993 * Expand the count'th word to its basename
1996 match
= words
[count
] +
1997 x_basename(words
[count
], (char *) 0);
1998 /* If more than one possible match, use full path */
1999 for (i
= 0; i
< nwords
; i
++)
2001 strcmp(words
[i
] + x_basename(words
[i
],
2002 (char *) 0), match
) == 0) {
2003 match
= words
[count
];
2007 match
= words
[count
];
2008 match_len
= strlen(match
);
2010 /* expanded = PRINT; next call undo */
2013 match_len
= x_longest_prefix(nwords
, words
);
2014 expanded
= COMPLETE
; /* next call will list completions */
2015 is_unique
= nwords
== 1;
2018 buf
= save_edstate(es
);
2019 del_range(start
, end
);
2022 /* escape all shell-sensitive characters and put the result into
2024 rval
= x_escape(match
, match_len
, x_vi_putbuf
);
2026 if (rval
== 0 && is_unique
) {
2027 /* If exact match, don't undo. Allows directory completions
2028 * to be used (ie, complete the next portion of the path).
2032 /* If not a directory, add a space to the end... */
2033 if (match_len
> 0 && match
[match_len
- 1] != '/')
2034 rval
= putbuf(space
, 1, 0);
2036 x_free_words(nwords
, words
);
2038 modified
= 1; hnum
= hlast
;
2040 lastac
= 0; /* prevent this from being redone... */
2047 print_expansions(struct edstate
*e
, int command
)
2054 nwords
= x_cf_glob(XCF_COMMAND_FILE
|XCF_FULLPATH
,
2055 e
->cbuf
, e
->linelen
, e
->cursor
,
2056 &start
, &end
, &words
, &is_command
);
2061 x_print_expansions(nwords
, words
, is_command
);
2062 x_free_words(nwords
, words
);
2067 /* How long is char when displayed (not counting tabs) */
2073 if ((c
& 0x80) && Flag(FVISHOW8
)) {
2077 if (c
< ' ' || c
== 0x7f)
2082 /* Similar to x_zotc(emacs.c), but no tab weirdness */
2086 if (Flag(FVISHOW8
) && (c
& 0x80)) {
2090 if (c
< ' ' || c
== 0x7f) {
2098 vi_pprompt(int full
)
2100 pprompt(prompt
+ (full
? 0 : prompt_skip
), prompt_trunc
);
2106 /* Beem out of any macros as soon as an error occurs */
2113 vi_macro_reset(void)
2116 afree(macro
.buf
, APERM
);
2117 memset((char *) ¯o
, 0, sizeof(macro
));