Commit | Line | Data |
---|---|---|
970ed795 EL |
1 | /* $NetBSD: vi.c,v 1.31 2009/12/30 22:37:40 christos Exp $ */ |
2 | ||
3 | /*- | |
4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * Christos Zoulas of Cornell University. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #include "config.h" | |
36 | #include <stdlib.h> | |
37 | #include <unistd.h> | |
38 | #include <limits.h> | |
39 | #include <sys/wait.h> | |
40 | ||
41 | #if !defined(lint) && !defined(SCCSID) | |
42 | #if 0 | |
43 | static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; | |
44 | #else | |
45 | __RCSID("$NetBSD: vi.c,v 1.31 2009/12/30 22:37:40 christos Exp $"); | |
46 | #endif | |
47 | #endif /* not lint && not SCCSID */ | |
48 | ||
49 | /* | |
50 | * vi.c: Vi mode commands. | |
51 | */ | |
52 | #include "el.h" | |
53 | ||
54 | private el_action_t cv_action(EditLine *, Int); | |
55 | private el_action_t cv_paste(EditLine *, Int); | |
56 | ||
57 | /* cv_action(): | |
58 | * Handle vi actions. | |
59 | */ | |
60 | private el_action_t | |
61 | cv_action(EditLine *el, Int c) | |
62 | { | |
63 | ||
64 | if (el->el_chared.c_vcmd.action != NOP) { | |
65 | /* 'cc', 'dd' and (possibly) friends */ | |
66 | if (c != el->el_chared.c_vcmd.action) | |
67 | return CC_ERROR; | |
68 | ||
69 | if (!(c & YANK)) | |
70 | cv_undo(el); | |
71 | cv_yank(el, el->el_line.buffer, | |
72 | (int)(el->el_line.lastchar - el->el_line.buffer)); | |
73 | el->el_chared.c_vcmd.action = NOP; | |
74 | el->el_chared.c_vcmd.pos = 0; | |
75 | if (!(c & YANK)) { | |
76 | el->el_line.lastchar = el->el_line.buffer; | |
77 | el->el_line.cursor = el->el_line.buffer; | |
78 | } | |
79 | if (c & INSERT) | |
80 | el->el_map.current = el->el_map.key; | |
81 | ||
82 | return (CC_REFRESH); | |
83 | } | |
84 | el->el_chared.c_vcmd.pos = el->el_line.cursor; | |
85 | el->el_chared.c_vcmd.action = c; | |
86 | return (CC_ARGHACK); | |
87 | } | |
88 | ||
89 | /* cv_paste(): | |
90 | * Paste previous deletion before or after the cursor | |
91 | */ | |
92 | private el_action_t | |
93 | cv_paste(EditLine *el, Int c) | |
94 | { | |
95 | c_kill_t *k = &el->el_chared.c_kill; | |
96 | size_t len = (size_t)(k->last - k->buf); | |
97 | ||
98 | if (k->buf == NULL || len == 0) | |
99 | return (CC_ERROR); | |
100 | #ifdef DEBUG_PASTE | |
101 | (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf); | |
102 | #endif | |
103 | ||
104 | cv_undo(el); | |
105 | ||
106 | if (!c && el->el_line.cursor < el->el_line.lastchar) | |
107 | el->el_line.cursor++; | |
108 | ||
109 | c_insert(el, (int)len); | |
110 | if (el->el_line.cursor + len > el->el_line.lastchar) | |
111 | return (CC_ERROR); | |
112 | (void) memcpy(el->el_line.cursor, k->buf, len * | |
113 | sizeof(*el->el_line.cursor)); | |
114 | ||
115 | return (CC_REFRESH); | |
116 | } | |
117 | ||
118 | ||
119 | /* vi_paste_next(): | |
120 | * Vi paste previous deletion to the right of the cursor | |
121 | * [p] | |
122 | */ | |
123 | protected el_action_t | |
124 | /*ARGSUSED*/ | |
125 | vi_paste_next(EditLine *el, Int c __attribute__((__unused__))) | |
126 | { | |
127 | ||
128 | return (cv_paste(el, 0)); | |
129 | } | |
130 | ||
131 | ||
132 | /* vi_paste_prev(): | |
133 | * Vi paste previous deletion to the left of the cursor | |
134 | * [P] | |
135 | */ | |
136 | protected el_action_t | |
137 | /*ARGSUSED*/ | |
138 | vi_paste_prev(EditLine *el, Int c __attribute__((__unused__))) | |
139 | { | |
140 | ||
141 | return (cv_paste(el, 1)); | |
142 | } | |
143 | ||
144 | ||
145 | /* vi_prev_big_word(): | |
146 | * Vi move to the previous space delimited word | |
147 | * [B] | |
148 | */ | |
149 | protected el_action_t | |
150 | /*ARGSUSED*/ | |
151 | vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__))) | |
152 | { | |
153 | ||
154 | if (el->el_line.cursor == el->el_line.buffer) | |
155 | return (CC_ERROR); | |
156 | ||
157 | el->el_line.cursor = cv_prev_word(el->el_line.cursor, | |
158 | el->el_line.buffer, | |
159 | el->el_state.argument, | |
160 | cv__isWord); | |
161 | ||
162 | if (el->el_chared.c_vcmd.action != NOP) { | |
163 | cv_delfini(el); | |
164 | return (CC_REFRESH); | |
165 | } | |
166 | return (CC_CURSOR); | |
167 | } | |
168 | ||
169 | ||
170 | /* vi_prev_word(): | |
171 | * Vi move to the previous word | |
172 | * [b] | |
173 | */ | |
174 | protected el_action_t | |
175 | /*ARGSUSED*/ | |
176 | vi_prev_word(EditLine *el, Int c __attribute__((__unused__))) | |
177 | { | |
178 | ||
179 | if (el->el_line.cursor == el->el_line.buffer) | |
180 | return (CC_ERROR); | |
181 | ||
182 | el->el_line.cursor = cv_prev_word(el->el_line.cursor, | |
183 | el->el_line.buffer, | |
184 | el->el_state.argument, | |
185 | cv__isword); | |
186 | ||
187 | if (el->el_chared.c_vcmd.action != NOP) { | |
188 | cv_delfini(el); | |
189 | return (CC_REFRESH); | |
190 | } | |
191 | return (CC_CURSOR); | |
192 | } | |
193 | ||
194 | ||
195 | /* vi_next_big_word(): | |
196 | * Vi move to the next space delimited word | |
197 | * [W] | |
198 | */ | |
199 | protected el_action_t | |
200 | /*ARGSUSED*/ | |
201 | vi_next_big_word(EditLine *el, Int c __attribute__((__unused__))) | |
202 | { | |
203 | ||
204 | if (el->el_line.cursor >= el->el_line.lastchar - 1) | |
205 | return (CC_ERROR); | |
206 | ||
207 | el->el_line.cursor = cv_next_word(el, el->el_line.cursor, | |
208 | el->el_line.lastchar, el->el_state.argument, cv__isWord); | |
209 | ||
210 | if (el->el_map.type == MAP_VI) | |
211 | if (el->el_chared.c_vcmd.action != NOP) { | |
212 | cv_delfini(el); | |
213 | return (CC_REFRESH); | |
214 | } | |
215 | return (CC_CURSOR); | |
216 | } | |
217 | ||
218 | ||
219 | /* vi_next_word(): | |
220 | * Vi move to the next word | |
221 | * [w] | |
222 | */ | |
223 | protected el_action_t | |
224 | /*ARGSUSED*/ | |
225 | vi_next_word(EditLine *el, Int c __attribute__((__unused__))) | |
226 | { | |
227 | ||
228 | if (el->el_line.cursor >= el->el_line.lastchar - 1) | |
229 | return (CC_ERROR); | |
230 | ||
231 | el->el_line.cursor = cv_next_word(el, el->el_line.cursor, | |
232 | el->el_line.lastchar, el->el_state.argument, cv__isword); | |
233 | ||
234 | if (el->el_map.type == MAP_VI) | |
235 | if (el->el_chared.c_vcmd.action != NOP) { | |
236 | cv_delfini(el); | |
237 | return (CC_REFRESH); | |
238 | } | |
239 | return (CC_CURSOR); | |
240 | } | |
241 | ||
242 | ||
243 | /* vi_change_case(): | |
244 | * Vi change case of character under the cursor and advance one character | |
245 | * [~] | |
246 | */ | |
247 | protected el_action_t | |
248 | vi_change_case(EditLine *el, Int c) | |
249 | { | |
250 | int i; | |
251 | ||
252 | if (el->el_line.cursor >= el->el_line.lastchar) | |
253 | return (CC_ERROR); | |
254 | cv_undo(el); | |
255 | for (i = 0; i < el->el_state.argument; i++) { | |
256 | ||
257 | c = *el->el_line.cursor; | |
258 | if (Isupper(c)) | |
259 | *el->el_line.cursor = Tolower(c); | |
260 | else if (Islower(c)) | |
261 | *el->el_line.cursor = Toupper(c); | |
262 | ||
263 | if (++el->el_line.cursor >= el->el_line.lastchar) { | |
264 | el->el_line.cursor--; | |
265 | re_fastaddc(el); | |
266 | break; | |
267 | } | |
268 | re_fastaddc(el); | |
269 | } | |
270 | return CC_NORM; | |
271 | } | |
272 | ||
273 | ||
274 | /* vi_change_meta(): | |
275 | * Vi change prefix command | |
276 | * [c] | |
277 | */ | |
278 | protected el_action_t | |
279 | /*ARGSUSED*/ | |
280 | vi_change_meta(EditLine *el, Int c __attribute__((__unused__))) | |
281 | { | |
282 | ||
283 | /* | |
284 | * Delete with insert == change: first we delete and then we leave in | |
285 | * insert mode. | |
286 | */ | |
287 | return (cv_action(el, DELETE | INSERT)); | |
288 | } | |
289 | ||
290 | ||
291 | /* vi_insert_at_bol(): | |
292 | * Vi enter insert mode at the beginning of line | |
293 | * [I] | |
294 | */ | |
295 | protected el_action_t | |
296 | /*ARGSUSED*/ | |
297 | vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__))) | |
298 | { | |
299 | ||
300 | el->el_line.cursor = el->el_line.buffer; | |
301 | cv_undo(el); | |
302 | el->el_map.current = el->el_map.key; | |
303 | return (CC_CURSOR); | |
304 | } | |
305 | ||
306 | ||
307 | /* vi_replace_char(): | |
308 | * Vi replace character under the cursor with the next character typed | |
309 | * [r] | |
310 | */ | |
311 | protected el_action_t | |
312 | /*ARGSUSED*/ | |
313 | vi_replace_char(EditLine *el, Int c __attribute__((__unused__))) | |
314 | { | |
315 | ||
316 | if (el->el_line.cursor >= el->el_line.lastchar) | |
317 | return CC_ERROR; | |
318 | ||
319 | el->el_map.current = el->el_map.key; | |
320 | el->el_state.inputmode = MODE_REPLACE_1; | |
321 | cv_undo(el); | |
322 | return (CC_ARGHACK); | |
323 | } | |
324 | ||
325 | ||
326 | /* vi_replace_mode(): | |
327 | * Vi enter replace mode | |
328 | * [R] | |
329 | */ | |
330 | protected el_action_t | |
331 | /*ARGSUSED*/ | |
332 | vi_replace_mode(EditLine *el, Int c __attribute__((__unused__))) | |
333 | { | |
334 | ||
335 | el->el_map.current = el->el_map.key; | |
336 | el->el_state.inputmode = MODE_REPLACE; | |
337 | cv_undo(el); | |
338 | return (CC_NORM); | |
339 | } | |
340 | ||
341 | ||
342 | /* vi_substitute_char(): | |
343 | * Vi replace character under the cursor and enter insert mode | |
344 | * [s] | |
345 | */ | |
346 | protected el_action_t | |
347 | /*ARGSUSED*/ | |
348 | vi_substitute_char(EditLine *el, Int c __attribute__((__unused__))) | |
349 | { | |
350 | ||
351 | c_delafter(el, el->el_state.argument); | |
352 | el->el_map.current = el->el_map.key; | |
353 | return (CC_REFRESH); | |
354 | } | |
355 | ||
356 | ||
357 | /* vi_substitute_line(): | |
358 | * Vi substitute entire line | |
359 | * [S] | |
360 | */ | |
361 | protected el_action_t | |
362 | /*ARGSUSED*/ | |
363 | vi_substitute_line(EditLine *el, Int c __attribute__((__unused__))) | |
364 | { | |
365 | ||
366 | cv_undo(el); | |
367 | cv_yank(el, el->el_line.buffer, | |
368 | (int)(el->el_line.lastchar - el->el_line.buffer)); | |
369 | (void) em_kill_line(el, 0); | |
370 | el->el_map.current = el->el_map.key; | |
371 | return (CC_REFRESH); | |
372 | } | |
373 | ||
374 | ||
375 | /* vi_change_to_eol(): | |
376 | * Vi change to end of line | |
377 | * [C] | |
378 | */ | |
379 | protected el_action_t | |
380 | /*ARGSUSED*/ | |
381 | vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__))) | |
382 | { | |
383 | ||
384 | cv_undo(el); | |
385 | cv_yank(el, el->el_line.cursor, | |
386 | (int)(el->el_line.lastchar - el->el_line.cursor)); | |
387 | (void) ed_kill_line(el, 0); | |
388 | el->el_map.current = el->el_map.key; | |
389 | return (CC_REFRESH); | |
390 | } | |
391 | ||
392 | ||
393 | /* vi_insert(): | |
394 | * Vi enter insert mode | |
395 | * [i] | |
396 | */ | |
397 | protected el_action_t | |
398 | /*ARGSUSED*/ | |
399 | vi_insert(EditLine *el, Int c __attribute__((__unused__))) | |
400 | { | |
401 | ||
402 | el->el_map.current = el->el_map.key; | |
403 | cv_undo(el); | |
404 | return (CC_NORM); | |
405 | } | |
406 | ||
407 | ||
408 | /* vi_add(): | |
409 | * Vi enter insert mode after the cursor | |
410 | * [a] | |
411 | */ | |
412 | protected el_action_t | |
413 | /*ARGSUSED*/ | |
414 | vi_add(EditLine *el, Int c __attribute__((__unused__))) | |
415 | { | |
416 | int ret; | |
417 | ||
418 | el->el_map.current = el->el_map.key; | |
419 | if (el->el_line.cursor < el->el_line.lastchar) { | |
420 | el->el_line.cursor++; | |
421 | if (el->el_line.cursor > el->el_line.lastchar) | |
422 | el->el_line.cursor = el->el_line.lastchar; | |
423 | ret = CC_CURSOR; | |
424 | } else | |
425 | ret = CC_NORM; | |
426 | ||
427 | cv_undo(el); | |
428 | ||
429 | return (ret); | |
430 | } | |
431 | ||
432 | ||
433 | /* vi_add_at_eol(): | |
434 | * Vi enter insert mode at end of line | |
435 | * [A] | |
436 | */ | |
437 | protected el_action_t | |
438 | /*ARGSUSED*/ | |
439 | vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__))) | |
440 | { | |
441 | ||
442 | el->el_map.current = el->el_map.key; | |
443 | el->el_line.cursor = el->el_line.lastchar; | |
444 | cv_undo(el); | |
445 | return (CC_CURSOR); | |
446 | } | |
447 | ||
448 | ||
449 | /* vi_delete_meta(): | |
450 | * Vi delete prefix command | |
451 | * [d] | |
452 | */ | |
453 | protected el_action_t | |
454 | /*ARGSUSED*/ | |
455 | vi_delete_meta(EditLine *el, Int c __attribute__((__unused__))) | |
456 | { | |
457 | ||
458 | return (cv_action(el, DELETE)); | |
459 | } | |
460 | ||
461 | ||
462 | /* vi_end_big_word(): | |
463 | * Vi move to the end of the current space delimited word | |
464 | * [E] | |
465 | */ | |
466 | protected el_action_t | |
467 | /*ARGSUSED*/ | |
468 | vi_end_big_word(EditLine *el, Int c __attribute__((__unused__))) | |
469 | { | |
470 | ||
471 | if (el->el_line.cursor == el->el_line.lastchar) | |
472 | return (CC_ERROR); | |
473 | ||
474 | el->el_line.cursor = cv__endword(el->el_line.cursor, | |
475 | el->el_line.lastchar, el->el_state.argument, cv__isWord); | |
476 | ||
477 | if (el->el_chared.c_vcmd.action != NOP) { | |
478 | el->el_line.cursor++; | |
479 | cv_delfini(el); | |
480 | return (CC_REFRESH); | |
481 | } | |
482 | return (CC_CURSOR); | |
483 | } | |
484 | ||
485 | ||
486 | /* vi_end_word(): | |
487 | * Vi move to the end of the current word | |
488 | * [e] | |
489 | */ | |
490 | protected el_action_t | |
491 | /*ARGSUSED*/ | |
492 | vi_end_word(EditLine *el, Int c __attribute__((__unused__))) | |
493 | { | |
494 | ||
495 | if (el->el_line.cursor == el->el_line.lastchar) | |
496 | return (CC_ERROR); | |
497 | ||
498 | el->el_line.cursor = cv__endword(el->el_line.cursor, | |
499 | el->el_line.lastchar, el->el_state.argument, cv__isword); | |
500 | ||
501 | if (el->el_chared.c_vcmd.action != NOP) { | |
502 | el->el_line.cursor++; | |
503 | cv_delfini(el); | |
504 | return (CC_REFRESH); | |
505 | } | |
506 | return (CC_CURSOR); | |
507 | } | |
508 | ||
509 | ||
510 | /* vi_undo(): | |
511 | * Vi undo last change | |
512 | * [u] | |
513 | */ | |
514 | protected el_action_t | |
515 | /*ARGSUSED*/ | |
516 | vi_undo(EditLine *el, Int c __attribute__((__unused__))) | |
517 | { | |
518 | c_undo_t un = el->el_chared.c_undo; | |
519 | ||
520 | if (un.len == -1) | |
521 | return CC_ERROR; | |
522 | ||
523 | /* switch line buffer and undo buffer */ | |
524 | el->el_chared.c_undo.buf = el->el_line.buffer; | |
525 | el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; | |
526 | el->el_chared.c_undo.cursor = | |
527 | (int)(el->el_line.cursor - el->el_line.buffer); | |
528 | el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); | |
529 | el->el_line.buffer = un.buf; | |
530 | el->el_line.cursor = un.buf + un.cursor; | |
531 | el->el_line.lastchar = un.buf + un.len; | |
532 | ||
533 | return (CC_REFRESH); | |
534 | } | |
535 | ||
536 | ||
537 | /* vi_command_mode(): | |
538 | * Vi enter command mode (use alternative key bindings) | |
539 | * [<ESC>] | |
540 | */ | |
541 | protected el_action_t | |
542 | /*ARGSUSED*/ | |
543 | vi_command_mode(EditLine *el, Int c __attribute__((__unused__))) | |
544 | { | |
545 | ||
546 | /* [Esc] cancels pending action */ | |
547 | el->el_chared.c_vcmd.action = NOP; | |
548 | el->el_chared.c_vcmd.pos = 0; | |
549 | ||
550 | el->el_state.doingarg = 0; | |
551 | ||
552 | el->el_state.inputmode = MODE_INSERT; | |
553 | el->el_map.current = el->el_map.alt; | |
554 | #ifdef VI_MOVE | |
555 | if (el->el_line.cursor > el->el_line.buffer) | |
556 | el->el_line.cursor--; | |
557 | #endif | |
558 | return (CC_CURSOR); | |
559 | } | |
560 | ||
561 | ||
562 | /* vi_zero(): | |
563 | * Vi move to the beginning of line | |
564 | * [0] | |
565 | */ | |
566 | protected el_action_t | |
567 | vi_zero(EditLine *el, Int c) | |
568 | { | |
569 | ||
570 | if (el->el_state.doingarg) | |
571 | return ed_argument_digit(el, c); | |
572 | ||
573 | el->el_line.cursor = el->el_line.buffer; | |
574 | if (el->el_chared.c_vcmd.action != NOP) { | |
575 | cv_delfini(el); | |
576 | return (CC_REFRESH); | |
577 | } | |
578 | return (CC_CURSOR); | |
579 | } | |
580 | ||
581 | ||
582 | /* vi_delete_prev_char(): | |
583 | * Vi move to previous character (backspace) | |
584 | * [^H] in insert mode only | |
585 | */ | |
586 | protected el_action_t | |
587 | /*ARGSUSED*/ | |
588 | vi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
589 | { | |
590 | ||
591 | if (el->el_line.cursor <= el->el_line.buffer) | |
592 | return (CC_ERROR); | |
593 | ||
594 | c_delbefore1(el); | |
595 | el->el_line.cursor--; | |
596 | return (CC_REFRESH); | |
597 | } | |
598 | ||
599 | ||
600 | /* vi_list_or_eof(): | |
601 | * Vi list choices for completion or indicate end of file if empty line | |
602 | * [^D] | |
603 | */ | |
604 | protected el_action_t | |
605 | /*ARGSUSED*/ | |
606 | vi_list_or_eof(EditLine *el, Int c) | |
607 | { | |
608 | ||
609 | if (el->el_line.cursor == el->el_line.lastchar) { | |
610 | if (el->el_line.cursor == el->el_line.buffer) { | |
611 | term_writec(el, c); /* then do a EOF */ | |
612 | return (CC_EOF); | |
613 | } else { | |
614 | /* | |
615 | * Here we could list completions, but it is an | |
616 | * error right now | |
617 | */ | |
618 | term_beep(el); | |
619 | return (CC_ERROR); | |
620 | } | |
621 | } else { | |
622 | #ifdef notyet | |
623 | re_goto_bottom(el); | |
624 | *el->el_line.lastchar = '\0'; /* just in case */ | |
625 | return (CC_LIST_CHOICES); | |
626 | #else | |
627 | /* | |
628 | * Just complain for now. | |
629 | */ | |
630 | term_beep(el); | |
631 | return (CC_ERROR); | |
632 | #endif | |
633 | } | |
634 | } | |
635 | ||
636 | ||
637 | /* vi_kill_line_prev(): | |
638 | * Vi cut from beginning of line to cursor | |
639 | * [^U] | |
640 | */ | |
641 | protected el_action_t | |
642 | /*ARGSUSED*/ | |
643 | vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__))) | |
644 | { | |
645 | Char *kp, *cp; | |
646 | ||
647 | cp = el->el_line.buffer; | |
648 | kp = el->el_chared.c_kill.buf; | |
649 | while (cp < el->el_line.cursor) | |
650 | *kp++ = *cp++; /* copy it */ | |
651 | el->el_chared.c_kill.last = kp; | |
652 | c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); | |
653 | el->el_line.cursor = el->el_line.buffer; /* zap! */ | |
654 | return (CC_REFRESH); | |
655 | } | |
656 | ||
657 | ||
658 | /* vi_search_prev(): | |
659 | * Vi search history previous | |
660 | * [?] | |
661 | */ | |
662 | protected el_action_t | |
663 | /*ARGSUSED*/ | |
664 | vi_search_prev(EditLine *el, Int c __attribute__((__unused__))) | |
665 | { | |
666 | ||
667 | return (cv_search(el, ED_SEARCH_PREV_HISTORY)); | |
668 | } | |
669 | ||
670 | ||
671 | /* vi_search_next(): | |
672 | * Vi search history next | |
673 | * [/] | |
674 | */ | |
675 | protected el_action_t | |
676 | /*ARGSUSED*/ | |
677 | vi_search_next(EditLine *el, Int c __attribute__((__unused__))) | |
678 | { | |
679 | ||
680 | return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); | |
681 | } | |
682 | ||
683 | ||
684 | /* vi_repeat_search_next(): | |
685 | * Vi repeat current search in the same search direction | |
686 | * [n] | |
687 | */ | |
688 | protected el_action_t | |
689 | /*ARGSUSED*/ | |
690 | vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__))) | |
691 | { | |
692 | ||
693 | if (el->el_search.patlen == 0) | |
694 | return (CC_ERROR); | |
695 | else | |
696 | return (cv_repeat_srch(el, el->el_search.patdir)); | |
697 | } | |
698 | ||
699 | ||
700 | /* vi_repeat_search_prev(): | |
701 | * Vi repeat current search in the opposite search direction | |
702 | * [N] | |
703 | */ | |
704 | /*ARGSUSED*/ | |
705 | protected el_action_t | |
706 | vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__))) | |
707 | { | |
708 | ||
709 | if (el->el_search.patlen == 0) | |
710 | return (CC_ERROR); | |
711 | else | |
712 | return (cv_repeat_srch(el, | |
713 | el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? | |
714 | ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); | |
715 | } | |
716 | ||
717 | ||
718 | /* vi_next_char(): | |
719 | * Vi move to the character specified next | |
720 | * [f] | |
721 | */ | |
722 | protected el_action_t | |
723 | /*ARGSUSED*/ | |
724 | vi_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
725 | { | |
726 | return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); | |
727 | } | |
728 | ||
729 | ||
730 | /* vi_prev_char(): | |
731 | * Vi move to the character specified previous | |
732 | * [F] | |
733 | */ | |
734 | protected el_action_t | |
735 | /*ARGSUSED*/ | |
736 | vi_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
737 | { | |
738 | return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); | |
739 | } | |
740 | ||
741 | ||
742 | /* vi_to_next_char(): | |
743 | * Vi move up to the character specified next | |
744 | * [t] | |
745 | */ | |
746 | protected el_action_t | |
747 | /*ARGSUSED*/ | |
748 | vi_to_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
749 | { | |
750 | return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); | |
751 | } | |
752 | ||
753 | ||
754 | /* vi_to_prev_char(): | |
755 | * Vi move up to the character specified previous | |
756 | * [T] | |
757 | */ | |
758 | protected el_action_t | |
759 | /*ARGSUSED*/ | |
760 | vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
761 | { | |
762 | return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); | |
763 | } | |
764 | ||
765 | ||
766 | /* vi_repeat_next_char(): | |
767 | * Vi repeat current character search in the same search direction | |
768 | * [;] | |
769 | */ | |
770 | protected el_action_t | |
771 | /*ARGSUSED*/ | |
772 | vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
773 | { | |
774 | ||
775 | return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, | |
776 | el->el_state.argument, el->el_search.chatflg); | |
777 | } | |
778 | ||
779 | ||
780 | /* vi_repeat_prev_char(): | |
781 | * Vi repeat current character search in the opposite search direction | |
782 | * [,] | |
783 | */ | |
784 | protected el_action_t | |
785 | /*ARGSUSED*/ | |
786 | vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
787 | { | |
788 | el_action_t r; | |
789 | int dir = el->el_search.chadir; | |
790 | ||
791 | r = cv_csearch(el, -dir, el->el_search.chacha, | |
792 | el->el_state.argument, el->el_search.chatflg); | |
793 | el->el_search.chadir = dir; | |
794 | return r; | |
795 | } | |
796 | ||
797 | ||
798 | /* vi_match(): | |
799 | * Vi go to matching () {} or [] | |
800 | * [%] | |
801 | */ | |
802 | protected el_action_t | |
803 | /*ARGSUSED*/ | |
804 | vi_match(EditLine *el, Int c __attribute__((__unused__))) | |
805 | { | |
806 | const Char match_chars[] = STR("()[]{}"); | |
807 | Char *cp; | |
808 | size_t delta, i, count; | |
809 | Char o_ch, c_ch; | |
810 | ||
811 | *el->el_line.lastchar = '\0'; /* just in case */ | |
812 | ||
813 | i = Strcspn(el->el_line.cursor, match_chars); | |
814 | o_ch = el->el_line.cursor[i]; | |
815 | if (o_ch == 0) | |
816 | return CC_ERROR; | |
817 | delta = Strchr(match_chars, o_ch) - match_chars; | |
818 | c_ch = match_chars[delta ^ 1]; | |
819 | count = 1; | |
820 | delta = 1 - (delta & 1) * 2; | |
821 | ||
822 | for (cp = &el->el_line.cursor[i]; count; ) { | |
823 | cp += delta; | |
824 | if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) | |
825 | return CC_ERROR; | |
826 | if (*cp == o_ch) | |
827 | count++; | |
828 | else if (*cp == c_ch) | |
829 | count--; | |
830 | } | |
831 | ||
832 | el->el_line.cursor = cp; | |
833 | ||
834 | if (el->el_chared.c_vcmd.action != NOP) { | |
835 | /* NB posix says char under cursor should NOT be deleted | |
836 | for -ve delta - this is different to netbsd vi. */ | |
837 | if (delta > 0) | |
838 | el->el_line.cursor++; | |
839 | cv_delfini(el); | |
840 | return (CC_REFRESH); | |
841 | } | |
842 | return (CC_CURSOR); | |
843 | } | |
844 | ||
845 | /* vi_undo_line(): | |
846 | * Vi undo all changes to line | |
847 | * [U] | |
848 | */ | |
849 | protected el_action_t | |
850 | /*ARGSUSED*/ | |
851 | vi_undo_line(EditLine *el, Int c __attribute__((__unused__))) | |
852 | { | |
853 | ||
854 | cv_undo(el); | |
855 | return hist_get(el); | |
856 | } | |
857 | ||
858 | /* vi_to_column(): | |
859 | * Vi go to specified column | |
860 | * [|] | |
861 | * NB netbsd vi goes to screen column 'n', posix says nth character | |
862 | */ | |
863 | protected el_action_t | |
864 | /*ARGSUSED*/ | |
865 | vi_to_column(EditLine *el, Int c __attribute__((__unused__))) | |
866 | { | |
867 | ||
868 | el->el_line.cursor = el->el_line.buffer; | |
869 | el->el_state.argument--; | |
870 | return ed_next_char(el, 0); | |
871 | } | |
872 | ||
873 | /* vi_yank_end(): | |
874 | * Vi yank to end of line | |
875 | * [Y] | |
876 | */ | |
877 | protected el_action_t | |
878 | /*ARGSUSED*/ | |
879 | vi_yank_end(EditLine *el, Int c __attribute__((__unused__))) | |
880 | { | |
881 | ||
882 | cv_yank(el, el->el_line.cursor, | |
883 | (int)(el->el_line.lastchar - el->el_line.cursor)); | |
884 | return CC_REFRESH; | |
885 | } | |
886 | ||
887 | /* vi_yank(): | |
888 | * Vi yank | |
889 | * [y] | |
890 | */ | |
891 | protected el_action_t | |
892 | /*ARGSUSED*/ | |
893 | vi_yank(EditLine *el, Int c __attribute__((__unused__))) | |
894 | { | |
895 | ||
896 | return cv_action(el, YANK); | |
897 | } | |
898 | ||
899 | /* vi_comment_out(): | |
900 | * Vi comment out current command | |
901 | * [#] | |
902 | */ | |
903 | protected el_action_t | |
904 | /*ARGSUSED*/ | |
905 | vi_comment_out(EditLine *el, Int c __attribute__((__unused__))) | |
906 | { | |
907 | ||
908 | el->el_line.cursor = el->el_line.buffer; | |
909 | c_insert(el, 1); | |
910 | *el->el_line.cursor = '#'; | |
911 | re_refresh(el); | |
912 | return ed_newline(el, 0); | |
913 | } | |
914 | ||
915 | /* vi_alias(): | |
916 | * Vi include shell alias | |
917 | * [@] | |
918 | * NB: posix implies that we should enter insert mode, however | |
919 | * this is against historical precedent... | |
920 | */ | |
921 | //#ifdef __weak_reference | |
922 | //extern char *get_alias_text(const char *) __weak_reference(get_alias_text); | |
923 | //#endif | |
924 | protected el_action_t | |
925 | /*ARGSUSED*/ | |
926 | vi_alias(EditLine *el __attribute__((__unused__)), Int c __attribute__((__unused__))) | |
927 | { | |
928 | /* | |
929 | #ifdef __weak_reference | |
930 | char alias_name[3]; | |
931 | char *alias_text; | |
932 | ||
933 | if (get_alias_text == 0) { | |
934 | return CC_ERROR; | |
935 | } | |
936 | ||
937 | alias_name[0] = '_'; | |
938 | alias_name[2] = 0; | |
939 | if (el_getc(el, &alias_name[1]) != 1) | |
940 | return CC_ERROR; | |
941 | ||
942 | alias_text = get_alias_text(alias_name); | |
943 | if (alias_text != NULL) | |
944 | FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch)); | |
945 | return CC_NORM; | |
946 | #else | |
947 | */ | |
948 | return CC_ERROR; | |
949 | //#endif | |
950 | } | |
951 | ||
952 | /* vi_to_history_line(): | |
953 | * Vi go to specified history file line. | |
954 | * [G] | |
955 | */ | |
956 | protected el_action_t | |
957 | /*ARGSUSED*/ | |
958 | vi_to_history_line(EditLine *el, Int c __attribute__((__unused__))) | |
959 | { | |
960 | int sv_event_no = el->el_history.eventno; | |
961 | el_action_t rval; | |
962 | ||
963 | ||
964 | if (el->el_history.eventno == 0) { | |
965 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | |
966 | EL_BUFSIZ); | |
967 | el->el_history.last = el->el_history.buf + | |
968 | (el->el_line.lastchar - el->el_line.buffer); | |
969 | } | |
970 | ||
971 | /* Lack of a 'count' means oldest, not 1 */ | |
972 | if (!el->el_state.doingarg) { | |
973 | el->el_history.eventno = 0x7fffffff; | |
974 | hist_get(el); | |
975 | } else { | |
976 | /* This is brain dead, all the rest of this code counts | |
977 | * upwards going into the past. Here we need count in the | |
978 | * other direction (to match the output of fc -l). | |
979 | * I could change the world, but this seems to suffice. | |
980 | */ | |
981 | el->el_history.eventno = 1; | |
982 | if (hist_get(el) == CC_ERROR) | |
983 | return CC_ERROR; | |
984 | el->el_history.eventno = 1 + el->el_history.ev.num | |
985 | - el->el_state.argument; | |
986 | if (el->el_history.eventno < 0) { | |
987 | el->el_history.eventno = sv_event_no; | |
988 | return CC_ERROR; | |
989 | } | |
990 | } | |
991 | rval = hist_get(el); | |
992 | if (rval == CC_ERROR) | |
993 | el->el_history.eventno = sv_event_no; | |
994 | return rval; | |
995 | } | |
996 | ||
997 | /* vi_histedit(): | |
998 | * Vi edit history line with vi | |
999 | * [v] | |
1000 | */ | |
1001 | protected el_action_t | |
1002 | /*ARGSUSED*/ | |
1003 | vi_histedit(EditLine *el, Int c __attribute__((__unused__))) | |
1004 | { | |
1005 | int fd; | |
1006 | pid_t pid; | |
1007 | ssize_t st; | |
1008 | int status; | |
1009 | char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; | |
1010 | char *cp; | |
1011 | size_t len; | |
1012 | Char *line; | |
1013 | ||
1014 | if (el->el_state.doingarg) { | |
1015 | if (vi_to_history_line(el, 0) == CC_ERROR) | |
1016 | return CC_ERROR; | |
1017 | } | |
1018 | ||
1019 | fd = mkstemp(tempfile); | |
1020 | if (fd < 0) | |
1021 | return CC_ERROR; | |
1022 | len = (size_t)(el->el_line.lastchar - el->el_line.buffer); | |
1023 | #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) | |
1024 | cp = el_malloc(TMP_BUFSIZ); | |
1025 | if (cp == NULL) | |
1026 | return CC_ERROR; | |
1027 | line = el_malloc(len * sizeof(*line)); | |
1028 | if (line == NULL) { | |
1029 | el_free((ptr_t)cp); | |
1030 | return CC_ERROR; | |
1031 | } | |
1032 | Strncpy(line, el->el_line.buffer, len); | |
1033 | line[len] = '\0'; | |
1034 | ct_wcstombs(cp, line, TMP_BUFSIZ - 1); | |
1035 | cp[TMP_BUFSIZ - 1] = '\0'; | |
1036 | len = strlen(cp); | |
1037 | write(fd, cp, len); | |
1038 | write(fd, "\n", 1); | |
1039 | pid = fork(); | |
1040 | switch (pid) { | |
1041 | case -1: | |
1042 | close(fd); | |
1043 | unlink(tempfile); | |
1044 | el_free(cp); | |
1045 | el_free(line); | |
1046 | return CC_ERROR; | |
1047 | case 0: | |
1048 | close(fd); | |
1049 | execlp("vi", "vi", tempfile, (char *)NULL); | |
1050 | exit(0); | |
1051 | /*NOTREACHED*/ | |
1052 | default: | |
1053 | while (waitpid(pid, &status, 0) != pid) | |
1054 | continue; | |
1055 | lseek(fd, (off_t)0, SEEK_SET); | |
1056 | st = read(fd, cp, TMP_BUFSIZ); | |
1057 | if (st > 0) { | |
1058 | len = (size_t)(el->el_line.lastchar - | |
1059 | el->el_line.buffer); | |
1060 | len = ct_mbstowcs(el->el_line.buffer, cp, len); | |
1061 | if (len > 0 && el->el_line.buffer[len -1] == '\n') | |
1062 | --len; | |
1063 | } | |
1064 | else | |
1065 | len = 0; | |
1066 | el->el_line.cursor = el->el_line.buffer; | |
1067 | el->el_line.lastchar = el->el_line.buffer + len; | |
1068 | el_free(cp); | |
1069 | el_free(line); | |
1070 | break; | |
1071 | } | |
1072 | ||
1073 | close(fd); | |
1074 | unlink(tempfile); | |
1075 | /* return CC_REFRESH; */ | |
1076 | return ed_newline(el, 0); | |
1077 | } | |
1078 | ||
1079 | /* vi_history_word(): | |
1080 | * Vi append word from previous input line | |
1081 | * [_] | |
1082 | * Who knows where this one came from! | |
1083 | * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' | |
1084 | */ | |
1085 | protected el_action_t | |
1086 | /*ARGSUSED*/ | |
1087 | vi_history_word(EditLine *el, Int c __attribute__((__unused__))) | |
1088 | { | |
1089 | const Char *wp = HIST_FIRST(el); | |
1090 | const Char *wep, *wsp; | |
1091 | int len; | |
1092 | Char *cp; | |
1093 | const Char *lim; | |
1094 | ||
1095 | if (wp == NULL) | |
1096 | return CC_ERROR; | |
1097 | ||
1098 | wep = wsp = 0; | |
1099 | do { | |
1100 | while (Isspace(*wp)) | |
1101 | wp++; | |
1102 | if (*wp == 0) | |
1103 | break; | |
1104 | wsp = wp; | |
1105 | while (*wp && !Isspace(*wp)) | |
1106 | wp++; | |
1107 | wep = wp; | |
1108 | } while ((!el->el_state.doingarg || --el->el_state.argument > 0) | |
1109 | && *wp != 0); | |
1110 | ||
1111 | if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) | |
1112 | return CC_ERROR; | |
1113 | ||
1114 | cv_undo(el); | |
1115 | len = (int)(wep - wsp); | |
1116 | if (el->el_line.cursor < el->el_line.lastchar) | |
1117 | el->el_line.cursor++; | |
1118 | c_insert(el, len + 1); | |
1119 | cp = el->el_line.cursor; | |
1120 | lim = el->el_line.limit; | |
1121 | if (cp < lim) | |
1122 | *cp++ = ' '; | |
1123 | while (wsp < wep && cp < lim) | |
1124 | *cp++ = *wsp++; | |
1125 | el->el_line.cursor = cp; | |
1126 | ||
1127 | el->el_map.current = el->el_map.key; | |
1128 | return CC_REFRESH; | |
1129 | } | |
1130 | ||
1131 | /* vi_redo(): | |
1132 | * Vi redo last non-motion command | |
1133 | * [.] | |
1134 | */ | |
1135 | protected el_action_t | |
1136 | /*ARGSUSED*/ | |
1137 | vi_redo(EditLine *el, Int c __attribute__((__unused__))) | |
1138 | { | |
1139 | c_redo_t *r = &el->el_chared.c_redo; | |
1140 | ||
1141 | if (!el->el_state.doingarg && r->count) { | |
1142 | el->el_state.doingarg = 1; | |
1143 | el->el_state.argument = r->count; | |
1144 | } | |
1145 | ||
1146 | el->el_chared.c_vcmd.pos = el->el_line.cursor; | |
1147 | el->el_chared.c_vcmd.action = r->action; | |
1148 | if (r->pos != r->buf) { | |
1149 | if (r->pos + 1 > r->lim) | |
1150 | /* sanity */ | |
1151 | r->pos = r->lim - 1; | |
1152 | r->pos[0] = 0; | |
1153 | FUN(el,push)(el, r->buf); | |
1154 | } | |
1155 | ||
1156 | el->el_state.thiscmd = r->cmd; | |
1157 | el->el_state.thisch = r->ch; | |
1158 | return (*el->el_map.func[r->cmd])(el, r->ch); | |
1159 | } |