Pull up CVS idents from FreeBSD to match our current version.
[dragonfly.git] / contrib / readline-5.0 / vi_mode.c
blob74d8acbbc05ed830846bcfe7f33329d561e39f64
1 /* vi_mode.c -- A vi emulation mode for Bash.
2 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
4 /* Copyright (C) 1987-2004 Free Software Foundation, Inc.
6 This file is part of the GNU Readline Library, a library for
7 reading lines of text with interactive input and history editing.
9 The GNU Readline Library is free software; you can redistribute it
10 and/or modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2, or
12 (at your option) any later version.
14 The GNU Readline Library is distributed in the hope that it will be
15 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 The GNU General Public License is often shipped with GNU software, and
20 is generally kept in a file called COPYING or LICENSE. If you do not
21 have a copy of the license, write to the Free Software Foundation,
22 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #define READLINE_LIBRARY
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 int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
68 /* Non-zero means enter insertion mode. */
69 static int _rl_vi_doing_insert;
71 /* Command keys which do movement for xxx_to commands. */
72 static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|";
74 /* Keymap used for vi replace characters. Created dynamically since
75 rarely used. */
76 static Keymap vi_replace_map;
78 /* The number of characters inserted in the last replace operation. */
79 static int vi_replace_count;
81 /* If non-zero, we have text inserted after a c[motion] command that put
82 us implicitly into insert mode. Some people want this text to be
83 attached to the command so that it is `redoable' with `.'. */
84 static int vi_continued_command;
85 static char *vi_insert_buffer;
86 static int vi_insert_buffer_size;
88 static int _rl_vi_last_repeat = 1;
89 static int _rl_vi_last_arg_sign = 1;
90 static int _rl_vi_last_motion;
91 #if defined (HANDLE_MULTIBYTE)
92 static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
93 #else
94 static int _rl_vi_last_search_char;
95 #endif
96 static int _rl_vi_last_replacement;
98 static int _rl_vi_last_key_before_insert;
100 static int vi_redoing;
102 /* Text modification commands. These are the `redoable' commands. */
103 static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
105 /* Arrays for the saved marks. */
106 static int vi_mark_chars['z' - 'a' + 1];
108 static void _rl_vi_stuff_insert PARAMS((int));
109 static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
110 static int rl_digit_loop1 PARAMS((void));
112 void
113 _rl_vi_initialize_line ()
115 register int i;
117 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
118 vi_mark_chars[i] = -1;
121 void
122 _rl_vi_reset_last ()
124 _rl_vi_last_command = 'i';
125 _rl_vi_last_repeat = 1;
126 _rl_vi_last_arg_sign = 1;
127 _rl_vi_last_motion = 0;
130 void
131 _rl_vi_set_last (key, repeat, sign)
132 int key, repeat, sign;
134 _rl_vi_last_command = key;
135 _rl_vi_last_repeat = repeat;
136 _rl_vi_last_arg_sign = sign;
139 /* A convenience function that calls _rl_vi_set_last to save the last command
140 information and enters insertion mode. */
141 void
142 rl_vi_start_inserting (key, repeat, sign)
143 int key, repeat, sign;
145 _rl_vi_set_last (key, repeat, sign);
146 rl_vi_insertion_mode (1, key);
149 /* Is the command C a VI mode text modification command? */
151 _rl_vi_textmod_command (c)
152 int c;
154 return (member (c, vi_textmod));
157 static void
158 _rl_vi_stuff_insert (count)
159 int count;
161 rl_begin_undo_group ();
162 while (count--)
163 rl_insert_text (vi_insert_buffer);
164 rl_end_undo_group ();
167 /* Bound to `.'. Called from command mode, so we know that we have to
168 redo a text modification command. The default for _rl_vi_last_command
169 puts you back into insert mode. */
171 rl_vi_redo (count, c)
172 int count, c;
174 int r;
176 if (!rl_explicit_arg)
178 rl_numeric_arg = _rl_vi_last_repeat;
179 rl_arg_sign = _rl_vi_last_arg_sign;
182 r = 0;
183 vi_redoing = 1;
184 /* If we're redoing an insert with `i', stuff in the inserted text
185 and do not go into insertion mode. */
186 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
188 _rl_vi_stuff_insert (count);
189 /* And back up point over the last character inserted. */
190 if (rl_point > 0)
191 rl_point--;
193 else
194 r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
195 vi_redoing = 0;
197 return (r);
200 /* A placeholder for further expansion. */
202 rl_vi_undo (count, key)
203 int count, key;
205 return (rl_undo_command (count, key));
208 /* Yank the nth arg from the previous line into this line at point. */
210 rl_vi_yank_arg (count, key)
211 int count, key;
213 /* Readline thinks that the first word on a line is the 0th, while vi
214 thinks the first word on a line is the 1st. Compensate. */
215 if (rl_explicit_arg)
216 rl_yank_nth_arg (count - 1, 0);
217 else
218 rl_yank_nth_arg ('$', 0);
220 return (0);
223 /* With an argument, move back that many history lines, else move to the
224 beginning of history. */
226 rl_vi_fetch_history (count, c)
227 int count, c;
229 int wanted;
231 /* Giving an argument of n means we want the nth command in the history
232 file. The command number is interpreted the same way that the bash
233 `history' command does it -- that is, giving an argument count of 450
234 to this command would get the command listed as number 450 in the
235 output of `history'. */
236 if (rl_explicit_arg)
238 wanted = history_base + where_history () - count;
239 if (wanted <= 0)
240 rl_beginning_of_history (0, 0);
241 else
242 rl_get_previous_history (wanted, c);
244 else
245 rl_beginning_of_history (count, 0);
246 return (0);
249 /* Search again for the last thing searched for. */
251 rl_vi_search_again (count, key)
252 int count, key;
254 switch (key)
256 case 'n':
257 rl_noninc_reverse_search_again (count, key);
258 break;
260 case 'N':
261 rl_noninc_forward_search_again (count, key);
262 break;
264 return (0);
267 /* Do a vi style search. */
269 rl_vi_search (count, key)
270 int count, key;
272 switch (key)
274 case '?':
275 rl_noninc_forward_search (count, key);
276 break;
278 case '/':
279 rl_noninc_reverse_search (count, key);
280 break;
282 default:
283 rl_ding ();
284 break;
286 return (0);
289 /* Completion, from vi's point of view. */
291 rl_vi_complete (ignore, key)
292 int ignore, key;
294 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
296 if (!whitespace (rl_line_buffer[rl_point + 1]))
297 rl_vi_end_word (1, 'E');
298 rl_point++;
301 if (key == '*')
302 rl_complete_internal ('*'); /* Expansion and replacement. */
303 else if (key == '=')
304 rl_complete_internal ('?'); /* List possible completions. */
305 else if (key == '\\')
306 rl_complete_internal (TAB); /* Standard Readline completion. */
307 else
308 rl_complete (0, key);
310 if (key == '*' || key == '\\')
311 rl_vi_start_inserting (key, 1, rl_arg_sign);
313 return (0);
316 /* Tilde expansion for vi mode. */
318 rl_vi_tilde_expand (ignore, key)
319 int ignore, key;
321 rl_tilde_expand (0, key);
322 rl_vi_start_inserting (key, 1, rl_arg_sign);
323 return (0);
326 /* Previous word in vi mode. */
328 rl_vi_prev_word (count, key)
329 int count, key;
331 if (count < 0)
332 return (rl_vi_next_word (-count, key));
334 if (rl_point == 0)
336 rl_ding ();
337 return (0);
340 if (_rl_uppercase_p (key))
341 rl_vi_bWord (count, key);
342 else
343 rl_vi_bword (count, key);
345 return (0);
348 /* Next word in vi mode. */
350 rl_vi_next_word (count, key)
351 int count, key;
353 if (count < 0)
354 return (rl_vi_prev_word (-count, key));
356 if (rl_point >= (rl_end - 1))
358 rl_ding ();
359 return (0);
362 if (_rl_uppercase_p (key))
363 rl_vi_fWord (count, key);
364 else
365 rl_vi_fword (count, key);
366 return (0);
369 /* Move to the end of the ?next? word. */
371 rl_vi_end_word (count, key)
372 int count, key;
374 if (count < 0)
376 rl_ding ();
377 return -1;
380 if (_rl_uppercase_p (key))
381 rl_vi_eWord (count, key);
382 else
383 rl_vi_eword (count, key);
384 return (0);
387 /* Move forward a word the way that 'W' does. */
389 rl_vi_fWord (count, ignore)
390 int count, ignore;
392 while (count-- && rl_point < (rl_end - 1))
394 /* Skip until whitespace. */
395 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
396 rl_point++;
398 /* Now skip whitespace. */
399 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
400 rl_point++;
402 return (0);
406 rl_vi_bWord (count, ignore)
407 int count, ignore;
409 while (count-- && rl_point > 0)
411 /* If we are at the start of a word, move back to whitespace so
412 we will go back to the start of the previous word. */
413 if (!whitespace (rl_line_buffer[rl_point]) &&
414 whitespace (rl_line_buffer[rl_point - 1]))
415 rl_point--;
417 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
418 rl_point--;
420 if (rl_point > 0)
422 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
423 rl_point++;
426 return (0);
430 rl_vi_eWord (count, ignore)
431 int count, ignore;
433 while (count-- && rl_point < (rl_end - 1))
435 if (!whitespace (rl_line_buffer[rl_point]))
436 rl_point++;
438 /* Move to the next non-whitespace character (to the start of the
439 next word). */
440 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
441 rl_point++;
443 if (rl_point && rl_point < rl_end)
445 /* Skip whitespace. */
446 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
447 rl_point++;
449 /* Skip until whitespace. */
450 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
451 rl_point++;
453 /* Move back to the last character of the word. */
454 rl_point--;
457 return (0);
461 rl_vi_fword (count, ignore)
462 int count, ignore;
464 while (count-- && rl_point < (rl_end - 1))
466 /* Move to white space (really non-identifer). */
467 if (_rl_isident (rl_line_buffer[rl_point]))
469 while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
470 rl_point++;
472 else /* if (!whitespace (rl_line_buffer[rl_point])) */
474 while (!_rl_isident (rl_line_buffer[rl_point]) &&
475 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
476 rl_point++;
479 /* Move past whitespace. */
480 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
481 rl_point++;
483 return (0);
487 rl_vi_bword (count, ignore)
488 int count, ignore;
490 while (count-- && rl_point > 0)
492 int last_is_ident;
494 /* If we are at the start of a word, move back to whitespace
495 so we will go back to the start of the previous word. */
496 if (!whitespace (rl_line_buffer[rl_point]) &&
497 whitespace (rl_line_buffer[rl_point - 1]))
498 rl_point--;
500 /* If this character and the previous character are `opposite', move
501 back so we don't get messed up by the rl_point++ down there in
502 the while loop. Without this code, words like `l;' screw up the
503 function. */
504 last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
505 if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
506 (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
507 rl_point--;
509 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
510 rl_point--;
512 if (rl_point > 0)
514 if (_rl_isident (rl_line_buffer[rl_point]))
515 while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
516 else
517 while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
518 !whitespace (rl_line_buffer[rl_point]));
519 rl_point++;
522 return (0);
526 rl_vi_eword (count, ignore)
527 int count, ignore;
529 while (count-- && rl_point < rl_end - 1)
531 if (!whitespace (rl_line_buffer[rl_point]))
532 rl_point++;
534 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
535 rl_point++;
537 if (rl_point < rl_end)
539 if (_rl_isident (rl_line_buffer[rl_point]))
540 while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
541 else
542 while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
543 && !whitespace (rl_line_buffer[rl_point]));
545 rl_point--;
547 return (0);
551 rl_vi_insert_beg (count, key)
552 int count, key;
554 rl_beg_of_line (1, key);
555 rl_vi_insertion_mode (1, key);
556 return (0);
560 rl_vi_append_mode (count, key)
561 int count, key;
563 if (rl_point < rl_end)
565 if (MB_CUR_MAX == 1 || rl_byte_oriented)
566 rl_point++;
567 else
569 int point = rl_point;
570 rl_forward_char (1, key);
571 if (point == rl_point)
572 rl_point = rl_end;
575 rl_vi_insertion_mode (1, key);
576 return (0);
580 rl_vi_append_eol (count, key)
581 int count, key;
583 rl_end_of_line (1, key);
584 rl_vi_append_mode (1, key);
585 return (0);
588 /* What to do in the case of C-d. */
590 rl_vi_eof_maybe (count, c)
591 int count, c;
593 return (rl_newline (1, '\n'));
596 /* Insertion mode stuff. */
598 /* Switching from one mode to the other really just involves
599 switching keymaps. */
601 rl_vi_insertion_mode (count, key)
602 int count, key;
604 _rl_keymap = vi_insertion_keymap;
605 _rl_vi_last_key_before_insert = key;
606 return (0);
609 static void
610 _rl_vi_save_insert (up)
611 UNDO_LIST *up;
613 int len, start, end;
615 if (up == 0)
617 if (vi_insert_buffer_size >= 1)
618 vi_insert_buffer[0] = '\0';
619 return;
622 start = up->start;
623 end = up->end;
624 len = end - start + 1;
625 if (len >= vi_insert_buffer_size)
627 vi_insert_buffer_size += (len + 32) - (len % 32);
628 vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
630 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
631 vi_insert_buffer[len-1] = '\0';
634 void
635 _rl_vi_done_inserting ()
637 if (_rl_vi_doing_insert)
639 /* The `C', `s', and `S' commands set this. */
640 rl_end_undo_group ();
641 /* Now, the text between rl_undo_list->next->start and
642 rl_undo_list->next->end is what was inserted while in insert
643 mode. It gets copied to VI_INSERT_BUFFER because it depends
644 on absolute indices into the line which may change (though they
645 probably will not). */
646 _rl_vi_doing_insert = 0;
647 _rl_vi_save_insert (rl_undo_list->next);
648 vi_continued_command = 1;
650 else
652 if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list)
653 _rl_vi_save_insert (rl_undo_list);
654 /* XXX - Other keys probably need to be checked. */
655 else if (_rl_vi_last_key_before_insert == 'C')
656 rl_end_undo_group ();
657 while (_rl_undo_group_level > 0)
658 rl_end_undo_group ();
659 vi_continued_command = 0;
664 rl_vi_movement_mode (count, key)
665 int count, key;
667 if (rl_point > 0)
668 rl_backward_char (1, key);
670 _rl_keymap = vi_movement_keymap;
671 _rl_vi_done_inserting ();
672 return (0);
676 rl_vi_arg_digit (count, c)
677 int count, c;
679 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
680 return (rl_beg_of_line (1, c));
681 else
682 return (rl_digit_argument (count, c));
685 /* Change the case of the next COUNT characters. */
686 #if defined (HANDLE_MULTIBYTE)
687 static int
688 _rl_vi_change_mbchar_case (count)
689 int count;
691 wchar_t wc;
692 char mb[MB_LEN_MAX+1];
693 int mblen;
694 mbstate_t ps;
696 memset (&ps, 0, sizeof (mbstate_t));
697 if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
698 count--;
699 while (count-- && rl_point < rl_end)
701 mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
702 if (iswupper (wc))
703 wc = towlower (wc);
704 else if (iswlower (wc))
705 wc = towupper (wc);
706 else
708 /* Just skip over chars neither upper nor lower case */
709 rl_forward_char (1, 0);
710 continue;
713 /* Vi is kind of strange here. */
714 if (wc)
716 mblen = wcrtomb (mb, wc, &ps);
717 if (mblen >= 0)
718 mb[mblen] = '\0';
719 rl_begin_undo_group ();
720 rl_delete (1, 0);
721 rl_insert_text (mb);
722 rl_end_undo_group ();
723 rl_vi_check ();
725 else
726 rl_forward_char (1, 0);
729 return 0;
731 #endif
734 rl_vi_change_case (count, ignore)
735 int count, ignore;
737 int c, p;
739 /* Don't try this on an empty line. */
740 if (rl_point >= rl_end)
741 return (0);
743 c = 0;
744 #if defined (HANDLE_MULTIBYTE)
745 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
746 return (_rl_vi_change_mbchar_case (count));
747 #endif
749 while (count-- && rl_point < rl_end)
751 if (_rl_uppercase_p (rl_line_buffer[rl_point]))
752 c = _rl_to_lower (rl_line_buffer[rl_point]);
753 else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
754 c = _rl_to_upper (rl_line_buffer[rl_point]);
755 else
757 /* Just skip over characters neither upper nor lower case. */
758 rl_forward_char (1, c);
759 continue;
762 /* Vi is kind of strange here. */
763 if (c)
765 p = rl_point;
766 rl_begin_undo_group ();
767 rl_vi_delete (1, c);
768 if (rl_point < p) /* Did we retreat at EOL? */
769 rl_point++;
770 _rl_insert_char (1, c);
771 rl_end_undo_group ();
772 rl_vi_check ();
774 else
775 rl_forward_char (1, c);
777 return (0);
781 rl_vi_put (count, key)
782 int count, key;
784 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
785 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
787 while (count--)
788 rl_yank (1, key);
790 rl_backward_char (1, key);
791 return (0);
795 rl_vi_check ()
797 if (rl_point && rl_point == rl_end)
799 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
800 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
801 else
802 rl_point--;
804 return (0);
808 rl_vi_column (count, key)
809 int count, key;
811 if (count > rl_end)
812 rl_end_of_line (1, key);
813 else
814 rl_point = count - 1;
815 return (0);
819 rl_vi_domove (key, nextkey)
820 int key, *nextkey;
822 int c, save;
823 int old_end;
825 rl_mark = rl_point;
826 RL_SETSTATE(RL_STATE_MOREINPUT);
827 c = rl_read_key ();
828 RL_UNSETSTATE(RL_STATE_MOREINPUT);
829 *nextkey = c;
831 if (!member (c, vi_motion))
833 if (_rl_digit_p (c))
835 save = rl_numeric_arg;
836 rl_numeric_arg = _rl_digit_value (c);
837 rl_explicit_arg = 1;
838 rl_digit_loop1 ();
839 rl_numeric_arg *= save;
840 RL_SETSTATE(RL_STATE_MOREINPUT);
841 c = rl_read_key (); /* real command */
842 RL_UNSETSTATE(RL_STATE_MOREINPUT);
843 *nextkey = c;
845 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
847 rl_mark = rl_end;
848 rl_beg_of_line (1, c);
849 _rl_vi_last_motion = c;
850 return (0);
852 else
853 return (-1);
856 _rl_vi_last_motion = c;
858 /* Append a blank character temporarily so that the motion routines
859 work right at the end of the line. */
860 old_end = rl_end;
861 rl_line_buffer[rl_end++] = ' ';
862 rl_line_buffer[rl_end] = '\0';
864 _rl_dispatch (c, _rl_keymap);
866 /* Remove the blank that we added. */
867 rl_end = old_end;
868 rl_line_buffer[rl_end] = '\0';
869 if (rl_point > rl_end)
870 rl_point = rl_end;
872 /* No change in position means the command failed. */
873 if (rl_mark == rl_point)
874 return (-1);
876 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
877 word. If we are not at the end of the line, and we are on a
878 non-whitespace character, move back one (presumably to whitespace). */
879 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
880 !whitespace (rl_line_buffer[rl_point]))
881 rl_point--;
883 /* If cw or cW, back up to the end of a word, so the behaviour of ce
884 or cE is the actual result. Brute-force, no subtlety. */
885 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
887 /* Don't move farther back than where we started. */
888 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
889 rl_point--;
891 /* Posix.2 says that if cw or cW moves the cursor towards the end of
892 the line, the character under the cursor should be deleted. */
893 if (rl_point == rl_mark)
894 rl_point++;
895 else
897 /* Move past the end of the word so that the kill doesn't
898 remove the last letter of the previous word. Only do this
899 if we are not at the end of the line. */
900 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
901 rl_point++;
905 if (rl_mark < rl_point)
906 SWAP (rl_point, rl_mark);
908 return (0);
911 /* A simplified loop for vi. Don't dispatch key at end.
912 Don't recognize minus sign?
913 Should this do rl_save_prompt/rl_restore_prompt? */
914 static int
915 rl_digit_loop1 ()
917 int key, c;
919 RL_SETSTATE(RL_STATE_NUMERICARG);
920 while (1)
922 if (rl_numeric_arg > 1000000)
924 rl_explicit_arg = rl_numeric_arg = 0;
925 rl_ding ();
926 rl_clear_message ();
927 RL_UNSETSTATE(RL_STATE_NUMERICARG);
928 return 1;
930 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
931 RL_SETSTATE(RL_STATE_MOREINPUT);
932 key = c = rl_read_key ();
933 RL_UNSETSTATE(RL_STATE_MOREINPUT);
935 if (c >= 0 && _rl_keymap[c].type == ISFUNC &&
936 _rl_keymap[c].function == rl_universal_argument)
938 rl_numeric_arg *= 4;
939 continue;
942 c = UNMETA (c);
943 if (_rl_digit_p (c))
945 if (rl_explicit_arg)
946 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
947 else
948 rl_numeric_arg = _rl_digit_value (c);
949 rl_explicit_arg = 1;
951 else
953 rl_clear_message ();
954 rl_stuff_char (key);
955 break;
959 RL_UNSETSTATE(RL_STATE_NUMERICARG);
960 return (0);
964 rl_vi_delete_to (count, key)
965 int count, key;
967 int c;
969 if (_rl_uppercase_p (key))
970 rl_stuff_char ('$');
971 else if (vi_redoing)
972 rl_stuff_char (_rl_vi_last_motion);
974 if (rl_vi_domove (key, &c))
976 rl_ding ();
977 return -1;
980 /* These are the motion commands that do not require adjusting the
981 mark. */
982 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
983 rl_mark++;
985 rl_kill_text (rl_point, rl_mark);
986 return (0);
990 rl_vi_change_to (count, key)
991 int count, key;
993 int c, start_pos;
995 if (_rl_uppercase_p (key))
996 rl_stuff_char ('$');
997 else if (vi_redoing)
998 rl_stuff_char (_rl_vi_last_motion);
1000 start_pos = rl_point;
1002 if (rl_vi_domove (key, &c))
1004 rl_ding ();
1005 return -1;
1008 /* These are the motion commands that do not require adjusting the
1009 mark. c[wW] are handled by special-case code in rl_vi_domove(),
1010 and already leave the mark at the correct location. */
1011 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
1012 rl_mark++;
1014 /* The cursor never moves with c[wW]. */
1015 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
1016 rl_point = start_pos;
1018 if (vi_redoing)
1020 if (vi_insert_buffer && *vi_insert_buffer)
1021 rl_begin_undo_group ();
1022 rl_delete_text (rl_point, rl_mark);
1023 if (vi_insert_buffer && *vi_insert_buffer)
1025 rl_insert_text (vi_insert_buffer);
1026 rl_end_undo_group ();
1029 else
1031 rl_begin_undo_group (); /* to make the `u' command work */
1032 rl_kill_text (rl_point, rl_mark);
1033 /* `C' does not save the text inserted for undoing or redoing. */
1034 if (_rl_uppercase_p (key) == 0)
1035 _rl_vi_doing_insert = 1;
1036 rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign);
1039 return (0);
1043 rl_vi_yank_to (count, key)
1044 int count, key;
1046 int c, save = rl_point;
1048 if (_rl_uppercase_p (key))
1049 rl_stuff_char ('$');
1051 if (rl_vi_domove (key, &c))
1053 rl_ding ();
1054 return -1;
1057 /* These are the motion commands that do not require adjusting the
1058 mark. */
1059 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
1060 rl_mark++;
1062 rl_begin_undo_group ();
1063 rl_kill_text (rl_point, rl_mark);
1064 rl_end_undo_group ();
1065 rl_do_undo ();
1066 rl_point = save;
1068 return (0);
1072 rl_vi_delete (count, key)
1073 int count, key;
1075 int end;
1077 if (rl_end == 0)
1079 rl_ding ();
1080 return -1;
1083 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1084 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1085 else
1086 end = rl_point + count;
1088 if (end >= rl_end)
1089 end = rl_end;
1091 rl_kill_text (rl_point, end);
1093 if (rl_point > 0 && rl_point == rl_end)
1094 rl_backward_char (1, key);
1095 return (0);
1099 rl_vi_back_to_indent (count, key)
1100 int count, key;
1102 rl_beg_of_line (1, key);
1103 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1104 rl_point++;
1105 return (0);
1109 rl_vi_first_print (count, key)
1110 int count, key;
1112 return (rl_vi_back_to_indent (1, key));
1116 rl_vi_char_search (count, key)
1117 int count, key;
1119 #if defined (HANDLE_MULTIBYTE)
1120 static char *target;
1121 static int mb_len;
1122 #else
1123 static char target;
1124 #endif
1125 static int orig_dir, dir;
1127 if (key == ';' || key == ',')
1128 dir = key == ';' ? orig_dir : -orig_dir;
1129 else
1131 if (vi_redoing)
1132 #if defined (HANDLE_MULTIBYTE)
1133 target = _rl_vi_last_search_mbchar;
1134 #else
1135 target = _rl_vi_last_search_char;
1136 #endif
1137 else
1139 #if defined (HANDLE_MULTIBYTE)
1140 mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1141 target = _rl_vi_last_search_mbchar;
1142 #else
1143 RL_SETSTATE(RL_STATE_MOREINPUT);
1144 _rl_vi_last_search_char = target = rl_read_key ();
1145 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1146 #endif
1149 switch (key)
1151 case 't':
1152 orig_dir = dir = FTO;
1153 break;
1155 case 'T':
1156 orig_dir = dir = BTO;
1157 break;
1159 case 'f':
1160 orig_dir = dir = FFIND;
1161 break;
1163 case 'F':
1164 orig_dir = dir = BFIND;
1165 break;
1169 #if defined (HANDLE_MULTIBYTE)
1170 return (_rl_char_search_internal (count, dir, target, mb_len));
1171 #else
1172 return (_rl_char_search_internal (count, dir, target));
1173 #endif
1176 /* Match brackets */
1178 rl_vi_match (ignore, key)
1179 int ignore, key;
1181 int count = 1, brack, pos, tmp, pre;
1183 pos = rl_point;
1184 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1186 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1188 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1190 pre = rl_point;
1191 rl_forward_char (1, key);
1192 if (pre == rl_point)
1193 break;
1196 else
1197 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1198 rl_point < rl_end - 1)
1199 rl_forward_char (1, key);
1201 if (brack <= 0)
1203 rl_point = pos;
1204 rl_ding ();
1205 return -1;
1209 pos = rl_point;
1211 if (brack < 0)
1213 while (count)
1215 tmp = pos;
1216 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1217 pos--;
1218 else
1220 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1221 if (tmp == pos)
1222 pos--;
1224 if (pos >= 0)
1226 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1227 if (b == -brack)
1228 count--;
1229 else if (b == brack)
1230 count++;
1232 else
1234 rl_ding ();
1235 return -1;
1239 else
1240 { /* brack > 0 */
1241 while (count)
1243 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1244 pos++;
1245 else
1246 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1248 if (pos < rl_end)
1250 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1251 if (b == -brack)
1252 count--;
1253 else if (b == brack)
1254 count++;
1256 else
1258 rl_ding ();
1259 return -1;
1263 rl_point = pos;
1264 return (0);
1268 rl_vi_bracktype (c)
1269 int c;
1271 switch (c)
1273 case '(': return 1;
1274 case ')': return -1;
1275 case '[': return 2;
1276 case ']': return -2;
1277 case '{': return 3;
1278 case '}': return -3;
1279 default: return 0;
1283 /* XXX - think about reading an entire mbchar with _rl_read_mbchar and
1284 inserting it in one bunch instead of the loop below (like in
1285 rl_vi_char_search or _rl_vi_change_mbchar_case). Set c to mbchar[0]
1286 for test against 033 or ^C. Make sure that _rl_read_mbchar does
1287 this right. */
1289 rl_vi_change_char (count, key)
1290 int count, key;
1292 int c, p;
1294 if (vi_redoing)
1295 c = _rl_vi_last_replacement;
1296 else
1298 RL_SETSTATE(RL_STATE_MOREINPUT);
1299 _rl_vi_last_replacement = c = rl_read_key ();
1300 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1303 if (c == '\033' || c == CTRL ('C'))
1304 return -1;
1306 rl_begin_undo_group ();
1307 while (count-- && rl_point < rl_end)
1309 p = rl_point;
1310 rl_vi_delete (1, c);
1311 #if defined (HANDLE_MULTIBYTE)
1312 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1313 while (_rl_insert_char (1, c))
1315 RL_SETSTATE (RL_STATE_MOREINPUT);
1316 c = rl_read_key ();
1317 RL_UNSETSTATE (RL_STATE_MOREINPUT);
1319 else
1320 #endif
1322 if (rl_point < p) /* Did we retreat at EOL? */
1323 rl_point++;
1324 _rl_insert_char (1, c);
1327 rl_end_undo_group ();
1329 return (0);
1333 rl_vi_subst (count, key)
1334 int count, key;
1336 /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1337 if (vi_redoing == 0)
1338 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
1340 return (rl_vi_change_to (count, 'c'));
1344 rl_vi_overstrike (count, key)
1345 int count, key;
1347 if (_rl_vi_doing_insert == 0)
1349 _rl_vi_doing_insert = 1;
1350 rl_begin_undo_group ();
1353 if (count > 0)
1355 _rl_overwrite_char (count, key);
1356 vi_replace_count += count;
1359 return (0);
1363 rl_vi_overstrike_delete (count, key)
1364 int count, key;
1366 int i, s;
1368 for (i = 0; i < count; i++)
1370 if (vi_replace_count == 0)
1372 rl_ding ();
1373 break;
1375 s = rl_point;
1377 if (rl_do_undo ())
1378 vi_replace_count--;
1380 if (rl_point == s)
1381 rl_backward_char (1, key);
1384 if (vi_replace_count == 0 && _rl_vi_doing_insert)
1386 rl_end_undo_group ();
1387 rl_do_undo ();
1388 _rl_vi_doing_insert = 0;
1390 return (0);
1394 rl_vi_replace (count, key)
1395 int count, key;
1397 int i;
1399 vi_replace_count = 0;
1401 if (!vi_replace_map)
1403 vi_replace_map = rl_make_bare_keymap ();
1405 for (i = ' '; i < KEYMAP_SIZE; i++)
1406 vi_replace_map[i].function = rl_vi_overstrike;
1408 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1409 vi_replace_map[ESC].function = rl_vi_movement_mode;
1410 vi_replace_map[RETURN].function = rl_newline;
1411 vi_replace_map[NEWLINE].function = rl_newline;
1413 /* If the normal vi insertion keymap has ^H bound to erase, do the
1414 same here. Probably should remove the assignment to RUBOUT up
1415 there, but I don't think it will make a difference in real life. */
1416 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1417 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1418 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1421 _rl_keymap = vi_replace_map;
1422 return (0);
1425 #if 0
1426 /* Try to complete the word we are standing on or the word that ends with
1427 the previous character. A space matches everything. Word delimiters are
1428 space and ;. */
1430 rl_vi_possible_completions()
1432 int save_pos = rl_point;
1434 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1436 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1437 rl_line_buffer[rl_point] != ';')
1438 rl_point++;
1440 else if (rl_line_buffer[rl_point - 1] == ';')
1442 rl_ding ();
1443 return (0);
1446 rl_possible_completions ();
1447 rl_point = save_pos;
1449 return (0);
1451 #endif
1453 /* Functions to save and restore marks. */
1455 rl_vi_set_mark (count, key)
1456 int count, key;
1458 int ch;
1460 RL_SETSTATE(RL_STATE_MOREINPUT);
1461 ch = rl_read_key ();
1462 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1464 if (ch < 'a' || ch > 'z')
1466 rl_ding ();
1467 return -1;
1469 ch -= 'a';
1470 vi_mark_chars[ch] = rl_point;
1471 return 0;
1475 rl_vi_goto_mark (count, key)
1476 int count, key;
1478 int ch;
1480 RL_SETSTATE(RL_STATE_MOREINPUT);
1481 ch = rl_read_key ();
1482 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1484 if (ch == '`')
1486 rl_point = rl_mark;
1487 return 0;
1489 else if (ch < 'a' || ch > 'z')
1491 rl_ding ();
1492 return -1;
1495 ch -= 'a';
1496 if (vi_mark_chars[ch] == -1)
1498 rl_ding ();
1499 return -1;
1501 rl_point = vi_mark_chars[ch];
1502 return 0;
1505 #endif /* VI_MODE */