import gdb-1999-08-02 snapshot
[platform/upstream/binutils.git] / readline / vi_mode.c
1 /* vi_mode.c -- A vi emulation mode for Bash.
2    Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  */
3
4 /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
5
6    This file is part of the GNU Readline Library, a library for
7    reading lines of text with interactive input and history editing.
8
9    The GNU Readline Library is free software; you can redistribute it
10    and/or modify it under the terms of the GNU General Public License
11    as published by the Free Software Foundation; either version 1, or
12    (at your option) any later version.
13
14    The GNU Readline Library is distributed in the hope that it will be
15    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    The GNU General Public License is often shipped with GNU software, and
20    is generally kept in a file called COPYING or LICENSE.  If you do not
21    have a copy of the license, write to the Free Software Foundation,
22    675 Mass Ave, Cambridge, MA 02139, USA. */
23 #define READLINE_LIBRARY
24
25 /* **************************************************************** */
26 /*                                                                  */
27 /*                      VI Emulation Mode                           */
28 /*                                                                  */
29 /* **************************************************************** */
30 #include "rlconf.h"
31
32 #if defined (VI_MODE)
33
34 #if defined (HAVE_CONFIG_H)
35 #  include <config.h>
36 #endif
37
38 #include <sys/types.h>
39
40 #if defined (HAVE_STDLIB_H)
41 #  include <stdlib.h>
42 #else
43 #  include "ansi_stdlib.h"
44 #endif /* HAVE_STDLIB_H */
45
46 #if defined (HAVE_UNISTD_H)
47 #  include <unistd.h>
48 #endif
49
50 #include <stdio.h>
51
52 /* Some standard library routines. */
53 #include "rldefs.h"
54 #include "readline.h"
55 #include "history.h"
56
57 #ifndef _rl_digit_p
58 #define _rl_digit_p(c)  ((c) >= '0' && (c) <= '9')
59 #endif
60
61 #ifndef _rl_digit_value
62 #define _rl_digit_value(c) ((c) - '0')
63 #endif
64
65 #ifndef member
66 #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
67 #endif
68
69 #ifndef isident
70 #define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
71 #endif
72
73 #ifndef exchange
74 #define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
75 #endif
76
77 extern char *xmalloc (), *xrealloc ();
78
79 /* Variables imported from readline.c */
80 extern int rl_point, rl_end, rl_mark;
81 extern FILE *rl_instream;
82 extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
83 extern Keymap _rl_keymap;
84 extern char *rl_prompt;
85 extern char *rl_line_buffer;
86 extern int rl_arg_sign;
87
88 extern int _rl_doing_an_undo;
89 extern int _rl_undo_group_level;
90
91 extern void _rl_dispatch ();
92 extern int _rl_char_search_internal ();
93
94 extern void rl_extend_line_buffer ();
95 extern int rl_vi_check ();
96
97 /* Non-zero means enter insertion mode. */
98 static int _rl_vi_doing_insert;
99
100 /* Command keys which do movement for xxx_to commands. */
101 static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
102
103 /* Keymap used for vi replace characters.  Created dynamically since
104    rarely used. */
105 static Keymap vi_replace_map;
106
107 /* The number of characters inserted in the last replace operation. */
108 static int vi_replace_count;
109
110 /* If non-zero, we have text inserted after a c[motion] command that put
111    us implicitly into insert mode.  Some people want this text to be
112    attached to the command so that it is `redoable' with `.'. */
113 static int vi_continued_command;
114 static char *vi_insert_buffer;
115 static int vi_insert_buffer_size;
116
117 static int _rl_vi_last_command = 'i';   /* default `.' puts you in insert mode */
118 static int _rl_vi_last_repeat = 1;
119 static int _rl_vi_last_arg_sign = 1;
120 static int _rl_vi_last_motion;
121 static int _rl_vi_last_search_char;
122 static int _rl_vi_last_replacement;
123
124 static int _rl_vi_last_key_before_insert;
125
126 static int vi_redoing;
127
128 /* Text modification commands.  These are the `redoable' commands. */
129 static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
130
131 /* Arrays for the saved marks. */
132 static int vi_mark_chars[27];
133
134 static int rl_digit_loop1 ();
135
136 void
137 _rl_vi_initialize_line ()
138 {
139   register int i;
140
141   for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
142     vi_mark_chars[i] = -1;
143 }
144
145 void
146 _rl_vi_reset_last ()
147 {
148   _rl_vi_last_command = 'i';
149   _rl_vi_last_repeat = 1;
150   _rl_vi_last_arg_sign = 1;
151   _rl_vi_last_motion = 0;
152 }
153
154 void
155 _rl_vi_set_last (key, repeat, sign)
156      int key, repeat, sign;
157 {
158   _rl_vi_last_command = key;
159   _rl_vi_last_repeat = repeat;
160   _rl_vi_last_arg_sign = sign;
161 }
162
163 /* Is the command C a VI mode text modification command? */
164 int
165 _rl_vi_textmod_command (c)
166      int c;
167 {
168   return (member (c, vi_textmod));
169 }
170
171 static void
172 _rl_vi_stuff_insert (count)
173      int count;
174 {
175   rl_begin_undo_group ();
176   while (count--)
177     rl_insert_text (vi_insert_buffer);
178   rl_end_undo_group ();
179 }
180
181 /* Bound to `.'.  Called from command mode, so we know that we have to
182    redo a text modification command.  The default for _rl_vi_last_command
183    puts you back into insert mode. */
184 int
185 rl_vi_redo (count, c)
186      int count, c;
187 {
188   if (!rl_explicit_arg)
189     {
190       rl_numeric_arg = _rl_vi_last_repeat;
191       rl_arg_sign = _rl_vi_last_arg_sign;
192     }
193
194   vi_redoing = 1;
195   /* If we're redoing an insert with `i', stuff in the inserted text
196      and do not go into insertion mode. */
197   if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
198     {
199       _rl_vi_stuff_insert (count);
200       /* And back up point over the last character inserted. */
201       if (rl_point > 0)
202         rl_point--;
203     }
204   else
205     _rl_dispatch (_rl_vi_last_command, _rl_keymap);
206   vi_redoing = 0;
207
208   return (0);
209 }
210
211 /* A placeholder for further expansion. */
212 int
213 rl_vi_undo (count, key)
214      int count, key;
215 {
216   return (rl_undo_command (count, key));
217 }
218     
219 /* Yank the nth arg from the previous line into this line at point. */
220 int
221 rl_vi_yank_arg (count, key)
222      int count, key;
223 {
224   /* Readline thinks that the first word on a line is the 0th, while vi
225      thinks the first word on a line is the 1st.  Compensate. */
226   if (rl_explicit_arg)
227     rl_yank_nth_arg (count - 1, 0);
228   else
229     rl_yank_nth_arg ('$', 0);
230
231   return (0);
232 }
233
234 /* With an argument, move back that many history lines, else move to the
235    beginning of history. */
236 int
237 rl_vi_fetch_history (count, c)
238      int count, c;
239 {
240   int wanted;
241
242   /* Giving an argument of n means we want the nth command in the history
243      file.  The command number is interpreted the same way that the bash
244      `history' command does it -- that is, giving an argument count of 450
245      to this command would get the command listed as number 450 in the
246      output of `history'. */
247   if (rl_explicit_arg)
248     {
249       wanted = history_base + where_history () - count;
250       if (wanted <= 0)
251         rl_beginning_of_history (0, 0);
252       else
253         rl_get_previous_history (wanted, c);
254     }
255   else
256     rl_beginning_of_history (count, 0);
257   return (0);
258 }
259
260 /* Search again for the last thing searched for. */
261 int
262 rl_vi_search_again (count, key)
263      int count, key;
264 {
265   switch (key)
266     {
267     case 'n':
268       rl_noninc_reverse_search_again (count, key);
269       break;
270
271     case 'N':
272       rl_noninc_forward_search_again (count, key);
273       break;
274     }
275   return (0);
276 }
277
278 /* Do a vi style search. */
279 int
280 rl_vi_search (count, key)
281      int count, key;
282 {
283   switch (key)
284     {
285     case '?':
286       rl_noninc_forward_search (count, key);
287       break;
288
289     case '/':
290       rl_noninc_reverse_search (count, key);
291       break;
292
293     default:
294       ding ();
295       break;
296     }
297   return (0);
298 }
299
300 /* Completion, from vi's point of view. */
301 int
302 rl_vi_complete (ignore, key)
303      int ignore, key;
304 {
305   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
306     {
307       if (!whitespace (rl_line_buffer[rl_point + 1]))
308         rl_vi_end_word (1, 'E');
309       rl_point++;
310     }
311
312   if (key == '*')
313     rl_complete_internal ('*'); /* Expansion and replacement. */
314   else if (key == '=')
315     rl_complete_internal ('?'); /* List possible completions. */
316   else if (key == '\\')
317     rl_complete_internal (TAB); /* Standard Readline completion. */
318   else
319     rl_complete (0, key);
320
321   if (key == '*' || key == '\\')
322     {
323       _rl_vi_set_last (key, 1, rl_arg_sign);
324       rl_vi_insertion_mode (1, key);
325     }
326   return (0);
327 }
328
329 /* Tilde expansion for vi mode. */
330 int
331 rl_vi_tilde_expand (ignore, key)
332      int ignore, key;
333 {
334   rl_tilde_expand (0, key);
335   _rl_vi_set_last (key, 1, rl_arg_sign);        /* XXX */
336   rl_vi_insertion_mode (1, key);
337   return (0);
338 }
339
340 /* Previous word in vi mode. */
341 int
342 rl_vi_prev_word (count, key)
343      int count, key;
344 {
345   if (count < 0)
346     return (rl_vi_next_word (-count, key));
347
348   if (rl_point == 0)
349     {
350       ding ();
351       return (0);
352     }
353
354   if (_rl_uppercase_p (key))
355     rl_vi_bWord (count, key);
356   else
357     rl_vi_bword (count, key);
358
359   return (0);
360 }
361
362 /* Next word in vi mode. */
363 int
364 rl_vi_next_word (count, key)
365      int count, key;
366 {
367   if (count < 0)
368     return (rl_vi_prev_word (-count, key));
369
370   if (rl_point >= (rl_end - 1))
371     {
372       ding ();
373       return (0);
374     }
375
376   if (_rl_uppercase_p (key))
377     rl_vi_fWord (count, key);
378   else
379     rl_vi_fword (count, key);
380   return (0);
381 }
382
383 /* Move to the end of the ?next? word. */
384 int
385 rl_vi_end_word (count, key)
386      int count, key;
387 {
388   if (count < 0)
389     {
390       ding ();
391       return -1;
392     }
393
394   if (_rl_uppercase_p (key))
395     rl_vi_eWord (count, key);
396   else
397     rl_vi_eword (count, key);
398   return (0);
399 }
400
401 /* Move forward a word the way that 'W' does. */
402 int
403 rl_vi_fWord (count, ignore)
404      int count, ignore;
405 {
406   while (count-- && rl_point < (rl_end - 1))
407     {
408       /* Skip until whitespace. */
409       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
410         rl_point++;
411
412       /* Now skip whitespace. */
413       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
414         rl_point++;
415     }
416   return (0);
417 }
418
419 int
420 rl_vi_bWord (count, ignore)
421      int count, ignore;
422 {
423   while (count-- && rl_point > 0)
424     {
425       /* If we are at the start of a word, move back to whitespace so
426          we will go back to the start of the previous word. */
427       if (!whitespace (rl_line_buffer[rl_point]) &&
428           whitespace (rl_line_buffer[rl_point - 1]))
429         rl_point--;
430
431       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
432         rl_point--;
433
434       if (rl_point > 0)
435         {
436           while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
437           rl_point++;
438         }
439     }
440   return (0);
441 }
442
443 int
444 rl_vi_eWord (count, ignore)
445      int count, ignore;
446 {
447   while (count-- && rl_point < (rl_end - 1))
448     {
449       if (!whitespace (rl_line_buffer[rl_point]))
450         rl_point++;
451
452       /* Move to the next non-whitespace character (to the start of the
453          next word). */
454       while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
455
456       if (rl_point && rl_point < rl_end)
457         {
458           /* Skip whitespace. */
459           while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
460             rl_point++;
461
462           /* Skip until whitespace. */
463           while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
464             rl_point++;
465
466           /* Move back to the last character of the word. */
467           rl_point--;
468         }
469     }
470   return (0);
471 }
472
473 int
474 rl_vi_fword (count, ignore)
475      int count, ignore;
476 {
477   while (count-- && rl_point < (rl_end - 1))
478     {
479       /* Move to white space (really non-identifer). */
480       if (isident (rl_line_buffer[rl_point]))
481         {
482           while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
483             rl_point++;
484         }
485       else /* if (!whitespace (rl_line_buffer[rl_point])) */
486         {
487           while (!isident (rl_line_buffer[rl_point]) &&
488                  !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
489             rl_point++;
490         }
491
492       /* Move past whitespace. */
493       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
494         rl_point++;
495     }
496   return (0);
497 }
498
499 int
500 rl_vi_bword (count, ignore)
501      int count, ignore;
502 {
503   while (count-- && rl_point > 0)
504     {
505       int last_is_ident;
506
507       /* If we are at the start of a word, move back to whitespace
508          so we will go back to the start of the previous word. */
509       if (!whitespace (rl_line_buffer[rl_point]) &&
510           whitespace (rl_line_buffer[rl_point - 1]))
511         rl_point--;
512
513       /* If this character and the previous character are `opposite', move
514          back so we don't get messed up by the rl_point++ down there in
515          the while loop.  Without this code, words like `l;' screw up the
516          function. */
517       last_is_ident = isident (rl_line_buffer[rl_point - 1]);
518       if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
519           (!isident (rl_line_buffer[rl_point]) && last_is_ident))
520         rl_point--;
521
522       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
523         rl_point--;
524
525       if (rl_point > 0)
526         {
527           if (isident (rl_line_buffer[rl_point]))
528             while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
529           else
530             while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
531                    !whitespace (rl_line_buffer[rl_point]));
532           rl_point++;
533         }
534     }
535   return (0);
536 }
537
538 int
539 rl_vi_eword (count, ignore)
540      int count, ignore;
541 {
542   while (count-- && rl_point < rl_end - 1)
543     {
544       if (!whitespace (rl_line_buffer[rl_point]))
545         rl_point++;
546
547       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
548         rl_point++;
549
550       if (rl_point < rl_end)
551         {
552           if (isident (rl_line_buffer[rl_point]))
553             while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
554           else
555             while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
556                    && !whitespace (rl_line_buffer[rl_point]));
557         }
558       rl_point--;
559     }
560   return (0);
561 }
562
563 int
564 rl_vi_insert_beg (count, key)
565      int count, key;
566 {
567   rl_beg_of_line (1, key);
568   rl_vi_insertion_mode (1, key);
569   return (0);
570 }
571
572 int
573 rl_vi_append_mode (count, key)
574      int count, key;
575 {
576   if (rl_point < rl_end)
577     rl_point++;
578   rl_vi_insertion_mode (1, key);
579   return (0);
580 }
581
582 int
583 rl_vi_append_eol (count, key)
584      int count, key;
585 {
586   rl_end_of_line (1, key);
587   rl_vi_append_mode (1, key);
588   return (0);
589 }
590
591 /* What to do in the case of C-d. */
592 int
593 rl_vi_eof_maybe (count, c)
594      int count, c;
595 {
596   return (rl_newline (1, '\n'));
597 }
598
599 /* Insertion mode stuff. */
600
601 /* Switching from one mode to the other really just involves
602    switching keymaps. */
603 int
604 rl_vi_insertion_mode (count, key)
605      int count, key;
606 {
607   _rl_keymap = vi_insertion_keymap;
608   _rl_vi_last_key_before_insert = key;
609   return (0);
610 }
611
612 static void
613 _rl_vi_save_insert (up)
614       UNDO_LIST *up;
615 {
616   int len, start, end;
617
618   if (up == 0)
619     {
620       if (vi_insert_buffer_size >= 1)
621         vi_insert_buffer[0] = '\0';
622       return;
623     }
624
625   start = up->start;
626   end = up->end;
627   len = end - start + 1;
628   if (len >= vi_insert_buffer_size)
629     {
630       vi_insert_buffer_size += (len + 32) - (len % 32);
631       vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
632     }
633   strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
634   vi_insert_buffer[len-1] = '\0';
635 }
636     
637 void
638 _rl_vi_done_inserting ()
639 {
640   if (_rl_vi_doing_insert)
641     {
642       rl_end_undo_group ();
643       /* Now, the text between rl_undo_list->next->start and
644          rl_undo_list->next->end is what was inserted while in insert
645          mode.  It gets copied to VI_INSERT_BUFFER because it depends
646          on absolute indices into the line which may change (though they
647          probably will not). */
648       _rl_vi_doing_insert = 0;
649       _rl_vi_save_insert (rl_undo_list->next);
650       vi_continued_command = 1;
651     }
652   else
653     {
654       if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
655         _rl_vi_save_insert (rl_undo_list);
656       /* XXX - Other keys probably need to be checked. */
657       else if (_rl_vi_last_key_before_insert == 'C')
658         rl_end_undo_group ();
659       while (_rl_undo_group_level > 0)
660         rl_end_undo_group ();
661       vi_continued_command = 0;
662     }
663 }
664
665 int
666 rl_vi_movement_mode (count, key)
667      int count, key;
668 {
669   if (rl_point > 0)
670     rl_backward (1, key);
671
672   _rl_keymap = vi_movement_keymap;
673   _rl_vi_done_inserting ();
674   return (0);
675 }
676
677 int
678 rl_vi_arg_digit (count, c)
679      int count, c;
680 {
681   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
682     return (rl_beg_of_line (1, c));
683   else
684     return (rl_digit_argument (count, c));
685 }
686
687 int
688 rl_vi_change_case (count, ignore)
689      int count, ignore;
690 {
691   char c = 0;
692
693   /* Don't try this on an empty line. */
694   if (rl_point >= rl_end)
695     return (0);
696
697   while (count-- && rl_point < rl_end)
698     {
699       if (_rl_uppercase_p (rl_line_buffer[rl_point]))
700         c = _rl_to_lower (rl_line_buffer[rl_point]);
701       else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
702         c = _rl_to_upper (rl_line_buffer[rl_point]);
703       else
704         {
705           /* Just skip over characters neither upper nor lower case. */
706           rl_forward (1, c);
707           continue;
708         }
709
710       /* Vi is kind of strange here. */
711       if (c)
712         {
713           rl_begin_undo_group ();
714           rl_delete (1, c);
715           rl_insert (1, c);
716           rl_end_undo_group ();
717           rl_vi_check ();
718         }
719       else
720         rl_forward (1, c);
721     }
722   return (0);
723 }
724
725 int
726 rl_vi_put (count, key)
727      int count, key;
728 {
729   if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
730     rl_point++;
731
732   rl_yank (1, key);
733   rl_backward (1, key);
734   return (0);
735 }
736
737 int
738 rl_vi_check ()
739 {
740   if (rl_point && rl_point == rl_end)
741     rl_point--;
742   return (0);
743 }
744
745 int
746 rl_vi_column (count, key)
747      int count, key;
748 {
749   if (count > rl_end)
750     rl_end_of_line (1, key);
751   else
752     rl_point = count - 1;
753   return (0);
754 }
755
756 int
757 rl_vi_domove (key, nextkey)
758      int key, *nextkey;
759 {
760   int c, save;
761   int old_end;
762
763   rl_mark = rl_point;
764   c = rl_read_key ();
765   *nextkey = c;
766
767   if (!member (c, vi_motion))
768     {
769       if (_rl_digit_p (c))
770         {
771           save = rl_numeric_arg;
772           rl_numeric_arg = _rl_digit_value (c);
773           rl_digit_loop1 ();
774           rl_numeric_arg *= save;
775           c = rl_read_key ();   /* real command */
776           *nextkey = c;
777         }
778       else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
779         {
780           rl_mark = rl_end;
781           rl_beg_of_line (1, c);
782           _rl_vi_last_motion = c;
783           return (0);
784         }
785       else
786         return (-1);
787     }
788
789   _rl_vi_last_motion = c;
790
791   /* Append a blank character temporarily so that the motion routines
792      work right at the end of the line. */
793   old_end = rl_end;
794   rl_line_buffer[rl_end++] = ' ';
795   rl_line_buffer[rl_end] = '\0';
796
797   _rl_dispatch (c, _rl_keymap);
798
799   /* Remove the blank that we added. */
800   rl_end = old_end;
801   rl_line_buffer[rl_end] = '\0';
802   if (rl_point > rl_end)
803     rl_point = rl_end;
804
805   /* No change in position means the command failed. */
806   if (rl_mark == rl_point)
807     return (-1);
808
809   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
810      word.  If we are not at the end of the line, and we are on a
811      non-whitespace character, move back one (presumably to whitespace). */
812   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
813       !whitespace (rl_line_buffer[rl_point]))
814     rl_point--;
815
816   /* If cw or cW, back up to the end of a word, so the behaviour of ce
817      or cE is the actual result.  Brute-force, no subtlety. */
818   if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
819     {
820       /* Don't move farther back than where we started. */
821       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
822         rl_point--;
823
824       /* Posix.2 says that if cw or cW moves the cursor towards the end of
825          the line, the character under the cursor should be deleted. */
826       if (rl_point == rl_mark)
827         rl_point++;
828       else
829         {
830           /* Move past the end of the word so that the kill doesn't
831              remove the last letter of the previous word.  Only do this
832              if we are not at the end of the line. */
833           if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
834             rl_point++;
835         }
836     }
837
838   if (rl_mark < rl_point)
839     exchange (rl_point, rl_mark);
840
841   return (0);
842 }
843
844 /* A simplified loop for vi. Don't dispatch key at end.
845    Don't recognize minus sign? */
846 static int
847 rl_digit_loop1 ()
848 {
849   int key, c;
850
851   while (1)
852     {
853       rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
854       key = c = rl_read_key ();
855
856       if (_rl_keymap[c].type == ISFUNC &&
857           _rl_keymap[c].function == rl_universal_argument)
858         {
859           rl_numeric_arg *= 4;
860           continue;
861         }
862
863       c = UNMETA (c);
864       if (_rl_digit_p (c))
865         {
866           if (rl_explicit_arg)
867             rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
868           else
869             rl_numeric_arg = _rl_digit_value (c);
870           rl_explicit_arg = 1;
871         }
872       else
873         {
874           rl_clear_message ();
875           rl_stuff_char (key);
876           break;
877         }
878     }
879   return (0);
880 }
881
882 int
883 rl_vi_delete_to (count, key)
884      int count, key;
885 {
886   int c;
887
888   if (_rl_uppercase_p (key))
889     rl_stuff_char ('$');
890   else if (vi_redoing)
891     rl_stuff_char (_rl_vi_last_motion);
892
893   if (rl_vi_domove (key, &c))
894     {
895       ding ();
896       return -1;
897     }
898
899   /* These are the motion commands that do not require adjusting the
900      mark. */
901   if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
902     rl_mark++;
903
904   rl_kill_text (rl_point, rl_mark);
905   return (0);
906 }
907
908 int
909 rl_vi_change_to (count, key)
910      int count, key;
911 {
912   int c, start_pos;
913
914   if (_rl_uppercase_p (key))
915     rl_stuff_char ('$');
916   else if (vi_redoing)
917     rl_stuff_char (_rl_vi_last_motion);
918
919   start_pos = rl_point;
920
921   if (rl_vi_domove (key, &c))
922     {
923       ding ();
924       return -1;
925     }
926
927   /* These are the motion commands that do not require adjusting the
928      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
929      and already leave the mark at the correct location. */
930   if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
931     rl_mark++;
932
933   /* The cursor never moves with c[wW]. */
934   if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
935     rl_point = start_pos;
936
937   if (vi_redoing)
938     {
939       if (vi_insert_buffer && *vi_insert_buffer)
940         rl_begin_undo_group ();
941       rl_delete_text (rl_point, rl_mark);
942       if (vi_insert_buffer && *vi_insert_buffer)
943         {
944           rl_insert_text (vi_insert_buffer);
945           rl_end_undo_group ();
946         }
947     }
948   else
949     {
950       rl_begin_undo_group ();           /* to make the `u' command work */
951       rl_kill_text (rl_point, rl_mark);
952       /* `C' does not save the text inserted for undoing or redoing. */
953       if (_rl_uppercase_p (key) == 0)
954         _rl_vi_doing_insert = 1;
955       _rl_vi_set_last (key, count, rl_arg_sign);
956       rl_vi_insertion_mode (1, key);
957     }
958
959   return (0);
960 }
961
962 int
963 rl_vi_yank_to (count, key)
964      int count, key;
965 {
966   int c, save = rl_point;
967
968   if (_rl_uppercase_p (key))
969     rl_stuff_char ('$');
970
971   if (rl_vi_domove (key, &c))
972     {
973       ding ();
974       return -1;
975     }
976
977   /* These are the motion commands that do not require adjusting the
978      mark. */
979   if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
980     rl_mark++;
981
982   rl_begin_undo_group ();
983   rl_kill_text (rl_point, rl_mark);
984   rl_end_undo_group ();
985   rl_do_undo ();
986   rl_point = save;
987
988   return (0);
989 }
990
991 int
992 rl_vi_delete (count, key)
993      int count, key;
994 {
995   int end;
996
997   if (rl_end == 0)
998     {
999       ding ();
1000       return -1;
1001     }
1002
1003   end = rl_point + count;
1004
1005   if (end >= rl_end)
1006     end = rl_end;
1007
1008   rl_kill_text (rl_point, end);
1009   
1010   if (rl_point > 0 && rl_point == rl_end)
1011     rl_backward (1, key);
1012   return (0);
1013 }
1014
1015 int
1016 rl_vi_back_to_indent (count, key)
1017      int count, key;
1018 {
1019   rl_beg_of_line (1, key);
1020   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1021     rl_point++;
1022   return (0);
1023 }
1024
1025 int
1026 rl_vi_first_print (count, key)
1027      int count, key;
1028 {
1029   return (rl_vi_back_to_indent (1, key));
1030 }
1031
1032 int
1033 rl_vi_char_search (count, key)
1034      int count, key;
1035 {
1036   static char target;
1037   static int orig_dir, dir;
1038
1039   if (key == ';' || key == ',')
1040     dir = key == ';' ? orig_dir : -orig_dir;
1041   else
1042     {
1043       if (vi_redoing)
1044         target = _rl_vi_last_search_char;
1045       else
1046         _rl_vi_last_search_char = target = rl_getc (rl_instream);
1047
1048       switch (key)
1049         {
1050         case 't':
1051           orig_dir = dir = FTO;
1052           break;
1053
1054         case 'T':
1055           orig_dir = dir = BTO;
1056           break;
1057
1058         case 'f':
1059           orig_dir = dir = FFIND;
1060           break;
1061
1062         case 'F':
1063           orig_dir = dir = BFIND;
1064           break;
1065         }
1066     }
1067
1068   return (_rl_char_search_internal (count, dir, target));
1069 }
1070
1071 /* Match brackets */
1072 int
1073 rl_vi_match (ignore, key)
1074      int ignore, key;
1075 {
1076   int count = 1, brack, pos;
1077
1078   pos = rl_point;
1079   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1080     {
1081       while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1082              rl_point < rl_end - 1)
1083         rl_forward (1, key);
1084
1085       if (brack <= 0)
1086         {
1087           rl_point = pos;
1088           ding ();
1089           return -1;
1090         }
1091     }
1092
1093   pos = rl_point;
1094
1095   if (brack < 0)
1096     {
1097       while (count)
1098         {
1099           if (--pos >= 0)
1100             {
1101               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1102               if (b == -brack)
1103                 count--;
1104               else if (b == brack)
1105                 count++;
1106             }
1107           else
1108             {
1109               ding ();
1110               return -1;
1111             }
1112         }
1113     }
1114   else
1115     {                   /* brack > 0 */
1116       while (count)
1117         {
1118           if (++pos < rl_end)
1119             {
1120               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1121               if (b == -brack)
1122                 count--;
1123               else if (b == brack)
1124                 count++;
1125             }
1126           else
1127             {
1128               ding ();
1129               return -1;
1130             }
1131         }
1132     }
1133   rl_point = pos;
1134   return (0);
1135 }
1136
1137 int
1138 rl_vi_bracktype (c)
1139      int c;
1140 {
1141   switch (c)
1142     {
1143     case '(': return  1;
1144     case ')': return -1;
1145     case '[': return  2;
1146     case ']': return -2;
1147     case '{': return  3;
1148     case '}': return -3;
1149     default:  return  0;
1150     }
1151 }
1152
1153 int
1154 rl_vi_change_char (count, key)
1155      int count, key;
1156 {
1157   int c;
1158
1159   if (vi_redoing)
1160     c = _rl_vi_last_replacement;
1161   else
1162     _rl_vi_last_replacement = c = rl_getc (rl_instream);
1163
1164   if (c == '\033' || c == CTRL ('C'))
1165     return -1;
1166
1167   while (count-- && rl_point < rl_end)
1168     {
1169       rl_begin_undo_group ();
1170
1171       rl_delete (1, c);
1172       rl_insert (1, c);
1173       if (count == 0)
1174         rl_backward (1, c);
1175
1176       rl_end_undo_group ();
1177     }
1178   return (0);
1179 }
1180
1181 int
1182 rl_vi_subst (count, key)
1183      int count, key;
1184 {
1185   rl_begin_undo_group ();
1186
1187   if (_rl_uppercase_p (key))
1188     {
1189       rl_beg_of_line (1, key);
1190       rl_kill_line (1, key);
1191     }
1192   else
1193     rl_delete_text (rl_point, rl_point+count);
1194
1195   rl_end_undo_group ();
1196
1197   _rl_vi_set_last (key, count, rl_arg_sign);
1198
1199   if (vi_redoing)
1200     {
1201       int o = _rl_doing_an_undo;
1202
1203       _rl_doing_an_undo = 1;
1204       if (vi_insert_buffer && *vi_insert_buffer)
1205         rl_insert_text (vi_insert_buffer);
1206       _rl_doing_an_undo = o;
1207     }
1208   else
1209     {
1210       rl_begin_undo_group ();
1211       _rl_vi_doing_insert = 1;
1212       rl_vi_insertion_mode (1, key);
1213     }
1214
1215   return (0);
1216 }
1217
1218 int
1219 rl_vi_overstrike (count, key)
1220      int count, key;
1221 {
1222   int i;
1223
1224   if (_rl_vi_doing_insert == 0)
1225     {
1226       _rl_vi_doing_insert = 1;
1227       rl_begin_undo_group ();
1228     }
1229
1230   for (i = 0; i < count; i++)
1231     {
1232       vi_replace_count++;
1233       rl_begin_undo_group ();
1234
1235       if (rl_point < rl_end)
1236         {
1237           rl_delete (1, key);
1238           rl_insert (1, key);
1239         }
1240       else
1241         rl_insert (1, key);
1242
1243       rl_end_undo_group ();
1244     }
1245   return (0);
1246 }
1247
1248 int
1249 rl_vi_overstrike_delete (count, key)
1250      int count, key;
1251 {
1252   int i, s;
1253
1254   for (i = 0; i < count; i++)
1255     {
1256       if (vi_replace_count == 0)
1257         {
1258           ding ();
1259           break;
1260         }
1261       s = rl_point;
1262
1263       if (rl_do_undo ())
1264         vi_replace_count--;
1265
1266       if (rl_point == s)
1267         rl_backward (1, key);
1268     }
1269
1270   if (vi_replace_count == 0 && _rl_vi_doing_insert)
1271     {
1272       rl_end_undo_group ();
1273       rl_do_undo ();
1274       _rl_vi_doing_insert = 0;
1275     }
1276   return (0);
1277 }
1278
1279 int
1280 rl_vi_replace (count, key)
1281      int count, key;
1282 {
1283   int i;
1284
1285   vi_replace_count = 0;
1286
1287   if (!vi_replace_map)
1288     {
1289       vi_replace_map = rl_make_bare_keymap ();
1290
1291       for (i = ' '; i < KEYMAP_SIZE; i++)
1292         vi_replace_map[i].function = rl_vi_overstrike;
1293
1294       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1295       vi_replace_map[ESC].function = rl_vi_movement_mode;
1296       vi_replace_map[RETURN].function = rl_newline;
1297       vi_replace_map[NEWLINE].function = rl_newline;
1298
1299       /* If the normal vi insertion keymap has ^H bound to erase, do the
1300          same here.  Probably should remove the assignment to RUBOUT up
1301          there, but I don't think it will make a difference in real life. */
1302       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1303           vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1304         vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1305
1306     }
1307   _rl_keymap = vi_replace_map;
1308   return (0);
1309 }
1310
1311 #if 0
1312 /* Try to complete the word we are standing on or the word that ends with
1313    the previous character.  A space matches everything.  Word delimiters are
1314    space and ;. */
1315 int
1316 rl_vi_possible_completions()
1317 {
1318   int save_pos = rl_point;
1319
1320   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1321     {
1322       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1323              rl_line_buffer[rl_point] != ';')
1324         rl_point++;
1325     }
1326   else if (rl_line_buffer[rl_point - 1] == ';')
1327     {
1328       ding ();
1329       return (0);
1330     }
1331
1332   rl_possible_completions ();
1333   rl_point = save_pos;
1334
1335   return (0);
1336 }
1337 #endif
1338
1339 /* Functions to save and restore marks. */
1340 int
1341 rl_vi_set_mark (count, key)
1342      int count, key;
1343 {
1344   int ch;
1345
1346   ch = rl_read_key ();
1347   if (_rl_lowercase_p (ch) == 0)
1348     {
1349       ding ();
1350       return -1;
1351     }
1352   ch -= 'a';
1353   vi_mark_chars[ch] = rl_point;
1354   return 0;
1355 }
1356
1357 int
1358 rl_vi_goto_mark (count, key)
1359      int count, key;
1360 {
1361   int ch;
1362
1363   ch = rl_read_key ();
1364   if (ch == '`')
1365     {
1366       rl_point = rl_mark;
1367       return 0;
1368     }
1369   else if (_rl_lowercase_p (ch) == 0)
1370     {
1371       ding ();
1372       return -1;
1373     }
1374
1375   ch -= 'a';
1376   if (vi_mark_chars[ch] == -1)
1377     {
1378       ding ();
1379       return -1;
1380     }
1381   rl_point = vi_mark_chars[ch];
1382   return 0;
1383 }
1384
1385 #endif /* VI_MODE */