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