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