]>
Commit | Line | Data |
---|---|---|
bd5635a1 RP |
1 | /* vi_mode.c -- A vi emulation mode for Bash. |
2 | ||
3 | Derived from code written by Jeff Sparkes (jeff1@????). | |
4 | */ | |
5 | ||
6 | \f | |
7 | /* **************************************************************** */ | |
8 | /* */ | |
9 | /* VI Emulation Mode */ | |
10 | /* */ | |
11 | /* **************************************************************** */ | |
12 | ||
13 | /* Last string searched for from `/' or `?'. */ | |
14 | static char *vi_last_search = (char *)NULL; | |
15 | static int vi_histpos; | |
16 | ||
17 | /* Non-zero means enter insertion mode. */ | |
18 | int vi_doing_insert = 0; | |
19 | ||
20 | /* *** UNCLEAN *** */ | |
21 | /* Command keys which do movement for xxx_to commands. */ | |
22 | static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; | |
23 | ||
24 | /* Keymap used for vi replace characters. Created dynamically since | |
25 | rarely used. */ | |
26 | static Keymap vi_replace_map = (Keymap)NULL; | |
27 | ||
28 | /* The number of characters inserted in the last replace operation. */ | |
29 | static vi_replace_count = 0; | |
30 | ||
31 | /* Yank the nth arg from the previous line into this line at point. */ | |
32 | rl_vi_yank_arg (count) | |
33 | int count; | |
34 | { | |
35 | rl_yank_nth_arg (count, 0); | |
36 | } | |
37 | ||
38 | /* Search again for the last thing searched for. */ | |
39 | rl_vi_search_again (ignore, key) | |
40 | int ignore, key; | |
41 | { | |
42 | switch (key) | |
43 | { | |
44 | case 'n': | |
45 | rl_vi_dosearch (vi_last_search, -1); | |
46 | break; | |
47 | ||
48 | case 'N': | |
49 | rl_vi_dosearch (vi_last_search, 1); | |
50 | break; | |
51 | } | |
52 | } | |
53 | ||
54 | /* Do a vi style search. */ | |
55 | rl_vi_search (count, key) | |
56 | int count, key; | |
57 | { | |
58 | int dir, c, save_pos; | |
59 | char *p; | |
60 | ||
61 | switch (key) | |
62 | { | |
63 | case '?': | |
64 | dir = 1; | |
65 | break; | |
66 | ||
67 | case '/': | |
68 | dir = -1; | |
69 | break; | |
70 | ||
71 | default: | |
72 | ding (); | |
73 | return; | |
74 | } | |
75 | ||
76 | vi_histpos = where_history (); | |
77 | maybe_save_line (); | |
78 | save_pos = rl_point; | |
79 | ||
80 | /* Reuse the line input buffer to read the search string. */ | |
81 | the_line[0] = 0; | |
82 | rl_end = rl_point = 0; | |
83 | p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0)); | |
84 | ||
85 | sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key); | |
86 | ||
87 | rl_message (p, 0, 0); | |
88 | ||
89 | while (c = rl_read_key ()) | |
90 | { | |
91 | switch (c) | |
92 | { | |
93 | case CTRL('H'): | |
94 | case RUBOUT: | |
95 | if (rl_point == 0) | |
96 | { | |
97 | maybe_unsave_line (); | |
98 | rl_clear_message (); | |
99 | rl_point = save_pos; | |
100 | return; | |
101 | } | |
102 | ||
103 | case CTRL('W'): | |
104 | case CTRL('U'): | |
105 | rl_dispatch (c, keymap); | |
106 | break; | |
107 | ||
108 | case ESC: | |
109 | case RETURN: | |
110 | case NEWLINE: | |
111 | goto dosearch; | |
112 | break; | |
113 | ||
114 | case CTRL('C'): | |
115 | maybe_unsave_line (); | |
116 | rl_clear_message (); | |
117 | rl_point = 0; | |
118 | ding (); | |
119 | return; | |
120 | ||
121 | default: | |
122 | rl_insert (1, c); | |
123 | break; | |
124 | } | |
125 | rl_redisplay (); | |
126 | } | |
127 | dosearch: | |
128 | if (vi_last_search) | |
129 | free (vi_last_search); | |
130 | ||
131 | vi_last_search = savestring (the_line); | |
132 | rl_vi_dosearch (the_line, dir); | |
133 | } | |
134 | ||
135 | rl_vi_dosearch (string, dir) | |
136 | char *string; | |
137 | int dir; | |
138 | { | |
139 | int old, save = vi_histpos; | |
140 | HIST_ENTRY *h; | |
141 | ||
142 | if (string == 0 || *string == 0 || vi_histpos < 0) | |
143 | { | |
144 | ding (); | |
145 | return; | |
146 | } | |
147 | ||
148 | if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1) | |
149 | { | |
150 | maybe_unsave_line (); | |
151 | rl_clear_message (); | |
152 | rl_point = 0; | |
153 | ding (); | |
154 | return; | |
155 | } | |
156 | ||
157 | vi_histpos = save; | |
158 | ||
159 | old = where_history (); | |
160 | history_set_pos (vi_histpos); | |
161 | h = current_history (); | |
162 | history_set_pos (old); | |
163 | ||
164 | strcpy (the_line, h->line); | |
165 | rl_undo_list = (UNDO_LIST *)h->data; | |
166 | rl_end = strlen (the_line); | |
167 | rl_point = 0; | |
168 | rl_clear_message (); | |
169 | } | |
170 | ||
171 | /* Completion, from vi's point of view. */ | |
172 | rl_vi_complete (ignore, key) | |
173 | int ignore, key; | |
174 | { | |
175 | if (!whitespace (the_line[rl_point])) | |
176 | { | |
177 | if (!whitespace (the_line[rl_point + 1])) | |
178 | rl_vi_end_word (1, 'E'); | |
179 | rl_point++; | |
180 | } | |
181 | ||
182 | if (key == '*') | |
183 | rl_complete_internal ('*'); | |
184 | else | |
185 | rl_complete (0, key); | |
186 | ||
187 | rl_vi_insertion_mode (); | |
188 | } | |
189 | ||
190 | /* Previous word in vi mode. */ | |
191 | rl_vi_prev_word (count, key) | |
192 | int count, key; | |
193 | { | |
194 | if (count < 0) | |
195 | { | |
196 | rl_vi_next_word (-count, key); | |
197 | return; | |
198 | } | |
199 | ||
200 | if (uppercase_p (key)) | |
201 | rl_vi_bWord (count); | |
202 | else | |
203 | rl_vi_bword (count); | |
204 | } | |
205 | ||
206 | /* Next word in vi mode. */ | |
207 | rl_vi_next_word (count, key) | |
208 | int count; | |
209 | { | |
210 | if (count < 0) | |
211 | { | |
212 | rl_vi_prev_word (-count, key); | |
213 | return; | |
214 | } | |
215 | ||
216 | if (uppercase_p (key)) | |
217 | rl_vi_fWord (count); | |
218 | else | |
219 | rl_vi_fword (count); | |
220 | } | |
221 | ||
222 | /* Move to the end of the ?next? word. */ | |
223 | rl_vi_end_word (count, key) | |
224 | int count, key; | |
225 | { | |
226 | if (count < 0) | |
227 | { | |
228 | ding (); | |
229 | return; | |
230 | } | |
231 | ||
232 | if (uppercase_p (key)) | |
233 | rl_vi_eWord (count); | |
234 | else | |
235 | rl_vi_eword (count); | |
236 | } | |
237 | ||
238 | /* Move forward a word the way that 'W' does. */ | |
239 | rl_vi_fWord (count) | |
240 | int count; | |
241 | { | |
242 | while (count-- && rl_point < (rl_end - 1)) | |
243 | { | |
244 | /* Skip until whitespace. */ | |
245 | while (!whitespace (the_line[rl_point]) && rl_point < rl_end) | |
246 | rl_point++; | |
247 | ||
248 | /* Now skip whitespace. */ | |
249 | while (whitespace (the_line[rl_point]) && rl_point < rl_end) | |
250 | rl_point++; | |
251 | } | |
252 | } | |
253 | ||
254 | rl_vi_bWord (count) | |
255 | int count; | |
256 | { | |
257 | while (count-- && rl_point > 0) | |
258 | { | |
259 | while (rl_point-- >= 0 && whitespace (the_line[rl_point])); | |
260 | while (rl_point >= 0 && !whitespace (the_line[rl_point])) | |
261 | rl_point--; | |
262 | rl_point++; | |
263 | } | |
264 | } | |
265 | ||
266 | rl_vi_eWord (count) | |
267 | int count; | |
268 | { | |
269 | while (count -- && rl_point < (rl_end - 1)) | |
270 | { | |
271 | while (rl_point++ < rl_end && whitespace (the_line[rl_point])); | |
272 | while (rl_point++ < rl_end && !whitespace (the_line[rl_point])); | |
273 | rl_point--; | |
274 | } | |
275 | } | |
276 | ||
277 | rl_vi_fword (count) | |
278 | int count; | |
279 | { | |
280 | while (count -- && rl_point < (rl_end - 1)) | |
281 | { | |
282 | if (isident (the_line[rl_point])) | |
283 | { | |
284 | while (isident (the_line[rl_point]) && rl_point < rl_end) | |
285 | rl_point += 1; | |
286 | } | |
287 | else if (!whitespace (the_line[rl_point])) | |
288 | { | |
289 | while (!isident (the_line[rl_point]) && | |
290 | !whitespace (the_line[rl_point]) && rl_point < rl_end) | |
291 | rl_point += 1; | |
292 | } | |
293 | ||
294 | while (whitespace (the_line[rl_point]) && rl_point < rl_end) | |
295 | rl_point++; | |
296 | } | |
297 | } | |
298 | ||
299 | rl_vi_bword (count) | |
300 | int count; | |
301 | { | |
302 | while (count -- && rl_point > 0) | |
303 | { | |
304 | while (--rl_point > 0 && whitespace (the_line[rl_point])); | |
305 | if (rl_point > 0) | |
306 | { | |
307 | if (isident (the_line[rl_point])) | |
308 | while (--rl_point >= 0 && isident (the_line[rl_point])); | |
309 | else | |
310 | while (--rl_point >= 0 && !isident (the_line[rl_point]) && | |
311 | !whitespace (the_line[rl_point])); | |
312 | rl_point++; | |
313 | } | |
314 | } | |
315 | } | |
316 | ||
317 | rl_vi_eword (count) | |
318 | int count; | |
319 | { | |
320 | while (count -- && rl_point < rl_end - 1) | |
321 | { | |
322 | while (++rl_point < rl_end && whitespace (the_line[rl_point])); | |
323 | ||
324 | if (rl_point < rl_end) | |
325 | { | |
326 | if (isident (the_line[rl_point])) | |
327 | while (++rl_point < rl_end && isident (the_line[rl_point])); | |
328 | else | |
329 | while (++rl_point < rl_end && !isident (the_line[rl_point]) | |
330 | && !whitespace (the_line[rl_point])); | |
331 | rl_point--; | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | rl_vi_insert_beg () | |
337 | { | |
338 | rl_beg_of_line (); | |
339 | rl_vi_insertion_mode (); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | rl_vi_append_mode () | |
344 | { | |
345 | if (rl_point < rl_end) | |
346 | rl_point += 1; | |
347 | rl_vi_insertion_mode (); | |
348 | return 0; | |
349 | } | |
350 | ||
351 | rl_vi_append_eol () | |
352 | { | |
353 | rl_end_of_line (); | |
354 | rl_vi_append_mode (); | |
355 | return 0; | |
356 | } | |
357 | ||
358 | /* What to do in the case of C-d. */ | |
359 | rl_vi_eof_maybe (count, c) | |
360 | int count, c; | |
361 | { | |
362 | rl_newline (1, '\n'); | |
363 | } | |
364 | ||
365 | /* Insertion mode stuff. */ | |
366 | ||
367 | /* Switching from one mode to the other really just involves | |
368 | switching keymaps. */ | |
369 | rl_vi_insertion_mode () | |
370 | { | |
371 | keymap = vi_insertion_keymap; | |
372 | } | |
373 | ||
374 | rl_vi_movement_mode () | |
375 | { | |
376 | if (rl_point > 0) | |
377 | rl_backward (1); | |
378 | ||
379 | keymap = vi_movement_keymap; | |
380 | vi_done_inserting (); | |
381 | } | |
382 | ||
383 | vi_done_inserting () | |
384 | { | |
385 | if (vi_doing_insert) | |
386 | { | |
387 | rl_end_undo_group (); | |
388 | vi_doing_insert = 0; | |
389 | } | |
390 | } | |
391 | ||
392 | rl_vi_arg_digit (count, c) | |
393 | int count, c; | |
394 | { | |
395 | if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) | |
396 | rl_beg_of_line (); | |
397 | else | |
398 | rl_digit_argument (count, c); | |
399 | } | |
400 | ||
401 | /* Doesn't take an arg count in vi */ | |
402 | rl_vi_change_case (ignore1, ignore2) | |
403 | int ignore1, ignore2; | |
404 | { | |
405 | char c = 0; | |
406 | ||
407 | if (uppercase_p (the_line[rl_point])) | |
408 | c = to_lower (the_line[rl_point]); | |
409 | else if (lowercase_p (the_line[rl_point])) | |
410 | c = to_upper (the_line[rl_point]); | |
411 | ||
412 | /* Vi is kind of strange here. */ | |
413 | if (c) | |
414 | { | |
415 | rl_begin_undo_group (); | |
416 | rl_delete (1, c); | |
417 | rl_insert (1, c); | |
418 | rl_end_undo_group (); | |
419 | rl_vi_check (); | |
420 | } | |
421 | else | |
422 | rl_forward (1); | |
423 | } | |
424 | ||
425 | rl_vi_put (count, key) | |
426 | int count, key; | |
427 | { | |
428 | if (!uppercase_p (key)) | |
429 | rl_forward (1); | |
430 | ||
431 | rl_yank (); | |
432 | rl_backward (1); | |
433 | } | |
434 | ||
435 | rl_vi_check () | |
436 | { | |
437 | if (rl_point && rl_point == rl_end) | |
438 | rl_point--; | |
439 | } | |
440 | ||
441 | rl_vi_column (count) | |
442 | { | |
443 | if (count > rl_end) | |
444 | rl_end_of_line (); | |
445 | else | |
446 | rl_point = count - 1; | |
447 | } | |
448 | ||
449 | int | |
450 | rl_vi_domove (key, nextkey) | |
451 | int key, *nextkey; | |
452 | { | |
453 | int c, save; | |
454 | ||
455 | rl_mark = rl_point; | |
456 | c = rl_read_key (); | |
457 | *nextkey = c; | |
458 | ||
459 | if (!member (c, vi_motion)) | |
460 | { | |
461 | if (digit (c)) | |
462 | { | |
463 | save = rl_numeric_arg; | |
464 | rl_digit_loop1 (); | |
465 | rl_numeric_arg *= save; | |
466 | } | |
467 | else if ((key == 'd' && c == 'd') || | |
468 | (key == 'c' && c == 'c')) | |
469 | { | |
470 | rl_mark = rl_end; | |
471 | rl_beg_of_line (); | |
472 | return (0); | |
473 | } | |
474 | else | |
475 | return (-1); | |
476 | } | |
477 | ||
478 | rl_dispatch (c, keymap); | |
479 | ||
480 | /* No change in position means the command failed. */ | |
481 | if (rl_mark == rl_point) | |
482 | return (-1); | |
483 | ||
484 | if ((c == 'w' || c == 'W') && rl_point < rl_end) | |
485 | rl_point--; | |
486 | ||
487 | if (rl_mark < rl_point) | |
488 | exchange (rl_point, rl_mark); | |
489 | ||
490 | return (0); | |
491 | } | |
492 | ||
493 | /* A simplified loop for vi. Don't dispatch key at end. | |
494 | Don't recognize minus sign? */ | |
495 | rl_digit_loop1 () | |
496 | { | |
497 | int key, c; | |
498 | ||
499 | while (1) | |
500 | { | |
501 | rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0); | |
502 | key = c = rl_read_key (); | |
503 | ||
504 | if (keymap[c].type == ISFUNC && | |
505 | keymap[c].function == rl_universal_argument) | |
506 | { | |
507 | rl_numeric_arg *= 4; | |
508 | continue; | |
509 | } | |
510 | c = UNMETA (c); | |
511 | if (numeric (c)) | |
512 | { | |
513 | if (rl_explicit_arg) | |
514 | rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); | |
515 | else | |
516 | rl_numeric_arg = (c - '0'); | |
517 | rl_explicit_arg = 1; | |
518 | } | |
519 | else | |
520 | { | |
521 | rl_clear_message (); | |
522 | rl_stuff_char (key); | |
523 | } | |
524 | } | |
525 | } | |
526 | ||
527 | rl_vi_delete_to (count, key) | |
528 | int count, key; | |
529 | { | |
530 | int c; | |
531 | ||
532 | if (uppercase_p (key)) | |
533 | rl_stuff_char ('$'); | |
534 | ||
535 | if (rl_vi_domove (key, &c)) | |
536 | { | |
537 | ding (); | |
538 | return; | |
539 | } | |
540 | ||
541 | if ((c != '|') && (c != 'h') && rl_mark < rl_end) | |
542 | rl_mark++; | |
543 | ||
544 | rl_kill_text (rl_point, rl_mark); | |
545 | } | |
546 | ||
547 | rl_vi_change_to (count, key) | |
548 | int count, key; | |
549 | { | |
550 | int c; | |
551 | ||
552 | if (uppercase_p (key)) | |
553 | rl_stuff_char ('$'); | |
554 | ||
555 | if (rl_vi_domove (key, &c)) | |
556 | { | |
557 | ding (); | |
558 | return; | |
559 | } | |
560 | ||
561 | if ((c != '|') && (c != 'h') && rl_mark < rl_end) | |
562 | rl_mark++; | |
563 | ||
564 | rl_begin_undo_group (); | |
565 | vi_doing_insert = 1; | |
566 | rl_kill_text (rl_point, rl_mark); | |
567 | rl_vi_insertion_mode (); | |
568 | } | |
569 | ||
570 | rl_vi_yank_to (count, key) | |
571 | int count, key; | |
572 | { | |
573 | int c, save = rl_point; | |
574 | ||
575 | if (uppercase_p (key)) | |
576 | rl_stuff_char ('$'); | |
577 | ||
578 | if (rl_vi_domove (key, &c)) | |
579 | { | |
580 | ding (); | |
581 | return; | |
582 | } | |
583 | ||
584 | rl_begin_undo_group (); | |
585 | rl_kill_text (rl_point, rl_mark); | |
586 | rl_end_undo_group (); | |
587 | rl_do_undo (); | |
588 | rl_point = save; | |
589 | } | |
590 | ||
591 | rl_vi_delete (count) | |
592 | { | |
593 | if (rl_point >= rl_end - 1) | |
594 | { | |
595 | rl_delete (count, 0); | |
596 | if (rl_point > 0) | |
597 | rl_backward (1); | |
598 | } | |
599 | else | |
600 | rl_delete (count, 0); | |
601 | } | |
602 | ||
603 | /* Turn the current line into a comment in shell history. A ksh function */ | |
604 | rl_vi_comment () | |
605 | { | |
606 | rl_beg_of_line (); | |
607 | rl_insert_text (": "); /* # doesn't work in interactive mode */ | |
608 | rl_redisplay (); | |
609 | rl_newline (1, '\010'); | |
610 | } | |
611 | ||
612 | rl_vi_first_print () | |
613 | { | |
614 | rl_back_to_indent (); | |
615 | } | |
616 | ||
617 | rl_back_to_indent (ignore1, ignore2) | |
618 | int ignore1, ignore2; | |
619 | { | |
620 | rl_beg_of_line (); | |
621 | while (rl_point < rl_end && whitespace (the_line[rl_point])) | |
622 | rl_point++; | |
623 | } | |
624 | ||
625 | /* NOTE: it is necessary that opposite directions are inverses */ | |
626 | #define FTO 1 /* forward to */ | |
627 | #define BTO -1 /* backward to */ | |
628 | #define FFIND 2 /* forward find */ | |
629 | #define BFIND -2 /* backward find */ | |
630 | ||
631 | rl_vi_char_search (count, key) | |
632 | int count, key; | |
633 | { | |
634 | static char target; | |
635 | static int orig_dir, dir; | |
636 | int pos; | |
637 | ||
638 | if (key == ';' || key == ',') | |
639 | dir = (key == ';' ? orig_dir : -orig_dir); | |
640 | else | |
641 | { | |
642 | target = rl_getc (in_stream); | |
643 | ||
644 | switch (key) | |
645 | { | |
646 | case 't': | |
647 | orig_dir = dir = FTO; | |
648 | break; | |
649 | ||
650 | case 'T': | |
651 | orig_dir = dir = BTO; | |
652 | break; | |
653 | ||
654 | case 'f': | |
655 | orig_dir = dir = FFIND; | |
656 | break; | |
657 | ||
658 | case 'F': | |
659 | orig_dir = dir = BFIND; | |
660 | break; | |
661 | } | |
662 | } | |
663 | ||
664 | pos = rl_point; | |
665 | ||
666 | if (dir < 0) | |
667 | { | |
668 | pos--; | |
669 | do | |
670 | { | |
671 | if (the_line[pos] == target) | |
672 | { | |
673 | if (dir == BTO) | |
674 | rl_point = pos + 1; | |
675 | else | |
676 | rl_point = pos; | |
677 | return; | |
678 | } | |
679 | } | |
680 | while (pos--); | |
681 | ||
682 | if (pos < 0) | |
683 | { | |
684 | ding (); | |
685 | return; | |
686 | } | |
687 | } | |
688 | else | |
689 | { /* dir > 0 */ | |
690 | pos++; | |
691 | do | |
692 | { | |
693 | if (the_line[pos] == target) | |
694 | { | |
695 | if (dir == FTO) | |
696 | rl_point = pos - 1; | |
697 | else | |
698 | rl_point = pos; | |
699 | return; | |
700 | } | |
701 | } | |
702 | while (++pos < rl_end); | |
703 | ||
704 | if (pos >= (rl_end - 1)) | |
705 | ding (); | |
706 | } | |
707 | } | |
708 | ||
709 | /* Match brackets */ | |
710 | rl_vi_match () | |
711 | { | |
712 | int count = 1, brack, pos; | |
713 | ||
714 | pos = rl_point; | |
715 | if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0) | |
716 | { | |
717 | while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 && | |
718 | rl_point < rl_end - 1) | |
719 | rl_forward (1); | |
720 | ||
721 | if (brack <= 0) | |
722 | { | |
723 | rl_point = pos; | |
724 | ding (); | |
725 | return; | |
726 | } | |
727 | } | |
728 | ||
729 | pos = rl_point; | |
730 | ||
731 | if (brack < 0) | |
732 | { | |
733 | while (count) | |
734 | { | |
735 | if (--pos >= 0) | |
736 | { | |
737 | int b = rl_vi_bracktype (the_line[pos]); | |
738 | if (b == -brack) | |
739 | count--; | |
740 | else if (b == brack) | |
741 | count++; | |
742 | } | |
743 | else | |
744 | { | |
745 | ding (); | |
746 | return; | |
747 | } | |
748 | } | |
749 | } | |
750 | else | |
751 | { /* brack > 0 */ | |
752 | while (count) | |
753 | { | |
754 | if (++pos < rl_end) | |
755 | { | |
756 | int b = rl_vi_bracktype (the_line[pos]); | |
757 | if (b == -brack) | |
758 | count--; | |
759 | else if (b == brack) | |
760 | count++; | |
761 | } | |
762 | else | |
763 | { | |
764 | ding (); | |
765 | return; | |
766 | } | |
767 | } | |
768 | } | |
769 | rl_point = pos; | |
770 | } | |
771 | ||
772 | int | |
773 | rl_vi_bracktype (c) | |
774 | int c; | |
775 | { | |
776 | switch (c) | |
777 | { | |
778 | case '(': return 1; | |
779 | case ')': return -1; | |
780 | case '[': return 2; | |
781 | case ']': return -2; | |
782 | case '{': return 3; | |
783 | case '}': return -3; | |
784 | default: return 0; | |
785 | } | |
786 | } | |
787 | ||
788 | rl_vi_change_char () | |
789 | { | |
790 | int c; | |
791 | ||
792 | c = rl_getc (in_stream); | |
793 | ||
794 | switch (c) | |
795 | { | |
796 | case '\033': | |
797 | case CTRL('C'): | |
798 | return; | |
799 | ||
800 | default: | |
801 | rl_begin_undo_group (); | |
802 | rl_delete (1, c); | |
803 | rl_insert (1, c); | |
804 | rl_end_undo_group (); | |
805 | break; | |
806 | } | |
807 | } | |
808 | ||
809 | rl_vi_subst (count, key) | |
810 | int count, key; | |
811 | { | |
812 | rl_begin_undo_group (); | |
813 | vi_doing_insert = 1; | |
814 | ||
815 | if (uppercase_p (key)) | |
816 | { | |
817 | rl_beg_of_line (); | |
818 | rl_kill_line (1); | |
819 | } | |
820 | else | |
821 | rl_delete (1, key); | |
822 | ||
823 | rl_vi_insertion_mode (); | |
824 | } | |
825 | ||
826 | rl_vi_overstrike (count, key) | |
827 | int count, key; | |
828 | { | |
829 | int i; | |
830 | ||
831 | if (vi_doing_insert == 0) | |
832 | { | |
833 | vi_doing_insert = 1; | |
834 | rl_begin_undo_group (); | |
835 | } | |
836 | ||
837 | for (i = 0; i < count; i++) | |
838 | { | |
839 | vi_replace_count++; | |
840 | rl_begin_undo_group (); | |
841 | ||
842 | if (rl_point < rl_end) | |
843 | { | |
844 | rl_delete (1, key); | |
845 | rl_insert (1, key); | |
846 | } | |
847 | else | |
848 | rl_insert (1, key); | |
849 | ||
850 | rl_end_undo_group (); | |
851 | } | |
852 | } | |
853 | ||
854 | rl_vi_overstrike_delete (count) | |
855 | int count; | |
856 | { | |
857 | int i, s; | |
858 | ||
859 | for (i = 0; i < count; i++) | |
860 | { | |
861 | if (vi_replace_count == 0) | |
862 | { | |
863 | ding (); | |
864 | break; | |
865 | } | |
866 | s = rl_point; | |
867 | ||
868 | if (rl_do_undo ()) | |
869 | vi_replace_count--; | |
870 | ||
871 | if (rl_point == s) | |
872 | rl_backward (1); | |
873 | } | |
874 | ||
875 | if (vi_replace_count == 0 && vi_doing_insert) | |
876 | { | |
877 | rl_end_undo_group (); | |
878 | rl_do_undo (); | |
879 | vi_doing_insert = 0; | |
880 | } | |
881 | } | |
882 | ||
883 | rl_vi_replace () | |
884 | { | |
885 | int i; | |
886 | ||
887 | vi_replace_count = 0; | |
888 | ||
889 | vi_replace_map = rl_make_bare_keymap (); | |
890 | ||
891 | for (i = ' '; i < 127; i++) | |
892 | vi_replace_map[i].function = rl_vi_overstrike; | |
893 | ||
894 | vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; | |
895 | vi_replace_map[ESC].function = rl_vi_movement_mode; | |
896 | vi_replace_map[RETURN].function = rl_newline; | |
897 | vi_replace_map[NEWLINE].function = rl_newline; | |
898 | keymap = vi_replace_map; | |
899 | } | |
900 | ||
901 | /* | |
902 | * Try to complete the word we are standing on or the word that ends with | |
903 | * the previous character. A space matches everything. | |
904 | * Word delimiters are space and ;. | |
905 | */ | |
906 | rl_vi_possible_completions() | |
907 | { | |
908 | int save_pos = rl_point; | |
909 | ||
910 | if (!index (" ;", the_line[rl_point])) | |
911 | { | |
912 | while (!index(" ;", the_line[++rl_point])) | |
913 | ; | |
914 | } | |
915 | else if (the_line[rl_point-1] == ';') | |
916 | { | |
917 | ding (); | |
918 | return (0); | |
919 | } | |
920 | ||
921 | rl_possible_completions (); | |
922 | rl_point = save_pos; | |
923 | ||
924 | return (0); | |
925 | } |