init version.
[bush.git] / lib / readline / vi_mode.c
blobfa87f506efa9ca9a940eaca762e56ea90cf825db
1 /* vi_mode.c -- A vi emulation mode for Bush.
2 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
4 /* Copyright (C) 1987-2020 Free Software Foundation, Inc.
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.
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.
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.
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/>.
23 #define READLINE_LIBRARY
25 /* **************************************************************** */
26 /* */
27 /* VI Emulation Mode */
28 /* */
29 /* **************************************************************** */
30 #include "rlconf.h"
32 #if defined (VI_MODE)
34 #if defined (HAVE_CONFIG_H)
35 # include <config.h>
36 #endif
38 #include <sys/types.h>
40 #if defined (HAVE_STDLIB_H)
41 # include <stdlib.h>
42 #else
43 # include "ansi_stdlib.h"
44 #endif /* HAVE_STDLIB_H */
46 #if defined (HAVE_UNISTD_H)
47 # include <unistd.h>
48 #endif
50 #include <stdio.h>
52 /* Some standard library routines. */
53 #include "rldefs.h"
54 #include "rlmbutil.h"
56 #include "readline.h"
57 #include "history.h"
59 #include "rlprivate.h"
60 #include "xmalloc.h"
62 #ifndef member
63 #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
64 #endif
66 /* Increment START to the next character in RL_LINE_BUFFER, handling multibyte chars */
67 #if defined (HANDLE_MULTIBYTE)
68 #define INCREMENT_POS(start) \
69 do { \
70 if (MB_CUR_MAX == 1 || rl_byte_oriented) \
71 start++; \
72 else \
73 start = _rl_find_next_mbchar (rl_line_buffer, start, 1, MB_FIND_ANY); \
74 } while (0)
75 #else /* !HANDLE_MULTIBYTE */
76 #define INCREMENT_POS(start) (start)++
77 #endif /* !HANDLE_MULTIBYTE */
79 /* This is global so other parts of the code can check whether the last
80 command was a text modification command. */
81 int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
83 _rl_vimotion_cxt *_rl_vimvcxt = 0;
85 /* Non-zero indicates we are redoing a vi-mode command with `.' */
86 int _rl_vi_redoing;
88 /* Non-zero means enter insertion mode. */
89 static int _rl_vi_doing_insert;
91 /* Command keys which do movement for xxx_to commands. */
92 static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`";
94 /* Keymap used for vi replace characters. Created dynamically since
95 rarely used. */
96 static Keymap vi_replace_map;
98 /* The number of characters inserted in the last replace operation. */
99 static int vi_replace_count;
101 /* If non-zero, we have text inserted after a c[motion] command that put
102 us implicitly into insert mode. Some people want this text to be
103 attached to the command so that it is `redoable' with `.'. */
104 static int vi_continued_command;
105 static char *vi_insert_buffer;
106 static int vi_insert_buffer_size;
108 static int _rl_vi_last_repeat = 1;
109 static int _rl_vi_last_arg_sign = 1;
110 static int _rl_vi_last_motion;
111 #if defined (HANDLE_MULTIBYTE)
112 static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
113 static int _rl_vi_last_search_mblen;
114 #else
115 static int _rl_vi_last_search_char;
116 #endif
117 static char _rl_vi_last_replacement[MB_LEN_MAX+1]; /* reserve for trailing NULL */
119 static int _rl_vi_last_key_before_insert;
121 /* Text modification commands. These are the `redoable' commands. */
122 static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
124 /* Arrays for the saved marks. */
125 static int vi_mark_chars['z' - 'a' + 1];
127 static void _rl_vi_replace_insert PARAMS((int));
128 static void _rl_vi_save_replace PARAMS((void));
129 static void _rl_vi_stuff_insert PARAMS((int));
130 static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
132 static void vi_save_insert_buffer PARAMS ((int, int));
134 static inline void _rl_vi_backup PARAMS((void));
136 static int _rl_vi_arg_dispatch PARAMS((int));
137 static int rl_digit_loop1 PARAMS((void));
139 static int _rl_vi_set_mark PARAMS((void));
140 static int _rl_vi_goto_mark PARAMS((void));
142 static inline int _rl_vi_advance_point PARAMS((void));
143 static inline int _rl_vi_backup_point PARAMS((void));
145 static void _rl_vi_append_forward PARAMS((int));
147 static int _rl_vi_callback_getchar PARAMS((char *, int));
149 #if defined (READLINE_CALLBACKS)
150 static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
151 static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
152 static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
153 static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
154 #endif
156 static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *));
157 static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *));
158 static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *));
160 static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *));
161 static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *));
162 static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *));
164 static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *));
166 void
167 _rl_vi_initialize_line (void)
169 register int i, n;
171 n = sizeof (vi_mark_chars) / sizeof (vi_mark_chars[0]);
172 for (i = 0; i < n; i++)
173 vi_mark_chars[i] = -1;
175 RL_UNSETSTATE(RL_STATE_VICMDONCE);
178 void
179 _rl_vi_reset_last (void)
181 _rl_vi_last_command = 'i';
182 _rl_vi_last_repeat = 1;
183 _rl_vi_last_arg_sign = 1;
184 _rl_vi_last_motion = 0;
187 void
188 _rl_vi_set_last (int key, int repeat, int sign)
190 _rl_vi_last_command = key;
191 _rl_vi_last_repeat = repeat;
192 _rl_vi_last_arg_sign = sign;
195 /* A convenience function that calls _rl_vi_set_last to save the last command
196 information and enters insertion mode. */
197 void
198 rl_vi_start_inserting (int key, int repeat, int sign)
200 _rl_vi_set_last (key, repeat, sign);
201 rl_begin_undo_group (); /* ensure inserts aren't concatenated */
202 rl_vi_insertion_mode (1, key);
205 /* Is the command C a VI mode text modification command? */
207 _rl_vi_textmod_command (int c)
209 return (member (c, vi_textmod));
213 _rl_vi_motion_command (int c)
215 return (member (c, vi_motion));
218 static void
219 _rl_vi_replace_insert (int count)
221 int nchars;
223 nchars = strlen (vi_insert_buffer);
225 rl_begin_undo_group ();
226 while (count--)
227 /* nchars-1 to compensate for _rl_replace_text using `end+1' in call
228 to rl_delete_text */
229 _rl_replace_text (vi_insert_buffer, rl_point, rl_point+nchars-1);
230 rl_end_undo_group ();
233 static void
234 _rl_vi_stuff_insert (int count)
236 rl_begin_undo_group ();
237 while (count--)
238 rl_insert_text (vi_insert_buffer);
239 rl_end_undo_group ();
242 /* Bound to `.'. Called from command mode, so we know that we have to
243 redo a text modification command. The default for _rl_vi_last_command
244 puts you back into insert mode. */
246 rl_vi_redo (int count, int c)
248 int r;
250 if (rl_explicit_arg == 0)
252 rl_numeric_arg = _rl_vi_last_repeat;
253 rl_arg_sign = _rl_vi_last_arg_sign;
256 r = 0;
257 _rl_vi_redoing = 1;
258 /* If we're redoing an insert with `i', stuff in the inserted text
259 and do not go into insertion mode. */
260 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
262 _rl_vi_stuff_insert (count);
263 /* And back up point over the last character inserted. */
264 if (rl_point > 0)
265 _rl_vi_backup ();
267 else if (_rl_vi_last_command == 'R' && vi_insert_buffer && *vi_insert_buffer)
269 _rl_vi_replace_insert (count);
270 /* And back up point over the last character inserted. */
271 if (rl_point > 0)
272 _rl_vi_backup ();
274 /* Ditto for redoing an insert with `I', but move to the beginning of the
275 line like the `I' command does. */
276 else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer)
278 rl_beg_of_line (1, 'I');
279 _rl_vi_stuff_insert (count);
280 if (rl_point > 0)
281 _rl_vi_backup ();
283 /* Ditto for redoing an insert with `a', but move forward a character first
284 like the `a' command does. */
285 else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
287 _rl_vi_append_forward ('a');
288 _rl_vi_stuff_insert (count);
289 if (rl_point > 0)
290 _rl_vi_backup ();
292 /* Ditto for redoing an insert with `A', but move to the end of the line
293 like the `A' command does. */
294 else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer)
296 rl_end_of_line (1, 'A');
297 _rl_vi_stuff_insert (count);
298 if (rl_point > 0)
299 _rl_vi_backup ();
301 else if (_rl_vi_last_command == '.' && _rl_keymap == vi_movement_keymap)
303 rl_ding ();
304 r = 0;
306 else
307 r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
309 _rl_vi_redoing = 0;
311 return (r);
314 /* A placeholder for further expansion. */
316 rl_vi_undo (int count, int key)
318 return (rl_undo_command (count, key));
321 /* Yank the nth arg from the previous line into this line at point. */
323 rl_vi_yank_arg (int count, int key)
325 /* Readline thinks that the first word on a line is the 0th, while vi
326 thinks the first word on a line is the 1st. Compensate. */
327 if (rl_explicit_arg)
328 rl_yank_nth_arg (count - 1, key);
329 else
330 rl_yank_nth_arg ('$', key);
332 return (0);
335 /* With an argument, move back that many history lines, else move to the
336 beginning of history. */
338 rl_vi_fetch_history (int count, int c)
340 int wanted;
342 /* Giving an argument of n means we want the nth command in the history
343 file. The command number is interpreted the same way that the bush
344 `history' command does it -- that is, giving an argument count of 450
345 to this command would get the command listed as number 450 in the
346 output of `history'. */
347 if (rl_explicit_arg)
349 wanted = history_base + where_history () - count;
350 if (wanted <= 0)
351 rl_beginning_of_history (0, 0);
352 else
353 rl_get_previous_history (wanted, c);
355 else
356 rl_beginning_of_history (count, 0);
357 return (0);
360 /* Search again for the last thing searched for. */
362 rl_vi_search_again (int count, int key)
364 switch (key)
366 case 'n':
367 rl_noninc_reverse_search_again (count, key);
368 break;
370 case 'N':
371 rl_noninc_forward_search_again (count, key);
372 break;
374 return (0);
377 /* Do a vi style search. */
379 rl_vi_search (int count, int key)
381 switch (key)
383 case '?':
384 _rl_free_saved_history_line ();
385 rl_noninc_forward_search (count, key);
386 break;
388 case '/':
389 _rl_free_saved_history_line ();
390 rl_noninc_reverse_search (count, key);
391 break;
393 default:
394 rl_ding ();
395 break;
397 return (0);
400 /* Completion, from vi's point of view. */
402 rl_vi_complete (int ignore, int key)
404 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
406 if (!whitespace (rl_line_buffer[rl_point + 1]))
407 rl_vi_end_word (1, 'E');
408 _rl_vi_advance_point ();
411 if (key == '*')
412 rl_complete_internal ('*'); /* Expansion and replacement. */
413 else if (key == '=')
414 rl_complete_internal ('?'); /* List possible completions. */
415 else if (key == '\\')
416 rl_complete_internal (TAB); /* Standard Readline completion. */
417 else
418 rl_complete (0, key);
420 if (key == '*' || key == '\\')
421 rl_vi_start_inserting (key, 1, rl_arg_sign);
423 return (0);
426 /* Tilde expansion for vi mode. */
428 rl_vi_tilde_expand (int ignore, int key)
430 rl_tilde_expand (0, key);
431 rl_vi_start_inserting (key, 1, rl_arg_sign);
432 return (0);
435 /* Previous word in vi mode. */
437 rl_vi_prev_word (int count, int key)
439 if (count < 0)
440 return (rl_vi_next_word (-count, key));
442 if (rl_point == 0)
444 rl_ding ();
445 return (0);
448 if (_rl_uppercase_p (key))
449 rl_vi_bWord (count, key);
450 else
451 rl_vi_bword (count, key);
453 return (0);
456 /* Next word in vi mode. */
458 rl_vi_next_word (int count, int key)
460 if (count < 0)
461 return (rl_vi_prev_word (-count, key));
463 if (rl_point >= (rl_end - 1))
465 rl_ding ();
466 return (0);
469 if (_rl_uppercase_p (key))
470 rl_vi_fWord (count, key);
471 else
472 rl_vi_fword (count, key);
473 return (0);
476 static inline int
477 _rl_vi_advance_point (void)
479 int point;
481 point = rl_point;
482 if (rl_point < rl_end)
483 #if defined (HANDLE_MULTIBYTE)
485 if (MB_CUR_MAX == 1 || rl_byte_oriented)
486 rl_point++;
487 else
489 point = rl_point;
490 rl_point = _rl_forward_char_internal (1);
491 if (point == rl_point || rl_point > rl_end)
492 rl_point = rl_end;
495 #else
496 rl_point++;
497 #endif
499 return point;
502 /* Move the cursor back one character. */
503 static inline void
504 _rl_vi_backup (void)
506 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
507 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
508 else
509 rl_point--;
512 /* Move the point back one character, returning the starting value and not
513 doing anything at the beginning of the line */
514 static inline int
515 _rl_vi_backup_point (void)
517 int point;
519 point = rl_point;
520 if (rl_point > 0)
521 #if defined (HANDLE_MULTIBYTE)
523 if (MB_CUR_MAX == 1 || rl_byte_oriented)
524 rl_point--;
525 else
527 point = rl_point;
528 rl_point = _rl_backward_char_internal (1);
529 if (rl_point < 0)
530 rl_point = 0; /* XXX - not really necessary */
533 #else
534 rl_point--;
535 #endif
536 return point;
539 /* Move to the end of the ?next? word. */
541 rl_vi_end_word (int count, int key)
543 if (count < 0)
545 rl_ding ();
546 return 1;
549 if (_rl_uppercase_p (key))
550 rl_vi_eWord (count, key);
551 else
552 rl_vi_eword (count, key);
553 return (0);
556 /* Move forward a word the way that 'W' does. */
558 rl_vi_fWord (int count, int ignore)
560 while (count-- && rl_point < (rl_end - 1))
562 /* Skip until whitespace. */
563 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
564 _rl_vi_advance_point ();
566 /* Now skip whitespace. */
567 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
568 _rl_vi_advance_point ();
570 return (0);
574 rl_vi_bWord (int count, int ignore)
576 while (count-- && rl_point > 0)
578 /* If we are at the start of a word, move back to whitespace so
579 we will go back to the start of the previous word. */
580 if (!whitespace (rl_line_buffer[rl_point]) &&
581 whitespace (rl_line_buffer[rl_point - 1]))
582 rl_point--;
584 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
585 _rl_vi_backup_point ();
587 if (rl_point > 0)
590 _rl_vi_backup_point ();
591 while (rl_point > 0 && !whitespace (rl_line_buffer[rl_point]));
592 if (rl_point > 0) /* hit whitespace */
593 rl_point++;
595 if (rl_point < 0)
596 rl_point = 0;
599 return (0);
603 rl_vi_eWord (int count, int ignore)
605 int opoint;
607 while (count-- && rl_point < (rl_end - 1))
609 if (whitespace (rl_line_buffer[rl_point]) == 0)
610 _rl_vi_advance_point ();
612 /* Move to the next non-whitespace character (to the start of the
613 next word). */
614 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
615 _rl_vi_advance_point ();
617 if (rl_point && rl_point < rl_end)
619 opoint = rl_point;
621 /* Skip whitespace. */
622 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
623 opoint = _rl_vi_advance_point (); /* XXX - why? */
625 /* Skip until whitespace. */
626 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
627 opoint = _rl_vi_advance_point ();
629 /* Move back to the last character of the word. */
630 rl_point = opoint;
633 return (0);
637 rl_vi_fword (int count, int ignore)
639 int opoint;
641 while (count-- && rl_point < (rl_end - 1))
643 /* Move to white space (really non-identifer). */
644 if (_rl_isident (rl_line_buffer[rl_point]))
646 while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
647 _rl_vi_advance_point ();
649 else /* if (!whitespace (rl_line_buffer[rl_point])) */
651 while (!_rl_isident (rl_line_buffer[rl_point]) &&
652 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
653 _rl_vi_advance_point ();
656 opoint = rl_point;
658 /* Move past whitespace. */
659 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
660 opoint = _rl_vi_advance_point ();
662 return (0);
666 rl_vi_bword (int count, int ignore)
668 int opoint;
670 while (count-- && rl_point > 0)
672 int prev_is_ident, cur_is_ident;
674 /* If we are at the start of a word, move back to whitespace
675 so we will go back to the start of the previous word. */
676 if (!whitespace (rl_line_buffer[rl_point]) &&
677 whitespace (rl_line_buffer[rl_point - 1]))
678 if (--rl_point == 0)
679 break;
681 /* If this character and the previous character are `opposite', move
682 back so we don't get messed up by the rl_point++ down there in
683 the while loop. Without this code, words like `l;' screw up the
684 function. */
685 cur_is_ident = _rl_isident (rl_line_buffer[rl_point]);
686 opoint = _rl_vi_backup_point ();
687 prev_is_ident = _rl_isident (rl_line_buffer[rl_point]);
688 if ((cur_is_ident && !prev_is_ident) || (!cur_is_ident && prev_is_ident))
689 ; /* leave point alone, we backed it up one character */
690 else
691 rl_point = opoint;
693 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
694 _rl_vi_backup_point ();
696 if (rl_point > 0)
698 opoint = rl_point;
699 if (_rl_isident (rl_line_buffer[rl_point]))
701 opoint = _rl_vi_backup_point ();
702 while (rl_point > 0 && _rl_isident (rl_line_buffer[rl_point]));
703 else
705 opoint = _rl_vi_backup_point ();
706 while (rl_point > 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
707 !whitespace (rl_line_buffer[rl_point]));
709 if (rl_point > 0)
710 rl_point = opoint;
712 if (rl_point < 0)
713 rl_point = 0;
716 return (0);
720 rl_vi_eword (int count, int ignore)
722 int opoint;
724 while (count-- && rl_point < (rl_end - 1))
726 if (whitespace (rl_line_buffer[rl_point]) == 0)
727 _rl_vi_advance_point ();
729 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
730 _rl_vi_advance_point ();
732 opoint = rl_point;
733 if (rl_point < rl_end)
735 if (_rl_isident (rl_line_buffer[rl_point]))
738 opoint = _rl_vi_advance_point ();
740 while (rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
741 else
744 opoint = _rl_vi_advance_point ();
746 while (rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
747 && !whitespace (rl_line_buffer[rl_point]));
749 rl_point = opoint;
751 return (0);
755 rl_vi_insert_beg (int count, int key)
757 rl_beg_of_line (1, key);
758 rl_vi_insert_mode (1, key);
759 return (0);
762 static void
763 _rl_vi_append_forward (int key)
765 _rl_vi_advance_point ();
769 rl_vi_append_mode (int count, int key)
771 _rl_vi_append_forward (key);
772 rl_vi_start_inserting (key, 1, rl_arg_sign);
773 return (0);
777 rl_vi_append_eol (int count, int key)
779 rl_end_of_line (1, key);
780 rl_vi_append_mode (1, key);
781 return (0);
784 /* What to do in the case of C-d. */
786 rl_vi_eof_maybe (int count, int c)
788 return (rl_newline (1, '\n'));
791 /* Insertion mode stuff. */
793 /* Switching from one mode to the other really just involves
794 switching keymaps. */
796 rl_vi_insertion_mode (int count, int key)
798 _rl_keymap = vi_insertion_keymap;
799 _rl_vi_last_key_before_insert = key;
800 if (_rl_show_mode_in_prompt)
801 _rl_reset_prompt ();
802 return (0);
806 rl_vi_insert_mode (int count, int key)
808 rl_vi_start_inserting (key, 1, rl_arg_sign);
809 return (0);
812 static void
813 vi_save_insert_buffer (int start, int len)
815 /* Same code as _rl_vi_save_insert below */
816 if (len >= vi_insert_buffer_size)
818 vi_insert_buffer_size += (len + 32) - (len % 32);
819 vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
821 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
822 vi_insert_buffer[len-1] = '\0';
825 static void
826 _rl_vi_save_replace (void)
828 int len, start, end;
829 UNDO_LIST *up;
831 up = rl_undo_list;
832 if (up == 0 || up->what != UNDO_END || vi_replace_count <= 0)
834 if (vi_insert_buffer_size >= 1)
835 vi_insert_buffer[0] = '\0';
836 return;
838 /* Let's try it the quick and easy way for now. This should essentially
839 accommodate every UNDO_INSERT and save the inserted text to
840 vi_insert_buffer */
841 end = rl_point;
842 start = end - vi_replace_count + 1;
843 len = vi_replace_count + 1;
845 if (start < 0)
847 len = end + 1;
848 start = 0;
851 vi_save_insert_buffer (start, len);
854 static void
855 _rl_vi_save_insert (UNDO_LIST *up)
857 int len, start, end;
859 if (up == 0 || up->what != UNDO_INSERT)
861 if (vi_insert_buffer_size >= 1)
862 vi_insert_buffer[0] = '\0';
863 return;
866 start = up->start;
867 end = up->end;
868 len = end - start + 1;
870 vi_save_insert_buffer (start, len);
873 void
874 _rl_vi_done_inserting (void)
876 if (_rl_vi_doing_insert)
878 /* The `c', `s', `S', and `R' commands set this. */
879 rl_end_undo_group (); /* for the group in rl_vi_start_inserting */
880 /* Now, the text between rl_undo_list->next->start and
881 rl_undo_list->next->end is what was inserted while in insert
882 mode. It gets copied to VI_INSERT_BUFFER because it depends
883 on absolute indices into the line which may change (though they
884 probably will not). */
885 _rl_vi_doing_insert = 0;
886 if (_rl_vi_last_key_before_insert == 'R')
887 _rl_vi_save_replace (); /* Half the battle */
888 else
889 _rl_vi_save_insert (rl_undo_list->next);
890 /* sanity check, should always be >= 1 here */
891 if (_rl_undo_group_level > 0)
892 rl_end_undo_group (); /* for the group in the command (change or replace) */
894 else
896 if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' ||
897 _rl_vi_last_key_before_insert == 'a' ||
898 _rl_vi_last_key_before_insert == 'I' ||
899 _rl_vi_last_key_before_insert == 'A'))
900 _rl_vi_save_insert (rl_undo_list);
901 /* XXX - Other keys probably need to be checked. */
902 else if (_rl_vi_last_key_before_insert == 'C')
903 rl_end_undo_group ();
906 /* Sanity check, make sure all the undo groups are closed before we leave
907 insert mode */
908 while (_rl_undo_group_level > 0)
909 rl_end_undo_group ();
913 rl_vi_movement_mode (int count, int key)
915 if (rl_point > 0)
916 rl_backward_char (1, key);
918 _rl_keymap = vi_movement_keymap;
919 _rl_vi_done_inserting ();
921 /* This is how POSIX.2 says `U' should behave -- everything up until the
922 first time you go into command mode should not be undone. */
923 if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
924 rl_free_undo_list ();
926 if (_rl_show_mode_in_prompt)
927 _rl_reset_prompt ();
929 RL_SETSTATE (RL_STATE_VICMDONCE);
930 return (0);
934 rl_vi_arg_digit (int count, int c)
936 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
937 return (rl_beg_of_line (1, c));
938 else
939 return (rl_digit_argument (count, c));
942 /* Change the case of the next COUNT characters. */
943 #if defined (HANDLE_MULTIBYTE)
944 static int
945 _rl_vi_change_mbchar_case (int count)
947 wchar_t wc;
948 char mb[MB_LEN_MAX+1];
949 int mlen, p;
950 size_t m;
951 mbstate_t ps;
953 memset (&ps, 0, sizeof (mbstate_t));
954 if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
955 count--;
956 while (count-- && rl_point < rl_end)
958 m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
959 if (MB_INVALIDCH (m))
960 wc = (wchar_t)rl_line_buffer[rl_point];
961 else if (MB_NULLWCH (m))
962 wc = L'\0';
963 if (iswupper (wc))
964 wc = towlower (wc);
965 else if (iswlower (wc))
966 wc = towupper (wc);
967 else
969 /* Just skip over chars neither upper nor lower case */
970 rl_forward_char (1, 0);
971 continue;
974 /* Vi is kind of strange here. */
975 if (wc)
977 p = rl_point;
978 mlen = wcrtomb (mb, wc, &ps);
979 if (mlen >= 0)
980 mb[mlen] = '\0';
981 rl_begin_undo_group ();
982 rl_vi_delete (1, 0);
983 if (rl_point < p) /* Did we retreat at EOL? */
984 _rl_vi_advance_point ();
985 rl_insert_text (mb);
986 rl_end_undo_group ();
987 rl_vi_check ();
989 else
990 rl_forward_char (1, 0);
993 return 0;
995 #endif
998 rl_vi_change_case (int count, int ignore)
1000 int c, p;
1002 /* Don't try this on an empty line. */
1003 if (rl_point >= rl_end)
1004 return (0);
1006 c = 0;
1007 #if defined (HANDLE_MULTIBYTE)
1008 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1009 return (_rl_vi_change_mbchar_case (count));
1010 #endif
1012 while (count-- && rl_point < rl_end)
1014 if (_rl_uppercase_p (rl_line_buffer[rl_point]))
1015 c = _rl_to_lower (rl_line_buffer[rl_point]);
1016 else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
1017 c = _rl_to_upper (rl_line_buffer[rl_point]);
1018 else
1020 /* Just skip over characters neither upper nor lower case. */
1021 rl_forward_char (1, c);
1022 continue;
1025 /* Vi is kind of strange here. */
1026 if (c)
1028 p = rl_point;
1029 rl_begin_undo_group ();
1030 rl_vi_delete (1, c);
1031 if (rl_point < p) /* Did we retreat at EOL? */
1032 rl_point++;
1033 _rl_insert_char (1, c);
1034 rl_end_undo_group ();
1035 rl_vi_check ();
1037 else
1038 rl_forward_char (1, c);
1040 return (0);
1044 rl_vi_put (int count, int key)
1046 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
1047 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
1049 while (count--)
1050 rl_yank (1, key);
1052 rl_backward_char (1, key);
1053 return (0);
1056 /* Move the cursor back one character if you're at the end of the line */
1058 rl_vi_check (void)
1060 if (rl_point && rl_point == rl_end)
1061 _rl_vi_backup ();
1062 return (0);
1065 /* Move to the character position specified by COUNT */
1067 rl_vi_column (int count, int key)
1069 if (count > rl_end)
1070 rl_end_of_line (1, key);
1071 else
1073 rl_point = 0;
1074 rl_point = _rl_forward_char_internal (count - 1);
1076 return (0);
1079 /* Process C as part of the current numeric argument. Return -1 if the
1080 argument should be aborted, 0 if we should not read any more chars, and
1081 1 if we should continue to read chars. */
1082 static int
1083 _rl_vi_arg_dispatch (int c)
1085 int key;
1087 key = c;
1088 if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
1090 rl_numeric_arg *= 4;
1091 return 1;
1094 c = UNMETA (c);
1096 if (_rl_digit_p (c))
1098 if (rl_explicit_arg)
1099 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
1100 else
1101 rl_numeric_arg = _rl_digit_value (c);
1102 rl_explicit_arg = 1;
1103 return 1; /* keep going */
1105 else
1107 rl_clear_message ();
1108 rl_stuff_char (key);
1109 return 0; /* done */
1113 /* A simplified loop for vi. Don't dispatch key at end.
1114 Don't recognize minus sign?
1115 Should this do rl_save_prompt/rl_restore_prompt? */
1116 static int
1117 rl_digit_loop1 (void)
1119 int c, r;
1121 while (1)
1123 if (_rl_arg_overflow ())
1124 return 1;
1126 c = _rl_arg_getchar ();
1128 r = _rl_vi_arg_dispatch (c);
1129 if (r <= 0)
1130 break;
1133 RL_UNSETSTATE(RL_STATE_NUMERICARG);
1134 return (0);
1137 /* This set of functions is basically to handle the commands that take a
1138 motion argument while in callback mode: read the command, read the motion
1139 command modifier, find the extent of the text to affect, and dispatch the
1140 command for execution. */
1141 static void
1142 _rl_mvcxt_init (_rl_vimotion_cxt *m, int op, int key)
1144 m->op = op;
1145 m->state = m->flags = 0;
1146 m->ncxt = 0;
1147 m->numeric_arg = -1;
1148 m->start = rl_point;
1149 m->end = rl_end;
1150 m->key = key;
1151 m->motion = -1;
1154 static _rl_vimotion_cxt *
1155 _rl_mvcxt_alloc (int op, int key)
1157 _rl_vimotion_cxt *m;
1159 m = xmalloc (sizeof (_rl_vimotion_cxt));
1160 _rl_mvcxt_init (m, op, key);
1161 return m;
1164 static void
1165 _rl_mvcxt_dispose (_rl_vimotion_cxt *m)
1167 xfree (m);
1170 static int
1171 rl_domove_motion_callback (_rl_vimotion_cxt *m)
1173 int c;
1175 _rl_vi_last_motion = c = m->motion;
1177 /* Append a blank character temporarily so that the motion routines
1178 work right at the end of the line. Original value of rl_end is saved
1179 as m->end. */
1180 rl_extend_line_buffer (rl_end + 1);
1181 rl_line_buffer[rl_end++] = ' ';
1182 rl_line_buffer[rl_end] = '\0';
1184 _rl_dispatch (c, _rl_keymap);
1186 #if defined (READLINE_CALLBACKS)
1187 if (RL_ISSTATE (RL_STATE_CALLBACK))
1189 /* Messy case where char search can be vi motion command; see rest of
1190 details in callback.c. vi_char_search and callback_char_search just
1191 set and unset the CHARSEARCH state. This is where any vi motion
1192 command that needs to set its own state should be handled, with any
1193 corresponding code to manage that state in callback.c */
1194 if (RL_ISSTATE (RL_STATE_CHARSEARCH))
1195 return 0;
1196 else
1197 return (_rl_vi_domove_motion_cleanup (c, m));
1199 #endif
1201 return (_rl_vi_domove_motion_cleanup (c, m));
1205 _rl_vi_domove_motion_cleanup (int c, _rl_vimotion_cxt *m)
1207 int r;
1209 /* Remove the blank that we added in rl_domove_motion_callback. */
1210 rl_end = m->end;
1211 rl_line_buffer[rl_end] = '\0';
1212 _rl_fix_point (0);
1214 /* No change in position means the command failed. */
1215 if (rl_mark == rl_point)
1217 /* 'c' and 'C' enter insert mode after the delete even if the motion
1218 didn't delete anything, as long as the motion command is valid. */
1219 if (_rl_to_upper (m->key) == 'C' && _rl_vi_motion_command (c))
1220 return (vidomove_dispatch (m));
1221 RL_UNSETSTATE (RL_STATE_VIMOTION);
1222 return (-1);
1225 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
1226 word. If we are not at the end of the line, and we are on a
1227 non-whitespace character, move back one (presumably to whitespace). */
1228 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
1229 !whitespace (rl_line_buffer[rl_point]))
1230 rl_point--; /* XXX */
1232 /* If cw or cW, back up to the end of a word, so the behaviour of ce
1233 or cE is the actual result. Brute-force, no subtlety. */
1234 if (m->key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
1236 /* Don't move farther back than where we started. */
1237 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
1238 rl_point--;
1240 /* Posix.2 says that if cw or cW moves the cursor towards the end of
1241 the line, the character under the cursor should be deleted. */
1242 if (rl_point == rl_mark)
1243 _rl_vi_advance_point ();
1244 else
1246 /* Move past the end of the word so that the kill doesn't
1247 remove the last letter of the previous word. Only do this
1248 if we are not at the end of the line. */
1249 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
1250 _rl_vi_advance_point ();
1254 if (rl_mark < rl_point)
1255 SWAP (rl_point, rl_mark);
1257 #if defined (READLINE_CALLBACKS)
1258 if (RL_ISSTATE (RL_STATE_CALLBACK))
1259 (*rl_redisplay_function)(); /* make sure motion is displayed */
1260 #endif
1262 r = vidomove_dispatch (m);
1264 return (r);
1267 #define RL_VIMOVENUMARG() (RL_ISSTATE (RL_STATE_VIMOTION) && RL_ISSTATE (RL_STATE_NUMERICARG))
1269 static int
1270 rl_domove_read_callback (_rl_vimotion_cxt *m)
1272 int c, save;
1274 c = m->motion;
1276 if (member (c, vi_motion))
1278 #if defined (READLINE_CALLBACKS)
1279 /* If we just read a vi-mode motion command numeric argument, turn off
1280 the `reading numeric arg' state */
1281 if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1282 RL_UNSETSTATE (RL_STATE_NUMERICARG);
1283 #endif
1284 /* Should do everything, including turning off RL_STATE_VIMOTION */
1285 return (rl_domove_motion_callback (m));
1287 else if (m->key == c && (m->key == 'd' || m->key == 'y' || m->key == 'c'))
1289 rl_mark = rl_end;
1290 rl_beg_of_line (1, c);
1291 _rl_vi_last_motion = c;
1292 RL_UNSETSTATE (RL_STATE_VIMOTION);
1293 return (vidomove_dispatch (m));
1295 #if defined (READLINE_CALLBACKS)
1296 /* XXX - these need to handle rl_universal_argument bindings */
1297 /* Reading vi motion char continuing numeric argument */
1298 else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1300 return (_rl_vi_arg_dispatch (c));
1302 /* Readine vi motion char starting numeric argument */
1303 else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_VIMOTION) && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
1305 RL_SETSTATE (RL_STATE_NUMERICARG);
1306 return (_rl_vi_arg_dispatch (c));
1308 #endif
1309 else if (_rl_digit_p (c))
1311 /* This code path taken when not in callback mode */
1312 save = rl_numeric_arg;
1313 rl_numeric_arg = _rl_digit_value (c);
1314 rl_explicit_arg = 1;
1315 RL_SETSTATE (RL_STATE_NUMERICARG);
1316 rl_digit_loop1 ();
1317 rl_numeric_arg *= save;
1318 c = rl_vi_domove_getchar (m);
1319 if (c < 0)
1321 m->motion = 0;
1322 return -1;
1324 m->motion = c;
1325 return (rl_domove_motion_callback (m));
1327 else
1329 RL_UNSETSTATE (RL_STATE_VIMOTION);
1330 RL_UNSETSTATE (RL_STATE_NUMERICARG);
1331 return (1);
1335 static int
1336 rl_vi_domove_getchar (_rl_vimotion_cxt *m)
1338 return (_rl_bracketed_read_key ());
1341 #if defined (READLINE_CALLBACKS)
1343 _rl_vi_domove_callback (_rl_vimotion_cxt *m)
1345 int c, r;
1347 m->motion = c = rl_vi_domove_getchar (m);
1348 if (c < 0)
1349 return 1; /* EOF */
1350 r = rl_domove_read_callback (m);
1352 return ((r == 0) ? r : 1); /* normalize return values */
1354 #endif
1356 /* This code path is taken when not in callback mode. */
1358 rl_vi_domove (int x, int *ignore)
1360 int r;
1361 _rl_vimotion_cxt *m;
1363 m = _rl_vimvcxt;
1364 *ignore = m->motion = rl_vi_domove_getchar (m);
1366 if (m->motion < 0)
1368 m->motion = 0;
1369 return -1;
1372 return (rl_domove_read_callback (m));
1375 static int
1376 vi_delete_dispatch (_rl_vimotion_cxt *m)
1378 /* These are the motion commands that do not require adjusting the
1379 mark. */
1380 if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1381 (rl_mark < rl_end))
1382 INCREMENT_POS (rl_mark);
1384 rl_kill_text (rl_point, rl_mark);
1385 return (0);
1389 rl_vi_delete_to (int count, int key)
1391 int c, r;
1393 if (_rl_vimvcxt)
1394 _rl_mvcxt_init (_rl_vimvcxt, VIM_DELETE, key);
1395 else
1396 _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
1398 _rl_vimvcxt->start = rl_point;
1400 rl_mark = rl_point;
1401 if (_rl_uppercase_p (key))
1403 _rl_vimvcxt->motion = '$';
1404 r = rl_domove_motion_callback (_rl_vimvcxt);
1406 else if (_rl_vi_redoing && _rl_vi_last_motion != 'd') /* `dd' is special */
1408 _rl_vimvcxt->motion = _rl_vi_last_motion;
1409 r = rl_domove_motion_callback (_rl_vimvcxt);
1411 else if (_rl_vi_redoing) /* handle redoing `dd' here */
1413 _rl_vimvcxt->motion = _rl_vi_last_motion;
1414 rl_mark = rl_end;
1415 rl_beg_of_line (1, key);
1416 RL_UNSETSTATE (RL_STATE_VIMOTION);
1417 r = vidomove_dispatch (_rl_vimvcxt);
1419 #if defined (READLINE_CALLBACKS)
1420 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1422 RL_SETSTATE (RL_STATE_VIMOTION);
1423 return (0);
1425 #endif
1426 else
1427 r = rl_vi_domove (key, &c);
1429 if (r < 0)
1431 rl_ding ();
1432 r = -1;
1435 _rl_mvcxt_dispose (_rl_vimvcxt);
1436 _rl_vimvcxt = 0;
1438 return r;
1441 static int
1442 vi_change_dispatch (_rl_vimotion_cxt *m)
1444 /* These are the motion commands that do not require adjusting the
1445 mark. c[wW] are handled by special-case code in rl_vi_domove(),
1446 and already leave the mark at the correct location. */
1447 if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1448 (rl_mark < rl_end))
1449 INCREMENT_POS (rl_mark);
1451 /* The cursor never moves with c[wW]. */
1452 if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
1453 rl_point = m->start;
1455 if (_rl_vi_redoing)
1457 if (vi_insert_buffer && *vi_insert_buffer)
1458 rl_begin_undo_group ();
1459 rl_delete_text (rl_point, rl_mark);
1460 if (vi_insert_buffer && *vi_insert_buffer)
1462 rl_insert_text (vi_insert_buffer);
1463 rl_end_undo_group ();
1466 else
1468 rl_begin_undo_group (); /* to make the `u' command work */
1469 rl_kill_text (rl_point, rl_mark);
1470 /* `C' does not save the text inserted for undoing or redoing. */
1471 if (_rl_uppercase_p (m->key) == 0)
1472 _rl_vi_doing_insert = 1;
1473 /* XXX -- TODO -- use m->numericarg? */
1474 rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign);
1477 return (0);
1481 rl_vi_change_to (int count, int key)
1483 int c, r;
1485 if (_rl_vimvcxt)
1486 _rl_mvcxt_init (_rl_vimvcxt, VIM_CHANGE, key);
1487 else
1488 _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
1489 _rl_vimvcxt->start = rl_point;
1491 rl_mark = rl_point;
1492 if (_rl_uppercase_p (key))
1494 _rl_vimvcxt->motion = '$';
1495 r = rl_domove_motion_callback (_rl_vimvcxt);
1497 else if (_rl_vi_redoing && _rl_vi_last_motion != 'c') /* `cc' is special */
1499 _rl_vimvcxt->motion = _rl_vi_last_motion;
1500 r = rl_domove_motion_callback (_rl_vimvcxt);
1502 else if (_rl_vi_redoing) /* handle redoing `cc' here */
1504 _rl_vimvcxt->motion = _rl_vi_last_motion;
1505 rl_mark = rl_end;
1506 rl_beg_of_line (1, key);
1507 RL_UNSETSTATE (RL_STATE_VIMOTION);
1508 r = vidomove_dispatch (_rl_vimvcxt);
1510 #if defined (READLINE_CALLBACKS)
1511 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1513 RL_SETSTATE (RL_STATE_VIMOTION);
1514 return (0);
1516 #endif
1517 else
1518 r = rl_vi_domove (key, &c);
1520 if (r < 0)
1522 rl_ding ();
1523 r = -1; /* normalize return value */
1526 _rl_mvcxt_dispose (_rl_vimvcxt);
1527 _rl_vimvcxt = 0;
1529 return r;
1532 static int
1533 vi_yank_dispatch (_rl_vimotion_cxt *m)
1535 /* These are the motion commands that do not require adjusting the
1536 mark. */
1537 if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1538 (rl_mark < rl_end))
1539 INCREMENT_POS (rl_mark);
1541 rl_begin_undo_group ();
1542 rl_kill_text (rl_point, rl_mark);
1543 rl_end_undo_group ();
1544 rl_do_undo ();
1545 rl_point = m->start;
1547 _rl_fix_point (1);
1549 return (0);
1553 rl_vi_yank_to (int count, int key)
1555 int c, r;
1557 if (_rl_vimvcxt)
1558 _rl_mvcxt_init (_rl_vimvcxt, VIM_YANK, key);
1559 else
1560 _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
1561 _rl_vimvcxt->start = rl_point;
1563 rl_mark = rl_point;
1564 if (_rl_uppercase_p (key))
1566 _rl_vimvcxt->motion = '$';
1567 r = rl_domove_motion_callback (_rl_vimvcxt);
1569 else if (_rl_vi_redoing && _rl_vi_last_motion != 'y') /* `yy' is special */
1571 _rl_vimvcxt->motion = _rl_vi_last_motion;
1572 r = rl_domove_motion_callback (_rl_vimvcxt);
1574 else if (_rl_vi_redoing) /* handle redoing `yy' here */
1576 _rl_vimvcxt->motion = _rl_vi_last_motion;
1577 rl_mark = rl_end;
1578 rl_beg_of_line (1, key);
1579 RL_UNSETSTATE (RL_STATE_VIMOTION);
1580 r = vidomove_dispatch (_rl_vimvcxt);
1582 #if defined (READLINE_CALLBACKS)
1583 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1585 RL_SETSTATE (RL_STATE_VIMOTION);
1586 return (0);
1588 #endif
1589 else
1590 r = rl_vi_domove (key, &c);
1592 if (r < 0)
1594 rl_ding ();
1595 r = -1;
1598 _rl_mvcxt_dispose (_rl_vimvcxt);
1599 _rl_vimvcxt = 0;
1601 return r;
1604 static int
1605 vidomove_dispatch (_rl_vimotion_cxt *m)
1607 int r;
1609 switch (m->op)
1611 case VIM_DELETE:
1612 r = vi_delete_dispatch (m);
1613 break;
1614 case VIM_CHANGE:
1615 r = vi_change_dispatch (m);
1616 break;
1617 case VIM_YANK:
1618 r = vi_yank_dispatch (m);
1619 break;
1620 default:
1621 _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op);
1622 r = 1;
1623 break;
1626 RL_UNSETSTATE (RL_STATE_VIMOTION);
1627 return r;
1631 rl_vi_rubout (int count, int key)
1633 int opoint;
1635 if (count < 0)
1636 return (rl_vi_delete (-count, key));
1638 if (rl_point == 0)
1640 rl_ding ();
1641 return 1;
1644 opoint = rl_point;
1645 if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1646 rl_backward_char (count, key);
1647 else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1648 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1649 else
1650 rl_point -= count;
1652 if (rl_point < 0)
1653 rl_point = 0;
1655 rl_kill_text (rl_point, opoint);
1657 return (0);
1661 rl_vi_delete (int count, int key)
1663 int end;
1665 if (count < 0)
1666 return (rl_vi_rubout (-count, key));
1668 if (rl_end == 0)
1670 rl_ding ();
1671 return 1;
1674 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1675 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1676 else
1677 end = rl_point + count;
1679 if (end >= rl_end)
1680 end = rl_end;
1682 rl_kill_text (rl_point, end);
1684 if (rl_point > 0 && rl_point == rl_end)
1685 rl_backward_char (1, key);
1687 return (0);
1690 /* This does what Posix specifies vi-mode C-w to do: using whitespace and
1691 punctuation characters as the word boundaries. */
1693 #define vi_unix_word_boundary(c) (whitespace(c) || ispunct(c))
1696 rl_vi_unix_word_rubout (int count, int key)
1698 int orig_point;
1700 if (rl_point == 0)
1701 rl_ding ();
1702 else
1704 orig_point = rl_point;
1705 if (count <= 0)
1706 count = 1;
1708 while (count--)
1710 /* This isn't quite what ksh93 does but it seems to match what the
1711 Posix description of sh specifies, with a few accommodations
1712 for sequences of whitespace characters between words and at
1713 the end of the line. */
1715 /* Skip over whitespace at the end of the line as a special case */
1716 if (rl_point > 0 && (rl_line_buffer[rl_point] == 0) &&
1717 whitespace (rl_line_buffer[rl_point - 1]))
1718 while (--rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
1721 /* If we're at the start of a word, move back to word boundary so we
1722 move back to the `preceding' word */
1723 if (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0) &&
1724 vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
1725 rl_point--;
1727 /* If we are at a word boundary (whitespace/punct), move backward
1728 past a sequence of word boundary characters. If we are at the
1729 end of a word (non-word boundary), move back to a word boundary */
1730 if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]))
1731 while (rl_point && vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
1732 rl_point--;
1733 else if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0)
1734 while (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point - 1]) == 0))
1735 _rl_vi_backup_point ();
1738 rl_kill_text (orig_point, rl_point);
1741 return 0;
1746 rl_vi_back_to_indent (int count, int key)
1748 rl_beg_of_line (1, key);
1749 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1750 rl_point++;
1751 return (0);
1755 rl_vi_first_print (int count, int key)
1757 return (rl_vi_back_to_indent (1, key));
1760 static int _rl_cs_dir, _rl_cs_orig_dir;
1762 #if defined (READLINE_CALLBACKS)
1763 static int
1764 _rl_vi_callback_char_search (_rl_callback_generic_arg *data)
1766 int c;
1767 #if defined (HANDLE_MULTIBYTE)
1768 c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1769 #else
1770 RL_SETSTATE(RL_STATE_MOREINPUT);
1771 c = rl_read_key ();
1772 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1773 #endif
1775 if (c <= 0)
1777 RL_UNSETSTATE (RL_STATE_CHARSEARCH);
1778 return -1;
1781 #if !defined (HANDLE_MULTIBYTE)
1782 _rl_vi_last_search_char = c;
1783 #endif
1785 _rl_callback_func = 0;
1786 _rl_want_redisplay = 1;
1787 RL_UNSETSTATE (RL_STATE_CHARSEARCH);
1789 #if defined (HANDLE_MULTIBYTE)
1790 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1791 #else
1792 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1793 #endif
1795 #endif
1798 rl_vi_char_search (int count, int key)
1800 int c;
1801 #if defined (HANDLE_MULTIBYTE)
1802 static char *target;
1803 static int tlen;
1804 #else
1805 static char target;
1806 #endif
1808 if (key == ';' || key == ',')
1810 if (_rl_cs_orig_dir == 0)
1811 return 1;
1812 #if defined (HANDLE_MULTIBYTE)
1813 if (_rl_vi_last_search_mblen == 0)
1814 return 1;
1815 #else
1816 if (_rl_vi_last_search_char == 0)
1817 return 1;
1818 #endif
1819 _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1821 else
1823 switch (key)
1825 case 't':
1826 _rl_cs_orig_dir = _rl_cs_dir = FTO;
1827 break;
1829 case 'T':
1830 _rl_cs_orig_dir = _rl_cs_dir = BTO;
1831 break;
1833 case 'f':
1834 _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1835 break;
1837 case 'F':
1838 _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1839 break;
1842 if (_rl_vi_redoing)
1844 /* set target and tlen below */
1846 #if defined (READLINE_CALLBACKS)
1847 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1849 _rl_callback_data = _rl_callback_data_alloc (count);
1850 _rl_callback_data->i1 = _rl_cs_dir;
1851 _rl_callback_data->i2 = key;
1852 _rl_callback_func = _rl_vi_callback_char_search;
1853 RL_SETSTATE (RL_STATE_CHARSEARCH);
1854 return (0);
1856 #endif
1857 else
1859 #if defined (HANDLE_MULTIBYTE)
1860 c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1861 if (c <= 0)
1862 return -1;
1863 _rl_vi_last_search_mblen = c;
1864 #else
1865 RL_SETSTATE(RL_STATE_MOREINPUT);
1866 c = rl_read_key ();
1867 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1868 if (c < 0)
1869 return -1;
1870 _rl_vi_last_search_char = c;
1871 #endif
1875 #if defined (HANDLE_MULTIBYTE)
1876 target = _rl_vi_last_search_mbchar;
1877 tlen = _rl_vi_last_search_mblen;
1878 #else
1879 target = _rl_vi_last_search_char;
1880 #endif
1882 #if defined (HANDLE_MULTIBYTE)
1883 return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1884 #else
1885 return (_rl_char_search_internal (count, _rl_cs_dir, target));
1886 #endif
1889 /* Match brackets */
1891 rl_vi_match (int ignore, int key)
1893 int count = 1, brack, pos, tmp, pre;
1895 pos = rl_point;
1896 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1898 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1900 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1902 pre = rl_point;
1903 rl_forward_char (1, key);
1904 if (pre == rl_point)
1905 break;
1908 else
1909 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1910 rl_point < rl_end - 1)
1911 rl_forward_char (1, key);
1913 if (brack <= 0)
1915 rl_point = pos;
1916 rl_ding ();
1917 return 1;
1921 pos = rl_point;
1923 if (brack < 0)
1925 while (count)
1927 tmp = pos;
1928 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1929 pos--;
1930 else
1932 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1933 if (tmp == pos)
1934 pos--;
1936 if (pos >= 0)
1938 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1939 if (b == -brack)
1940 count--;
1941 else if (b == brack)
1942 count++;
1944 else
1946 rl_ding ();
1947 return 1;
1951 else
1952 { /* brack > 0 */
1953 while (count)
1955 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1956 pos++;
1957 else
1958 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1960 if (pos < rl_end)
1962 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1963 if (b == -brack)
1964 count--;
1965 else if (b == brack)
1966 count++;
1968 else
1970 rl_ding ();
1971 return 1;
1975 rl_point = pos;
1976 return (0);
1980 rl_vi_bracktype (int c)
1982 switch (c)
1984 case '(': return 1;
1985 case ')': return -1;
1986 case '[': return 2;
1987 case ']': return -2;
1988 case '{': return 3;
1989 case '}': return -3;
1990 default: return 0;
1994 static int
1995 _rl_vi_change_char (int count, int c, char *mb)
1997 int p;
1999 if (c == '\033' || c == CTRL ('C'))
2000 return -1;
2002 rl_begin_undo_group ();
2003 while (count-- && rl_point < rl_end)
2005 p = rl_point;
2006 rl_vi_delete (1, c);
2007 if (rl_point < p) /* Did we retreat at EOL? */
2008 _rl_vi_append_forward (c);
2009 #if defined (HANDLE_MULTIBYTE)
2010 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
2011 rl_insert_text (mb);
2012 else
2013 #endif
2014 _rl_insert_char (1, c);
2017 /* The cursor shall be left on the last character changed. */
2018 rl_backward_char (1, c);
2020 rl_end_undo_group ();
2022 return (0);
2025 static int
2026 _rl_vi_callback_getchar (char *mb, int mlen)
2028 return (_rl_bracketed_read_mbstring (mb, mlen));
2031 #if defined (READLINE_CALLBACKS)
2032 static int
2033 _rl_vi_callback_change_char (_rl_callback_generic_arg *data)
2035 int c;
2036 char mb[MB_LEN_MAX+1];
2038 c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
2039 #if defined (HANDLE_MULTIBYTE)
2040 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
2041 strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX);
2042 else
2043 #endif
2044 _rl_vi_last_replacement[0] = c;
2045 _rl_vi_last_replacement[MB_LEN_MAX] = '\0'; /* XXX */
2047 if (c < 0)
2048 return -1;
2050 _rl_callback_func = 0;
2051 _rl_want_redisplay = 1;
2053 return (_rl_vi_change_char (data->count, c, mb));
2055 #endif
2058 rl_vi_change_char (int count, int key)
2060 int c;
2061 char mb[MB_LEN_MAX+1];
2063 if (_rl_vi_redoing)
2065 strncpy (mb, _rl_vi_last_replacement, MB_LEN_MAX);
2066 c = (unsigned char)_rl_vi_last_replacement[0]; /* XXX */
2067 mb[MB_LEN_MAX] = '\0';
2069 #if defined (READLINE_CALLBACKS)
2070 else if (RL_ISSTATE (RL_STATE_CALLBACK))
2072 _rl_callback_data = _rl_callback_data_alloc (count);
2073 _rl_callback_func = _rl_vi_callback_change_char;
2074 return (0);
2076 #endif
2077 else
2079 c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
2080 #ifdef HANDLE_MULTIBYTE
2081 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
2082 strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX);
2083 else
2084 #endif
2085 _rl_vi_last_replacement[0] = c;
2086 _rl_vi_last_replacement[MB_LEN_MAX] = '\0'; /* just in case */
2089 if (c < 0)
2090 return -1;
2092 return (_rl_vi_change_char (count, c, mb));
2096 rl_vi_subst (int count, int key)
2098 /* If we are redoing, rl_vi_change_to will stuff the last motion char */
2099 if (_rl_vi_redoing == 0)
2100 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
2102 return (rl_vi_change_to (count, 'c'));
2106 rl_vi_overstrike (int count, int key)
2108 if (_rl_vi_doing_insert == 0)
2110 _rl_vi_doing_insert = 1;
2111 rl_begin_undo_group ();
2114 if (count > 0)
2116 _rl_overwrite_char (count, key);
2117 vi_replace_count += count;
2120 return (0);
2124 rl_vi_overstrike_delete (int count, int key)
2126 int i, s;
2128 for (i = 0; i < count; i++)
2130 if (vi_replace_count == 0)
2132 rl_ding ();
2133 break;
2135 s = rl_point;
2137 if (rl_do_undo ())
2138 vi_replace_count--; /* XXX */
2140 if (rl_point == s)
2141 rl_backward_char (1, key);
2144 if (vi_replace_count == 0 && _rl_vi_doing_insert)
2146 rl_end_undo_group ();
2147 rl_do_undo ();
2148 _rl_vi_doing_insert = 0;
2150 return (0);
2153 static int
2154 rl_vi_overstrike_kill_line (int count, int key)
2156 int r, end;
2158 end = rl_end;
2159 r = rl_unix_line_discard (count, key);
2160 vi_replace_count -= end - rl_end;
2161 return r;
2164 static int
2165 rl_vi_overstrike_kill_word (int count, int key)
2167 int r, end;
2169 end = rl_end;
2170 r = rl_vi_unix_word_rubout (count, key);
2171 vi_replace_count -= end - rl_end;
2172 return r;
2175 static int
2176 rl_vi_overstrike_yank (int count, int key)
2178 int r, end;
2180 end = rl_end;
2181 r = rl_yank (count, key);
2182 vi_replace_count += rl_end - end;
2183 return r;
2186 /* Read bracketed paste mode pasted text and insert it in overwrite mode */
2187 static int
2188 rl_vi_overstrike_bracketed_paste (int count, int key)
2190 int r;
2191 char *pbuf;
2192 size_t pblen;
2194 pbuf = _rl_bracketed_text (&pblen);
2195 if (pblen == 0)
2197 xfree (pbuf);
2198 return 0;
2200 r = pblen;
2201 while (--r >= 0)
2202 _rl_unget_char ((unsigned char)pbuf[r]);
2203 xfree (pbuf);
2205 while (_rl_pushed_input_available ())
2207 key = rl_read_key ();
2208 r = rl_vi_overstrike (1, key);
2211 return r;
2215 rl_vi_replace (int count, int key)
2217 int i;
2219 vi_replace_count = 0;
2221 if (vi_replace_map == 0)
2223 vi_replace_map = rl_make_bare_keymap ();
2225 for (i = 0; i < ' '; i++)
2226 if (vi_insertion_keymap[i].type == ISFUNC)
2227 vi_replace_map[i].function = vi_insertion_keymap[i].function;
2229 for (i = ' '; i < KEYMAP_SIZE; i++)
2230 vi_replace_map[i].function = rl_vi_overstrike;
2232 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
2234 /* Make sure these are what we want. */
2235 vi_replace_map[ESC].function = rl_vi_movement_mode;
2236 vi_replace_map[RETURN].function = rl_newline;
2237 vi_replace_map[NEWLINE].function = rl_newline;
2239 /* If the normal vi insertion keymap has ^H bound to erase, do the
2240 same here. Probably should remove the assignment to RUBOUT up
2241 there, but I don't think it will make a difference in real life. */
2242 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
2243 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
2244 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
2246 /* Same for ^U and unix-line-discard. */
2247 if (vi_insertion_keymap[CTRL ('U')].type == ISFUNC &&
2248 vi_insertion_keymap[CTRL ('U')].function == rl_unix_line_discard)
2249 vi_replace_map[CTRL ('U')].function = rl_vi_overstrike_kill_line;
2251 /* And for ^W and unix-word-rubout. */
2252 if (vi_insertion_keymap[CTRL ('W')].type == ISFUNC &&
2253 vi_insertion_keymap[CTRL ('W')].function == rl_vi_unix_word_rubout)
2254 vi_replace_map[CTRL ('W')].function = rl_vi_overstrike_kill_word;
2256 /* And finally for ^Y and yank. */
2257 if (vi_insertion_keymap[CTRL ('Y')].type == ISFUNC &&
2258 vi_insertion_keymap[CTRL ('Y')].function == rl_yank)
2259 vi_replace_map[CTRL ('Y')].function = rl_vi_overstrike_yank;
2261 /* Make sure this is the value we need. */
2262 vi_replace_map[ANYOTHERKEY].type = ISFUNC;
2263 vi_replace_map[ANYOTHERKEY].function = (rl_command_func_t *)NULL;
2266 rl_vi_start_inserting (key, 1, rl_arg_sign);
2268 _rl_vi_last_key_before_insert = 'R'; /* in case someone rebinds it */
2269 _rl_keymap = vi_replace_map;
2271 if (_rl_enable_bracketed_paste)
2272 rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_vi_overstrike_bracketed_paste);
2274 return (0);
2277 #if 0
2278 /* Try to complete the word we are standing on or the word that ends with
2279 the previous character. A space matches everything. Word delimiters are
2280 space and ;. */
2282 rl_vi_possible_completions (void)
2284 int save_pos = rl_point;
2286 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
2288 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
2289 rl_line_buffer[rl_point] != ';')
2290 _rl_vi_advance_point ();
2292 else if (rl_line_buffer[rl_point - 1] == ';')
2294 rl_ding ();
2295 return (0);
2298 rl_possible_completions ();
2299 rl_point = save_pos;
2301 return (0);
2303 #endif
2305 /* Functions to save and restore marks. */
2306 static int
2307 _rl_vi_set_mark (void)
2309 int ch;
2311 RL_SETSTATE(RL_STATE_MOREINPUT);
2312 ch = rl_read_key ();
2313 RL_UNSETSTATE(RL_STATE_MOREINPUT);
2315 if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
2317 rl_ding ();
2318 return 1;
2320 ch -= 'a';
2321 vi_mark_chars[ch] = rl_point;
2322 return 0;
2325 #if defined (READLINE_CALLBACKS)
2326 static int
2327 _rl_vi_callback_set_mark (_rl_callback_generic_arg *data)
2329 _rl_callback_func = 0;
2330 _rl_want_redisplay = 1;
2332 return (_rl_vi_set_mark ());
2334 #endif
2337 rl_vi_set_mark (int count, int key)
2339 #if defined (READLINE_CALLBACKS)
2340 if (RL_ISSTATE (RL_STATE_CALLBACK))
2342 _rl_callback_data = 0;
2343 _rl_callback_func = _rl_vi_callback_set_mark;
2344 return (0);
2346 #endif
2348 return (_rl_vi_set_mark ());
2351 static int
2352 _rl_vi_goto_mark (void)
2354 int ch;
2356 RL_SETSTATE(RL_STATE_MOREINPUT);
2357 ch = rl_read_key ();
2358 RL_UNSETSTATE(RL_STATE_MOREINPUT);
2360 if (ch == '`')
2362 rl_point = rl_mark;
2363 _rl_fix_point (1);
2364 return 0;
2366 else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
2368 rl_ding ();
2369 return 1;
2372 ch -= 'a';
2373 if (vi_mark_chars[ch] == -1)
2375 rl_ding ();
2376 return 1;
2378 rl_point = vi_mark_chars[ch];
2379 _rl_fix_point (1);
2380 return 0;
2383 #if defined (READLINE_CALLBACKS)
2384 static int
2385 _rl_vi_callback_goto_mark (_rl_callback_generic_arg *data)
2387 _rl_callback_func = 0;
2388 _rl_want_redisplay = 1;
2390 return (_rl_vi_goto_mark ());
2392 #endif
2395 rl_vi_goto_mark (int count, int key)
2397 #if defined (READLINE_CALLBACKS)
2398 if (RL_ISSTATE (RL_STATE_CALLBACK))
2400 _rl_callback_data = 0;
2401 _rl_callback_func = _rl_vi_callback_goto_mark;
2402 return (0);
2404 #endif
2406 return (_rl_vi_goto_mark ());
2408 #endif /* VI_MODE */