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