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-2020 Free Software Foundation, Inc.
5 
6    This file is part of the GNU Readline Library (Readline), a library
7    for reading lines of text with interactive input and history editing.
8 
9    Readline is free software: you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13 
14    Readline is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
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 /* Increment START to the next character in RL_LINE_BUFFER, handling multibyte chars */
67 #if defined (HANDLE_MULTIBYTE)
68 #define INCREMENT_POS(start) \
69   do { \
70 	if (MB_CUR_MAX == 1 || rl_byte_oriented) \
71 	  start++; \
72 	else \
73 	  start = _rl_find_next_mbchar (rl_line_buffer, start, 1, MB_FIND_ANY); \
74   } while (0)
75 #else /* !HANDLE_MULTIBYTE */
76 #define INCREMENT_POS(start)    (start)++
77 #endif /* !HANDLE_MULTIBYTE */
78 
79 /* This is global so other parts of the code can check whether the last
80    command was a text modification command. */
81 int _rl_vi_last_command = 'i';	/* default `.' puts you in insert mode */
82 
83 _rl_vimotion_cxt *_rl_vimvcxt = 0;
84 
85 /* Non-zero indicates we are redoing a vi-mode command with `.' */
86 int _rl_vi_redoing;
87 
88 /* Non-zero means enter insertion mode. */
89 static int _rl_vi_doing_insert;
90 
91 /* Command keys which do movement for xxx_to commands. */
92 static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`";
93 
94 /* Keymap used for vi replace characters.  Created dynamically since
95    rarely used. */
96 static Keymap vi_replace_map;
97 
98 /* The number of characters inserted in the last replace operation. */
99 static int vi_replace_count;
100 
101 /* If non-zero, we have text inserted after a c[motion] command that put
102    us implicitly into insert mode.  Some people want this text to be
103    attached to the command so that it is `redoable' with `.'. */
104 static int vi_continued_command;
105 static char *vi_insert_buffer;
106 static int vi_insert_buffer_size;
107 
108 static int _rl_vi_last_repeat = 1;
109 static int _rl_vi_last_arg_sign = 1;
110 static int _rl_vi_last_motion;
111 #if defined (HANDLE_MULTIBYTE)
112 static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
113 static int _rl_vi_last_search_mblen;
114 #else
115 static int _rl_vi_last_search_char;
116 #endif
117 static char _rl_vi_last_replacement[MB_LEN_MAX+1];	/* reserve for trailing NULL */
118 
119 static int _rl_vi_last_key_before_insert;
120 
121 /* Text modification commands.  These are the `redoable' commands. */
122 static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
123 
124 /* Arrays for the saved marks. */
125 static int vi_mark_chars['z' - 'a' + 1];
126 
127 static void _rl_vi_replace_insert PARAMS((int));
128 static void _rl_vi_save_replace PARAMS((void));
129 static void _rl_vi_stuff_insert PARAMS((int));
130 static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
131 
132 static void vi_save_insert_buffer PARAMS ((int, int));
133 
134 static inline void _rl_vi_backup PARAMS((void));
135 
136 static int _rl_vi_arg_dispatch PARAMS((int));
137 static int rl_digit_loop1 PARAMS((void));
138 
139 static int _rl_vi_set_mark PARAMS((void));
140 static int _rl_vi_goto_mark PARAMS((void));
141 
142 static inline int _rl_vi_advance_point PARAMS((void));
143 static inline int _rl_vi_backup_point PARAMS((void));
144 
145 static void _rl_vi_append_forward PARAMS((int));
146 
147 static int _rl_vi_callback_getchar PARAMS((char *, int));
148 
149 #if defined (READLINE_CALLBACKS)
150 static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
151 static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
152 static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
153 static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
154 #endif
155 
156 static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *));
157 static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *));
158 static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *));
159 
160 static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *));
161 static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *));
162 static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *));
163 
164 static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *));
165 
166 void
_rl_vi_initialize_line(void)167 _rl_vi_initialize_line (void)
168 {
169   register int i, n;
170 
171   n = sizeof (vi_mark_chars) / sizeof (vi_mark_chars[0]);
172   for (i = 0; i < n; i++)
173     vi_mark_chars[i] = -1;
174 
175   RL_UNSETSTATE(RL_STATE_VICMDONCE);
176 }
177 
178 void
_rl_vi_reset_last(void)179 _rl_vi_reset_last (void)
180 {
181   _rl_vi_last_command = 'i';
182   _rl_vi_last_repeat = 1;
183   _rl_vi_last_arg_sign = 1;
184   _rl_vi_last_motion = 0;
185 }
186 
187 void
_rl_vi_set_last(int key,int repeat,int sign)188 _rl_vi_set_last (int key, int repeat, int sign)
189 {
190   _rl_vi_last_command = key;
191   _rl_vi_last_repeat = repeat;
192   _rl_vi_last_arg_sign = sign;
193 }
194 
195 /* A convenience function that calls _rl_vi_set_last to save the last command
196    information and enters insertion mode. */
197 void
rl_vi_start_inserting(int key,int repeat,int sign)198 rl_vi_start_inserting (int key, int repeat, int sign)
199 {
200   _rl_vi_set_last (key, repeat, sign);
201   rl_begin_undo_group ();		/* ensure inserts aren't concatenated */
202   rl_vi_insertion_mode (1, key);
203 }
204 
205 /* Is the command C a VI mode text modification command? */
206 int
_rl_vi_textmod_command(int c)207 _rl_vi_textmod_command (int c)
208 {
209   return (member (c, vi_textmod));
210 }
211 
212 int
_rl_vi_motion_command(int c)213 _rl_vi_motion_command (int c)
214 {
215   return (member (c, vi_motion));
216 }
217 
218 static void
_rl_vi_replace_insert(int count)219 _rl_vi_replace_insert (int count)
220 {
221   int nchars;
222 
223   nchars = strlen (vi_insert_buffer);
224 
225   rl_begin_undo_group ();
226   while (count--)
227     /* nchars-1 to compensate for _rl_replace_text using `end+1' in call
228        to rl_delete_text */
229     _rl_replace_text (vi_insert_buffer, rl_point, rl_point+nchars-1);
230   rl_end_undo_group ();
231 }
232 
233 static void
_rl_vi_stuff_insert(int count)234 _rl_vi_stuff_insert (int count)
235 {
236   rl_begin_undo_group ();
237   while (count--)
238     rl_insert_text (vi_insert_buffer);
239   rl_end_undo_group ();
240 }
241 
242 /* Bound to `.'.  Called from command mode, so we know that we have to
243    redo a text modification command.  The default for _rl_vi_last_command
244    puts you back into insert mode. */
245 int
rl_vi_redo(int count,int c)246 rl_vi_redo (int count, int c)
247 {
248   int r;
249 
250   if (rl_explicit_arg == 0)
251     {
252       rl_numeric_arg = _rl_vi_last_repeat;
253       rl_arg_sign = _rl_vi_last_arg_sign;
254     }
255 
256   r = 0;
257   _rl_vi_redoing = 1;
258   /* If we're redoing an insert with `i', stuff in the inserted text
259      and do not go into insertion mode. */
260   if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
261     {
262       _rl_vi_stuff_insert (count);
263       /* And back up point over the last character inserted. */
264       if (rl_point > 0)
265 	_rl_vi_backup ();
266     }
267   else if (_rl_vi_last_command == 'R' && vi_insert_buffer && *vi_insert_buffer)
268     {
269       _rl_vi_replace_insert (count);
270       /* And back up point over the last character inserted. */
271       if (rl_point > 0)
272 	_rl_vi_backup ();
273     }
274   /* Ditto for redoing an insert with `I', but move to the beginning of the
275      line like the `I' command does. */
276   else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer)
277     {
278       rl_beg_of_line (1, 'I');
279       _rl_vi_stuff_insert (count);
280       if (rl_point > 0)
281 	_rl_vi_backup ();
282     }
283   /* Ditto for redoing an insert with `a', but move forward a character first
284      like the `a' command does. */
285   else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
286     {
287       _rl_vi_append_forward ('a');
288       _rl_vi_stuff_insert (count);
289       if (rl_point > 0)
290 	_rl_vi_backup ();
291     }
292   /* Ditto for redoing an insert with `A', but move to the end of the line
293      like the `A' command does. */
294   else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer)
295     {
296       rl_end_of_line (1, 'A');
297       _rl_vi_stuff_insert (count);
298       if (rl_point > 0)
299 	_rl_vi_backup ();
300     }
301   else if (_rl_vi_last_command == '.' && _rl_keymap == vi_movement_keymap)
302     {
303       rl_ding ();
304       r = 0;
305     }
306   else
307     r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
308 
309   _rl_vi_redoing = 0;
310 
311   return (r);
312 }
313 
314 /* A placeholder for further expansion. */
315 int
rl_vi_undo(int count,int key)316 rl_vi_undo (int count, int key)
317 {
318   return (rl_undo_command (count, key));
319 }
320 
321 /* Yank the nth arg from the previous line into this line at point. */
322 int
rl_vi_yank_arg(int count,int key)323 rl_vi_yank_arg (int count, int key)
324 {
325   /* Readline thinks that the first word on a line is the 0th, while vi
326      thinks the first word on a line is the 1st.  Compensate. */
327   if (rl_explicit_arg)
328     rl_yank_nth_arg (count - 1, key);
329   else
330     rl_yank_nth_arg ('$', key);
331 
332   return (0);
333 }
334 
335 /* With an argument, move back that many history lines, else move to the
336    beginning of history. */
337 int
rl_vi_fetch_history(int count,int c)338 rl_vi_fetch_history (int count, int c)
339 {
340   int wanted;
341 
342   /* Giving an argument of n means we want the nth command in the history
343      file.  The command number is interpreted the same way that the bash
344      `history' command does it -- that is, giving an argument count of 450
345      to this command would get the command listed as number 450 in the
346      output of `history'. */
347   if (rl_explicit_arg)
348     {
349       wanted = history_base + where_history () - count;
350       if (wanted <= 0)
351         rl_beginning_of_history (0, 0);
352       else
353         rl_get_previous_history (wanted, c);
354     }
355   else
356     rl_beginning_of_history (count, 0);
357   return (0);
358 }
359 
360 /* Search again for the last thing searched for. */
361 int
rl_vi_search_again(int count,int key)362 rl_vi_search_again (int count, int key)
363 {
364   switch (key)
365     {
366     case 'n':
367       rl_noninc_reverse_search_again (count, key);
368       break;
369 
370     case 'N':
371       rl_noninc_forward_search_again (count, key);
372       break;
373     }
374   return (0);
375 }
376 
377 /* Do a vi style search. */
378 int
rl_vi_search(int count,int key)379 rl_vi_search (int count, int key)
380 {
381   switch (key)
382     {
383     case '?':
384       _rl_free_saved_history_line ();
385       rl_noninc_forward_search (count, key);
386       break;
387 
388     case '/':
389       _rl_free_saved_history_line ();
390       rl_noninc_reverse_search (count, key);
391       break;
392 
393     default:
394       rl_ding ();
395       break;
396     }
397   return (0);
398 }
399 
400 /* Completion, from vi's point of view. */
401 int
rl_vi_complete(int ignore,int key)402 rl_vi_complete (int ignore, int key)
403 {
404   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
405     {
406       if (!whitespace (rl_line_buffer[rl_point + 1]))
407 	rl_vi_end_word (1, 'E');
408       _rl_vi_advance_point ();
409     }
410 
411   if (key == '*')
412     rl_complete_internal ('*');	/* Expansion and replacement. */
413   else if (key == '=')
414     rl_complete_internal ('?');	/* List possible completions. */
415   else if (key == '\\')
416     rl_complete_internal (TAB);	/* Standard Readline completion. */
417   else
418     rl_complete (0, key);
419 
420   if (key == '*' || key == '\\')
421     rl_vi_start_inserting (key, 1, rl_arg_sign);
422 
423   return (0);
424 }
425 
426 /* Tilde expansion for vi mode. */
427 int
rl_vi_tilde_expand(int ignore,int key)428 rl_vi_tilde_expand (int ignore, int key)
429 {
430   rl_tilde_expand (0, key);
431   rl_vi_start_inserting (key, 1, rl_arg_sign);
432   return (0);
433 }
434 
435 /* Previous word in vi mode. */
436 int
rl_vi_prev_word(int count,int key)437 rl_vi_prev_word (int count, int key)
438 {
439   if (count < 0)
440     return (rl_vi_next_word (-count, key));
441 
442   if (rl_point == 0)
443     {
444       rl_ding ();
445       return (0);
446     }
447 
448   if (_rl_uppercase_p (key))
449     rl_vi_bWord (count, key);
450   else
451     rl_vi_bword (count, key);
452 
453   return (0);
454 }
455 
456 /* Next word in vi mode. */
457 int
rl_vi_next_word(int count,int key)458 rl_vi_next_word (int count, int key)
459 {
460   if (count < 0)
461     return (rl_vi_prev_word (-count, key));
462 
463   if (rl_point >= (rl_end - 1))
464     {
465       rl_ding ();
466       return (0);
467     }
468 
469   if (_rl_uppercase_p (key))
470     rl_vi_fWord (count, key);
471   else
472     rl_vi_fword (count, key);
473   return (0);
474 }
475 
476 static inline int
_rl_vi_advance_point(void)477 _rl_vi_advance_point (void)
478 {
479   int point;
480 
481   point = rl_point;
482   if (rl_point < rl_end)
483 #if defined (HANDLE_MULTIBYTE)
484     {
485       if (MB_CUR_MAX == 1 || rl_byte_oriented)
486 	rl_point++;
487       else
488 	{
489 	  point = rl_point;
490 	  rl_point = _rl_forward_char_internal (1);
491 	  if (point == rl_point || rl_point > rl_end)
492 	    rl_point = rl_end;
493 	}
494     }
495 #else
496     rl_point++;
497 #endif
498 
499   return point;
500 }
501 
502 /* Move the cursor back one character. */
503 static inline void
_rl_vi_backup(void)504 _rl_vi_backup (void)
505 {
506   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
507     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
508   else
509     rl_point--;
510 }
511 
512 /* Move the point back one character, returning the starting value and not
513    doing anything at the beginning of the line */
514 static inline int
_rl_vi_backup_point(void)515 _rl_vi_backup_point (void)
516 {
517   int point;
518 
519   point = rl_point;
520   if (rl_point > 0)
521 #if defined (HANDLE_MULTIBYTE)
522     {
523       if (MB_CUR_MAX == 1 || rl_byte_oriented)
524 	rl_point--;
525       else
526 	{
527 	  point = rl_point;
528 	  rl_point = _rl_backward_char_internal (1);
529 	  if (rl_point < 0)
530 	    rl_point = 0;		/* XXX - not really necessary */
531 	}
532     }
533 #else
534     rl_point--;
535 #endif
536   return point;
537 }
538 
539 /* Move to the end of the ?next? word. */
540 int
rl_vi_end_word(int count,int key)541 rl_vi_end_word (int count, int key)
542 {
543   if (count < 0)
544     {
545       rl_ding ();
546       return 1;
547     }
548 
549   if (_rl_uppercase_p (key))
550     rl_vi_eWord (count, key);
551   else
552     rl_vi_eword (count, key);
553   return (0);
554 }
555 
556 /* Move forward a word the way that 'W' does. */
557 int
rl_vi_fWord(int count,int ignore)558 rl_vi_fWord (int count, int ignore)
559 {
560   while (count-- && rl_point < (rl_end - 1))
561     {
562       /* Skip until whitespace. */
563       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
564 	_rl_vi_advance_point ();
565 
566       /* Now skip whitespace. */
567       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
568 	_rl_vi_advance_point ();
569     }
570   return (0);
571 }
572 
573 int
rl_vi_bWord(int count,int ignore)574 rl_vi_bWord (int count, int ignore)
575 {
576   while (count-- && rl_point > 0)
577     {
578       /* If we are at the start of a word, move back to whitespace so
579 	 we will go back to the start of the previous word. */
580       if (!whitespace (rl_line_buffer[rl_point]) &&
581 	  whitespace (rl_line_buffer[rl_point - 1]))
582 	rl_point--;
583 
584       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
585 	_rl_vi_backup_point ();
586 
587       if (rl_point > 0)
588 	{
589 	  do
590 	    _rl_vi_backup_point ();
591 	  while (rl_point > 0 && !whitespace (rl_line_buffer[rl_point]));
592 	  if (rl_point > 0)	/* hit whitespace */
593 	    rl_point++;
594 
595 	  if (rl_point < 0)
596 	    rl_point = 0;
597 	}
598     }
599   return (0);
600 }
601 
602 int
rl_vi_eWord(int count,int ignore)603 rl_vi_eWord (int count, int ignore)
604 {
605   int opoint;
606 
607   while (count-- && rl_point < (rl_end - 1))
608     {
609       if (whitespace (rl_line_buffer[rl_point]) == 0)
610 	_rl_vi_advance_point ();
611 
612       /* Move to the next non-whitespace character (to the start of the
613 	 next word). */
614       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
615 	_rl_vi_advance_point ();
616 
617       if (rl_point && rl_point < rl_end)
618 	{
619 	  opoint = rl_point;
620 
621 	  /* Skip whitespace. */
622 	  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
623 	    opoint = _rl_vi_advance_point ();	/* XXX - why? */
624 
625 	  /* Skip until whitespace. */
626 	  while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
627 	    opoint = _rl_vi_advance_point ();
628 
629 	  /* Move back to the last character of the word. */
630 	  rl_point = opoint;
631 	}
632     }
633   return (0);
634 }
635 
636 int
rl_vi_fword(int count,int ignore)637 rl_vi_fword (int count, int ignore)
638 {
639   int opoint;
640 
641   while (count-- && rl_point < (rl_end - 1))
642     {
643       /* Move to white space (really non-identifer). */
644       if (_rl_isident (rl_line_buffer[rl_point]))
645 	{
646 	  while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
647 	    _rl_vi_advance_point ();
648 	}
649       else /* if (!whitespace (rl_line_buffer[rl_point])) */
650 	{
651 	  while (!_rl_isident (rl_line_buffer[rl_point]) &&
652 		 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
653 	    _rl_vi_advance_point ();
654 	}
655 
656       opoint = rl_point;
657 
658       /* Move past whitespace. */
659       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
660 	opoint = _rl_vi_advance_point ();
661     }
662   return (0);
663 }
664 
665 int
rl_vi_bword(int count,int ignore)666 rl_vi_bword (int count, int ignore)
667 {
668   int opoint;
669 
670   while (count-- && rl_point > 0)
671     {
672       int prev_is_ident, cur_is_ident;
673 
674       /* If we are at the start of a word, move back to whitespace
675 	 so we will go back to the start of the previous word. */
676       if (!whitespace (rl_line_buffer[rl_point]) &&
677 	  whitespace (rl_line_buffer[rl_point - 1]))
678 	if (--rl_point == 0)
679 	  break;
680 
681       /* If this character and the previous character are `opposite', move
682 	 back so we don't get messed up by the rl_point++ down there in
683 	 the while loop.  Without this code, words like `l;' screw up the
684 	 function. */
685       cur_is_ident = _rl_isident (rl_line_buffer[rl_point]);
686       opoint = _rl_vi_backup_point ();
687       prev_is_ident = _rl_isident (rl_line_buffer[rl_point]);
688       if ((cur_is_ident && !prev_is_ident) || (!cur_is_ident && prev_is_ident))
689 	;	/* leave point alone, we backed it up one character */
690       else
691 	rl_point = opoint;
692 
693       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
694 	_rl_vi_backup_point ();
695 
696       if (rl_point > 0)
697 	{
698 	  opoint = rl_point;
699 	  if (_rl_isident (rl_line_buffer[rl_point]))
700 	    do
701 	      opoint = _rl_vi_backup_point ();
702 	    while (rl_point > 0 && _rl_isident (rl_line_buffer[rl_point]));
703 	  else
704 	    do
705 	      opoint = _rl_vi_backup_point ();
706 	    while (rl_point > 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
707 		   !whitespace (rl_line_buffer[rl_point]));
708 
709 	  if (rl_point > 0)
710 	    rl_point = opoint;
711 
712 	  if (rl_point < 0)
713 	    rl_point = 0;
714 	}
715     }
716   return (0);
717 }
718 
719 int
rl_vi_eword(int count,int ignore)720 rl_vi_eword (int count, int ignore)
721 {
722   int opoint;
723 
724   while (count-- && rl_point < (rl_end - 1))
725     {
726       if (whitespace (rl_line_buffer[rl_point]) == 0)
727 	_rl_vi_advance_point ();
728 
729       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
730 	_rl_vi_advance_point ();
731 
732       opoint = rl_point;
733       if (rl_point < rl_end)
734 	{
735 	  if (_rl_isident (rl_line_buffer[rl_point]))
736 	    do
737 	      {
738 		opoint = _rl_vi_advance_point ();
739 	      }
740 	    while (rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
741 	  else
742 	    do
743 	      {
744 		opoint = _rl_vi_advance_point ();
745 	      }
746 	    while (rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
747 		   && !whitespace (rl_line_buffer[rl_point]));
748 	}
749       rl_point = opoint;
750     }
751   return (0);
752 }
753 
754 int
rl_vi_insert_beg(int count,int key)755 rl_vi_insert_beg (int count, int key)
756 {
757   rl_beg_of_line (1, key);
758   rl_vi_insert_mode (1, key);
759   return (0);
760 }
761 
762 static void
_rl_vi_append_forward(int key)763 _rl_vi_append_forward (int key)
764 {
765   _rl_vi_advance_point ();
766 }
767 
768 int
rl_vi_append_mode(int count,int key)769 rl_vi_append_mode (int count, int key)
770 {
771   _rl_vi_append_forward (key);
772   rl_vi_start_inserting (key, 1, rl_arg_sign);
773   return (0);
774 }
775 
776 int
rl_vi_append_eol(int count,int key)777 rl_vi_append_eol (int count, int key)
778 {
779   rl_end_of_line (1, key);
780   rl_vi_append_mode (1, key);
781   return (0);
782 }
783 
784 /* What to do in the case of C-d. */
785 int
rl_vi_eof_maybe(int count,int c)786 rl_vi_eof_maybe (int count, int c)
787 {
788   return (rl_newline (1, '\n'));
789 }
790 
791 /* Insertion mode stuff. */
792 
793 /* Switching from one mode to the other really just involves
794    switching keymaps. */
795 int
rl_vi_insertion_mode(int count,int key)796 rl_vi_insertion_mode (int count, int key)
797 {
798   _rl_keymap = vi_insertion_keymap;
799   _rl_vi_last_key_before_insert = key;
800   if (_rl_show_mode_in_prompt)
801     _rl_reset_prompt ();
802   return (0);
803 }
804 
805 int
rl_vi_insert_mode(int count,int key)806 rl_vi_insert_mode (int count, int key)
807 {
808   rl_vi_start_inserting (key, 1, rl_arg_sign);
809   return (0);
810 }
811 
812 static void
vi_save_insert_buffer(int start,int len)813 vi_save_insert_buffer (int start, int len)
814 {
815   /* Same code as _rl_vi_save_insert below */
816   if (len >= vi_insert_buffer_size)
817     {
818       vi_insert_buffer_size += (len + 32) - (len % 32);
819       vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
820     }
821   strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
822   vi_insert_buffer[len-1] = '\0';
823 }
824 
825 static void
_rl_vi_save_replace(void)826 _rl_vi_save_replace (void)
827 {
828   int len, start, end;
829   UNDO_LIST *up;
830 
831   up = rl_undo_list;
832   if (up == 0 || up->what != UNDO_END || vi_replace_count <= 0)
833     {
834       if (vi_insert_buffer_size >= 1)
835 	vi_insert_buffer[0] = '\0';
836       return;
837     }
838   /* Let's try it the quick and easy way for now.  This should essentially
839      accommodate every UNDO_INSERT and save the inserted text to
840      vi_insert_buffer */
841   end = rl_point;
842   start = end - vi_replace_count + 1;
843   len = vi_replace_count + 1;
844 
845   if (start < 0)
846     {
847       len = end + 1;
848       start = 0;
849     }
850 
851   vi_save_insert_buffer (start, len);
852 }
853 
854 static void
_rl_vi_save_insert(UNDO_LIST * up)855 _rl_vi_save_insert (UNDO_LIST *up)
856 {
857   int len, start, end;
858 
859   if (up == 0 || up->what != UNDO_INSERT)
860     {
861       if (vi_insert_buffer_size >= 1)
862 	vi_insert_buffer[0] = '\0';
863       return;
864     }
865 
866   start = up->start;
867   end = up->end;
868   len = end - start + 1;
869 
870   vi_save_insert_buffer (start, len);
871 }
872 
873 void
_rl_vi_done_inserting(void)874 _rl_vi_done_inserting (void)
875 {
876   if (_rl_vi_doing_insert)
877     {
878       /* The `c', `s', `S', and `R' commands set this. */
879       rl_end_undo_group ();	/* for the group in rl_vi_start_inserting */
880       /* Now, the text between rl_undo_list->next->start and
881 	 rl_undo_list->next->end is what was inserted while in insert
882 	 mode.  It gets copied to VI_INSERT_BUFFER because it depends
883 	 on absolute indices into the line which may change (though they
884 	 probably will not). */
885       _rl_vi_doing_insert = 0;
886       if (_rl_vi_last_key_before_insert == 'R')
887 	_rl_vi_save_replace ();		/* Half the battle */
888       else
889 	_rl_vi_save_insert (rl_undo_list->next);
890       /* sanity check, should always be >= 1 here */
891       if (_rl_undo_group_level > 0)
892 	rl_end_undo_group ();	/* for the group in the command (change or replace) */
893     }
894   else
895     {
896       if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' ||
897 			   _rl_vi_last_key_before_insert == 'a' ||
898 			   _rl_vi_last_key_before_insert == 'I' ||
899 			   _rl_vi_last_key_before_insert == 'A'))
900 	_rl_vi_save_insert (rl_undo_list);
901       /* XXX - Other keys probably need to be checked. */
902       else if (_rl_vi_last_key_before_insert == 'C')
903 	rl_end_undo_group ();
904     }
905 
906   /* Sanity check, make sure all the undo groups are closed before we leave
907      insert mode */
908   while (_rl_undo_group_level > 0)
909     rl_end_undo_group ();
910 }
911 
912 int
rl_vi_movement_mode(int count,int key)913 rl_vi_movement_mode (int count, int key)
914 {
915   if (rl_point > 0)
916     rl_backward_char (1, key);
917 
918   _rl_keymap = vi_movement_keymap;
919   _rl_vi_done_inserting ();
920 
921   /* This is how POSIX.2 says `U' should behave -- everything up until the
922      first time you go into command mode should not be undone. */
923   if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
924     rl_free_undo_list ();
925 
926   if (_rl_show_mode_in_prompt)
927     _rl_reset_prompt ();
928 
929   RL_SETSTATE (RL_STATE_VICMDONCE);
930   return (0);
931 }
932 
933 int
rl_vi_arg_digit(int count,int c)934 rl_vi_arg_digit (int count, int c)
935 {
936   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
937     return (rl_beg_of_line (1, c));
938   else
939     return (rl_digit_argument (count, c));
940 }
941 
942 /* Change the case of the next COUNT characters. */
943 #if defined (HANDLE_MULTIBYTE)
944 static int
_rl_vi_change_mbchar_case(int count)945 _rl_vi_change_mbchar_case (int count)
946 {
947   wchar_t wc;
948   char mb[MB_LEN_MAX+1];
949   int mlen, p;
950   size_t m;
951   mbstate_t ps;
952 
953   memset (&ps, 0, sizeof (mbstate_t));
954   if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
955     count--;
956   while (count-- && rl_point < rl_end)
957     {
958       m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
959       if (MB_INVALIDCH (m))
960 	wc = (wchar_t)rl_line_buffer[rl_point];
961       else if (MB_NULLWCH (m))
962 	wc = L'\0';
963       if (iswupper (wc))
964 	wc = towlower (wc);
965       else if (iswlower (wc))
966 	wc = towupper (wc);
967       else
968 	{
969 	  /* Just skip over chars neither upper nor lower case */
970 	  rl_forward_char (1, 0);
971 	  continue;
972 	}
973 
974       /* Vi is kind of strange here. */
975       if (wc)
976 	{
977 	  p = rl_point;
978 	  mlen = wcrtomb (mb, wc, &ps);
979 	  if (mlen >= 0)
980 	    mb[mlen] = '\0';
981 	  rl_begin_undo_group ();
982 	  rl_vi_delete (1, 0);
983 	  if (rl_point < p)	/* Did we retreat at EOL? */
984 	    _rl_vi_advance_point ();
985 	  rl_insert_text (mb);
986 	  rl_end_undo_group ();
987 	  rl_vi_check ();
988 	}
989       else
990 	rl_forward_char (1, 0);
991     }
992 
993   return 0;
994 }
995 #endif
996 
997 int
rl_vi_change_case(int count,int ignore)998 rl_vi_change_case (int count, int ignore)
999 {
1000   int c, p;
1001 
1002   /* Don't try this on an empty line. */
1003   if (rl_point >= rl_end)
1004     return (0);
1005 
1006   c = 0;
1007 #if defined (HANDLE_MULTIBYTE)
1008   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1009     return (_rl_vi_change_mbchar_case (count));
1010 #endif
1011 
1012   while (count-- && rl_point < rl_end)
1013     {
1014       if (_rl_uppercase_p (rl_line_buffer[rl_point]))
1015 	c = _rl_to_lower (rl_line_buffer[rl_point]);
1016       else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
1017 	c = _rl_to_upper (rl_line_buffer[rl_point]);
1018       else
1019 	{
1020 	  /* Just skip over characters neither upper nor lower case. */
1021 	  rl_forward_char (1, c);
1022 	  continue;
1023 	}
1024 
1025       /* Vi is kind of strange here. */
1026       if (c)
1027 	{
1028 	  p = rl_point;
1029 	  rl_begin_undo_group ();
1030 	  rl_vi_delete (1, c);
1031 	  if (rl_point < p)	/* Did we retreat at EOL? */
1032 	    rl_point++;
1033 	  _rl_insert_char (1, c);
1034 	  rl_end_undo_group ();
1035 	  rl_vi_check ();
1036 	}
1037       else
1038 	rl_forward_char (1, c);
1039     }
1040   return (0);
1041 }
1042 
1043 int
rl_vi_put(int count,int key)1044 rl_vi_put (int count, int key)
1045 {
1046   if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
1047     rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
1048 
1049   while (count--)
1050     rl_yank (1, key);
1051 
1052   rl_backward_char (1, key);
1053   return (0);
1054 }
1055 
1056 /* Move the cursor back one character if you're at the end of the line */
1057 int
rl_vi_check(void)1058 rl_vi_check (void)
1059 {
1060   if (rl_point && rl_point == rl_end)
1061     _rl_vi_backup ();
1062   return (0);
1063 }
1064 
1065 /* Move to the character position specified by COUNT */
1066 int
rl_vi_column(int count,int key)1067 rl_vi_column (int count, int key)
1068 {
1069   if (count > rl_end)
1070     rl_end_of_line (1, key);
1071   else
1072     {
1073       rl_point = 0;
1074       rl_point = _rl_forward_char_internal (count - 1);
1075     }
1076   return (0);
1077 }
1078 
1079 /* Process C as part of the current numeric argument.  Return -1 if the
1080    argument should be aborted, 0 if we should not read any more chars, and
1081    1 if we should continue to read chars. */
1082 static int
_rl_vi_arg_dispatch(int c)1083 _rl_vi_arg_dispatch (int c)
1084 {
1085   int key;
1086 
1087   key = c;
1088   if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
1089     {
1090       rl_numeric_arg *= 4;
1091       return 1;
1092     }
1093 
1094   c = UNMETA (c);
1095 
1096   if (_rl_digit_p (c))
1097     {
1098       if (rl_explicit_arg)
1099 	rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
1100       else
1101 	rl_numeric_arg = _rl_digit_value (c);
1102       rl_explicit_arg = 1;
1103       return 1;		/* keep going */
1104     }
1105   else
1106     {
1107       rl_clear_message ();
1108       rl_stuff_char (key);
1109       return 0;		/* done */
1110     }
1111 }
1112 
1113 /* A simplified loop for vi. Don't dispatch key at end.
1114    Don't recognize minus sign?
1115    Should this do rl_save_prompt/rl_restore_prompt? */
1116 static int
rl_digit_loop1(void)1117 rl_digit_loop1 (void)
1118 {
1119   int c, r;
1120 
1121   while (1)
1122     {
1123       if (_rl_arg_overflow ())
1124 	return 1;
1125 
1126       c = _rl_arg_getchar ();
1127 
1128       r = _rl_vi_arg_dispatch (c);
1129       if (r <= 0)
1130 	break;
1131     }
1132 
1133   RL_UNSETSTATE(RL_STATE_NUMERICARG);
1134   return (0);
1135 }
1136 
1137 /* This set of functions is basically to handle the commands that take a
1138    motion argument while in callback mode: read the command, read the motion
1139    command modifier, find the extent of the text to affect, and dispatch the
1140    command for execution. */
1141 static void
_rl_mvcxt_init(_rl_vimotion_cxt * m,int op,int key)1142 _rl_mvcxt_init (_rl_vimotion_cxt *m, int op, int key)
1143 {
1144   m->op = op;
1145   m->state = m->flags = 0;
1146   m->ncxt = 0;
1147   m->numeric_arg = -1;
1148   m->start = rl_point;
1149   m->end = rl_end;
1150   m->key = key;
1151   m->motion = -1;
1152 }
1153 
1154 static _rl_vimotion_cxt *
_rl_mvcxt_alloc(int op,int key)1155 _rl_mvcxt_alloc (int op, int key)
1156 {
1157   _rl_vimotion_cxt *m;
1158 
1159   m = xmalloc (sizeof (_rl_vimotion_cxt));
1160   _rl_mvcxt_init (m, op, key);
1161   return m;
1162 }
1163 
1164 static void
_rl_mvcxt_dispose(_rl_vimotion_cxt * m)1165 _rl_mvcxt_dispose (_rl_vimotion_cxt *m)
1166 {
1167   xfree (m);
1168 }
1169 
1170 static int
rl_domove_motion_callback(_rl_vimotion_cxt * m)1171 rl_domove_motion_callback (_rl_vimotion_cxt *m)
1172 {
1173   int c;
1174 
1175   _rl_vi_last_motion = c = m->motion;
1176 
1177   /* Append a blank character temporarily so that the motion routines
1178      work right at the end of the line.  Original value of rl_end is saved
1179      as m->end. */
1180   rl_extend_line_buffer (rl_end + 1);
1181   rl_line_buffer[rl_end++] = ' ';
1182   rl_line_buffer[rl_end] = '\0';
1183 
1184   _rl_dispatch (c, _rl_keymap);
1185 
1186 #if defined (READLINE_CALLBACKS)
1187   if (RL_ISSTATE (RL_STATE_CALLBACK))
1188     {
1189       /* Messy case where char search can be vi motion command; see rest of
1190 	 details in callback.c.  vi_char_search and callback_char_search just
1191 	 set and unset the CHARSEARCH state.  This is where any vi motion
1192 	 command that needs to set its own state should be handled, with any
1193 	 corresponding code to manage that state in callback.c */
1194       if (RL_ISSTATE (RL_STATE_CHARSEARCH))
1195 	return 0;
1196       else
1197 	return (_rl_vi_domove_motion_cleanup (c, m));
1198     }
1199 #endif
1200 
1201   return (_rl_vi_domove_motion_cleanup (c, m));
1202 }
1203 
1204 int
_rl_vi_domove_motion_cleanup(int c,_rl_vimotion_cxt * m)1205 _rl_vi_domove_motion_cleanup (int c, _rl_vimotion_cxt *m)
1206 {
1207   int r;
1208 
1209   /* Remove the blank that we added in rl_domove_motion_callback. */
1210   rl_end = m->end;
1211   rl_line_buffer[rl_end] = '\0';
1212   _rl_fix_point (0);
1213 
1214   /* No change in position means the command failed. */
1215   if (rl_mark == rl_point)
1216     {
1217       /* 'c' and 'C' enter insert mode after the delete even if the motion
1218 	 didn't delete anything, as long as the motion command is valid. */
1219       if (_rl_to_upper (m->key) == 'C' && _rl_vi_motion_command (c))
1220 	return (vidomove_dispatch (m));
1221       RL_UNSETSTATE (RL_STATE_VIMOTION);
1222       return (-1);
1223     }
1224 
1225   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
1226      word.  If we are not at the end of the line, and we are on a
1227      non-whitespace character, move back one (presumably to whitespace). */
1228   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
1229       !whitespace (rl_line_buffer[rl_point]))
1230     rl_point--;		/* XXX */
1231 
1232   /* If cw or cW, back up to the end of a word, so the behaviour of ce
1233      or cE is the actual result.  Brute-force, no subtlety. */
1234   if (m->key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
1235     {
1236       /* Don't move farther back than where we started. */
1237       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
1238 	rl_point--;
1239 
1240       /* Posix.2 says that if cw or cW moves the cursor towards the end of
1241 	 the line, the character under the cursor should be deleted. */
1242       if (rl_point == rl_mark)
1243 	_rl_vi_advance_point ();
1244       else
1245 	{
1246 	  /* Move past the end of the word so that the kill doesn't
1247 	     remove the last letter of the previous word.  Only do this
1248 	     if we are not at the end of the line. */
1249 	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
1250 	    _rl_vi_advance_point ();
1251 	}
1252     }
1253 
1254   if (rl_mark < rl_point)
1255     SWAP (rl_point, rl_mark);
1256 
1257 #if defined (READLINE_CALLBACKS)
1258   if (RL_ISSTATE (RL_STATE_CALLBACK))
1259     (*rl_redisplay_function)();		/* make sure motion is displayed */
1260 #endif
1261 
1262   r = vidomove_dispatch (m);
1263 
1264   return (r);
1265 }
1266 
1267 #define RL_VIMOVENUMARG()	(RL_ISSTATE (RL_STATE_VIMOTION) && RL_ISSTATE (RL_STATE_NUMERICARG))
1268 
1269 static int
rl_domove_read_callback(_rl_vimotion_cxt * m)1270 rl_domove_read_callback (_rl_vimotion_cxt *m)
1271 {
1272   int c, save;
1273 
1274   c = m->motion;
1275 
1276   if (member (c, vi_motion))
1277     {
1278 #if defined (READLINE_CALLBACKS)
1279       /* If we just read a vi-mode motion command numeric argument, turn off
1280 	 the `reading numeric arg' state */
1281       if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1282 	RL_UNSETSTATE (RL_STATE_NUMERICARG);
1283 #endif
1284       /* Should do everything, including turning off RL_STATE_VIMOTION */
1285       return (rl_domove_motion_callback (m));
1286     }
1287   else if (m->key == c && (m->key == 'd' || m->key == 'y' || m->key == 'c'))
1288     {
1289       rl_mark = rl_end;
1290       rl_beg_of_line (1, c);
1291       _rl_vi_last_motion = c;
1292       RL_UNSETSTATE (RL_STATE_VIMOTION);
1293       return (vidomove_dispatch (m));
1294     }
1295 #if defined (READLINE_CALLBACKS)
1296   /* XXX - these need to handle rl_universal_argument bindings */
1297   /* Reading vi motion char continuing numeric argument */
1298   else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1299     {
1300       return (_rl_vi_arg_dispatch (c));
1301     }
1302   /* Readine vi motion char starting numeric argument */
1303   else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_VIMOTION) && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
1304     {
1305       RL_SETSTATE (RL_STATE_NUMERICARG);
1306       return (_rl_vi_arg_dispatch (c));
1307     }
1308 #endif
1309   else if (_rl_digit_p (c))
1310     {
1311       /* This code path taken when not in callback mode */
1312       save = rl_numeric_arg;
1313       rl_numeric_arg = _rl_digit_value (c);
1314       rl_explicit_arg = 1;
1315       RL_SETSTATE (RL_STATE_NUMERICARG);
1316       rl_digit_loop1 ();
1317       rl_numeric_arg *= save;
1318       c = rl_vi_domove_getchar (m);
1319       if (c < 0)
1320 	{
1321 	  m->motion = 0;
1322 	  return -1;
1323 	}
1324       m->motion = c;
1325       return (rl_domove_motion_callback (m));
1326     }
1327   else
1328     {
1329       RL_UNSETSTATE (RL_STATE_VIMOTION);
1330       RL_UNSETSTATE (RL_STATE_NUMERICARG);
1331       return (1);
1332     }
1333 }
1334 
1335 static int
rl_vi_domove_getchar(_rl_vimotion_cxt * m)1336 rl_vi_domove_getchar (_rl_vimotion_cxt *m)
1337 {
1338   return (_rl_bracketed_read_key ());
1339 }
1340 
1341 #if defined (READLINE_CALLBACKS)
1342 int
_rl_vi_domove_callback(_rl_vimotion_cxt * m)1343 _rl_vi_domove_callback (_rl_vimotion_cxt *m)
1344 {
1345   int c, r;
1346 
1347   m->motion = c = rl_vi_domove_getchar (m);
1348   if (c < 0)
1349     return 1;		/* EOF */
1350   r = rl_domove_read_callback (m);
1351 
1352   return ((r == 0) ? r : 1);	/* normalize return values */
1353 }
1354 #endif
1355 
1356 /* This code path is taken when not in callback mode. */
1357 int
rl_vi_domove(int x,int * ignore)1358 rl_vi_domove (int x, int *ignore)
1359 {
1360   int r;
1361   _rl_vimotion_cxt *m;
1362 
1363   m = _rl_vimvcxt;
1364   *ignore = m->motion = rl_vi_domove_getchar (m);
1365 
1366   if (m->motion < 0)
1367     {
1368       m->motion = 0;
1369       return -1;
1370     }
1371 
1372   return (rl_domove_read_callback (m));
1373 }
1374 
1375 static int
vi_delete_dispatch(_rl_vimotion_cxt * m)1376 vi_delete_dispatch (_rl_vimotion_cxt *m)
1377 {
1378   /* These are the motion commands that do not require adjusting the
1379      mark. */
1380   if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1381       (rl_mark < rl_end))
1382     INCREMENT_POS (rl_mark);
1383 
1384   rl_kill_text (rl_point, rl_mark);
1385   return (0);
1386 }
1387 
1388 int
rl_vi_delete_to(int count,int key)1389 rl_vi_delete_to (int count, int key)
1390 {
1391   int c, r;
1392 
1393   if (_rl_vimvcxt)
1394     _rl_mvcxt_init (_rl_vimvcxt, VIM_DELETE, key);
1395   else
1396     _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
1397 
1398   _rl_vimvcxt->start = rl_point;
1399 
1400   rl_mark = rl_point;
1401   if (_rl_uppercase_p (key))
1402     {
1403       _rl_vimvcxt->motion = '$';
1404       r = rl_domove_motion_callback (_rl_vimvcxt);
1405     }
1406   else if (_rl_vi_redoing && _rl_vi_last_motion != 'd')	/* `dd' is special */
1407     {
1408       _rl_vimvcxt->motion = _rl_vi_last_motion;
1409       r = rl_domove_motion_callback (_rl_vimvcxt);
1410     }
1411   else if (_rl_vi_redoing)		/* handle redoing `dd' here */
1412     {
1413       _rl_vimvcxt->motion = _rl_vi_last_motion;
1414       rl_mark = rl_end;
1415       rl_beg_of_line (1, key);
1416       RL_UNSETSTATE (RL_STATE_VIMOTION);
1417       r = vidomove_dispatch (_rl_vimvcxt);
1418     }
1419 #if defined (READLINE_CALLBACKS)
1420   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1421     {
1422       RL_SETSTATE (RL_STATE_VIMOTION);
1423       return (0);
1424     }
1425 #endif
1426   else
1427     r = rl_vi_domove (key, &c);
1428 
1429   if (r < 0)
1430     {
1431       rl_ding ();
1432       r = -1;
1433     }
1434 
1435   _rl_mvcxt_dispose (_rl_vimvcxt);
1436   _rl_vimvcxt = 0;
1437 
1438   return r;
1439 }
1440 
1441 static int
vi_change_dispatch(_rl_vimotion_cxt * m)1442 vi_change_dispatch (_rl_vimotion_cxt *m)
1443 {
1444   /* These are the motion commands that do not require adjusting the
1445      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
1446      and already leave the mark at the correct location. */
1447   if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1448       (rl_mark < rl_end))
1449     INCREMENT_POS (rl_mark);
1450 
1451   /* The cursor never moves with c[wW]. */
1452   if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
1453     rl_point = m->start;
1454 
1455   if (_rl_vi_redoing)
1456     {
1457       if (vi_insert_buffer && *vi_insert_buffer)
1458 	rl_begin_undo_group ();
1459       rl_delete_text (rl_point, rl_mark);
1460       if (vi_insert_buffer && *vi_insert_buffer)
1461 	{
1462 	  rl_insert_text (vi_insert_buffer);
1463 	  rl_end_undo_group ();
1464 	}
1465     }
1466   else
1467     {
1468       rl_begin_undo_group ();		/* to make the `u' command work */
1469       rl_kill_text (rl_point, rl_mark);
1470       /* `C' does not save the text inserted for undoing or redoing. */
1471       if (_rl_uppercase_p (m->key) == 0)
1472 	_rl_vi_doing_insert = 1;
1473       /* XXX -- TODO -- use m->numericarg? */
1474       rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign);
1475     }
1476 
1477   return (0);
1478 }
1479 
1480 int
rl_vi_change_to(int count,int key)1481 rl_vi_change_to (int count, int key)
1482 {
1483   int c, r;
1484 
1485   if (_rl_vimvcxt)
1486     _rl_mvcxt_init (_rl_vimvcxt, VIM_CHANGE, key);
1487   else
1488     _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
1489   _rl_vimvcxt->start = rl_point;
1490 
1491   rl_mark = rl_point;
1492   if (_rl_uppercase_p (key))
1493     {
1494       _rl_vimvcxt->motion = '$';
1495       r = rl_domove_motion_callback (_rl_vimvcxt);
1496     }
1497   else if (_rl_vi_redoing && _rl_vi_last_motion != 'c')	/* `cc' is special */
1498     {
1499       _rl_vimvcxt->motion = _rl_vi_last_motion;
1500       r = rl_domove_motion_callback (_rl_vimvcxt);
1501     }
1502   else if (_rl_vi_redoing)		/* handle redoing `cc' here */
1503     {
1504       _rl_vimvcxt->motion = _rl_vi_last_motion;
1505       rl_mark = rl_end;
1506       rl_beg_of_line (1, key);
1507       RL_UNSETSTATE (RL_STATE_VIMOTION);
1508       r = vidomove_dispatch (_rl_vimvcxt);
1509     }
1510 #if defined (READLINE_CALLBACKS)
1511   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1512     {
1513       RL_SETSTATE (RL_STATE_VIMOTION);
1514       return (0);
1515     }
1516 #endif
1517   else
1518     r = rl_vi_domove (key, &c);
1519 
1520   if (r < 0)
1521     {
1522       rl_ding ();
1523       r = -1;	/* normalize return value */
1524     }
1525 
1526   _rl_mvcxt_dispose (_rl_vimvcxt);
1527   _rl_vimvcxt = 0;
1528 
1529   return r;
1530 }
1531 
1532 static int
vi_yank_dispatch(_rl_vimotion_cxt * m)1533 vi_yank_dispatch (_rl_vimotion_cxt *m)
1534 {
1535   /* These are the motion commands that do not require adjusting the
1536      mark. */
1537   if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1538       (rl_mark < rl_end))
1539     INCREMENT_POS (rl_mark);
1540 
1541   rl_begin_undo_group ();
1542   rl_kill_text (rl_point, rl_mark);
1543   rl_end_undo_group ();
1544   rl_do_undo ();
1545   rl_point = m->start;
1546 
1547   _rl_fix_point (1);
1548 
1549   return (0);
1550 }
1551 
1552 int
rl_vi_yank_to(int count,int key)1553 rl_vi_yank_to (int count, int key)
1554 {
1555   int c, r;
1556 
1557   if (_rl_vimvcxt)
1558     _rl_mvcxt_init (_rl_vimvcxt, VIM_YANK, key);
1559   else
1560     _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
1561   _rl_vimvcxt->start = rl_point;
1562 
1563   rl_mark = rl_point;
1564   if (_rl_uppercase_p (key))
1565     {
1566       _rl_vimvcxt->motion = '$';
1567       r = rl_domove_motion_callback (_rl_vimvcxt);
1568     }
1569   else if (_rl_vi_redoing && _rl_vi_last_motion != 'y')	/* `yy' is special */
1570     {
1571       _rl_vimvcxt->motion = _rl_vi_last_motion;
1572       r = rl_domove_motion_callback (_rl_vimvcxt);
1573     }
1574   else if (_rl_vi_redoing)			/* handle redoing `yy' here */
1575     {
1576       _rl_vimvcxt->motion = _rl_vi_last_motion;
1577       rl_mark = rl_end;
1578       rl_beg_of_line (1, key);
1579       RL_UNSETSTATE (RL_STATE_VIMOTION);
1580       r = vidomove_dispatch (_rl_vimvcxt);
1581     }
1582 #if defined (READLINE_CALLBACKS)
1583   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1584     {
1585       RL_SETSTATE (RL_STATE_VIMOTION);
1586       return (0);
1587     }
1588 #endif
1589   else
1590     r = rl_vi_domove (key, &c);
1591 
1592   if (r < 0)
1593     {
1594       rl_ding ();
1595       r = -1;
1596     }
1597 
1598   _rl_mvcxt_dispose (_rl_vimvcxt);
1599   _rl_vimvcxt = 0;
1600 
1601   return r;
1602 }
1603 
1604 static int
vidomove_dispatch(_rl_vimotion_cxt * m)1605 vidomove_dispatch (_rl_vimotion_cxt *m)
1606 {
1607   int r;
1608 
1609   switch (m->op)
1610     {
1611     case VIM_DELETE:
1612       r = vi_delete_dispatch (m);
1613       break;
1614     case VIM_CHANGE:
1615       r = vi_change_dispatch (m);
1616       break;
1617     case VIM_YANK:
1618       r = vi_yank_dispatch (m);
1619       break;
1620     default:
1621       _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op);
1622       r = 1;
1623       break;
1624     }
1625 
1626   RL_UNSETSTATE (RL_STATE_VIMOTION);
1627   return r;
1628 }
1629 
1630 int
rl_vi_rubout(int count,int key)1631 rl_vi_rubout (int count, int key)
1632 {
1633   int opoint;
1634 
1635   if (count < 0)
1636     return (rl_vi_delete (-count, key));
1637 
1638   if (rl_point == 0)
1639     {
1640       rl_ding ();
1641       return 1;
1642     }
1643 
1644   opoint = rl_point;
1645   if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1646     rl_backward_char (count, key);
1647   else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1648     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1649   else
1650     rl_point -= count;
1651 
1652   if (rl_point < 0)
1653     rl_point = 0;
1654 
1655   rl_kill_text (rl_point, opoint);
1656 
1657   return (0);
1658 }
1659 
1660 int
rl_vi_delete(int count,int key)1661 rl_vi_delete (int count, int key)
1662 {
1663   int end;
1664 
1665   if (count < 0)
1666     return (rl_vi_rubout (-count, key));
1667 
1668   if (rl_end == 0)
1669     {
1670       rl_ding ();
1671       return 1;
1672     }
1673 
1674   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1675     end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1676   else
1677     end = rl_point + count;
1678 
1679   if (end >= rl_end)
1680     end = rl_end;
1681 
1682   rl_kill_text (rl_point, end);
1683 
1684   if (rl_point > 0 && rl_point == rl_end)
1685     rl_backward_char (1, key);
1686 
1687   return (0);
1688 }
1689 
1690 /* This does what Posix specifies vi-mode C-w to do: using whitespace and
1691    punctuation characters as the word boundaries. */
1692 
1693 #define vi_unix_word_boundary(c)	(whitespace(c) || ispunct(c))
1694 
1695 int
rl_vi_unix_word_rubout(int count,int key)1696 rl_vi_unix_word_rubout (int count, int key)
1697 {
1698   int orig_point;
1699 
1700   if (rl_point == 0)
1701     rl_ding ();
1702   else
1703     {
1704       orig_point = rl_point;
1705       if (count <= 0)
1706 	count = 1;
1707 
1708       while (count--)
1709 	{
1710 	  /* This isn't quite what ksh93 does but it seems to match what the
1711 	     Posix description of sh specifies, with a few accommodations
1712 	     for sequences of whitespace characters between words and at
1713 	     the end of the line. */
1714 
1715 	  /* Skip over whitespace at the end of the line as a special case */
1716 	  if (rl_point > 0 && (rl_line_buffer[rl_point] == 0) &&
1717 		whitespace (rl_line_buffer[rl_point - 1]))
1718 	    while (--rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
1719 	      ;
1720 
1721 	  /* If we're at the start of a word, move back to word boundary so we
1722 	     move back to the `preceding' word */
1723 	  if (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0) &&
1724 		vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
1725 	    rl_point--;
1726 
1727 	  /* If we are at a word boundary (whitespace/punct), move backward
1728 	     past a sequence of word boundary characters.  If we are at the
1729 	     end of a word (non-word boundary), move back to a word boundary */
1730 	  if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]))
1731 	    while (rl_point && vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
1732 	      rl_point--;
1733 	  else if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0)
1734 	    while (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point - 1]) == 0))
1735 	      _rl_vi_backup_point ();
1736 	}
1737 
1738       rl_kill_text (orig_point, rl_point);
1739     }
1740 
1741   return 0;
1742 }
1743 
1744 
1745 int
rl_vi_back_to_indent(int count,int key)1746 rl_vi_back_to_indent (int count, int key)
1747 {
1748   rl_beg_of_line (1, key);
1749   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1750     rl_point++;
1751   return (0);
1752 }
1753 
1754 int
rl_vi_first_print(int count,int key)1755 rl_vi_first_print (int count, int key)
1756 {
1757   return (rl_vi_back_to_indent (1, key));
1758 }
1759 
1760 static int _rl_cs_dir, _rl_cs_orig_dir;
1761 
1762 #if defined (READLINE_CALLBACKS)
1763 static int
_rl_vi_callback_char_search(_rl_callback_generic_arg * data)1764 _rl_vi_callback_char_search (_rl_callback_generic_arg *data)
1765 {
1766   int c;
1767 #if defined (HANDLE_MULTIBYTE)
1768   c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1769 #else
1770   RL_SETSTATE(RL_STATE_MOREINPUT);
1771   c = rl_read_key ();
1772   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1773 #endif
1774 
1775   if (c <= 0)
1776     {
1777       RL_UNSETSTATE (RL_STATE_CHARSEARCH);
1778       return -1;
1779     }
1780 
1781 #if !defined (HANDLE_MULTIBYTE)
1782   _rl_vi_last_search_char = c;
1783 #endif
1784 
1785   _rl_callback_func = 0;
1786   _rl_want_redisplay = 1;
1787   RL_UNSETSTATE (RL_STATE_CHARSEARCH);
1788 
1789 #if defined (HANDLE_MULTIBYTE)
1790   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1791 #else
1792   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1793 #endif
1794 }
1795 #endif
1796 
1797 int
rl_vi_char_search(int count,int key)1798 rl_vi_char_search (int count, int key)
1799 {
1800   int c;
1801 #if defined (HANDLE_MULTIBYTE)
1802   static char *target;
1803   static int tlen;
1804 #else
1805   static char target;
1806 #endif
1807 
1808   if (key == ';' || key == ',')
1809     {
1810       if (_rl_cs_orig_dir == 0)
1811 	return 1;
1812 #if defined (HANDLE_MULTIBYTE)
1813       if (_rl_vi_last_search_mblen == 0)
1814 	return 1;
1815 #else
1816       if (_rl_vi_last_search_char == 0)
1817 	return 1;
1818 #endif
1819       _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1820     }
1821   else
1822     {
1823       switch (key)
1824 	{
1825 	case 't':
1826 	  _rl_cs_orig_dir = _rl_cs_dir = FTO;
1827 	  break;
1828 
1829 	case 'T':
1830 	  _rl_cs_orig_dir = _rl_cs_dir = BTO;
1831 	  break;
1832 
1833 	case 'f':
1834 	  _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1835 	  break;
1836 
1837 	case 'F':
1838 	  _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1839 	  break;
1840 	}
1841 
1842       if (_rl_vi_redoing)
1843 	{
1844 	  /* set target and tlen below */
1845 	}
1846 #if defined (READLINE_CALLBACKS)
1847       else if (RL_ISSTATE (RL_STATE_CALLBACK))
1848 	{
1849 	  _rl_callback_data = _rl_callback_data_alloc (count);
1850 	  _rl_callback_data->i1 = _rl_cs_dir;
1851 	  _rl_callback_data->i2 = key;
1852 	  _rl_callback_func = _rl_vi_callback_char_search;
1853 	  RL_SETSTATE (RL_STATE_CHARSEARCH);
1854 	  return (0);
1855 	}
1856 #endif
1857       else
1858 	{
1859 #if defined (HANDLE_MULTIBYTE)
1860 	  c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1861 	  if (c <= 0)
1862 	    return -1;
1863 	  _rl_vi_last_search_mblen = c;
1864 #else
1865 	  RL_SETSTATE(RL_STATE_MOREINPUT);
1866 	  c = rl_read_key ();
1867 	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1868 	  if (c < 0)
1869 	    return -1;
1870 	  _rl_vi_last_search_char = c;
1871 #endif
1872 	}
1873     }
1874 
1875 #if defined (HANDLE_MULTIBYTE)
1876   target = _rl_vi_last_search_mbchar;
1877   tlen = _rl_vi_last_search_mblen;
1878 #else
1879   target = _rl_vi_last_search_char;
1880 #endif
1881 
1882 #if defined (HANDLE_MULTIBYTE)
1883   return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1884 #else
1885   return (_rl_char_search_internal (count, _rl_cs_dir, target));
1886 #endif
1887 }
1888 
1889 /* Match brackets */
1890 int
rl_vi_match(int ignore,int key)1891 rl_vi_match (int ignore, int key)
1892 {
1893   int count = 1, brack, pos, tmp, pre;
1894 
1895   pos = rl_point;
1896   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1897     {
1898       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1899 	{
1900 	  while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1901 	    {
1902 	      pre = rl_point;
1903 	      rl_forward_char (1, key);
1904 	      if (pre == rl_point)
1905 		break;
1906 	    }
1907 	}
1908       else
1909 	while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1910 		rl_point < rl_end - 1)
1911 	  rl_forward_char (1, key);
1912 
1913       if (brack <= 0)
1914 	{
1915 	  rl_point = pos;
1916 	  rl_ding ();
1917 	  return 1;
1918 	}
1919     }
1920 
1921   pos = rl_point;
1922 
1923   if (brack < 0)
1924     {
1925       while (count)
1926 	{
1927 	  tmp = pos;
1928 	  if (MB_CUR_MAX == 1 || rl_byte_oriented)
1929 	    pos--;
1930 	  else
1931 	    {
1932 	      pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1933 	      if (tmp == pos)
1934 		pos--;
1935 	    }
1936 	  if (pos >= 0)
1937 	    {
1938 	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1939 	      if (b == -brack)
1940 		count--;
1941 	      else if (b == brack)
1942 		count++;
1943 	    }
1944 	  else
1945 	    {
1946 	      rl_ding ();
1947 	      return 1;
1948 	    }
1949 	}
1950     }
1951   else
1952     {			/* brack > 0 */
1953       while (count)
1954 	{
1955 	  if (MB_CUR_MAX == 1 || rl_byte_oriented)
1956 	    pos++;
1957 	  else
1958 	    pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1959 
1960 	  if (pos < rl_end)
1961 	    {
1962 	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1963 	      if (b == -brack)
1964 		count--;
1965 	      else if (b == brack)
1966 		count++;
1967 	    }
1968 	  else
1969 	    {
1970 	      rl_ding ();
1971 	      return 1;
1972 	    }
1973 	}
1974     }
1975   rl_point = pos;
1976   return (0);
1977 }
1978 
1979 int
rl_vi_bracktype(int c)1980 rl_vi_bracktype (int c)
1981 {
1982   switch (c)
1983     {
1984     case '(': return  1;
1985     case ')': return -1;
1986     case '[': return  2;
1987     case ']': return -2;
1988     case '{': return  3;
1989     case '}': return -3;
1990     default:  return  0;
1991     }
1992 }
1993 
1994 static int
_rl_vi_change_char(int count,int c,char * mb)1995 _rl_vi_change_char (int count, int c, char *mb)
1996 {
1997   int p;
1998 
1999   if (c == '\033' || c == CTRL ('C'))
2000     return -1;
2001 
2002   rl_begin_undo_group ();
2003   while (count-- && rl_point < rl_end)
2004     {
2005       p = rl_point;
2006       rl_vi_delete (1, c);
2007       if (rl_point < p)		/* Did we retreat at EOL? */
2008 	_rl_vi_append_forward (c);
2009 #if defined (HANDLE_MULTIBYTE)
2010       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
2011 	rl_insert_text (mb);
2012       else
2013 #endif
2014 	_rl_insert_char (1, c);
2015     }
2016 
2017   /* The cursor shall be left on the last character changed. */
2018   rl_backward_char (1, c);
2019 
2020   rl_end_undo_group ();
2021 
2022   return (0);
2023 }
2024 
2025 static int
_rl_vi_callback_getchar(char * mb,int mlen)2026 _rl_vi_callback_getchar (char *mb, int mlen)
2027 {
2028   return (_rl_bracketed_read_mbstring (mb, mlen));
2029 }
2030 
2031 #if defined (READLINE_CALLBACKS)
2032 static int
_rl_vi_callback_change_char(_rl_callback_generic_arg * data)2033 _rl_vi_callback_change_char (_rl_callback_generic_arg *data)
2034 {
2035   int c;
2036   char mb[MB_LEN_MAX+1];
2037 
2038   c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
2039 #if defined (HANDLE_MULTIBYTE)
2040   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
2041     strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX);
2042   else
2043 #endif
2044     _rl_vi_last_replacement[0] = c;
2045   _rl_vi_last_replacement[MB_LEN_MAX] = '\0';	/* XXX */
2046 
2047   if (c < 0)
2048     return -1;
2049 
2050   _rl_callback_func = 0;
2051   _rl_want_redisplay = 1;
2052 
2053   return (_rl_vi_change_char (data->count, c, mb));
2054 }
2055 #endif
2056 
2057 int
rl_vi_change_char(int count,int key)2058 rl_vi_change_char (int count, int key)
2059 {
2060   int c;
2061   char mb[MB_LEN_MAX+1];
2062 
2063   if (_rl_vi_redoing)
2064     {
2065       strncpy (mb, _rl_vi_last_replacement, MB_LEN_MAX);
2066       c = (unsigned char)_rl_vi_last_replacement[0];	/* XXX */
2067       mb[MB_LEN_MAX] = '\0';
2068     }
2069 #if defined (READLINE_CALLBACKS)
2070   else if (RL_ISSTATE (RL_STATE_CALLBACK))
2071     {
2072       _rl_callback_data = _rl_callback_data_alloc (count);
2073       _rl_callback_func = _rl_vi_callback_change_char;
2074       return (0);
2075     }
2076 #endif
2077   else
2078     {
2079       c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
2080 #ifdef HANDLE_MULTIBYTE
2081       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
2082 	strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX);
2083       else
2084 #endif
2085 	_rl_vi_last_replacement[0] = c;
2086       _rl_vi_last_replacement[MB_LEN_MAX] = '\0';	/* just in case */
2087     }
2088 
2089   if (c < 0)
2090     return -1;
2091 
2092   return (_rl_vi_change_char (count, c, mb));
2093 }
2094 
2095 int
rl_vi_subst(int count,int key)2096 rl_vi_subst (int count, int key)
2097 {
2098   /* If we are redoing, rl_vi_change_to will stuff the last motion char */
2099   if (_rl_vi_redoing == 0)
2100     rl_stuff_char ((key == 'S') ? 'c' : 'l');	/* `S' == `cc', `s' == `cl' */
2101 
2102   return (rl_vi_change_to (count, 'c'));
2103 }
2104 
2105 int
rl_vi_overstrike(int count,int key)2106 rl_vi_overstrike (int count, int key)
2107 {
2108   if (_rl_vi_doing_insert == 0)
2109     {
2110       _rl_vi_doing_insert = 1;
2111       rl_begin_undo_group ();
2112     }
2113 
2114   if (count > 0)
2115     {
2116       _rl_overwrite_char (count, key);
2117       vi_replace_count += count;
2118     }
2119 
2120   return (0);
2121 }
2122 
2123 int
rl_vi_overstrike_delete(int count,int key)2124 rl_vi_overstrike_delete (int count, int key)
2125 {
2126   int i, s;
2127 
2128   for (i = 0; i < count; i++)
2129     {
2130       if (vi_replace_count == 0)
2131 	{
2132 	  rl_ding ();
2133 	  break;
2134 	}
2135       s = rl_point;
2136 
2137       if (rl_do_undo ())
2138 	vi_replace_count--;		/* XXX */
2139 
2140       if (rl_point == s)
2141 	rl_backward_char (1, key);
2142     }
2143 
2144   if (vi_replace_count == 0 && _rl_vi_doing_insert)
2145     {
2146       rl_end_undo_group ();
2147       rl_do_undo ();
2148       _rl_vi_doing_insert = 0;
2149     }
2150   return (0);
2151 }
2152 
2153 static int
rl_vi_overstrike_kill_line(int count,int key)2154 rl_vi_overstrike_kill_line (int count, int key)
2155 {
2156   int r, end;
2157 
2158   end = rl_end;
2159   r = rl_unix_line_discard (count, key);
2160   vi_replace_count -= end - rl_end;
2161   return r;
2162 }
2163 
2164 static int
rl_vi_overstrike_kill_word(int count,int key)2165 rl_vi_overstrike_kill_word (int count, int key)
2166 {
2167   int r, end;
2168 
2169   end = rl_end;
2170   r = rl_vi_unix_word_rubout (count, key);
2171   vi_replace_count -= end - rl_end;
2172   return r;
2173 }
2174 
2175 static int
rl_vi_overstrike_yank(int count,int key)2176 rl_vi_overstrike_yank (int count, int key)
2177 {
2178   int r, end;
2179 
2180   end = rl_end;
2181   r = rl_yank (count, key);
2182   vi_replace_count += rl_end - end;
2183   return r;
2184 }
2185 
2186 /* Read bracketed paste mode pasted text and insert it in overwrite mode */
2187 static int
rl_vi_overstrike_bracketed_paste(int count,int key)2188 rl_vi_overstrike_bracketed_paste (int count, int key)
2189 {
2190   int r;
2191   char *pbuf;
2192   size_t pblen;
2193 
2194   pbuf = _rl_bracketed_text (&pblen);
2195   if (pblen == 0)
2196     {
2197       xfree (pbuf);
2198       return 0;
2199     }
2200   r = pblen;
2201   while (--r >= 0)
2202     _rl_unget_char ((unsigned char)pbuf[r]);
2203   xfree (pbuf);
2204 
2205   while (_rl_pushed_input_available ())
2206     {
2207       key = rl_read_key ();
2208       r = rl_vi_overstrike (1, key);
2209     }
2210 
2211   return r;
2212 }
2213 
2214 int
rl_vi_replace(int count,int key)2215 rl_vi_replace (int count, int key)
2216 {
2217   int i;
2218 
2219   vi_replace_count = 0;
2220 
2221   if (vi_replace_map == 0)
2222     {
2223       vi_replace_map = rl_make_bare_keymap ();
2224 
2225       for (i = 0; i < ' '; i++)
2226 	if (vi_insertion_keymap[i].type == ISFUNC)
2227 	  vi_replace_map[i].function = vi_insertion_keymap[i].function;
2228 
2229       for (i = ' '; i < KEYMAP_SIZE; i++)
2230 	vi_replace_map[i].function = rl_vi_overstrike;
2231 
2232       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
2233 
2234       /* Make sure these are what we want. */
2235       vi_replace_map[ESC].function = rl_vi_movement_mode;
2236       vi_replace_map[RETURN].function = rl_newline;
2237       vi_replace_map[NEWLINE].function = rl_newline;
2238 
2239       /* If the normal vi insertion keymap has ^H bound to erase, do the
2240 	 same here.  Probably should remove the assignment to RUBOUT up
2241 	 there, but I don't think it will make a difference in real life. */
2242       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
2243 	  vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
2244 	vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
2245 
2246       /* Same for ^U and unix-line-discard. */
2247       if (vi_insertion_keymap[CTRL ('U')].type == ISFUNC &&
2248 	  vi_insertion_keymap[CTRL ('U')].function == rl_unix_line_discard)
2249 	vi_replace_map[CTRL ('U')].function = rl_vi_overstrike_kill_line;
2250 
2251       /* And for ^W and unix-word-rubout. */
2252       if (vi_insertion_keymap[CTRL ('W')].type == ISFUNC &&
2253 	  vi_insertion_keymap[CTRL ('W')].function == rl_vi_unix_word_rubout)
2254 	vi_replace_map[CTRL ('W')].function = rl_vi_overstrike_kill_word;
2255 
2256       /* And finally for ^Y and yank. */
2257       if (vi_insertion_keymap[CTRL ('Y')].type == ISFUNC &&
2258 	  vi_insertion_keymap[CTRL ('Y')].function == rl_yank)
2259 	vi_replace_map[CTRL ('Y')].function = rl_vi_overstrike_yank;
2260 
2261       /* Make sure this is the value we need. */
2262       vi_replace_map[ANYOTHERKEY].type = ISFUNC;
2263       vi_replace_map[ANYOTHERKEY].function = (rl_command_func_t *)NULL;
2264     }
2265 
2266   rl_vi_start_inserting (key, 1, rl_arg_sign);
2267 
2268   _rl_vi_last_key_before_insert = 'R';	/* in case someone rebinds it */
2269   _rl_keymap = vi_replace_map;
2270 
2271   if (_rl_enable_bracketed_paste)
2272     rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_vi_overstrike_bracketed_paste);
2273 
2274   return (0);
2275 }
2276 
2277 #if 0
2278 /* Try to complete the word we are standing on or the word that ends with
2279    the previous character.  A space matches everything.  Word delimiters are
2280    space and ;. */
2281 int
2282 rl_vi_possible_completions (void)
2283 {
2284   int save_pos = rl_point;
2285 
2286   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
2287     {
2288       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
2289 	     rl_line_buffer[rl_point] != ';')
2290 	_rl_vi_advance_point ();
2291     }
2292   else if (rl_line_buffer[rl_point - 1] == ';')
2293     {
2294       rl_ding ();
2295       return (0);
2296     }
2297 
2298   rl_possible_completions ();
2299   rl_point = save_pos;
2300 
2301   return (0);
2302 }
2303 #endif
2304 
2305 /* Functions to save and restore marks. */
2306 static int
_rl_vi_set_mark(void)2307 _rl_vi_set_mark (void)
2308 {
2309   int ch;
2310 
2311   RL_SETSTATE(RL_STATE_MOREINPUT);
2312   ch = rl_read_key ();
2313   RL_UNSETSTATE(RL_STATE_MOREINPUT);
2314 
2315   if (ch < 0 || ch < 'a' || ch > 'z')	/* make test against 0 explicit */
2316     {
2317       rl_ding ();
2318       return 1;
2319     }
2320   ch -= 'a';
2321   vi_mark_chars[ch] = rl_point;
2322   return 0;
2323 }
2324 
2325 #if defined (READLINE_CALLBACKS)
2326 static int
_rl_vi_callback_set_mark(_rl_callback_generic_arg * data)2327 _rl_vi_callback_set_mark (_rl_callback_generic_arg *data)
2328 {
2329   _rl_callback_func = 0;
2330   _rl_want_redisplay = 1;
2331 
2332   return (_rl_vi_set_mark ());
2333 }
2334 #endif
2335 
2336 int
rl_vi_set_mark(int count,int key)2337 rl_vi_set_mark (int count, int key)
2338 {
2339 #if defined (READLINE_CALLBACKS)
2340   if (RL_ISSTATE (RL_STATE_CALLBACK))
2341     {
2342       _rl_callback_data = 0;
2343       _rl_callback_func = _rl_vi_callback_set_mark;
2344       return (0);
2345     }
2346 #endif
2347 
2348   return (_rl_vi_set_mark ());
2349 }
2350 
2351 static int
_rl_vi_goto_mark(void)2352 _rl_vi_goto_mark (void)
2353 {
2354   int ch;
2355 
2356   RL_SETSTATE(RL_STATE_MOREINPUT);
2357   ch = rl_read_key ();
2358   RL_UNSETSTATE(RL_STATE_MOREINPUT);
2359 
2360   if (ch == '`')
2361     {
2362       rl_point = rl_mark;
2363       _rl_fix_point (1);
2364       return 0;
2365     }
2366   else if (ch < 0 || ch < 'a' || ch > 'z')	/* make test against 0 explicit */
2367     {
2368       rl_ding ();
2369       return 1;
2370     }
2371 
2372   ch -= 'a';
2373   if (vi_mark_chars[ch] == -1)
2374     {
2375       rl_ding ();
2376       return 1;
2377     }
2378   rl_point = vi_mark_chars[ch];
2379   _rl_fix_point (1);
2380   return 0;
2381 }
2382 
2383 #if defined (READLINE_CALLBACKS)
2384 static int
_rl_vi_callback_goto_mark(_rl_callback_generic_arg * data)2385 _rl_vi_callback_goto_mark (_rl_callback_generic_arg *data)
2386 {
2387   _rl_callback_func = 0;
2388   _rl_want_redisplay = 1;
2389 
2390   return (_rl_vi_goto_mark ());
2391 }
2392 #endif
2393 
2394 int
rl_vi_goto_mark(int count,int key)2395 rl_vi_goto_mark (int count, int key)
2396 {
2397 #if defined (READLINE_CALLBACKS)
2398   if (RL_ISSTATE (RL_STATE_CALLBACK))
2399     {
2400       _rl_callback_data = 0;
2401       _rl_callback_func = _rl_vi_callback_goto_mark;
2402       return (0);
2403     }
2404 #endif
2405 
2406   return (_rl_vi_goto_mark ());
2407 }
2408 #endif /* VI_MODE */
2409