1 /* vi_mode.c -- A vi emulation mode for Bash.
2
3 Derived from code written by Jeff Sparkes (jeff1@????).
4 */
5
6
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. */
rl_vi_yank_arg(count)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. */
rl_vi_search_again(ignore,key)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. */
rl_vi_search(count,key)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
rl_vi_dosearch(string,dir)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. */
rl_vi_complete(ignore,key)172 rl_vi_complete (ignore, key)
173 int ignore, key;
174 {
175 if ((rl_point < rl_end) && (!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. */
rl_vi_prev_word(count,key)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. */
rl_vi_next_word(count,key)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. */
rl_vi_end_word(count,key)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 /* Move forward a word the way that 'W' does. */
rl_vi_fWord(count)240 rl_vi_fWord (count)
241 int count;
242 {
243 while (count-- && rl_point < (rl_end - 1))
244 {
245 /* Skip until whitespace. */
246 while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
247 rl_point++;
248
249 /* Now skip whitespace. */
250 while (whitespace (the_line[rl_point]) && rl_point < rl_end)
251 rl_point++;
252 }
253 }
254
rl_vi_bWord(count)255 rl_vi_bWord (count)
256 int count;
257 {
258 while (count-- && rl_point > 0)
259 {
260 /* If we are at the start of a word, move back to whitespace so
261 we will go back to the start of the previous word. */
262 if (!whitespace (the_line[rl_point]) &&
263 whitespace (the_line[rl_point - 1]))
264 rl_point--;
265
266 while (rl_point > 0 && whitespace (the_line[rl_point]))
267 rl_point--;
268
269 if (rl_point > 0)
270 {
271 while (--rl_point >= 0 && !whitespace (the_line[rl_point]));
272 rl_point++;
273 }
274 }
275 }
276
rl_vi_eWord(count)277 rl_vi_eWord (count)
278 int count;
279 {
280 while (count-- && rl_point < (rl_end - 1))
281 {
282 /* Move to white space. */
283 while (++rl_point < rl_end && whitespace (the_line[rl_point]))
284 ;
285
286 if (rl_point && rl_point < rl_end)
287 {
288 /* Skip whitespace. */
289 while (rl_point < rl_end && whitespace (the_line[rl_point]))
290 rl_point++;
291
292 /* Skip until whitespace. */
293 while (rl_point < rl_end && !whitespace (the_line[rl_point]))
294 rl_point++;
295
296 /* Move back to the last character of the word. */
297 rl_point--;
298 }
299 }
300 }
301
rl_vi_fword(count)302 rl_vi_fword (count)
303 int count;
304 {
305 while (count-- && rl_point < (rl_end - 1))
306 {
307 /* Move to white space (really non-identifer). */
308 if (isident (the_line[rl_point]))
309 {
310 while (isident (the_line[rl_point]) && rl_point < rl_end)
311 rl_point++;
312 }
313 else /* if (!whitespace (the_line[rl_point])) */
314 {
315 while (!isident (the_line[rl_point]) &&
316 !whitespace (the_line[rl_point]) && rl_point < rl_end)
317 rl_point++;
318 }
319
320 /* Move past whitespace. */
321 while (whitespace (the_line[rl_point]) && rl_point < rl_end)
322 rl_point++;
323 }
324 }
325
rl_vi_bword(count)326 rl_vi_bword (count)
327 int count;
328 {
329 while (count-- && rl_point > 0)
330 {
331 int last_is_ident;
332
333 /* If we are at the start of a word, move back to a non-identifier
334 so we will go back to the start of the previous word. */
335 if (isident (the_line[rl_point]) && !isident (the_line[rl_point - 1]))
336 rl_point--;
337
338 /* If this character and the previous character are `opposite', move
339 back so we don't get messed up by the rl_point++ down there in
340 the while loop. Without this code, words like `l;' screw up the
341 function. */
342 last_is_ident = isident (the_line[rl_point - 1]);
343 if ((isident (the_line[rl_point]) && !last_is_ident) ||
344 (!isident (the_line[rl_point]) && last_is_ident))
345 rl_point--;
346
347 while (rl_point > 0 && whitespace (the_line[rl_point]))
348 rl_point--;
349
350 if (rl_point > 0)
351 {
352 if (isident (the_line[rl_point]))
353 while (--rl_point >= 0 && isident (the_line[rl_point]));
354 else
355 while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
356 !whitespace (the_line[rl_point]));
357 rl_point++;
358 }
359 }
360 }
361
rl_vi_eword(count)362 rl_vi_eword (count)
363 int count;
364 {
365 while (count-- && rl_point < rl_end - 1)
366 {
367 while (++rl_point < rl_end && whitespace (the_line[rl_point]))
368 ;
369
370 if (rl_point < rl_end)
371 {
372 if (isident (the_line[rl_point]))
373 while (++rl_point < rl_end && isident (the_line[rl_point]));
374 else
375 while (++rl_point < rl_end && !isident (the_line[rl_point])
376 && !whitespace (the_line[rl_point]));
377 rl_point--;
378 }
379 }
380 }
381
rl_vi_insert_beg()382 rl_vi_insert_beg ()
383 {
384 rl_beg_of_line ();
385 rl_vi_insertion_mode ();
386 return 0;
387 }
388
rl_vi_append_mode()389 rl_vi_append_mode ()
390 {
391 if (rl_point < rl_end)
392 rl_point += 1;
393 rl_vi_insertion_mode ();
394 return 0;
395 }
396
rl_vi_append_eol()397 rl_vi_append_eol ()
398 {
399 rl_end_of_line ();
400 rl_vi_append_mode ();
401 return 0;
402 }
403
404 /* What to do in the case of C-d. */
rl_vi_eof_maybe(count,c)405 rl_vi_eof_maybe (count, c)
406 int count, c;
407 {
408 rl_newline (1, '\n');
409 }
410
411 /* Insertion mode stuff. */
412
413 /* Switching from one mode to the other really just involves
414 switching keymaps. */
rl_vi_insertion_mode()415 rl_vi_insertion_mode ()
416 {
417 keymap = vi_insertion_keymap;
418 }
419
rl_vi_movement_mode()420 rl_vi_movement_mode ()
421 {
422 if (rl_point > 0)
423 rl_backward (1);
424
425 keymap = vi_movement_keymap;
426 vi_done_inserting ();
427 }
428
vi_done_inserting()429 vi_done_inserting ()
430 {
431 if (vi_doing_insert)
432 {
433 rl_end_undo_group ();
434 vi_doing_insert = 0;
435 }
436 }
437
rl_vi_arg_digit(count,c)438 rl_vi_arg_digit (count, c)
439 int count, c;
440 {
441 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
442 rl_beg_of_line ();
443 else
444 rl_digit_argument (count, c);
445 }
446
447 /* Doesn't take an arg count in vi */
rl_vi_change_case(ignore1,ignore2)448 rl_vi_change_case (ignore1, ignore2)
449 int ignore1, ignore2;
450 {
451 char c = 0;
452
453 /* Don't try this on an empty line. */
454 if (rl_point >= rl_end - 1)
455 return;
456
457 if (uppercase_p (the_line[rl_point]))
458 c = to_lower (the_line[rl_point]);
459 else if (lowercase_p (the_line[rl_point]))
460 c = to_upper (the_line[rl_point]);
461
462 /* Vi is kind of strange here. */
463 if (c)
464 {
465 rl_begin_undo_group ();
466 rl_delete (1, c);
467 rl_insert (1, c);
468 rl_end_undo_group ();
469 rl_vi_check ();
470 }
471 else
472 rl_forward (1);
473 }
474
rl_vi_put(count,key)475 rl_vi_put (count, key)
476 int count, key;
477 {
478 if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
479 rl_forward (1);
480
481 rl_yank ();
482 rl_backward (1);
483 }
484
rl_vi_check()485 rl_vi_check ()
486 {
487 if (rl_point && rl_point == rl_end)
488 rl_point--;
489 }
490
rl_vi_column(count)491 rl_vi_column (count)
492 {
493 if (count > rl_end)
494 rl_end_of_line ();
495 else
496 rl_point = count - 1;
497 }
498
499 int
rl_vi_domove(key,nextkey)500 rl_vi_domove (key, nextkey)
501 int key, *nextkey;
502 {
503 int c, save;
504
505 rl_mark = rl_point;
506 c = rl_read_key ();
507 *nextkey = c;
508
509 if (!member (c, vi_motion))
510 {
511 if (digit (c))
512 {
513 save = rl_numeric_arg;
514 rl_digit_loop1 ();
515 rl_numeric_arg *= save;
516 }
517 else if ((key == 'd' && c == 'd') ||
518 (key == 'c' && c == 'c'))
519 {
520 rl_mark = rl_end;
521 rl_beg_of_line ();
522 return (0);
523 }
524 else
525 return (-1);
526 }
527
528 rl_dispatch (c, keymap);
529
530 /* No change in position means the command failed. */
531 if (rl_mark == rl_point)
532 return (-1);
533
534 if ((c == 'w' || c == 'W') && rl_point < rl_end)
535 rl_point--;
536
537 if (rl_mark < rl_point)
538 exchange (rl_point, rl_mark);
539
540 return (0);
541 }
542
543 /* A simplified loop for vi. Don't dispatch key at end.
544 Don't recognize minus sign? */
rl_digit_loop1()545 rl_digit_loop1 ()
546 {
547 int key, c;
548
549 while (1)
550 {
551 rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0);
552 key = c = rl_read_key ();
553
554 if (keymap[c].type == ISFUNC &&
555 keymap[c].function == rl_universal_argument)
556 {
557 rl_numeric_arg *= 4;
558 continue;
559 }
560
561 c = UNMETA (c);
562 if (numeric (c))
563 {
564 if (rl_explicit_arg)
565 rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
566 else
567 rl_numeric_arg = (c - '0');
568 rl_explicit_arg = 1;
569 }
570 else
571 {
572 rl_clear_message ();
573 rl_stuff_char (key);
574 break;
575 }
576 }
577 }
578
rl_vi_delete_to(count,key)579 rl_vi_delete_to (count, key)
580 int count, key;
581 {
582 int c;
583
584 if (uppercase_p (key))
585 rl_stuff_char ('$');
586
587 if (rl_vi_domove (key, &c))
588 {
589 ding ();
590 return;
591 }
592
593 if ((c != '|') && (c != 'h') && rl_mark < rl_end)
594 rl_mark++;
595
596 rl_kill_text (rl_point, rl_mark);
597 }
598
rl_vi_change_to(count,key)599 rl_vi_change_to (count, key)
600 int count, key;
601 {
602 int c;
603
604 if (uppercase_p (key))
605 rl_stuff_char ('$');
606
607 if (rl_vi_domove (key, &c))
608 {
609 ding ();
610 return;
611 }
612
613 if ((c != '|') && (c != 'h') && rl_mark < rl_end)
614 rl_mark++;
615
616 rl_begin_undo_group ();
617 vi_doing_insert = 1;
618 rl_kill_text (rl_point, rl_mark);
619 rl_vi_insertion_mode ();
620 }
621
rl_vi_yank_to(count,key)622 rl_vi_yank_to (count, key)
623 int count, key;
624 {
625 int c, save = rl_point;
626
627 if (uppercase_p (key))
628 rl_stuff_char ('$');
629
630 if (rl_vi_domove (key, &c))
631 {
632 ding ();
633 return;
634 }
635
636 rl_begin_undo_group ();
637 rl_kill_text (rl_point, rl_mark);
638 rl_end_undo_group ();
639 rl_do_undo ();
640 rl_point = save;
641 }
642
rl_vi_delete(count)643 rl_vi_delete (count)
644 {
645 int end;
646
647 if (rl_end == 0)
648 {
649 ding ();
650 return;
651 }
652
653 end = rl_point + count;
654
655 if (end >= rl_end)
656 end = rl_end;
657
658 rl_kill_text (rl_point, end);
659
660 if (rl_point > 0 && rl_point == rl_end)
661 rl_backward (1);
662 }
663
664 /* Turn the current line into a comment in shell history.
665 A K*rn shell style function. */
rl_vi_comment()666 rl_vi_comment ()
667 {
668 rl_beg_of_line ();
669 rl_insert_text (": "); /* `#' doesn't work in interactive mode */
670 rl_redisplay ();
671 rl_newline (1, '\010');
672 }
673
rl_vi_first_print()674 rl_vi_first_print ()
675 {
676 rl_back_to_indent ();
677 }
678
rl_back_to_indent(ignore1,ignore2)679 rl_back_to_indent (ignore1, ignore2)
680 int ignore1, ignore2;
681 {
682 rl_beg_of_line ();
683 while (rl_point < rl_end && whitespace (the_line[rl_point]))
684 rl_point++;
685 }
686
687 /* NOTE: it is necessary that opposite directions are inverses */
688 #define FTO 1 /* forward to */
689 #define BTO -1 /* backward to */
690 #define FFIND 2 /* forward find */
691 #define BFIND -2 /* backward find */
692
rl_vi_char_search(count,key)693 rl_vi_char_search (count, key)
694 int count, key;
695 {
696 static char target;
697 static int orig_dir, dir;
698 int pos;
699
700 if (key == ';' || key == ',')
701 dir = (key == ';' ? orig_dir : -orig_dir);
702 else
703 {
704 target = rl_getc (in_stream);
705
706 switch (key)
707 {
708 case 't':
709 orig_dir = dir = FTO;
710 break;
711
712 case 'T':
713 orig_dir = dir = BTO;
714 break;
715
716 case 'f':
717 orig_dir = dir = FFIND;
718 break;
719
720 case 'F':
721 orig_dir = dir = BFIND;
722 break;
723 }
724 }
725
726 pos = rl_point;
727
728 if (dir < 0)
729 {
730 pos--;
731 do
732 {
733 if (the_line[pos] == target)
734 {
735 if (dir == BTO)
736 rl_point = pos + 1;
737 else
738 rl_point = pos;
739 return;
740 }
741 }
742 while (pos--);
743
744 if (pos < 0)
745 {
746 ding ();
747 return;
748 }
749 }
750 else
751 { /* dir > 0 */
752 pos++;
753 do
754 {
755 if (the_line[pos] == target)
756 {
757 if (dir == FTO)
758 rl_point = pos - 1;
759 else
760 rl_point = pos;
761 return;
762 }
763 }
764 while (++pos < rl_end);
765
766 if (pos >= (rl_end - 1))
767 ding ();
768 }
769 }
770
771 /* Match brackets */
rl_vi_match()772 rl_vi_match ()
773 {
774 int count = 1, brack, pos;
775
776 pos = rl_point;
777 if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
778 {
779 while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
780 rl_point < rl_end - 1)
781 rl_forward (1);
782
783 if (brack <= 0)
784 {
785 rl_point = pos;
786 ding ();
787 return;
788 }
789 }
790
791 pos = rl_point;
792
793 if (brack < 0)
794 {
795 while (count)
796 {
797 if (--pos >= 0)
798 {
799 int b = rl_vi_bracktype (the_line[pos]);
800 if (b == -brack)
801 count--;
802 else if (b == brack)
803 count++;
804 }
805 else
806 {
807 ding ();
808 return;
809 }
810 }
811 }
812 else
813 { /* brack > 0 */
814 while (count)
815 {
816 if (++pos < rl_end)
817 {
818 int b = rl_vi_bracktype (the_line[pos]);
819 if (b == -brack)
820 count--;
821 else if (b == brack)
822 count++;
823 }
824 else
825 {
826 ding ();
827 return;
828 }
829 }
830 }
831 rl_point = pos;
832 }
833
834 int
rl_vi_bracktype(c)835 rl_vi_bracktype (c)
836 int c;
837 {
838 switch (c)
839 {
840 case '(': return 1;
841 case ')': return -1;
842 case '[': return 2;
843 case ']': return -2;
844 case '{': return 3;
845 case '}': return -3;
846 default: return 0;
847 }
848 }
849
rl_vi_change_char()850 rl_vi_change_char ()
851 {
852 int c;
853
854 c = rl_getc (in_stream);
855
856 switch (c)
857 {
858 case '\033':
859 case CTRL('C'):
860 return;
861
862 default:
863 rl_begin_undo_group ();
864 rl_delete (1, c);
865 rl_insert (1, c);
866 rl_end_undo_group ();
867 break;
868 }
869 }
870
rl_vi_subst(count,key)871 rl_vi_subst (count, key)
872 int count, key;
873 {
874 rl_begin_undo_group ();
875 vi_doing_insert = 1;
876
877 if (uppercase_p (key))
878 {
879 rl_beg_of_line ();
880 rl_kill_line (1);
881 }
882 else
883 rl_delete (count, key);
884
885 rl_vi_insertion_mode ();
886 }
887
rl_vi_overstrike(count,key)888 rl_vi_overstrike (count, key)
889 int count, key;
890 {
891 int i;
892
893 if (vi_doing_insert == 0)
894 {
895 vi_doing_insert = 1;
896 rl_begin_undo_group ();
897 }
898
899 for (i = 0; i < count; i++)
900 {
901 vi_replace_count++;
902 rl_begin_undo_group ();
903
904 if (rl_point < rl_end)
905 {
906 rl_delete (1, key);
907 rl_insert (1, key);
908 }
909 else
910 rl_insert (1, key);
911
912 rl_end_undo_group ();
913 }
914 }
915
rl_vi_overstrike_delete(count)916 rl_vi_overstrike_delete (count)
917 int count;
918 {
919 int i, s;
920
921 for (i = 0; i < count; i++)
922 {
923 if (vi_replace_count == 0)
924 {
925 ding ();
926 break;
927 }
928 s = rl_point;
929
930 if (rl_do_undo ())
931 vi_replace_count--;
932
933 if (rl_point == s)
934 rl_backward (1);
935 }
936
937 if (vi_replace_count == 0 && vi_doing_insert)
938 {
939 rl_end_undo_group ();
940 rl_do_undo ();
941 vi_doing_insert = 0;
942 }
943 }
944
rl_vi_replace()945 rl_vi_replace ()
946 {
947 int i;
948
949 vi_replace_count = 0;
950
951 vi_replace_map = rl_make_bare_keymap ();
952
953 for (i = ' '; i < 127; i++)
954 vi_replace_map[i].function = rl_vi_overstrike;
955
956 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
957 vi_replace_map[ESC].function = rl_vi_movement_mode;
958 vi_replace_map[RETURN].function = rl_newline;
959 vi_replace_map[NEWLINE].function = rl_newline;
960 keymap = vi_replace_map;
961 }
962
963 /*
964 * Try to complete the word we are standing on or the word that ends with
965 * the previous character. A space matches everything.
966 * Word delimiters are space and ;.
967 */
rl_vi_possible_completions()968 rl_vi_possible_completions()
969 {
970 int save_pos = rl_point;
971
972 if (!index (" ;", the_line[rl_point]))
973 {
974 while (!index(" ;", the_line[++rl_point]))
975 ;
976 }
977 else if (the_line[rl_point-1] == ';')
978 {
979 ding ();
980 return (0);
981 }
982
983 rl_possible_completions ();
984 rl_point = save_pos;
985
986 return (0);
987 }
988