GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: vi.c,v 1.49 2017/09/02 18:53:53 deraadt Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* vi command editing |
||
5 |
* written by John Rochester (initially for nsh) |
||
6 |
* bludgeoned to fit pdksh by Larry Bouzane, Jeff Sparkes & Eric Gisin |
||
7 |
* |
||
8 |
*/ |
||
9 |
#include "config.h" |
||
10 |
#ifdef VI |
||
11 |
|||
12 |
#include <sys/stat.h> /* completion */ |
||
13 |
|||
14 |
#include <ctype.h> |
||
15 |
#include <stdlib.h> |
||
16 |
#include <string.h> |
||
17 |
|||
18 |
#include "sh.h" |
||
19 |
#include "edit.h" |
||
20 |
|||
21 |
#define CTRL(c) (c & 0x1f) |
||
22 |
|||
23 |
struct edstate { |
||
24 |
char *cbuf; /* main buffer to build the command line */ |
||
25 |
int cbufsize; /* number of bytes allocated for cbuf */ |
||
26 |
int linelen; /* current number of bytes in cbuf */ |
||
27 |
int winleft; /* first byte# in cbuf to be displayed */ |
||
28 |
int cursor; /* byte# in cbuf having the cursor */ |
||
29 |
}; |
||
30 |
|||
31 |
|||
32 |
static int vi_hook(int); |
||
33 |
static void vi_reset(char *, size_t); |
||
34 |
static int nextstate(int); |
||
35 |
static int vi_insert(int); |
||
36 |
static int vi_cmd(int, const char *); |
||
37 |
static int domove(int, const char *, int); |
||
38 |
static int redo_insert(int); |
||
39 |
static void yank_range(int, int); |
||
40 |
static int bracktype(int); |
||
41 |
static void save_cbuf(void); |
||
42 |
static void restore_cbuf(void); |
||
43 |
static void edit_reset(char *, size_t); |
||
44 |
static int putbuf(const char *, int, int); |
||
45 |
static void del_range(int, int); |
||
46 |
static int findch(int, int, int, int); |
||
47 |
static int forwword(int); |
||
48 |
static int backword(int); |
||
49 |
static int endword(int); |
||
50 |
static int Forwword(int); |
||
51 |
static int Backword(int); |
||
52 |
static int Endword(int); |
||
53 |
static int grabhist(int, int); |
||
54 |
static int grabsearch(int, int, int, char *); |
||
55 |
static void redraw_line(int); |
||
56 |
static void refresh(int); |
||
57 |
static int outofwin(void); |
||
58 |
static void rewindow(void); |
||
59 |
static int newcol(int, int); |
||
60 |
static void display(char *, char *, int); |
||
61 |
static void ed_mov_opt(int, char *); |
||
62 |
static int expand_word(int); |
||
63 |
static int complete_word(int, int); |
||
64 |
static int print_expansions(struct edstate *, int); |
||
65 |
static int char_len(int); |
||
66 |
static void x_vi_zotc(int); |
||
67 |
static void vi_pprompt(int); |
||
68 |
static void vi_error(void); |
||
69 |
static void vi_macro_reset(void); |
||
70 |
static int x_vi_putbuf(const char *, size_t); |
||
71 |
static int isu8cont(unsigned char); |
||
72 |
|||
73 |
#define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */ |
||
74 |
#define M_ 0x2 /* movement command (h, l, etc.) */ |
||
75 |
#define E_ 0x4 /* extended command (c, d, y) */ |
||
76 |
#define X_ 0x8 /* long command (@, f, F, t, T, etc.) */ |
||
77 |
#define U_ 0x10 /* an UN-undoable command (that isn't a M_) */ |
||
78 |
#define B_ 0x20 /* bad command (^@) */ |
||
79 |
#define Z_ 0x40 /* repeat count defaults to 0 (not 1) */ |
||
80 |
#define S_ 0x80 /* search (/, ?) */ |
||
81 |
|||
82 |
#define is_bad(c) (classify[(c)&0x7f]&B_) |
||
83 |
#define is_cmd(c) (classify[(c)&0x7f]&(M_|E_|C_|U_)) |
||
84 |
#define is_move(c) (classify[(c)&0x7f]&M_) |
||
85 |
#define is_extend(c) (classify[(c)&0x7f]&E_) |
||
86 |
#define is_long(c) (classify[(c)&0x7f]&X_) |
||
87 |
#define is_undoable(c) (!(classify[(c)&0x7f]&U_)) |
||
88 |
#define is_srch(c) (classify[(c)&0x7f]&S_) |
||
89 |
#define is_zerocount(c) (classify[(c)&0x7f]&Z_) |
||
90 |
|||
91 |
const unsigned char classify[128] = { |
||
92 |
/* 0 1 2 3 4 5 6 7 */ |
||
93 |
/* 0 ^@ ^A ^B ^C ^D ^E ^F ^G */ |
||
94 |
B_, 0, 0, 0, 0, C_|U_, C_|Z_, 0, |
||
95 |
/* 01 ^H ^I ^J ^K ^L ^M ^N ^O */ |
||
96 |
M_, C_|Z_, 0, 0, C_|U_, 0, C_, 0, |
||
97 |
/* 02 ^P ^Q ^R ^S ^T ^U ^V ^W */ |
||
98 |
C_, 0, C_|U_, 0, 0, 0, C_, 0, |
||
99 |
/* 03 ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */ |
||
100 |
C_, 0, 0, C_|Z_, 0, 0, 0, 0, |
||
101 |
/* 04 <space> ! " # $ % & ' */ |
||
102 |
M_, 0, 0, C_, M_, M_, 0, 0, |
||
103 |
/* 05 ( ) * + , - . / */ |
||
104 |
0, 0, C_, C_, M_, C_, 0, C_|S_, |
||
105 |
/* 06 0 1 2 3 4 5 6 7 */ |
||
106 |
M_, 0, 0, 0, 0, 0, 0, 0, |
||
107 |
/* 07 8 9 : ; < = > ? */ |
||
108 |
0, 0, 0, M_, 0, C_, 0, C_|S_, |
||
109 |
/* 010 @ A B C D E F G */ |
||
110 |
C_|X_, C_, M_, C_, C_, M_, M_|X_, C_|U_|Z_, |
||
111 |
/* 011 H I J K L M N O */ |
||
112 |
0, C_, 0, 0, 0, 0, C_|U_, 0, |
||
113 |
/* 012 P Q R S T U V W */ |
||
114 |
C_, 0, C_, C_, M_|X_, C_, 0, M_, |
||
115 |
/* 013 X Y Z [ \ ] ^ _ */ |
||
116 |
C_, C_|U_, 0, 0, C_|Z_, 0, M_, C_|Z_, |
||
117 |
/* 014 ` a b c d e f g */ |
||
118 |
0, C_, M_, E_, E_, M_, M_|X_, C_|Z_, |
||
119 |
/* 015 h i j k l m n o */ |
||
120 |
M_, C_, C_|U_, C_|U_, M_, 0, C_|U_, 0, |
||
121 |
/* 016 p q r s t u v w */ |
||
122 |
C_, 0, X_, C_, M_|X_, C_|U_, C_|U_|Z_,M_, |
||
123 |
/* 017 x y z { | } ~ ^? */ |
||
124 |
C_, E_|U_, 0, 0, M_|Z_, 0, C_, 0 |
||
125 |
}; |
||
126 |
|||
127 |
#define MAXVICMD 3 |
||
128 |
#define SRCHLEN 40 |
||
129 |
|||
130 |
#define INSERT 1 |
||
131 |
#define REPLACE 2 |
||
132 |
|||
133 |
#define VNORMAL 0 /* command, insert or replace mode */ |
||
134 |
#define VARG1 1 /* digit prefix (first, eg, 5l) */ |
||
135 |
#define VEXTCMD 2 /* cmd + movement (eg, cl) */ |
||
136 |
#define VARG2 3 /* digit prefix (second, eg, 2c3l) */ |
||
137 |
#define VXCH 4 /* f, F, t, T, @ */ |
||
138 |
#define VFAIL 5 /* bad command */ |
||
139 |
#define VCMD 6 /* single char command (eg, X) */ |
||
140 |
#define VREDO 7 /* . */ |
||
141 |
#define VLIT 8 /* ^V */ |
||
142 |
#define VSEARCH 9 /* /, ? */ |
||
143 |
#define VVERSION 10 /* <ESC> ^V */ |
||
144 |
|||
145 |
static char undocbuf[LINE]; |
||
146 |
|||
147 |
static struct edstate *save_edstate(struct edstate *old); |
||
148 |
static void restore_edstate(struct edstate *old, struct edstate *new); |
||
149 |
static void free_edstate(struct edstate *old); |
||
150 |
|||
151 |
static struct edstate ebuf; |
||
152 |
static struct edstate undobuf = { undocbuf, LINE, 0, 0, 0 }; |
||
153 |
|||
154 |
static struct edstate *es; /* current editor state */ |
||
155 |
static struct edstate *undo; |
||
156 |
|||
157 |
static char ibuf[LINE]; /* input buffer */ |
||
158 |
static int first_insert; /* set when starting in insert mode */ |
||
159 |
static int saved_inslen; /* saved inslen for first insert */ |
||
160 |
static int inslen; /* length of input buffer */ |
||
161 |
static int srchlen; /* number of bytes in search pattern */ |
||
162 |
static char ybuf[LINE]; /* yank buffer */ |
||
163 |
static int yanklen; /* length of yank buffer */ |
||
164 |
static int fsavecmd = ' '; /* last find command */ |
||
165 |
static int fsavech; /* character to find */ |
||
166 |
static char lastcmd[MAXVICMD]; /* last non-move command */ |
||
167 |
static int lastac; /* argcnt for lastcmd */ |
||
168 |
static int lastsearch = ' '; /* last search command */ |
||
169 |
static char srchpat[SRCHLEN]; /* last search pattern */ |
||
170 |
static int insert; /* mode: INSERT, REPLACE, or 0 */ |
||
171 |
static int hnum; /* position in history */ |
||
172 |
static int ohnum; /* history line copied (after mod) */ |
||
173 |
static int hlast; /* 1 past last position in history */ |
||
174 |
static int modified; /* buffer has been "modified" */ |
||
175 |
static int state; |
||
176 |
|||
177 |
/* Information for keeping track of macros that are being expanded. |
||
178 |
* The format of buf is the alias contents followed by a null byte followed |
||
179 |
* by the name (letter) of the alias. The end of the buffer is marked by |
||
180 |
* a double null. The name of the alias is stored so recursive macros can |
||
181 |
* be detected. |
||
182 |
*/ |
||
183 |
struct macro_state { |
||
184 |
unsigned char *p; /* current position in buf */ |
||
185 |
unsigned char *buf; /* pointer to macro(s) being expanded */ |
||
186 |
int len; /* how much data in buffer */ |
||
187 |
}; |
||
188 |
static struct macro_state macro; |
||
189 |
|||
190 |
enum expand_mode { NONE, EXPAND, COMPLETE, PRINT }; |
||
191 |
static enum expand_mode expanded = NONE;/* last input was expanded */ |
||
192 |
|||
193 |
int |
||
194 |
x_vi(char *buf, size_t len) |
||
195 |
{ |
||
196 |
int c; |
||
197 |
|||
198 |
3550 |
vi_reset(buf, len > LINE ? LINE : len); |
|
199 |
1775 |
vi_pprompt(1); |
|
200 |
1775 |
x_flush(); |
|
201 |
17550 |
while (1) { |
|
202 |
✗✓ | 17550 |
if (macro.p) { |
203 |
c = (unsigned char)*macro.p++; |
||
204 |
/* end of current macro? */ |
||
205 |
if (!c) { |
||
206 |
/* more macros left to finish? */ |
||
207 |
if (*macro.p++) |
||
208 |
continue; |
||
209 |
/* must be the end of all the macros */ |
||
210 |
vi_macro_reset(); |
||
211 |
c = x_getc(); |
||
212 |
} |
||
213 |
} else |
||
214 |
17550 |
c = x_getc(); |
|
215 |
|||
216 |
✓✗ | 15875 |
if (c == -1) |
217 |
break; |
||
218 |
✓✓ | 15875 |
if (state != VLIT) { |
219 |
✓✗✗✓ |
31700 |
if (c == edchars.intr || c == edchars.quit) { |
220 |
/* pretend we got an interrupt */ |
||
221 |
x_vi_zotc(c); |
||
222 |
x_flush(); |
||
223 |
trapsig(c == edchars.intr ? SIGINT : SIGQUIT); |
||
224 |
x_mode(false); |
||
225 |
unwind(LSHELL); |
||
226 |
✗✓ | 15850 |
} else if (c == edchars.eof && state != VVERSION) { |
227 |
if (es->linelen == 0) { |
||
228 |
x_vi_zotc(edchars.eof); |
||
229 |
c = -1; |
||
230 |
break; |
||
231 |
} |
||
232 |
continue; |
||
233 |
} |
||
234 |
} |
||
235 |
✓✓ | 15875 |
if (vi_hook(c)) |
236 |
break; |
||
237 |
15775 |
x_flush(); |
|
238 |
} |
||
239 |
|||
240 |
100 |
x_putc('\r'); x_putc('\n'); x_flush(); |
|
241 |
|||
242 |
✓✗✗✓ |
200 |
if (c == -1 || len <= es->linelen) |
243 |
return -1; |
||
244 |
|||
245 |
✗✓ | 100 |
if (es->cbuf != buf) |
246 |
memmove(buf, es->cbuf, es->linelen); |
||
247 |
|||
248 |
100 |
buf[es->linelen++] = '\n'; |
|
249 |
|||
250 |
100 |
return es->linelen; |
|
251 |
100 |
} |
|
252 |
|||
253 |
static int |
||
254 |
vi_hook(int ch) |
||
255 |
{ |
||
256 |
static char curcmd[MAXVICMD], locpat[SRCHLEN]; |
||
257 |
static int cmdlen, argc1, argc2; |
||
258 |
|||
259 |
✓✓✗✓ ✓✗✓✗ ✓ |
36575 |
switch (state) { |
260 |
|||
261 |
case VNORMAL: |
||
262 |
✓✓ | 14450 |
if (insert != 0) { |
263 |
✓✓ | 11000 |
if (ch == CTRL('v')) { |
264 |
25 |
state = VLIT; |
|
265 |
ch = '^'; |
||
266 |
25 |
} |
|
267 |
✗✓✓✓ |
21950 |
switch (vi_insert(ch)) { |
268 |
case -1: |
||
269 |
vi_error(); |
||
270 |
state = VNORMAL; |
||
271 |
break; |
||
272 |
case 0: |
||
273 |
✓✓ | 10950 |
if (state == VLIT) { |
274 |
25 |
es->cursor--; |
|
275 |
25 |
refresh(0); |
|
276 |
25 |
} else |
|
277 |
10925 |
refresh(insert != 0); |
|
278 |
break; |
||
279 |
case 1: |
||
280 |
50 |
return 1; |
|
281 |
} |
||
282 |
} else { |
||
283 |
✓✓ | 3450 |
if (ch == '\r' || ch == '\n') |
284 |
50 |
return 1; |
|
285 |
3400 |
cmdlen = 0; |
|
286 |
3400 |
argc1 = 0; |
|
287 |
✓✓ | 3400 |
if (ch >= '1' && ch <= '9') { |
288 |
875 |
argc1 = ch - '0'; |
|
289 |
875 |
state = VARG1; |
|
290 |
875 |
} else { |
|
291 |
2525 |
curcmd[cmdlen++] = ch; |
|
292 |
2525 |
state = nextstate(ch); |
|
293 |
✗✓ | 2525 |
if (state == VSEARCH) { |
294 |
save_cbuf(); |
||
295 |
es->cursor = 0; |
||
296 |
es->linelen = 0; |
||
297 |
if (ch == '/') { |
||
298 |
if (putbuf("/", 1, 0) != 0) |
||
299 |
return -1; |
||
300 |
} else if (putbuf("?", 1, 0) != 0) |
||
301 |
return -1; |
||
302 |
refresh(0); |
||
303 |
} |
||
304 |
✗✓ | 2525 |
if (state == VVERSION) { |
305 |
save_cbuf(); |
||
306 |
es->cursor = 0; |
||
307 |
es->linelen = 0; |
||
308 |
putbuf(ksh_version + 4, |
||
309 |
strlen(ksh_version + 4), 0); |
||
310 |
refresh(0); |
||
311 |
} |
||
312 |
} |
||
313 |
} |
||
314 |
break; |
||
315 |
|||
316 |
case VLIT: |
||
317 |
✗✓ | 25 |
if (is_bad(ch)) { |
318 |
del_range(es->cursor, es->cursor + 1); |
||
319 |
vi_error(); |
||
320 |
} else |
||
321 |
25 |
es->cbuf[es->cursor++] = ch; |
|
322 |
25 |
refresh(1); |
|
323 |
25 |
state = VNORMAL; |
|
324 |
25 |
break; |
|
325 |
|||
326 |
case VVERSION: |
||
327 |
restore_cbuf(); |
||
328 |
state = VNORMAL; |
||
329 |
refresh(0); |
||
330 |
break; |
||
331 |
|||
332 |
case VARG1: |
||
333 |
✗✓ | 875 |
if (isdigit(ch)) |
334 |
argc1 = argc1 * 10 + ch - '0'; |
||
335 |
else { |
||
336 |
875 |
curcmd[cmdlen++] = ch; |
|
337 |
875 |
state = nextstate(ch); |
|
338 |
} |
||
339 |
break; |
||
340 |
|||
341 |
case VEXTCMD: |
||
342 |
150 |
argc2 = 0; |
|
343 |
✗✓ | 150 |
if (ch >= '1' && ch <= '9') { |
344 |
argc2 = ch - '0'; |
||
345 |
state = VARG2; |
||
346 |
return 0; |
||
347 |
} else { |
||
348 |
150 |
curcmd[cmdlen++] = ch; |
|
349 |
✓✗ | 150 |
if (ch == curcmd[0]) |
350 |
state = VCMD; |
||
351 |
✓✗ | 150 |
else if (is_move(ch)) |
352 |
150 |
state = nextstate(ch); |
|
353 |
else |
||
354 |
state = VFAIL; |
||
355 |
} |
||
356 |
150 |
break; |
|
357 |
|||
358 |
case VARG2: |
||
359 |
if (isdigit(ch)) |
||
360 |
argc2 = argc2 * 10 + ch - '0'; |
||
361 |
else { |
||
362 |
if (argc1 == 0) |
||
363 |
argc1 = argc2; |
||
364 |
else |
||
365 |
argc1 *= argc2; |
||
366 |
curcmd[cmdlen++] = ch; |
||
367 |
if (ch == curcmd[0]) |
||
368 |
state = VCMD; |
||
369 |
else if (is_move(ch)) |
||
370 |
state = nextstate(ch); |
||
371 |
else |
||
372 |
state = VFAIL; |
||
373 |
} |
||
374 |
break; |
||
375 |
|||
376 |
case VXCH: |
||
377 |
✓✗ | 375 |
if (ch == CTRL('[')) |
378 |
state = VNORMAL; |
||
379 |
else { |
||
380 |
375 |
curcmd[cmdlen++] = ch; |
|
381 |
state = VCMD; |
||
382 |
} |
||
383 |
375 |
break; |
|
384 |
|||
385 |
case VSEARCH: |
||
386 |
if (ch == '\r' || ch == '\n' /*|| ch == CTRL('[')*/ ) { |
||
387 |
restore_cbuf(); |
||
388 |
/* Repeat last search? */ |
||
389 |
if (srchlen == 0) { |
||
390 |
if (!srchpat[0]) { |
||
391 |
vi_error(); |
||
392 |
state = VNORMAL; |
||
393 |
refresh(0); |
||
394 |
return 0; |
||
395 |
} |
||
396 |
} else { |
||
397 |
locpat[srchlen] = '\0'; |
||
398 |
(void) strlcpy(srchpat, locpat, sizeof srchpat); |
||
399 |
} |
||
400 |
state = VCMD; |
||
401 |
} else if (ch == edchars.erase || ch == CTRL('h')) { |
||
402 |
if (srchlen != 0) { |
||
403 |
do { |
||
404 |
srchlen--; |
||
405 |
es->linelen -= char_len( |
||
406 |
(unsigned char)locpat[srchlen]); |
||
407 |
} while (srchlen > 0 && |
||
408 |
isu8cont(locpat[srchlen])); |
||
409 |
es->cursor = es->linelen; |
||
410 |
refresh(0); |
||
411 |
return 0; |
||
412 |
} |
||
413 |
restore_cbuf(); |
||
414 |
state = VNORMAL; |
||
415 |
refresh(0); |
||
416 |
} else if (ch == edchars.kill) { |
||
417 |
srchlen = 0; |
||
418 |
es->linelen = 1; |
||
419 |
es->cursor = 1; |
||
420 |
refresh(0); |
||
421 |
return 0; |
||
422 |
} else if (ch == edchars.werase) { |
||
423 |
struct edstate new_es, *save_es; |
||
424 |
int i; |
||
425 |
int n = srchlen; |
||
426 |
|||
427 |
new_es.cursor = n; |
||
428 |
new_es.cbuf = locpat; |
||
429 |
|||
430 |
save_es = es; |
||
431 |
es = &new_es; |
||
432 |
n = backword(1); |
||
433 |
es = save_es; |
||
434 |
|||
435 |
for (i = srchlen; --i >= n; ) |
||
436 |
es->linelen -= char_len((unsigned char)locpat[i]); |
||
437 |
srchlen = n; |
||
438 |
es->cursor = es->linelen; |
||
439 |
refresh(0); |
||
440 |
return 0; |
||
441 |
} else { |
||
442 |
if (srchlen == SRCHLEN - 1) |
||
443 |
vi_error(); |
||
444 |
else { |
||
445 |
locpat[srchlen++] = ch; |
||
446 |
if ((ch & 0x80) && Flag(FVISHOW8)) { |
||
447 |
if (es->linelen + 2 > es->cbufsize) |
||
448 |
vi_error(); |
||
449 |
es->cbuf[es->linelen++] = 'M'; |
||
450 |
es->cbuf[es->linelen++] = '-'; |
||
451 |
ch &= 0x7f; |
||
452 |
} |
||
453 |
if (ch < ' ' || ch == 0x7f) { |
||
454 |
if (es->linelen + 2 > es->cbufsize) |
||
455 |
vi_error(); |
||
456 |
es->cbuf[es->linelen++] = '^'; |
||
457 |
es->cbuf[es->linelen++] = ch ^ '@'; |
||
458 |
} else { |
||
459 |
if (es->linelen >= es->cbufsize) |
||
460 |
vi_error(); |
||
461 |
es->cbuf[es->linelen++] = ch; |
||
462 |
} |
||
463 |
es->cursor = es->linelen; |
||
464 |
refresh(0); |
||
465 |
} |
||
466 |
return 0; |
||
467 |
} |
||
468 |
break; |
||
469 |
} |
||
470 |
|||
471 |
✓✓✓✓ |
15800 |
switch (state) { |
472 |
case VCMD: |
||
473 |
6700 |
state = VNORMAL; |
|
474 |
✓✓✗✗ ✓ |
6700 |
switch (vi_cmd(argc1, curcmd)) { |
475 |
case -1: |
||
476 |
25 |
vi_error(); |
|
477 |
25 |
refresh(0); |
|
478 |
25 |
break; |
|
479 |
case 0: |
||
480 |
✓✓ | 3325 |
if (insert != 0) |
481 |
650 |
inslen = 0; |
|
482 |
3325 |
refresh(insert != 0); |
|
483 |
3325 |
break; |
|
484 |
case 1: |
||
485 |
refresh(0); |
||
486 |
return 1; |
||
487 |
case 2: |
||
488 |
/* back from a 'v' command - don't redraw the screen */ |
||
489 |
return 1; |
||
490 |
} |
||
491 |
break; |
||
492 |
|||
493 |
case VREDO: |
||
494 |
25 |
state = VNORMAL; |
|
495 |
✗✓ | 25 |
if (argc1 != 0) |
496 |
lastac = argc1; |
||
497 |
✗✓✗✓ |
50 |
switch (vi_cmd(lastac, lastcmd)) { |
498 |
case -1: |
||
499 |
vi_error(); |
||
500 |
refresh(0); |
||
501 |
break; |
||
502 |
case 0: |
||
503 |
✓✗ | 25 |
if (insert != 0) { |
504 |
✓✗✓✗ ✗✓ |
75 |
if (lastcmd[0] == 's' || lastcmd[0] == 'c' || |
505 |
25 |
lastcmd[0] == 'C') { |
|
506 |
if (redo_insert(1) != 0) |
||
507 |
vi_error(); |
||
508 |
} else { |
||
509 |
✗✓ | 25 |
if (redo_insert(lastac) != 0) |
510 |
vi_error(); |
||
511 |
} |
||
512 |
} |
||
513 |
25 |
refresh(0); |
|
514 |
25 |
break; |
|
515 |
case 1: |
||
516 |
refresh(0); |
||
517 |
return 1; |
||
518 |
case 2: |
||
519 |
/* back from a 'v' command - can't happen */ |
||
520 |
break; |
||
521 |
} |
||
522 |
break; |
||
523 |
|||
524 |
case VFAIL: |
||
525 |
25 |
state = VNORMAL; |
|
526 |
25 |
vi_error(); |
|
527 |
25 |
break; |
|
528 |
} |
||
529 |
15775 |
return 0; |
|
530 |
15875 |
} |
|
531 |
|||
532 |
static void |
||
533 |
vi_reset(char *buf, size_t len) |
||
534 |
{ |
||
535 |
3550 |
state = VNORMAL; |
|
536 |
1775 |
ohnum = hnum = hlast = histnum(-1) + 1; |
|
537 |
1775 |
insert = INSERT; |
|
538 |
1775 |
saved_inslen = inslen; |
|
539 |
1775 |
first_insert = 1; |
|
540 |
1775 |
inslen = 0; |
|
541 |
1775 |
modified = 1; |
|
542 |
1775 |
vi_macro_reset(); |
|
543 |
1775 |
edit_reset(buf, len); |
|
544 |
1775 |
} |
|
545 |
|||
546 |
static int |
||
547 |
nextstate(int ch) |
||
548 |
{ |
||
549 |
✓✓ | 7100 |
if (is_extend(ch)) |
550 |
150 |
return VEXTCMD; |
|
551 |
✗✓ | 3400 |
else if (is_srch(ch)) |
552 |
return VSEARCH; |
||
553 |
✓✓ | 3400 |
else if (is_long(ch)) |
554 |
375 |
return VXCH; |
|
555 |
✓✓ | 3025 |
else if (ch == '.') |
556 |
25 |
return VREDO; |
|
557 |
✗✓ | 3000 |
else if (ch == CTRL('v')) |
558 |
return VVERSION; |
||
559 |
✓✓ | 3000 |
else if (is_cmd(ch)) |
560 |
2975 |
return VCMD; |
|
561 |
else |
||
562 |
25 |
return VFAIL; |
|
563 |
3550 |
} |
|
564 |
|||
565 |
static int |
||
566 |
vi_insert(int ch) |
||
567 |
{ |
||
568 |
int tcursor; |
||
569 |
|||
570 |
✓✓ | 22000 |
if (ch == edchars.erase || ch == CTRL('h')) { |
571 |
✗✓ | 50 |
if (insert == REPLACE) { |
572 |
if (es->cursor == undo->cursor) { |
||
573 |
vi_error(); |
||
574 |
return 0; |
||
575 |
} |
||
576 |
} else { |
||
577 |
✗✓ | 50 |
if (es->cursor == 0) { |
578 |
/* x_putc(BEL); no annoying bell here */ |
||
579 |
return 0; |
||
580 |
} |
||
581 |
} |
||
582 |
50 |
tcursor = es->cursor - 1; |
|
583 |
✓✗✗✓ |
150 |
while(tcursor > 0 && isu8cont(es->cbuf[tcursor])) |
584 |
tcursor--; |
||
585 |
✓✗ | 50 |
if (insert == INSERT) |
586 |
100 |
memmove(es->cbuf + tcursor, es->cbuf + es->cursor, |
|
587 |
50 |
es->linelen - es->cursor); |
|
588 |
✗✓✗✗ |
50 |
if (insert == REPLACE && es->cursor < undo->linelen) |
589 |
memcpy(es->cbuf + tcursor, undo->cbuf + tcursor, |
||
590 |
es->cursor - tcursor); |
||
591 |
else |
||
592 |
50 |
es->linelen -= es->cursor - tcursor; |
|
593 |
✓✗ | 50 |
if (inslen < es->cursor - tcursor) |
594 |
inslen = 0; |
||
595 |
else |
||
596 |
50 |
inslen -= es->cursor - tcursor; |
|
597 |
50 |
es->cursor = tcursor; |
|
598 |
50 |
expanded = NONE; |
|
599 |
50 |
return 0; |
|
600 |
} |
||
601 |
✓✓ | 10950 |
if (ch == edchars.kill) { |
602 |
✓✗ | 25 |
if (es->cursor != 0) { |
603 |
25 |
inslen = 0; |
|
604 |
50 |
memmove(es->cbuf, &es->cbuf[es->cursor], |
|
605 |
25 |
es->linelen - es->cursor); |
|
606 |
25 |
es->linelen -= es->cursor; |
|
607 |
25 |
es->cursor = 0; |
|
608 |
25 |
} |
|
609 |
25 |
expanded = NONE; |
|
610 |
25 |
return 0; |
|
611 |
} |
||
612 |
✓✓ | 10925 |
if (ch == edchars.werase) { |
613 |
✓✗ | 25 |
if (es->cursor != 0) { |
614 |
25 |
tcursor = backword(1); |
|
615 |
50 |
memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor], |
|
616 |
25 |
es->linelen - es->cursor); |
|
617 |
25 |
es->linelen -= es->cursor - tcursor; |
|
618 |
✓✗ | 25 |
if (inslen < es->cursor - tcursor) |
619 |
inslen = 0; |
||
620 |
else |
||
621 |
25 |
inslen -= es->cursor - tcursor; |
|
622 |
25 |
es->cursor = tcursor; |
|
623 |
25 |
} |
|
624 |
25 |
expanded = NONE; |
|
625 |
25 |
return 0; |
|
626 |
} |
||
627 |
/* If any chars are entered before escape, trash the saved insert |
||
628 |
* buffer (if user inserts & deletes char, ibuf gets trashed and |
||
629 |
* we don't want to use it) |
||
630 |
*/ |
||
631 |
✓✓ | 10900 |
if (first_insert && ch != CTRL('[')) |
632 |
7950 |
saved_inslen = 0; |
|
633 |
✗✗✓✓ ✗✗✗✗ ✓ |
10900 |
switch (ch) { |
634 |
case '\0': |
||
635 |
return -1; |
||
636 |
|||
637 |
case '\r': |
||
638 |
case '\n': |
||
639 |
50 |
return 1; |
|
640 |
|||
641 |
case CTRL('['): |
||
642 |
1775 |
expanded = NONE; |
|
643 |
✓✓ | 1775 |
if (first_insert) { |
644 |
1525 |
first_insert = 0; |
|
645 |
✗✓ | 1525 |
if (inslen == 0) { |
646 |
inslen = saved_inslen; |
||
647 |
return redo_insert(0); |
||
648 |
} |
||
649 |
1525 |
lastcmd[0] = 'a'; |
|
650 |
1525 |
lastac = 1; |
|
651 |
1525 |
} |
|
652 |
✓✗✓✗ ✗✓ |
5325 |
if (lastcmd[0] == 's' || lastcmd[0] == 'c' || |
653 |
1775 |
lastcmd[0] == 'C') |
|
654 |
return redo_insert(0); |
||
655 |
else |
||
656 |
1775 |
return redo_insert(lastac - 1); |
|
657 |
|||
658 |
/* { Begin nonstandard vi commands */ |
||
659 |
case CTRL('x'): |
||
660 |
expand_word(0); |
||
661 |
break; |
||
662 |
|||
663 |
case CTRL('f'): |
||
664 |
complete_word(0, 0); |
||
665 |
break; |
||
666 |
|||
667 |
case CTRL('e'): |
||
668 |
print_expansions(es, 0); |
||
669 |
break; |
||
670 |
|||
671 |
case CTRL('i'): |
||
672 |
if (Flag(FVITABCOMPLETE)) { |
||
673 |
complete_word(0, 0); |
||
674 |
break; |
||
675 |
} |
||
676 |
/* FALLTHROUGH */ |
||
677 |
/* End nonstandard vi commands } */ |
||
678 |
|||
679 |
default: |
||
680 |
✗✓ | 9075 |
if (es->linelen >= es->cbufsize - 1) |
681 |
return -1; |
||
682 |
9075 |
ibuf[inslen++] = ch; |
|
683 |
✓✓ | 9075 |
if (insert == INSERT) { |
684 |
18000 |
memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor], |
|
685 |
9000 |
es->linelen - es->cursor); |
|
686 |
9000 |
es->linelen++; |
|
687 |
9000 |
} |
|
688 |
9075 |
es->cbuf[es->cursor++] = ch; |
|
689 |
✓✓✗✓ |
9150 |
if (insert == REPLACE && es->cursor > es->linelen) |
690 |
es->linelen++; |
||
691 |
9075 |
expanded = NONE; |
|
692 |
9075 |
} |
|
693 |
9075 |
return 0; |
|
694 |
11000 |
} |
|
695 |
|||
696 |
static int |
||
697 |
vi_cmd(int argcnt, const char *cmd) |
||
698 |
{ |
||
699 |
int ncursor; |
||
700 |
int cur, c1, c2, c3 = 0; |
||
701 |
int any; |
||
702 |
struct edstate *t; |
||
703 |
|||
704 |
✓✓✓✗ |
9225 |
if (argcnt == 0 && !is_zerocount(*cmd)) |
705 |
2475 |
argcnt = 1; |
|
706 |
|||
707 |
✓✓ | 3375 |
if (is_move(*cmd)) { |
708 |
✓✗ | 1525 |
if ((cur = domove(argcnt, cmd, 0)) >= 0) { |
709 |
✓✓ | 1525 |
if (cur == es->linelen && cur != 0) |
710 |
✗✓ | 25 |
while (isu8cont(es->cbuf[--cur])) |
711 |
continue; |
||
712 |
1525 |
es->cursor = cur; |
|
713 |
} else |
||
714 |
return -1; |
||
715 |
1525 |
} else { |
|
716 |
/* Don't save state in middle of macro.. */ |
||
717 |
✓✓ | 1850 |
if (is_undoable(*cmd) && !macro.p) { |
718 |
1700 |
undo->winleft = es->winleft; |
|
719 |
1700 |
memmove(undo->cbuf, es->cbuf, es->linelen); |
|
720 |
1700 |
undo->linelen = es->linelen; |
|
721 |
1700 |
undo->cursor = es->cursor; |
|
722 |
1700 |
lastac = argcnt; |
|
723 |
1700 |
memmove(lastcmd, cmd, MAXVICMD); |
|
724 |
1700 |
} |
|
725 |
✗✓✗✓ ✓✓✓✗ ✗✓✓✓ ✓✓✗✗ ✓✓✗✗ ✗✗✗✗ ✓✓✓✗ ✓✓✓✓ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗✗✓ |
3700 |
switch (*cmd) { |
726 |
|||
727 |
case CTRL('l'): |
||
728 |
case CTRL('r'): |
||
729 |
50 |
redraw_line(1); |
|
730 |
50 |
break; |
|
731 |
|||
732 |
case '@': |
||
733 |
{ |
||
734 |
static char alias[] = "_\0"; |
||
735 |
struct tbl *ap; |
||
736 |
int olen, nlen; |
||
737 |
char *p, *nbuf; |
||
738 |
|||
739 |
/* lookup letter in alias list... */ |
||
740 |
alias[1] = cmd[1]; |
||
741 |
ap = ktsearch(&aliases, alias, hash(alias)); |
||
742 |
if (!cmd[1] || !ap || !(ap->flag & ISSET)) |
||
743 |
return -1; |
||
744 |
/* check if this is a recursive call... */ |
||
745 |
if ((p = (char *) macro.p)) |
||
746 |
while ((p = strchr(p, '\0')) && p[1]) |
||
747 |
if (*++p == cmd[1]) |
||
748 |
return -1; |
||
749 |
/* insert alias into macro buffer */ |
||
750 |
nlen = strlen(ap->val.s) + 1; |
||
751 |
olen = !macro.p ? 2 : |
||
752 |
macro.len - (macro.p - macro.buf); |
||
753 |
nbuf = alloc(nlen + 1 + olen, APERM); |
||
754 |
memcpy(nbuf, ap->val.s, nlen); |
||
755 |
nbuf[nlen++] = cmd[1]; |
||
756 |
if (macro.p) { |
||
757 |
memcpy(nbuf + nlen, macro.p, olen); |
||
758 |
afree(macro.buf, APERM); |
||
759 |
nlen += olen; |
||
760 |
} else { |
||
761 |
nbuf[nlen++] = '\0'; |
||
762 |
nbuf[nlen++] = '\0'; |
||
763 |
} |
||
764 |
macro.p = macro.buf = (unsigned char *) nbuf; |
||
765 |
macro.len = nlen; |
||
766 |
} |
||
767 |
break; |
||
768 |
|||
769 |
case 'a': |
||
770 |
125 |
modified = 1; hnum = hlast; |
|
771 |
✓✗ | 125 |
if (es->linelen != 0) |
772 |
✗✓ | 125 |
while (isu8cont(es->cbuf[++es->cursor])) |
773 |
continue; |
||
774 |
125 |
insert = INSERT; |
|
775 |
125 |
break; |
|
776 |
|||
777 |
case 'A': |
||
778 |
50 |
modified = 1; hnum = hlast; |
|
779 |
50 |
del_range(0, 0); |
|
780 |
50 |
es->cursor = es->linelen; |
|
781 |
50 |
insert = INSERT; |
|
782 |
50 |
break; |
|
783 |
|||
784 |
case 'S': |
||
785 |
50 |
es->cursor = domove(1, "^", 1); |
|
786 |
50 |
del_range(es->cursor, es->linelen); |
|
787 |
50 |
modified = 1; hnum = hlast; |
|
788 |
50 |
insert = INSERT; |
|
789 |
50 |
break; |
|
790 |
|||
791 |
case 'Y': |
||
792 |
25 |
cmd = "y$"; |
|
793 |
/* ahhhhhh... */ |
||
794 |
case 'c': |
||
795 |
case 'd': |
||
796 |
case 'y': |
||
797 |
✗✓ | 175 |
if (*cmd == cmd[1]) { |
798 |
c1 = *cmd == 'c' ? domove(1, "^", 1) : 0; |
||
799 |
c2 = es->linelen; |
||
800 |
✗✓ | 175 |
} else if (!is_move(cmd[1])) |
801 |
return -1; |
||
802 |
else { |
||
803 |
✗✓ | 175 |
if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0) |
804 |
return -1; |
||
805 |
✓✓✗✗ |
175 |
if (*cmd == 'c' && |
806 |
✓✗✗✓ |
100 |
(cmd[1]=='w' || cmd[1]=='W') && |
807 |
!isspace((unsigned char)es->cbuf[es->cursor])) { |
||
808 |
while (isspace( |
||
809 |
(unsigned char)es->cbuf[--ncursor])) |
||
810 |
; |
||
811 |
ncursor++; |
||
812 |
} |
||
813 |
✓✓ | 175 |
if (ncursor > es->cursor) { |
814 |
c1 = es->cursor; |
||
815 |
c2 = ncursor; |
||
816 |
75 |
} else { |
|
817 |
c1 = ncursor; |
||
818 |
c2 = es->cursor; |
||
819 |
✗✓ | 100 |
if (cmd[1] == '%') |
820 |
c2++; |
||
821 |
} |
||
822 |
} |
||
823 |
✓✓✓✗ |
300 |
if (*cmd != 'c' && c1 != c2) |
824 |
125 |
yank_range(c1, c2); |
|
825 |
✓✓ | 175 |
if (*cmd != 'y') { |
826 |
100 |
del_range(c1, c2); |
|
827 |
100 |
es->cursor = c1; |
|
828 |
100 |
} |
|
829 |
✓✓ | 175 |
if (*cmd == 'c') { |
830 |
50 |
modified = 1; hnum = hlast; |
|
831 |
50 |
insert = INSERT; |
|
832 |
50 |
} |
|
833 |
break; |
||
834 |
|||
835 |
case 'p': |
||
836 |
125 |
modified = 1; hnum = hlast; |
|
837 |
✓✗ | 125 |
if (es->linelen != 0) |
838 |
125 |
es->cursor++; |
|
839 |
✓✗✓✓ |
300 |
while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0) |
840 |
; |
||
841 |
✓✗ | 125 |
if (es->cursor != 0) |
842 |
125 |
es->cursor--; |
|
843 |
✗✓ | 125 |
if (argcnt != 0) |
844 |
return -1; |
||
845 |
break; |
||
846 |
|||
847 |
case 'P': |
||
848 |
50 |
modified = 1; hnum = hlast; |
|
849 |
any = 0; |
||
850 |
✓✗✓✓ |
225 |
while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0) |
851 |
any = 1; |
||
852 |
✓✓✓✗ |
75 |
if (any && es->cursor != 0) |
853 |
25 |
es->cursor--; |
|
854 |
✗✓ | 50 |
if (argcnt != 0) |
855 |
return -1; |
||
856 |
break; |
||
857 |
|||
858 |
case 'C': |
||
859 |
25 |
modified = 1; hnum = hlast; |
|
860 |
25 |
del_range(es->cursor, es->linelen); |
|
861 |
25 |
insert = INSERT; |
|
862 |
25 |
break; |
|
863 |
|||
864 |
case 'D': |
||
865 |
425 |
yank_range(es->cursor, es->linelen); |
|
866 |
425 |
del_range(es->cursor, es->linelen); |
|
867 |
✓✗ | 425 |
if (es->cursor != 0) |
868 |
425 |
es->cursor--; |
|
869 |
break; |
||
870 |
|||
871 |
case 'g': |
||
872 |
if (!argcnt) |
||
873 |
argcnt = hlast; |
||
874 |
/* FALLTHROUGH */ |
||
875 |
case 'G': |
||
876 |
if (!argcnt) |
||
877 |
argcnt = 1; |
||
878 |
else |
||
879 |
argcnt = hlast - (source->line - argcnt); |
||
880 |
if (grabhist(modified, argcnt - 1) < 0) |
||
881 |
return -1; |
||
882 |
else { |
||
883 |
modified = 0; |
||
884 |
hnum = argcnt - 1; |
||
885 |
} |
||
886 |
break; |
||
887 |
|||
888 |
case 'i': |
||
889 |
225 |
modified = 1; hnum = hlast; |
|
890 |
225 |
insert = INSERT; |
|
891 |
225 |
break; |
|
892 |
|||
893 |
case 'I': |
||
894 |
50 |
modified = 1; hnum = hlast; |
|
895 |
50 |
es->cursor = domove(1, "^", 1); |
|
896 |
50 |
insert = INSERT; |
|
897 |
50 |
break; |
|
898 |
|||
899 |
case 'j': |
||
900 |
case '+': |
||
901 |
case CTRL('n'): |
||
902 |
if (grabhist(modified, hnum + argcnt) < 0) |
||
903 |
return -1; |
||
904 |
else { |
||
905 |
modified = 0; |
||
906 |
hnum += argcnt; |
||
907 |
} |
||
908 |
break; |
||
909 |
|||
910 |
case 'k': |
||
911 |
case '-': |
||
912 |
case CTRL('p'): |
||
913 |
if (grabhist(modified, hnum - argcnt) < 0) |
||
914 |
return -1; |
||
915 |
else { |
||
916 |
modified = 0; |
||
917 |
hnum -= argcnt; |
||
918 |
} |
||
919 |
break; |
||
920 |
|||
921 |
case 'r': |
||
922 |
✗✓ | 175 |
if (es->linelen == 0) |
923 |
return -1; |
||
924 |
175 |
modified = 1; hnum = hlast; |
|
925 |
✗✓ | 175 |
if (cmd[1] == 0) |
926 |
vi_error(); |
||
927 |
else { |
||
928 |
c1 = 0; |
||
929 |
✓✓ | 950 |
for (cur = es->cursor; |
930 |
775 |
cur < es->linelen; cur++) { |
|
931 |
✓✓ | 400 |
if (!isu8cont(es->cbuf[cur])) |
932 |
300 |
c1++; |
|
933 |
✓✓ | 400 |
if (c1 > argcnt) |
934 |
break; |
||
935 |
} |
||
936 |
✓✓ | 175 |
if (argcnt > c1) |
937 |
25 |
return -1; |
|
938 |
|||
939 |
150 |
del_range(es->cursor, cur); |
|
940 |
✓✓ | 650 |
while (argcnt-- > 0) |
941 |
175 |
putbuf(&cmd[1], 1, 0); |
|
942 |
✓✗ | 150 |
while (es->cursor > 0) |
943 |
✗✓ | 150 |
if (!isu8cont(es->cbuf[--es->cursor])) |
944 |
break; |
||
945 |
150 |
es->cbuf[es->linelen] = '\0'; |
|
946 |
} |
||
947 |
break; |
||
948 |
|||
949 |
case 'R': |
||
950 |
50 |
modified = 1; hnum = hlast; |
|
951 |
50 |
insert = REPLACE; |
|
952 |
50 |
break; |
|
953 |
|||
954 |
case 's': |
||
955 |
✗✓ | 50 |
if (es->linelen == 0) |
956 |
return -1; |
||
957 |
50 |
modified = 1; hnum = hlast; |
|
958 |
✓✓ | 300 |
for (cur = es->cursor; cur < es->linelen; cur++) |
959 |
✓✓ | 125 |
if (!isu8cont(es->cbuf[cur])) |
960 |
✓✓ | 100 |
if (argcnt-- == 0) |
961 |
break; |
||
962 |
50 |
del_range(es->cursor, cur); |
|
963 |
50 |
insert = INSERT; |
|
964 |
50 |
break; |
|
965 |
|||
966 |
case 'v': |
||
967 |
if (es->linelen == 0 && argcnt == 0) |
||
968 |
return -1; |
||
969 |
if (!argcnt) { |
||
970 |
if (modified) { |
||
971 |
es->cbuf[es->linelen] = '\0'; |
||
972 |
source->line++; |
||
973 |
histsave(source->line, es->cbuf, 1); |
||
974 |
} else |
||
975 |
argcnt = source->line + 1 |
||
976 |
- (hlast - hnum); |
||
977 |
} |
||
978 |
shf_snprintf(es->cbuf, es->cbufsize, |
||
979 |
argcnt ? "%s %d" : "%s", |
||
980 |
"fc -e ${VISUAL:-${EDITOR:-vi}} --", |
||
981 |
argcnt); |
||
982 |
es->linelen = strlen(es->cbuf); |
||
983 |
return 2; |
||
984 |
|||
985 |
case 'x': |
||
986 |
✗✓ | 125 |
if (es->linelen == 0) |
987 |
return -1; |
||
988 |
125 |
modified = 1; hnum = hlast; |
|
989 |
✓✓ | 600 |
for (cur = es->cursor; cur < es->linelen; cur++) |
990 |
✓✓ | 225 |
if (!isu8cont(es->cbuf[cur])) |
991 |
✓✓ | 200 |
if (argcnt-- == 0) |
992 |
break; |
||
993 |
125 |
yank_range(es->cursor, cur); |
|
994 |
125 |
del_range(es->cursor, cur); |
|
995 |
125 |
break; |
|
996 |
|||
997 |
case 'X': |
||
998 |
✗✓ | 25 |
if (es->cursor == 0) |
999 |
return -1; |
||
1000 |
25 |
modified = 1; hnum = hlast; |
|
1001 |
✓✗ | 150 |
for (cur = es->cursor; cur > 0; cur--) |
1002 |
✓✗ | 75 |
if (!isu8cont(es->cbuf[cur])) |
1003 |
✓✓ | 75 |
if (argcnt-- == 0) |
1004 |
break; |
||
1005 |
25 |
yank_range(cur, es->cursor); |
|
1006 |
25 |
del_range(cur, es->cursor); |
|
1007 |
25 |
es->cursor = cur; |
|
1008 |
25 |
break; |
|
1009 |
|||
1010 |
case 'u': |
||
1011 |
25 |
t = es; |
|
1012 |
25 |
es = undo; |
|
1013 |
25 |
undo = t; |
|
1014 |
25 |
break; |
|
1015 |
|||
1016 |
case 'U': |
||
1017 |
✗✓ | 25 |
if (!modified) |
1018 |
return -1; |
||
1019 |
✗✓ | 25 |
if (grabhist(modified, ohnum) < 0) |
1020 |
return -1; |
||
1021 |
25 |
modified = 0; |
|
1022 |
25 |
hnum = ohnum; |
|
1023 |
25 |
break; |
|
1024 |
|||
1025 |
case '?': |
||
1026 |
if (hnum == hlast) |
||
1027 |
hnum = -1; |
||
1028 |
/* ahhh */ |
||
1029 |
case '/': |
||
1030 |
c3 = 1; |
||
1031 |
srchlen = 0; |
||
1032 |
lastsearch = *cmd; |
||
1033 |
/* FALLTHROUGH */ |
||
1034 |
case 'n': |
||
1035 |
case 'N': |
||
1036 |
if (lastsearch == ' ') |
||
1037 |
return -1; |
||
1038 |
if (lastsearch == '?') |
||
1039 |
c1 = 1; |
||
1040 |
else |
||
1041 |
c1 = 0; |
||
1042 |
if (*cmd == 'N') |
||
1043 |
c1 = !c1; |
||
1044 |
if ((c2 = grabsearch(modified, hnum, |
||
1045 |
c1, srchpat)) < 0) { |
||
1046 |
if (c3) { |
||
1047 |
restore_cbuf(); |
||
1048 |
refresh(0); |
||
1049 |
} |
||
1050 |
return -1; |
||
1051 |
} else { |
||
1052 |
modified = 0; |
||
1053 |
hnum = c2; |
||
1054 |
ohnum = hnum; |
||
1055 |
} |
||
1056 |
break; |
||
1057 |
case '_': { |
||
1058 |
int inspace; |
||
1059 |
char *p, *sp; |
||
1060 |
|||
1061 |
if (histnum(-1) < 0) |
||
1062 |
return -1; |
||
1063 |
p = *histpos(); |
||
1064 |
#define issp(c) (isspace((unsigned char)(c)) || (c) == '\n') |
||
1065 |
if (argcnt) { |
||
1066 |
while (*p && issp(*p)) |
||
1067 |
p++; |
||
1068 |
while (*p && --argcnt) { |
||
1069 |
while (*p && !issp(*p)) |
||
1070 |
p++; |
||
1071 |
while (*p && issp(*p)) |
||
1072 |
p++; |
||
1073 |
} |
||
1074 |
if (!*p) |
||
1075 |
return -1; |
||
1076 |
sp = p; |
||
1077 |
} else { |
||
1078 |
sp = p; |
||
1079 |
inspace = 0; |
||
1080 |
while (*p) { |
||
1081 |
if (issp(*p)) |
||
1082 |
inspace = 1; |
||
1083 |
else if (inspace) { |
||
1084 |
inspace = 0; |
||
1085 |
sp = p; |
||
1086 |
} |
||
1087 |
p++; |
||
1088 |
} |
||
1089 |
p = sp; |
||
1090 |
} |
||
1091 |
modified = 1; hnum = hlast; |
||
1092 |
if (es->cursor != es->linelen) |
||
1093 |
es->cursor++; |
||
1094 |
while (*p && !issp(*p)) { |
||
1095 |
argcnt++; |
||
1096 |
p++; |
||
1097 |
} |
||
1098 |
if (putbuf(" ", 1, 0) != 0) |
||
1099 |
argcnt = -1; |
||
1100 |
else if (putbuf(sp, argcnt, 0) != 0) |
||
1101 |
argcnt = -1; |
||
1102 |
if (argcnt < 0) { |
||
1103 |
if (es->cursor != 0) |
||
1104 |
es->cursor--; |
||
1105 |
return -1; |
||
1106 |
} |
||
1107 |
insert = INSERT; |
||
1108 |
} |
||
1109 |
break; |
||
1110 |
|||
1111 |
case '~': { |
||
1112 |
char *p; |
||
1113 |
unsigned char c; |
||
1114 |
int i; |
||
1115 |
|||
1116 |
✗✓ | 25 |
if (es->linelen == 0) |
1117 |
return -1; |
||
1118 |
✓✓ | 100 |
for (i = 0; i < argcnt; i++) { |
1119 |
25 |
p = &es->cbuf[es->cursor]; |
|
1120 |
25 |
c = (unsigned char)*p; |
|
1121 |
✓✗ | 25 |
if (islower(c)) { |
1122 |
25 |
modified = 1; hnum = hlast; |
|
1123 |
25 |
*p = toupper(c); |
|
1124 |
✗✗ | 25 |
} else if (isupper(c)) { |
1125 |
modified = 1; hnum = hlast; |
||
1126 |
*p = tolower(c); |
||
1127 |
} |
||
1128 |
✗✓ | 25 |
if (es->cursor < es->linelen - 1) |
1129 |
es->cursor++; |
||
1130 |
} |
||
1131 |
✓✗ | 25 |
break; |
1132 |
} |
||
1133 |
|||
1134 |
case '#': |
||
1135 |
{ |
||
1136 |
int ret = x_do_comment(es->cbuf, es->cbufsize, |
||
1137 |
&es->linelen); |
||
1138 |
if (ret >= 0) |
||
1139 |
es->cursor = 0; |
||
1140 |
return ret; |
||
1141 |
} |
||
1142 |
|||
1143 |
case '=': /* at&t ksh */ |
||
1144 |
case CTRL('e'): /* Nonstandard vi/ksh */ |
||
1145 |
print_expansions(es, 1); |
||
1146 |
break; |
||
1147 |
|||
1148 |
|||
1149 |
case CTRL('i'): /* Nonstandard vi/ksh */ |
||
1150 |
if (!Flag(FVITABCOMPLETE)) |
||
1151 |
return -1; |
||
1152 |
complete_word(1, argcnt); |
||
1153 |
break; |
||
1154 |
|||
1155 |
case CTRL('['): /* some annoying at&t ksh's */ |
||
1156 |
if (!Flag(FVIESCCOMPLETE)) |
||
1157 |
return -1; |
||
1158 |
case '\\': /* at&t ksh */ |
||
1159 |
case CTRL('f'): /* Nonstandard vi/ksh */ |
||
1160 |
complete_word(1, argcnt); |
||
1161 |
break; |
||
1162 |
|||
1163 |
|||
1164 |
case '*': /* at&t ksh */ |
||
1165 |
case CTRL('x'): /* Nonstandard vi/ksh */ |
||
1166 |
expand_word(1); |
||
1167 |
break; |
||
1168 |
} |
||
1169 |
✓✓✓✓ |
2975 |
if (insert == 0 && es->cursor >= es->linelen) |
1170 |
✓✓ | 125 |
while (es->cursor > 0) |
1171 |
✓✓ | 75 |
if (!isu8cont(es->cbuf[--es->cursor])) |
1172 |
break; |
||
1173 |
} |
||
1174 |
3350 |
return 0; |
|
1175 |
3375 |
} |
|
1176 |
|||
1177 |
static int |
||
1178 |
domove(int argcnt, const char *cmd, int sub) |
||
1179 |
{ |
||
1180 |
int bcount, i = 0, t; |
||
1181 |
int ncursor = 0; |
||
1182 |
|||
1183 |
✗✓✗✓ ✗✗✗✓ ✗✓✗✓ ✗✓✗✓ ✓✓✓✓ ✓✗ |
3800 |
switch (*cmd) { |
1184 |
|||
1185 |
case 'b': |
||
1186 |
case 'B': |
||
1187 |
✓✓✗✓ |
275 |
if (!sub && es->cursor == 0) |
1188 |
return -1; |
||
1189 |
175 |
ncursor = (*cmd == 'b' ? backword : Backword)(argcnt); |
|
1190 |
175 |
break; |
|
1191 |
|||
1192 |
case 'e': |
||
1193 |
case 'E': |
||
1194 |
✓✗✗✓ |
100 |
if (!sub && es->cursor + 1 >= es->linelen) |
1195 |
return -1; |
||
1196 |
50 |
ncursor = (*cmd == 'e' ? endword : Endword)(argcnt); |
|
1197 |
✓✗ | 50 |
if (!sub) |
1198 |
✗✓ | 50 |
while (isu8cont((unsigned char)es->cbuf[--ncursor])) |
1199 |
continue; |
||
1200 |
break; |
||
1201 |
|||
1202 |
case 'f': |
||
1203 |
case 'F': |
||
1204 |
case 't': |
||
1205 |
case 'T': |
||
1206 |
200 |
fsavecmd = *cmd; |
|
1207 |
200 |
fsavech = cmd[1]; |
|
1208 |
/* drop through */ |
||
1209 |
|||
1210 |
case ',': |
||
1211 |
case ';': |
||
1212 |
✗✓ | 250 |
if (fsavecmd == ' ') |
1213 |
return -1; |
||
1214 |
250 |
i = fsavecmd == 'f' || fsavecmd == 'F'; |
|
1215 |
250 |
t = fsavecmd > 'a'; |
|
1216 |
✓✓ | 250 |
if (*cmd == ',') |
1217 |
25 |
t = !t; |
|
1218 |
✗✓ | 250 |
if ((ncursor = findch(fsavech, argcnt, t, i)) < 0) |
1219 |
return -1; |
||
1220 |
✗✓ | 250 |
if (sub && t) |
1221 |
ncursor++; |
||
1222 |
break; |
||
1223 |
|||
1224 |
case 'h': |
||
1225 |
case CTRL('h'): |
||
1226 |
✓✓✗✓ |
1025 |
if (!sub && es->cursor == 0) |
1227 |
return -1; |
||
1228 |
✓✓ | 2650 |
for (ncursor = es->cursor; ncursor > 0; ncursor--) |
1229 |
✓✗ | 1275 |
if (!isu8cont(es->cbuf[ncursor])) |
1230 |
✓✓ | 1275 |
if (argcnt-- == 0) |
1231 |
break; |
||
1232 |
break; |
||
1233 |
|||
1234 |
case ' ': |
||
1235 |
case 'l': |
||
1236 |
✓✓✗✓ |
200 |
if (!sub && es->cursor + 1 >= es->linelen) |
1237 |
return -1; |
||
1238 |
✓✗ | 650 |
for (ncursor = es->cursor; ncursor < es->linelen; ncursor++) |
1239 |
✓✗ | 325 |
if (!isu8cont(es->cbuf[ncursor])) |
1240 |
✓✓ | 325 |
if (argcnt-- == 0) |
1241 |
break; |
||
1242 |
break; |
||
1243 |
|||
1244 |
case 'w': |
||
1245 |
case 'W': |
||
1246 |
✓✗✗✓ |
100 |
if (!sub && es->cursor + 1 >= es->linelen) |
1247 |
return -1; |
||
1248 |
50 |
ncursor = (*cmd == 'w' ? forwword : Forwword)(argcnt); |
|
1249 |
50 |
break; |
|
1250 |
|||
1251 |
case '0': |
||
1252 |
ncursor = 0; |
||
1253 |
375 |
break; |
|
1254 |
|||
1255 |
case '^': |
||
1256 |
ncursor = 0; |
||
1257 |
✓✗✓✓ |
825 |
while (ncursor < es->linelen - 1 && |
1258 |
275 |
isspace((unsigned char)es->cbuf[ncursor])) |
|
1259 |
150 |
ncursor++; |
|
1260 |
break; |
||
1261 |
|||
1262 |
case '|': |
||
1263 |
ncursor = argcnt; |
||
1264 |
✗✓ | 25 |
if (ncursor > es->linelen) |
1265 |
ncursor = es->linelen; |
||
1266 |
✓✗ | 25 |
if (ncursor) |
1267 |
25 |
ncursor--; |
|
1268 |
✗✓ | 25 |
while (isu8cont(es->cbuf[ncursor])) |
1269 |
ncursor--; |
||
1270 |
break; |
||
1271 |
|||
1272 |
case '$': |
||
1273 |
50 |
ncursor = es->linelen; |
|
1274 |
50 |
break; |
|
1275 |
|||
1276 |
case '%': |
||
1277 |
50 |
ncursor = es->cursor; |
|
1278 |
✓✗✗✓ |
150 |
while (ncursor < es->linelen && |
1279 |
50 |
(i = bracktype(es->cbuf[ncursor])) == 0) |
|
1280 |
ncursor++; |
||
1281 |
✗✓ | 50 |
if (ncursor == es->linelen) |
1282 |
return -1; |
||
1283 |
bcount = 1; |
||
1284 |
50 |
do { |
|
1285 |
✓✓ | 100 |
if (i > 0) { |
1286 |
✗✓ | 50 |
if (++ncursor >= es->linelen) |
1287 |
return -1; |
||
1288 |
} else { |
||
1289 |
✗✓ | 50 |
if (--ncursor < 0) |
1290 |
return -1; |
||
1291 |
} |
||
1292 |
100 |
t = bracktype(es->cbuf[ncursor]); |
|
1293 |
✗✓ | 100 |
if (t == i) |
1294 |
bcount++; |
||
1295 |
✓✓ | 100 |
else if (t == -i) |
1296 |
50 |
bcount--; |
|
1297 |
✓✓ | 100 |
} while (bcount != 0); |
1298 |
✗✓ | 50 |
if (sub && i > 0) |
1299 |
ncursor++; |
||
1300 |
break; |
||
1301 |
|||
1302 |
default: |
||
1303 |
return -1; |
||
1304 |
} |
||
1305 |
1800 |
return ncursor; |
|
1306 |
1800 |
} |
|
1307 |
|||
1308 |
static int |
||
1309 |
redo_insert(int count) |
||
1310 |
{ |
||
1311 |
✓✓ | 5575 |
while (count-- > 0) |
1312 |
✓✗ | 175 |
if (putbuf(ibuf, inslen, insert==REPLACE) != 0) |
1313 |
return -1; |
||
1314 |
✓✗ | 1800 |
if (es->cursor > 0) |
1315 |
✓✓ | 1925 |
while (isu8cont(es->cbuf[--es->cursor])) |
1316 |
continue; |
||
1317 |
1800 |
insert = 0; |
|
1318 |
1800 |
return 0; |
|
1319 |
1800 |
} |
|
1320 |
|||
1321 |
static void |
||
1322 |
yank_range(int a, int b) |
||
1323 |
{ |
||
1324 |
1400 |
yanklen = b - a; |
|
1325 |
✓✗ | 700 |
if (yanklen != 0) |
1326 |
700 |
memmove(ybuf, &es->cbuf[a], yanklen); |
|
1327 |
700 |
} |
|
1328 |
|||
1329 |
static int |
||
1330 |
bracktype(int ch) |
||
1331 |
{ |
||
1332 |
✓✗✗✓ ✗✗✓ |
300 |
switch (ch) { |
1333 |
|||
1334 |
case '(': |
||
1335 |
50 |
return 1; |
|
1336 |
|||
1337 |
case '[': |
||
1338 |
return 2; |
||
1339 |
|||
1340 |
case '{': |
||
1341 |
return 3; |
||
1342 |
|||
1343 |
case ')': |
||
1344 |
50 |
return -1; |
|
1345 |
|||
1346 |
case ']': |
||
1347 |
return -2; |
||
1348 |
|||
1349 |
case '}': |
||
1350 |
return -3; |
||
1351 |
|||
1352 |
default: |
||
1353 |
50 |
return 0; |
|
1354 |
} |
||
1355 |
150 |
} |
|
1356 |
|||
1357 |
/* |
||
1358 |
* Non user interface editor routines below here |
||
1359 |
*/ |
||
1360 |
|||
1361 |
static int cur_col; /* current display column */ |
||
1362 |
static int pwidth; /* display columns needed for prompt */ |
||
1363 |
static int prompt_trunc; /* how much of prompt to truncate */ |
||
1364 |
static int prompt_skip; /* how much of prompt to skip */ |
||
1365 |
static int winwidth; /* available column positions */ |
||
1366 |
static char *wbuf[2]; /* current & previous window buffer */ |
||
1367 |
static int wbuf_len; /* length of window buffers (x_cols-3)*/ |
||
1368 |
static int win; /* number of window buffer in use */ |
||
1369 |
static char morec; /* more character at right of window */ |
||
1370 |
static char holdbuf[LINE]; /* place to hold last edit buffer */ |
||
1371 |
static int holdlen; /* length of holdbuf */ |
||
1372 |
|||
1373 |
static void |
||
1374 |
save_cbuf(void) |
||
1375 |
{ |
||
1376 |
memmove(holdbuf, es->cbuf, es->linelen); |
||
1377 |
holdlen = es->linelen; |
||
1378 |
holdbuf[holdlen] = '\0'; |
||
1379 |
} |
||
1380 |
|||
1381 |
static void |
||
1382 |
restore_cbuf(void) |
||
1383 |
{ |
||
1384 |
50 |
es->cursor = 0; |
|
1385 |
25 |
es->linelen = holdlen; |
|
1386 |
25 |
memmove(es->cbuf, holdbuf, holdlen); |
|
1387 |
25 |
} |
|
1388 |
|||
1389 |
/* return a new edstate */ |
||
1390 |
static struct edstate * |
||
1391 |
save_edstate(struct edstate *old) |
||
1392 |
{ |
||
1393 |
struct edstate *new; |
||
1394 |
|||
1395 |
new = alloc(sizeof(struct edstate), APERM); |
||
1396 |
new->cbuf = alloc(old->cbufsize, APERM); |
||
1397 |
memcpy(new->cbuf, old->cbuf, old->linelen); |
||
1398 |
new->cbufsize = old->cbufsize; |
||
1399 |
new->linelen = old->linelen; |
||
1400 |
new->cursor = old->cursor; |
||
1401 |
new->winleft = old->winleft; |
||
1402 |
return new; |
||
1403 |
} |
||
1404 |
|||
1405 |
static void |
||
1406 |
restore_edstate(struct edstate *new, struct edstate *old) |
||
1407 |
{ |
||
1408 |
memcpy(new->cbuf, old->cbuf, old->linelen); |
||
1409 |
new->linelen = old->linelen; |
||
1410 |
new->cursor = old->cursor; |
||
1411 |
new->winleft = old->winleft; |
||
1412 |
free_edstate(old); |
||
1413 |
} |
||
1414 |
|||
1415 |
static void |
||
1416 |
free_edstate(struct edstate *old) |
||
1417 |
{ |
||
1418 |
afree(old->cbuf, APERM); |
||
1419 |
afree(old, APERM); |
||
1420 |
} |
||
1421 |
|||
1422 |
|||
1423 |
|||
1424 |
static void |
||
1425 |
edit_reset(char *buf, size_t len) |
||
1426 |
{ |
||
1427 |
3550 |
const char *p; |
|
1428 |
|||
1429 |
1775 |
es = &ebuf; |
|
1430 |
1775 |
es->cbuf = buf; |
|
1431 |
1775 |
es->cbufsize = len; |
|
1432 |
1775 |
undo = &undobuf; |
|
1433 |
1775 |
undo->cbufsize = len; |
|
1434 |
|||
1435 |
1775 |
es->linelen = undo->linelen = 0; |
|
1436 |
1775 |
es->cursor = undo->cursor = 0; |
|
1437 |
1775 |
es->winleft = undo->winleft = 0; |
|
1438 |
|||
1439 |
1775 |
cur_col = pwidth = promptlen(prompt, &p); |
|
1440 |
1775 |
prompt_skip = p - prompt; |
|
1441 |
✗✓ | 1775 |
if (pwidth > x_cols - 3 - MIN_EDIT_SPACE) { |
1442 |
cur_col = x_cols - 3 - MIN_EDIT_SPACE; |
||
1443 |
prompt_trunc = pwidth - cur_col; |
||
1444 |
pwidth -= prompt_trunc; |
||
1445 |
} else |
||
1446 |
1775 |
prompt_trunc = 0; |
|
1447 |
✓✓✗✓ |
1875 |
if (!wbuf_len || wbuf_len != x_cols - 3) { |
1448 |
1675 |
wbuf_len = x_cols - 3; |
|
1449 |
1675 |
wbuf[0] = aresize(wbuf[0], wbuf_len, APERM); |
|
1450 |
1675 |
wbuf[1] = aresize(wbuf[1], wbuf_len, APERM); |
|
1451 |
1675 |
} |
|
1452 |
1775 |
(void) memset(wbuf[0], ' ', wbuf_len); |
|
1453 |
1775 |
(void) memset(wbuf[1], ' ', wbuf_len); |
|
1454 |
1775 |
winwidth = x_cols - pwidth - 3; |
|
1455 |
1775 |
win = 0; |
|
1456 |
1775 |
morec = ' '; |
|
1457 |
1775 |
holdlen = 0; |
|
1458 |
1775 |
} |
|
1459 |
|||
1460 |
/* |
||
1461 |
* this is used for calling x_escape() in complete_word() |
||
1462 |
*/ |
||
1463 |
static int |
||
1464 |
x_vi_putbuf(const char *s, size_t len) |
||
1465 |
{ |
||
1466 |
return putbuf(s, len, 0); |
||
1467 |
} |
||
1468 |
|||
1469 |
static int |
||
1470 |
putbuf(const char *buf, int len, int repl) |
||
1471 |
{ |
||
1472 |
✗✓ | 1150 |
if (len == 0) |
1473 |
return 0; |
||
1474 |
✓✓ | 575 |
if (repl) { |
1475 |
✗✓ | 50 |
if (es->cursor + len >= es->cbufsize) |
1476 |
return -1; |
||
1477 |
✗✓ | 50 |
if (es->cursor + len > es->linelen) |
1478 |
es->linelen = es->cursor + len; |
||
1479 |
} else { |
||
1480 |
✗✓ | 525 |
if (es->linelen + len >= es->cbufsize) |
1481 |
return -1; |
||
1482 |
1050 |
memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor], |
|
1483 |
525 |
es->linelen - es->cursor); |
|
1484 |
525 |
es->linelen += len; |
|
1485 |
} |
||
1486 |
575 |
memmove(&es->cbuf[es->cursor], buf, len); |
|
1487 |
575 |
es->cursor += len; |
|
1488 |
575 |
return 0; |
|
1489 |
575 |
} |
|
1490 |
|||
1491 |
static void |
||
1492 |
del_range(int a, int b) |
||
1493 |
{ |
||
1494 |
✓✓ | 2000 |
if (es->linelen != b) |
1495 |
350 |
memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b); |
|
1496 |
1000 |
es->linelen -= b - a; |
|
1497 |
1000 |
} |
|
1498 |
|||
1499 |
static int |
||
1500 |
findch(int ch, int cnt, int forw, int incl) |
||
1501 |
{ |
||
1502 |
int ncursor; |
||
1503 |
|||
1504 |
✗✓ | 500 |
if (es->linelen == 0) |
1505 |
return -1; |
||
1506 |
250 |
ncursor = es->cursor; |
|
1507 |
✓✓ | 900 |
while (cnt--) { |
1508 |
do { |
||
1509 |
✓✓ | 500 |
if (forw) { |
1510 |
✗✓ | 250 |
if (++ncursor == es->linelen) |
1511 |
return -1; |
||
1512 |
} else { |
||
1513 |
✗✓ | 250 |
if (--ncursor < 0) |
1514 |
return -1; |
||
1515 |
} |
||
1516 |
✓✓ | 500 |
} while (es->cbuf[ncursor] != ch); |
1517 |
} |
||
1518 |
✓✓ | 250 |
if (!incl) { |
1519 |
✓✓ | 100 |
if (forw) |
1520 |
50 |
ncursor--; |
|
1521 |
else |
||
1522 |
50 |
ncursor++; |
|
1523 |
} |
||
1524 |
250 |
return ncursor; |
|
1525 |
250 |
} |
|
1526 |
|||
1527 |
/* Move right one character, and then to the beginning of the next word. */ |
||
1528 |
static int |
||
1529 |
forwword(int argcnt) |
||
1530 |
{ |
||
1531 |
int ncursor, skip_space, want_letnum; |
||
1532 |
unsigned char uc; |
||
1533 |
|||
1534 |
50 |
ncursor = es->cursor; |
|
1535 |
✓✗✓✓ |
175 |
while (ncursor < es->linelen && argcnt--) { |
1536 |
skip_space = 0; |
||
1537 |
want_letnum = -1; |
||
1538 |
50 |
ncursor--; |
|
1539 |
✗✓ | 250 |
while (++ncursor < es->linelen) { |
1540 |
200 |
uc = es->cbuf[ncursor]; |
|
1541 |
✓✓ | 200 |
if (isspace(uc)) { |
1542 |
skip_space = 1; |
||
1543 |
50 |
continue; |
|
1544 |
✓✓ | 150 |
} else if (skip_space) |
1545 |
break; |
||
1546 |
✗✓ | 100 |
if (uc & 0x80) |
1547 |
continue; |
||
1548 |
✓✓ | 100 |
if (want_letnum == -1) |
1549 |
✗✓ | 100 |
want_letnum = letnum(uc); |
1550 |
✗✓✗✓ |
100 |
else if (want_letnum != letnum(uc)) |
1551 |
break; |
||
1552 |
} |
||
1553 |
} |
||
1554 |
25 |
return ncursor; |
|
1555 |
} |
||
1556 |
|||
1557 |
/* Move left one character, and then to the beginning of the word. */ |
||
1558 |
static int |
||
1559 |
backword(int argcnt) |
||
1560 |
{ |
||
1561 |
int ncursor, skip_space, want_letnum; |
||
1562 |
unsigned char uc; |
||
1563 |
|||
1564 |
350 |
ncursor = es->cursor; |
|
1565 |
✓✗✓✓ |
1200 |
while (ncursor > 0 && argcnt--) { |
1566 |
skip_space = 1; |
||
1567 |
want_letnum = -1; |
||
1568 |
✓✗ | 900 |
while (ncursor-- > 0) { |
1569 |
675 |
uc = es->cbuf[ncursor]; |
|
1570 |
✓✓ | 675 |
if (isspace(uc)) { |
1571 |
✓✓ | 200 |
if (skip_space) |
1572 |
continue; |
||
1573 |
else |
||
1574 |
break; |
||
1575 |
} |
||
1576 |
skip_space = 0; |
||
1577 |
✗✓ | 475 |
if (uc & 0x80) |
1578 |
continue; |
||
1579 |
✓✓ | 475 |
if (want_letnum == -1) |
1580 |
✓✓ | 475 |
want_letnum = letnum(uc); |
1581 |
✓✓✓✓ |
525 |
else if (want_letnum != letnum(uc)) |
1582 |
break; |
||
1583 |
} |
||
1584 |
ncursor++; |
||
1585 |
} |
||
1586 |
175 |
return ncursor; |
|
1587 |
} |
||
1588 |
|||
1589 |
/* Move right one character, and then to the byte after the word. */ |
||
1590 |
static int |
||
1591 |
endword(int argcnt) |
||
1592 |
{ |
||
1593 |
int ncursor, skip_space, want_letnum; |
||
1594 |
unsigned char uc; |
||
1595 |
|||
1596 |
50 |
ncursor = es->cursor; |
|
1597 |
✓✗✓✓ |
125 |
while (ncursor < es->linelen && argcnt--) { |
1598 |
skip_space = 1; |
||
1599 |
want_letnum = -1; |
||
1600 |
✗✓ | 125 |
while (++ncursor < es->linelen) { |
1601 |
100 |
uc = es->cbuf[ncursor]; |
|
1602 |
✓✓ | 100 |
if (isspace(uc)) { |
1603 |
✓✗ | 25 |
if (skip_space) |
1604 |
continue; |
||
1605 |
else |
||
1606 |
break; |
||
1607 |
} |
||
1608 |
skip_space = 0; |
||
1609 |
✗✓ | 75 |
if (uc & 0x80) |
1610 |
continue; |
||
1611 |
✓✓ | 75 |
if (want_letnum == -1) |
1612 |
✗✓ | 50 |
want_letnum = letnum(uc); |
1613 |
✗✓✗✓ |
100 |
else if (want_letnum != letnum(uc)) |
1614 |
break; |
||
1615 |
} |
||
1616 |
} |
||
1617 |
25 |
return ncursor; |
|
1618 |
} |
||
1619 |
|||
1620 |
/* Move right one character, and then to the beginning of the next big word. */ |
||
1621 |
static int |
||
1622 |
Forwword(int argcnt) |
||
1623 |
{ |
||
1624 |
int ncursor; |
||
1625 |
|||
1626 |
50 |
ncursor = es->cursor; |
|
1627 |
✓✗✓✓ |
125 |
while (ncursor < es->linelen && argcnt--) { |
1628 |
✓✓✓✗ |
250 |
while (!isspace((unsigned char)es->cbuf[ncursor]) && |
1629 |
75 |
ncursor < es->linelen) |
|
1630 |
75 |
ncursor++; |
|
1631 |
✓✓✗✓ |
100 |
while (isspace((unsigned char)es->cbuf[ncursor]) && |
1632 |
25 |
ncursor < es->linelen) |
|
1633 |
25 |
ncursor++; |
|
1634 |
} |
||
1635 |
25 |
return ncursor; |
|
1636 |
} |
||
1637 |
|||
1638 |
/* Move left one character, and then to the beginning of the big word. */ |
||
1639 |
static int |
||
1640 |
Backword(int argcnt) |
||
1641 |
{ |
||
1642 |
int ncursor; |
||
1643 |
|||
1644 |
50 |
ncursor = es->cursor; |
|
1645 |
✓✗✓✓ |
150 |
while (ncursor > 0 && argcnt--) { |
1646 |
✓✗✗✓ |
50 |
while (--ncursor >= 0 && |
1647 |
25 |
isspace((unsigned char)es->cbuf[ncursor])) |
|
1648 |
; |
||
1649 |
✓✗✓✓ |
200 |
while (ncursor >= 0 && |
1650 |
75 |
!isspace((unsigned char)es->cbuf[ncursor])) |
|
1651 |
50 |
ncursor--; |
|
1652 |
25 |
ncursor++; |
|
1653 |
} |
||
1654 |
25 |
return ncursor; |
|
1655 |
} |
||
1656 |
|||
1657 |
/* Move right one character, and then to the byte after the big word. */ |
||
1658 |
static int |
||
1659 |
Endword(int argcnt) |
||
1660 |
{ |
||
1661 |
int ncursor; |
||
1662 |
|||
1663 |
50 |
ncursor = es->cursor; |
|
1664 |
✓✗✓✓ |
125 |
while (ncursor < es->linelen && argcnt--) { |
1665 |
✓✗✗✓ |
50 |
while (++ncursor < es->linelen && |
1666 |
25 |
isspace((unsigned char)es->cbuf[ncursor])) |
|
1667 |
; |
||
1668 |
✗✓✓✓ |
275 |
while (ncursor < es->linelen && |
1669 |
100 |
!isspace((unsigned char)es->cbuf[ncursor])) |
|
1670 |
75 |
ncursor++; |
|
1671 |
} |
||
1672 |
25 |
return ncursor; |
|
1673 |
} |
||
1674 |
|||
1675 |
static int |
||
1676 |
grabhist(int save, int n) |
||
1677 |
{ |
||
1678 |
char *hptr; |
||
1679 |
|||
1680 |
✓✗✗✓ |
75 |
if (n < 0 || n > hlast) |
1681 |
return -1; |
||
1682 |
✓✗ | 25 |
if (n == hlast) { |
1683 |
25 |
restore_cbuf(); |
|
1684 |
25 |
ohnum = n; |
|
1685 |
25 |
return 0; |
|
1686 |
} |
||
1687 |
(void) histnum(n); |
||
1688 |
if ((hptr = *histpos()) == NULL) { |
||
1689 |
internal_errorf(0, "grabhist: bad history array"); |
||
1690 |
return -1; |
||
1691 |
} |
||
1692 |
if (save) |
||
1693 |
save_cbuf(); |
||
1694 |
if ((es->linelen = strlen(hptr)) >= es->cbufsize) |
||
1695 |
es->linelen = es->cbufsize - 1; |
||
1696 |
memmove(es->cbuf, hptr, es->linelen); |
||
1697 |
es->cursor = 0; |
||
1698 |
ohnum = n; |
||
1699 |
return 0; |
||
1700 |
25 |
} |
|
1701 |
|||
1702 |
static int |
||
1703 |
grabsearch(int save, int start, int fwd, char *pat) |
||
1704 |
{ |
||
1705 |
char *hptr; |
||
1706 |
int hist; |
||
1707 |
int anchored; |
||
1708 |
|||
1709 |
if ((start == 0 && fwd == 0) || (start >= hlast-1 && fwd == 1)) |
||
1710 |
return -1; |
||
1711 |
if (fwd) |
||
1712 |
start++; |
||
1713 |
else |
||
1714 |
start--; |
||
1715 |
anchored = *pat == '^' ? (++pat, 1) : 0; |
||
1716 |
if ((hist = findhist(start, fwd, pat, anchored)) < 0) { |
||
1717 |
/* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */ |
||
1718 |
/* XXX should strcmp be strncmp? */ |
||
1719 |
if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) { |
||
1720 |
restore_cbuf(); |
||
1721 |
return 0; |
||
1722 |
} else |
||
1723 |
return -1; |
||
1724 |
} |
||
1725 |
if (save) |
||
1726 |
save_cbuf(); |
||
1727 |
histnum(hist); |
||
1728 |
hptr = *histpos(); |
||
1729 |
if ((es->linelen = strlen(hptr)) >= es->cbufsize) |
||
1730 |
es->linelen = es->cbufsize - 1; |
||
1731 |
memmove(es->cbuf, hptr, es->linelen); |
||
1732 |
es->cursor = 0; |
||
1733 |
return hist; |
||
1734 |
} |
||
1735 |
|||
1736 |
static void |
||
1737 |
redraw_line(int newline) |
||
1738 |
{ |
||
1739 |
100 |
(void) memset(wbuf[win], ' ', wbuf_len); |
|
1740 |
✓✗ | 50 |
if (newline) { |
1741 |
50 |
x_putc('\r'); |
|
1742 |
50 |
x_putc('\n'); |
|
1743 |
50 |
} |
|
1744 |
50 |
vi_pprompt(0); |
|
1745 |
50 |
cur_col = pwidth; |
|
1746 |
50 |
morec = ' '; |
|
1747 |
50 |
} |
|
1748 |
|||
1749 |
static void |
||
1750 |
refresh(int leftside) |
||
1751 |
{ |
||
1752 |
✗✓ | 28700 |
if (outofwin()) |
1753 |
rewindow(); |
||
1754 |
14350 |
display(wbuf[1 - win], wbuf[win], leftside); |
|
1755 |
14350 |
win = 1 - win; |
|
1756 |
14350 |
} |
|
1757 |
|||
1758 |
static int |
||
1759 |
outofwin(void) |
||
1760 |
{ |
||
1761 |
int cur, col; |
||
1762 |
|||
1763 |
✗✓ | 28700 |
if (es->cursor < es->winleft) |
1764 |
return 1; |
||
1765 |
col = 0; |
||
1766 |
cur = es->winleft; |
||
1767 |
✓✓ | 113600 |
while (cur < es->cursor) |
1768 |
42450 |
col = newcol((unsigned char) es->cbuf[cur++], col); |
|
1769 |
✗✓ | 14350 |
if (col >= winwidth) |
1770 |
return 1; |
||
1771 |
14350 |
return 0; |
|
1772 |
14350 |
} |
|
1773 |
|||
1774 |
static void |
||
1775 |
rewindow(void) |
||
1776 |
{ |
||
1777 |
int tcur, tcol; |
||
1778 |
int holdcur1, holdcol1; |
||
1779 |
int holdcur2, holdcol2; |
||
1780 |
|||
1781 |
holdcur1 = holdcur2 = tcur = 0; |
||
1782 |
holdcol1 = holdcol2 = tcol = 0; |
||
1783 |
while (tcur < es->cursor) { |
||
1784 |
if (tcol - holdcol2 > winwidth / 2) { |
||
1785 |
holdcur1 = holdcur2; |
||
1786 |
holdcol1 = holdcol2; |
||
1787 |
holdcur2 = tcur; |
||
1788 |
holdcol2 = tcol; |
||
1789 |
} |
||
1790 |
tcol = newcol((unsigned char) es->cbuf[tcur++], tcol); |
||
1791 |
} |
||
1792 |
while (tcol - holdcol1 > winwidth / 2) |
||
1793 |
holdcol1 = newcol((unsigned char) es->cbuf[holdcur1++], |
||
1794 |
holdcol1); |
||
1795 |
es->winleft = holdcur1; |
||
1796 |
} |
||
1797 |
|||
1798 |
/* Printing the byte ch at display column col moves to which column? */ |
||
1799 |
static int |
||
1800 |
newcol(int ch, int col) |
||
1801 |
{ |
||
1802 |
✗✓ | 95400 |
if (ch == '\t') |
1803 |
return (col | 7) + 1; |
||
1804 |
✓✓ | 47700 |
if (isu8cont(ch)) |
1805 |
225 |
return col; |
|
1806 |
47475 |
return col + char_len(ch); |
|
1807 |
47700 |
} |
|
1808 |
|||
1809 |
/* Display wb1 assuming that wb2 is currently displayed. */ |
||
1810 |
static void |
||
1811 |
display(char *wb1, char *wb2, int leftside) |
||
1812 |
{ |
||
1813 |
char *twb1; /* pointer into the buffer to display */ |
||
1814 |
char *twb2; /* pointer into the previous display buffer */ |
||
1815 |
static int lastb = -1; /* last byte# written from wb1, if UTF-8 */ |
||
1816 |
int cur; /* byte# in the main command line buffer */ |
||
1817 |
int col; /* display column loop variable */ |
||
1818 |
int ncol; /* display column of the cursor */ |
||
1819 |
int cnt; /* remaining display columns to fill */ |
||
1820 |
int moreright; |
||
1821 |
char mc; /* new "more character" at the right of window */ |
||
1822 |
unsigned char ch; |
||
1823 |
|||
1824 |
/* |
||
1825 |
* Fill the current display buffer with data from cbuf. |
||
1826 |
* In this first loop, col does not include the prompt. |
||
1827 |
*/ |
||
1828 |
|||
1829 |
ncol = col = 0; |
||
1830 |
28700 |
cur = es->winleft; |
|
1831 |
moreright = 0; |
||
1832 |
twb1 = wb1; |
||
1833 |
✓✗✓✓ |
270700 |
while (col < winwidth && cur < es->linelen) { |
1834 |
✓✓ | 53325 |
if (cur == es->cursor && leftside) |
1835 |
1225 |
ncol = col + pwidth; |
|
1836 |
✗✓ | 53325 |
if ((ch = es->cbuf[cur]) == '\t') { |
1837 |
do { |
||
1838 |
*twb1++ = ' '; |
||
1839 |
} while (++col < winwidth && (col & 7) != 0); |
||
1840 |
} else { |
||
1841 |
✓✓✗✓ |
54200 |
if ((ch & 0x80) && Flag(FVISHOW8)) { |
1842 |
*twb1++ = 'M'; |
||
1843 |
if (++col < winwidth) { |
||
1844 |
*twb1++ = '-'; |
||
1845 |
col++; |
||
1846 |
} |
||
1847 |
ch &= 0x7f; |
||
1848 |
} |
||
1849 |
✓✗ | 53325 |
if (col < winwidth) { |
1850 |
✓✓✗✓ |
106600 |
if (ch < ' ' || ch == 0x7f) { |
1851 |
50 |
*twb1++ = '^'; |
|
1852 |
✓✗ | 50 |
if (++col < winwidth) { |
1853 |
50 |
*twb1++ = ch ^ '@'; |
|
1854 |
50 |
col++; |
|
1855 |
50 |
} |
|
1856 |
} else { |
||
1857 |
53275 |
*twb1++ = ch; |
|
1858 |
✓✓ | 53275 |
if (!isu8cont(ch)) |
1859 |
52875 |
col++; |
|
1860 |
} |
||
1861 |
} |
||
1862 |
} |
||
1863 |
✓✓ | 53325 |
if (cur == es->cursor && !leftside) |
1864 |
4475 |
ncol = col + pwidth - 1; |
|
1865 |
53325 |
cur++; |
|
1866 |
} |
||
1867 |
✓✓ | 14350 |
if (cur == es->cursor) |
1868 |
8650 |
ncol = col + pwidth; |
|
1869 |
|||
1870 |
/* Pad the current display buffer to the right margin. */ |
||
1871 |
|||
1872 |
✓✗ | 14350 |
if (col < winwidth) { |
1873 |
✓✓ | 2032200 |
while (col < winwidth) { |
1874 |
1008925 |
*twb1++ = ' '; |
|
1875 |
1008925 |
col++; |
|
1876 |
} |
||
1877 |
} else |
||
1878 |
moreright++; |
||
1879 |
14350 |
*twb1 = ' '; |
|
1880 |
|||
1881 |
/* |
||
1882 |
* Update the terminal display with data from wb1. |
||
1883 |
* In this final loop, col includes the prompt. |
||
1884 |
*/ |
||
1885 |
|||
1886 |
14350 |
col = pwidth; |
|
1887 |
14350 |
cnt = winwidth; |
|
1888 |
✓✓ | 2153000 |
for (twb1 = wb1, twb2 = wb2; cnt; twb1++, twb2++) { |
1889 |
✓✓ | 1062150 |
if (*twb1 != *twb2) { |
1890 |
|||
1891 |
/* |
||
1892 |
* When a byte changes in the middle of a UTF-8 |
||
1893 |
* character, back up to the start byte, unless |
||
1894 |
* the previous byte was the last one written. |
||
1895 |
*/ |
||
1896 |
|||
1897 |
✓✗✓✓ |
27350 |
if (col > 0 && isu8cont(*twb1)) { |
1898 |
150 |
col--; |
|
1899 |
✓✗✓✗ |
300 |
if (lastb >= 0 && twb1 == wb1 + lastb + 1) |
1900 |
150 |
cur_col = col; |
|
1901 |
else while (twb1 > wb1 && isu8cont(*twb1)) { |
||
1902 |
twb1--; |
||
1903 |
twb2--; |
||
1904 |
} |
||
1905 |
} |
||
1906 |
|||
1907 |
✓✓ | 13675 |
if (cur_col != col) |
1908 |
675 |
ed_mov_opt(col, wb1); |
|
1909 |
|||
1910 |
/* |
||
1911 |
* Always write complete characters, and |
||
1912 |
* advance all pointers accordingly. |
||
1913 |
*/ |
||
1914 |
|||
1915 |
13675 |
x_putc(*twb1); |
|
1916 |
✗✓ | 27350 |
while (isu8cont(twb1[1])) { |
1917 |
x_putc(*++twb1); |
||
1918 |
twb2++; |
||
1919 |
} |
||
1920 |
✓✓ | 27625 |
lastb = *twb1 & 0x80 ? twb1 - wb1 : -1; |
1921 |
13675 |
cur_col++; |
|
1922 |
✓✓ | 1062150 |
} else if (isu8cont(*twb1)) |
1923 |
continue; |
||
1924 |
|||
1925 |
/* |
||
1926 |
* For changed continuation bytes, we backed up. |
||
1927 |
* For unchanged ones, we jumped to the next byte. |
||
1928 |
* So, getting here, we had a real column. |
||
1929 |
*/ |
||
1930 |
|||
1931 |
1061900 |
col++; |
|
1932 |
1061900 |
cnt--; |
|
1933 |
1061900 |
} |
|
1934 |
|||
1935 |
/* Update the "more character". */ |
||
1936 |
|||
1937 |
✗✓ | 14350 |
if (es->winleft > 0 && moreright) |
1938 |
/* POSIX says to use * for this but that is a globbing |
||
1939 |
* character and may confuse people; + is more innocuous |
||
1940 |
*/ |
||
1941 |
mc = '+'; |
||
1942 |
✗✓ | 14350 |
else if (es->winleft > 0) |
1943 |
mc = '<'; |
||
1944 |
✗✓ | 14350 |
else if (moreright) |
1945 |
mc = '>'; |
||
1946 |
else |
||
1947 |
mc = ' '; |
||
1948 |
✗✓ | 14350 |
if (mc != morec) { |
1949 |
ed_mov_opt(pwidth + winwidth + 1, wb1); |
||
1950 |
x_putc(mc); |
||
1951 |
cur_col++; |
||
1952 |
morec = mc; |
||
1953 |
lastb = -1; |
||
1954 |
} |
||
1955 |
|||
1956 |
/* Move the cursor to its new position. */ |
||
1957 |
|||
1958 |
✓✓ | 14350 |
if (cur_col != ncol) { |
1959 |
6200 |
ed_mov_opt(ncol, wb1); |
|
1960 |
6200 |
lastb = -1; |
|
1961 |
6200 |
} |
|
1962 |
14350 |
} |
|
1963 |
|||
1964 |
/* Move the display cursor to display column number col. */ |
||
1965 |
static void |
||
1966 |
ed_mov_opt(int col, char *wb) |
||
1967 |
{ |
||
1968 |
int ci; |
||
1969 |
|||
1970 |
/* The cursor is already at the right place. */ |
||
1971 |
|||
1972 |
✗✓ | 13750 |
if (cur_col == col) |
1973 |
return; |
||
1974 |
|||
1975 |
/* The cursor is too far right. */ |
||
1976 |
|||
1977 |
✓✓ | 6875 |
if (cur_col > col) { |
1978 |
✓✓ | 5375 |
if (cur_col > 2 * col + 1) { |
1979 |
/* Much too far right, redraw from scratch. */ |
||
1980 |
175 |
x_putc('\r'); |
|
1981 |
175 |
vi_pprompt(0); |
|
1982 |
175 |
cur_col = pwidth; |
|
1983 |
} else { |
||
1984 |
/* Slightly too far right, back up. */ |
||
1985 |
do { |
||
1986 |
9225 |
x_putc('\b'); |
|
1987 |
✓✓ | 9225 |
} while (--cur_col > col); |
1988 |
5200 |
return; |
|
1989 |
} |
||
1990 |
175 |
} |
|
1991 |
|||
1992 |
/* Advance the cursor. */ |
||
1993 |
|||
1994 |
✓✓✓✓ |
22450 |
for (ci = pwidth; ci < col || isu8cont(*wb); |
1995 |
5250 |
ci = newcol((unsigned char)*wb++, ci)) |
|
1996 |
✓✓✓✓ ✓✗ |
11425 |
if (ci > cur_col || (ci == cur_col && !isu8cont(*wb))) |
1997 |
2075 |
x_putc(*wb); |
|
1998 |
1675 |
cur_col = ci; |
|
1999 |
8550 |
} |
|
2000 |
|||
2001 |
|||
2002 |
/* replace word with all expansions (ie, expand word*) */ |
||
2003 |
static int |
||
2004 |
expand_word(int command) |
||
2005 |
{ |
||
2006 |
static struct edstate *buf; |
||
2007 |
int rval = 0; |
||
2008 |
int nwords; |
||
2009 |
int start, end; |
||
2010 |
char **words; |
||
2011 |
int i; |
||
2012 |
|||
2013 |
/* Undo previous expansion */ |
||
2014 |
if (command == 0 && expanded == EXPAND && buf) { |
||
2015 |
restore_edstate(es, buf); |
||
2016 |
buf = NULL; |
||
2017 |
expanded = NONE; |
||
2018 |
return 0; |
||
2019 |
} |
||
2020 |
if (buf) { |
||
2021 |
free_edstate(buf); |
||
2022 |
buf = NULL; |
||
2023 |
} |
||
2024 |
|||
2025 |
nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH, |
||
2026 |
es->cbuf, es->linelen, es->cursor, |
||
2027 |
&start, &end, &words, NULL); |
||
2028 |
if (nwords == 0) { |
||
2029 |
vi_error(); |
||
2030 |
return -1; |
||
2031 |
} |
||
2032 |
|||
2033 |
buf = save_edstate(es); |
||
2034 |
expanded = EXPAND; |
||
2035 |
del_range(start, end); |
||
2036 |
es->cursor = start; |
||
2037 |
for (i = 0; i < nwords; ) { |
||
2038 |
if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) { |
||
2039 |
rval = -1; |
||
2040 |
break; |
||
2041 |
} |
||
2042 |
if (++i < nwords && putbuf(" ", 1, 0) != 0) { |
||
2043 |
rval = -1; |
||
2044 |
break; |
||
2045 |
} |
||
2046 |
} |
||
2047 |
i = buf->cursor - end; |
||
2048 |
if (rval == 0 && i > 0) |
||
2049 |
es->cursor += i; |
||
2050 |
modified = 1; hnum = hlast; |
||
2051 |
insert = INSERT; |
||
2052 |
lastac = 0; |
||
2053 |
refresh(0); |
||
2054 |
return rval; |
||
2055 |
} |
||
2056 |
|||
2057 |
static int |
||
2058 |
complete_word(int command, int count) |
||
2059 |
{ |
||
2060 |
static struct edstate *buf; |
||
2061 |
int rval = 0; |
||
2062 |
int nwords; |
||
2063 |
int start, end; |
||
2064 |
char **words; |
||
2065 |
char *match; |
||
2066 |
int match_len; |
||
2067 |
int is_unique; |
||
2068 |
int is_command; |
||
2069 |
|||
2070 |
/* Undo previous completion */ |
||
2071 |
if (command == 0 && expanded == COMPLETE && buf) { |
||
2072 |
print_expansions(buf, 0); |
||
2073 |
expanded = PRINT; |
||
2074 |
return 0; |
||
2075 |
} |
||
2076 |
if (command == 0 && expanded == PRINT && buf) { |
||
2077 |
restore_edstate(es, buf); |
||
2078 |
buf = NULL; |
||
2079 |
expanded = NONE; |
||
2080 |
return 0; |
||
2081 |
} |
||
2082 |
if (buf) { |
||
2083 |
free_edstate(buf); |
||
2084 |
buf = NULL; |
||
2085 |
} |
||
2086 |
|||
2087 |
/* XCF_FULLPATH for count 'cause the menu printed by print_expansions() |
||
2088 |
* was done this way. |
||
2089 |
*/ |
||
2090 |
nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0), |
||
2091 |
es->cbuf, es->linelen, es->cursor, |
||
2092 |
&start, &end, &words, &is_command); |
||
2093 |
if (nwords == 0) { |
||
2094 |
vi_error(); |
||
2095 |
return -1; |
||
2096 |
} |
||
2097 |
if (count) { |
||
2098 |
int i; |
||
2099 |
|||
2100 |
count--; |
||
2101 |
if (count >= nwords) { |
||
2102 |
vi_error(); |
||
2103 |
x_print_expansions(nwords, words, is_command); |
||
2104 |
x_free_words(nwords, words); |
||
2105 |
redraw_line(0); |
||
2106 |
return -1; |
||
2107 |
} |
||
2108 |
/* |
||
2109 |
* Expand the count'th word to its basename |
||
2110 |
*/ |
||
2111 |
if (is_command) { |
||
2112 |
match = words[count] + |
||
2113 |
x_basename(words[count], NULL); |
||
2114 |
/* If more than one possible match, use full path */ |
||
2115 |
for (i = 0; i < nwords; i++) |
||
2116 |
if (i != count && |
||
2117 |
strcmp(words[i] + x_basename(words[i], |
||
2118 |
NULL), match) == 0) { |
||
2119 |
match = words[count]; |
||
2120 |
break; |
||
2121 |
} |
||
2122 |
} else |
||
2123 |
match = words[count]; |
||
2124 |
match_len = strlen(match); |
||
2125 |
is_unique = 1; |
||
2126 |
/* expanded = PRINT; next call undo */ |
||
2127 |
} else { |
||
2128 |
match = words[0]; |
||
2129 |
match_len = x_longest_prefix(nwords, words); |
||
2130 |
expanded = COMPLETE; /* next call will list completions */ |
||
2131 |
is_unique = nwords == 1; |
||
2132 |
} |
||
2133 |
|||
2134 |
buf = save_edstate(es); |
||
2135 |
del_range(start, end); |
||
2136 |
es->cursor = start; |
||
2137 |
|||
2138 |
/* escape all shell-sensitive characters and put the result into |
||
2139 |
* command buffer */ |
||
2140 |
rval = x_escape(match, match_len, x_vi_putbuf); |
||
2141 |
|||
2142 |
if (rval == 0 && is_unique) { |
||
2143 |
/* If exact match, don't undo. Allows directory completions |
||
2144 |
* to be used (ie, complete the next portion of the path). |
||
2145 |
*/ |
||
2146 |
expanded = NONE; |
||
2147 |
|||
2148 |
/* If not a directory, add a space to the end... */ |
||
2149 |
if (match_len > 0 && match[match_len - 1] != '/') |
||
2150 |
rval = putbuf(" ", 1, 0); |
||
2151 |
} |
||
2152 |
x_free_words(nwords, words); |
||
2153 |
|||
2154 |
modified = 1; hnum = hlast; |
||
2155 |
insert = INSERT; |
||
2156 |
lastac = 0; /* prevent this from being redone... */ |
||
2157 |
refresh(0); |
||
2158 |
|||
2159 |
return rval; |
||
2160 |
} |
||
2161 |
|||
2162 |
static int |
||
2163 |
print_expansions(struct edstate *e, int command) |
||
2164 |
{ |
||
2165 |
int nwords; |
||
2166 |
int start, end; |
||
2167 |
char **words; |
||
2168 |
int is_command; |
||
2169 |
|||
2170 |
nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH, |
||
2171 |
e->cbuf, e->linelen, e->cursor, |
||
2172 |
&start, &end, &words, &is_command); |
||
2173 |
if (nwords == 0) { |
||
2174 |
vi_error(); |
||
2175 |
return -1; |
||
2176 |
} |
||
2177 |
x_print_expansions(nwords, words, is_command); |
||
2178 |
x_free_words(nwords, words); |
||
2179 |
redraw_line(0); |
||
2180 |
return 0; |
||
2181 |
} |
||
2182 |
|||
2183 |
/* |
||
2184 |
* The number of bytes needed to encode byte c. |
||
2185 |
* Control bytes get "M-" or "^" prepended. |
||
2186 |
* This function does not handle tabs. |
||
2187 |
*/ |
||
2188 |
static int |
||
2189 |
char_len(int c) |
||
2190 |
{ |
||
2191 |
int len = 1; |
||
2192 |
|||
2193 |
✓✓✗✓ |
95275 |
if ((c & 0x80) && Flag(FVISHOW8)) { |
2194 |
len += 2; |
||
2195 |
c &= 0x7f; |
||
2196 |
} |
||
2197 |
✓✓ | 47475 |
if (c < ' ' || c == 0x7f) |
2198 |
50 |
len++; |
|
2199 |
47475 |
return len; |
|
2200 |
} |
||
2201 |
|||
2202 |
/* Similar to x_zotc(emacs.c), but no tab weirdness */ |
||
2203 |
static void |
||
2204 |
x_vi_zotc(int c) |
||
2205 |
{ |
||
2206 |
if (Flag(FVISHOW8) && (c & 0x80)) { |
||
2207 |
x_puts("M-"); |
||
2208 |
c &= 0x7f; |
||
2209 |
} |
||
2210 |
if (c < ' ' || c == 0x7f) { |
||
2211 |
x_putc('^'); |
||
2212 |
c ^= '@'; |
||
2213 |
} |
||
2214 |
x_putc(c); |
||
2215 |
} |
||
2216 |
|||
2217 |
static void |
||
2218 |
vi_pprompt(int full) |
||
2219 |
{ |
||
2220 |
4000 |
pprompt(prompt + (full ? 0 : prompt_skip), prompt_trunc); |
|
2221 |
2000 |
} |
|
2222 |
|||
2223 |
static void |
||
2224 |
vi_error(void) |
||
2225 |
{ |
||
2226 |
/* Beem out of any macros as soon as an error occurs */ |
||
2227 |
100 |
vi_macro_reset(); |
|
2228 |
50 |
x_putc(BEL); |
|
2229 |
50 |
x_flush(); |
|
2230 |
50 |
} |
|
2231 |
|||
2232 |
static void |
||
2233 |
vi_macro_reset(void) |
||
2234 |
{ |
||
2235 |
✗✓ | 3650 |
if (macro.p) { |
2236 |
afree(macro.buf, APERM); |
||
2237 |
memset((char *) ¯o, 0, sizeof(macro)); |
||
2238 |
} |
||
2239 |
1825 |
} |
|
2240 |
|||
2241 |
static int |
||
2242 |
isu8cont(unsigned char c) |
||
2243 |
{ |
||
2244 |
✓✗ | 4739300 |
return !Flag(FVISHOW8) && (c & (0x80 | 0x40)) == 0x80; |
2245 |
} |
||
2246 |
#endif /* VI */ |
Generated by: GCOVR (Version 3.3) |