]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/vi_mode.c
d4868bf3b130728b977f62229880c135071dc683
[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, 1989, 1992 Free Software Foundation, Inc.
5
6 This file is part of the GNU Readline Library, a library for
7 reading lines of text with interactive input and history editing.
8
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 1, or
12 (at your option) any later version.
13
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.
18
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 675 Mass Ave, Cambridge, MA 02139, USA. */
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 "readline.h"
55 #include "history.h"
56
57 #ifndef _rl_digit_p
58 #define _rl_digit_p(c) ((c) >= '0' && (c) <= '9')
59 #endif
60
61 #ifndef _rl_digit_value
62 #define _rl_digit_value(c) ((c) - '0')
63 #endif
64
65 #ifndef member
66 #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
67 #endif
68
69 #ifndef isident
70 #define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
71 #endif
72
73 #ifndef exchange
74 #define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
75 #endif
76
77 extern char *xmalloc (), *xrealloc ();
78
79 /* Variables imported from readline.c */
80 extern int rl_point, rl_end, rl_mark;
81 extern FILE *rl_instream;
82 extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
83 extern Keymap _rl_keymap;
84 extern char *rl_prompt;
85 extern char *rl_line_buffer;
86 extern int rl_arg_sign;
87
88 extern int _rl_doing_an_undo;
89 extern int _rl_undo_group_level;
90
91 extern void _rl_dispatch ();
92 extern int _rl_char_search_internal ();
93
94 extern void rl_extend_line_buffer ();
95 extern int rl_vi_check ();
96
97 /* Non-zero means enter insertion mode. */
98 static int _rl_vi_doing_insert;
99
100 /* Command keys which do movement for xxx_to commands. */
101 static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
102
103 /* Keymap used for vi replace characters. Created dynamically since
104 rarely used. */
105 static Keymap vi_replace_map;
106
107 /* The number of characters inserted in the last replace operation. */
108 static int vi_replace_count;
109
110 /* If non-zero, we have text inserted after a c[motion] command that put
111 us implicitly into insert mode. Some people want this text to be
112 attached to the command so that it is `redoable' with `.'. */
113 static int vi_continued_command;
114 static char *vi_insert_buffer;
115 static int vi_insert_buffer_size;
116
117 static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
118 static int _rl_vi_last_repeat = 1;
119 static int _rl_vi_last_arg_sign = 1;
120 static int _rl_vi_last_motion;
121 static int _rl_vi_last_search_char;
122 static int _rl_vi_last_replacement;
123
124 static int _rl_vi_last_key_before_insert;
125
126 static int vi_redoing;
127
128 /* Text modification commands. These are the `redoable' commands. */
129 static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
130
131 /* Arrays for the saved marks. */
132 static int vi_mark_chars[27];
133
134 static int rl_digit_loop1 ();
135
136 void
137 _rl_vi_initialize_line ()
138 {
139 register int i;
140
141 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
142 vi_mark_chars[i] = -1;
143 }
144
145 void
146 _rl_vi_reset_last ()
147 {
148 _rl_vi_last_command = 'i';
149 _rl_vi_last_repeat = 1;
150 _rl_vi_last_arg_sign = 1;
151 _rl_vi_last_motion = 0;
152 }
153
154 void
155 _rl_vi_set_last (key, repeat, sign)
156 int key, repeat, sign;
157 {
158 _rl_vi_last_command = key;
159 _rl_vi_last_repeat = repeat;
160 _rl_vi_last_arg_sign = sign;
161 }
162
163 /* Is the command C a VI mode text modification command? */
164 int
165 _rl_vi_textmod_command (c)
166 int c;
167 {
168 return (member (c, vi_textmod));
169 }
170
171 static void
172 _rl_vi_stuff_insert (count)
173 int count;
174 {
175 rl_begin_undo_group ();
176 while (count--)
177 rl_insert_text (vi_insert_buffer);
178 rl_end_undo_group ();
179 }
180
181 /* Bound to `.'. Called from command mode, so we know that we have to
182 redo a text modification command. The default for _rl_vi_last_command
183 puts you back into insert mode. */
184 int
185 rl_vi_redo (count, c)
186 int count, c;
187 {
188 if (!rl_explicit_arg)
189 {
190 rl_numeric_arg = _rl_vi_last_repeat;
191 rl_arg_sign = _rl_vi_last_arg_sign;
192 }
193
194 vi_redoing = 1;
195 /* If we're redoing an insert with `i', stuff in the inserted text
196 and do not go into insertion mode. */
197 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
198 {
199 _rl_vi_stuff_insert (count);
200 /* And back up point over the last character inserted. */
201 if (rl_point > 0)
202 rl_point--;
203 }
204 else
205 _rl_dispatch (_rl_vi_last_command, _rl_keymap);
206 vi_redoing = 0;
207
208 return (0);
209 }
210
211 /* A placeholder for further expansion. */
212 int
213 rl_vi_undo (count, key)
214 int count, key;
215 {
216 return (rl_undo_command (count, key));
217 }
218
219 /* Yank the nth arg from the previous line into this line at point. */
220 int
221 rl_vi_yank_arg (count, key)
222 int count, key;
223 {
224 /* Readline thinks that the first word on a line is the 0th, while vi
225 thinks the first word on a line is the 1st. Compensate. */
226 if (rl_explicit_arg)
227 rl_yank_nth_arg (count - 1, 0);
228 else
229 rl_yank_nth_arg ('$', 0);
230
231 return (0);
232 }
233
234 /* With an argument, move back that many history lines, else move to the
235 beginning of history. */
236 int
237 rl_vi_fetch_history (count, c)
238 int count, c;
239 {
240 int wanted;
241
242 /* Giving an argument of n means we want the nth command in the history
243 file. The command number is interpreted the same way that the bash
244 `history' command does it -- that is, giving an argument count of 450
245 to this command would get the command listed as number 450 in the
246 output of `history'. */
247 if (rl_explicit_arg)
248 {
249 wanted = history_base + where_history () - count;
250 if (wanted <= 0)
251 rl_beginning_of_history (0, 0);
252 else
253 rl_get_previous_history (wanted, c);
254 }
255 else
256 rl_beginning_of_history (count, 0);
257 return (0);
258 }
259
260 /* Search again for the last thing searched for. */
261 int
262 rl_vi_search_again (count, key)
263 int count, key;
264 {
265 switch (key)
266 {
267 case 'n':
268 rl_noninc_reverse_search_again (count, key);
269 break;
270
271 case 'N':
272 rl_noninc_forward_search_again (count, key);
273 break;
274 }
275 return (0);
276 }
277
278 /* Do a vi style search. */
279 int
280 rl_vi_search (count, key)
281 int count, key;
282 {
283 switch (key)
284 {
285 case '?':
286 rl_noninc_forward_search (count, key);
287 break;
288
289 case '/':
290 rl_noninc_reverse_search (count, key);
291 break;
292
293 default:
294 ding ();
295 break;
296 }
297 return (0);
298 }
299
300 /* Completion, from vi's point of view. */
301 int
302 rl_vi_complete (ignore, key)
303 int ignore, key;
304 {
305 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
306 {
307 if (!whitespace (rl_line_buffer[rl_point + 1]))
308 rl_vi_end_word (1, 'E');
309 rl_point++;
310 }
311
312 if (key == '*')
313 rl_complete_internal ('*'); /* Expansion and replacement. */
314 else if (key == '=')
315 rl_complete_internal ('?'); /* List possible completions. */
316 else if (key == '\\')
317 rl_complete_internal (TAB); /* Standard Readline completion. */
318 else
319 rl_complete (0, key);
320
321 if (key == '*' || key == '\\')
322 {
323 _rl_vi_set_last (key, 1, rl_arg_sign);
324 rl_vi_insertion_mode (1, key);
325 }
326 return (0);
327 }
328
329 /* Tilde expansion for vi mode. */
330 int
331 rl_vi_tilde_expand (ignore, key)
332 int ignore, key;
333 {
334 rl_tilde_expand (0, key);
335 _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */
336 rl_vi_insertion_mode (1, key);
337 return (0);
338 }
339
340 /* Previous word in vi mode. */
341 int
342 rl_vi_prev_word (count, key)
343 int count, key;
344 {
345 if (count < 0)
346 return (rl_vi_next_word (-count, key));
347
348 if (rl_point == 0)
349 {
350 ding ();
351 return (0);
352 }
353
354 if (_rl_uppercase_p (key))
355 rl_vi_bWord (count, key);
356 else
357 rl_vi_bword (count, key);
358
359 return (0);
360 }
361
362 /* Next word in vi mode. */
363 int
364 rl_vi_next_word (count, key)
365 int count, key;
366 {
367 if (count < 0)
368 return (rl_vi_prev_word (-count, key));
369
370 if (rl_point >= (rl_end - 1))
371 {
372 ding ();
373 return (0);
374 }
375
376 if (_rl_uppercase_p (key))
377 rl_vi_fWord (count, key);
378 else
379 rl_vi_fword (count, key);
380 return (0);
381 }
382
383 /* Move to the end of the ?next? word. */
384 int
385 rl_vi_end_word (count, key)
386 int count, key;
387 {
388 if (count < 0)
389 {
390 ding ();
391 return -1;
392 }
393
394 if (_rl_uppercase_p (key))
395 rl_vi_eWord (count, key);
396 else
397 rl_vi_eword (count, key);
398 return (0);
399 }
400
401 /* Move forward a word the way that 'W' does. */
402 int
403 rl_vi_fWord (count, ignore)
404 int count, ignore;
405 {
406 while (count-- && rl_point < (rl_end - 1))
407 {
408 /* Skip until whitespace. */
409 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
410 rl_point++;
411
412 /* Now skip whitespace. */
413 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
414 rl_point++;
415 }
416 return (0);
417 }
418
419 int
420 rl_vi_bWord (count, ignore)
421 int count, ignore;
422 {
423 while (count-- && rl_point > 0)
424 {
425 /* If we are at the start of a word, move back to whitespace so
426 we will go back to the start of the previous word. */
427 if (!whitespace (rl_line_buffer[rl_point]) &&
428 whitespace (rl_line_buffer[rl_point - 1]))
429 rl_point--;
430
431 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
432 rl_point--;
433
434 if (rl_point > 0)
435 {
436 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
437 rl_point++;
438 }
439 }
440 return (0);
441 }
442
443 int
444 rl_vi_eWord (count, ignore)
445 int count, ignore;
446 {
447 while (count-- && rl_point < (rl_end - 1))
448 {
449 if (!whitespace (rl_line_buffer[rl_point]))
450 rl_point++;
451
452 /* Move to the next non-whitespace character (to the start of the
453 next word). */
454 while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
455
456 if (rl_point && rl_point < rl_end)
457 {
458 /* Skip whitespace. */
459 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
460 rl_point++;
461
462 /* Skip until whitespace. */
463 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
464 rl_point++;
465
466 /* Move back to the last character of the word. */
467 rl_point--;
468 }
469 }
470 return (0);
471 }
472
473 int
474 rl_vi_fword (count, ignore)
475 int count, ignore;
476 {
477 while (count-- && rl_point < (rl_end - 1))
478 {
479 /* Move to white space (really non-identifer). */
480 if (isident (rl_line_buffer[rl_point]))
481 {
482 while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
483 rl_point++;
484 }
485 else /* if (!whitespace (rl_line_buffer[rl_point])) */
486 {
487 while (!isident (rl_line_buffer[rl_point]) &&
488 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
489 rl_point++;
490 }
491
492 /* Move past whitespace. */
493 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
494 rl_point++;
495 }
496 return (0);
497 }
498
499 int
500 rl_vi_bword (count, ignore)
501 int count, ignore;
502 {
503 while (count-- && rl_point > 0)
504 {
505 int last_is_ident;
506
507 /* If we are at the start of a word, move back to whitespace
508 so we will go back to the start of the previous word. */
509 if (!whitespace (rl_line_buffer[rl_point]) &&
510 whitespace (rl_line_buffer[rl_point - 1]))
511 rl_point--;
512
513 /* If this character and the previous character are `opposite', move
514 back so we don't get messed up by the rl_point++ down there in
515 the while loop. Without this code, words like `l;' screw up the
516 function. */
517 last_is_ident = isident (rl_line_buffer[rl_point - 1]);
518 if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
519 (!isident (rl_line_buffer[rl_point]) && last_is_ident))
520 rl_point--;
521
522 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
523 rl_point--;
524
525 if (rl_point > 0)
526 {
527 if (isident (rl_line_buffer[rl_point]))
528 while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
529 else
530 while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
531 !whitespace (rl_line_buffer[rl_point]));
532 rl_point++;
533 }
534 }
535 return (0);
536 }
537
538 int
539 rl_vi_eword (count, ignore)
540 int count, ignore;
541 {
542 while (count-- && rl_point < rl_end - 1)
543 {
544 if (!whitespace (rl_line_buffer[rl_point]))
545 rl_point++;
546
547 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
548 rl_point++;
549
550 if (rl_point < rl_end)
551 {
552 if (isident (rl_line_buffer[rl_point]))
553 while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
554 else
555 while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
556 && !whitespace (rl_line_buffer[rl_point]));
557 }
558 rl_point--;
559 }
560 return (0);
561 }
562
563 int
564 rl_vi_insert_beg (count, key)
565 int count, key;
566 {
567 rl_beg_of_line (1, key);
568 rl_vi_insertion_mode (1, key);
569 return (0);
570 }
571
572 int
573 rl_vi_append_mode (count, key)
574 int count, key;
575 {
576 if (rl_point < rl_end)
577 rl_point++;
578 rl_vi_insertion_mode (1, key);
579 return (0);
580 }
581
582 int
583 rl_vi_append_eol (count, key)
584 int count, key;
585 {
586 rl_end_of_line (1, key);
587 rl_vi_append_mode (1, key);
588 return (0);
589 }
590
591 /* What to do in the case of C-d. */
592 int
593 rl_vi_eof_maybe (count, c)
594 int count, c;
595 {
596 return (rl_newline (1, '\n'));
597 }
598
599 /* Insertion mode stuff. */
600
601 /* Switching from one mode to the other really just involves
602 switching keymaps. */
603 int
604 rl_vi_insertion_mode (count, key)
605 int count, key;
606 {
607 _rl_keymap = vi_insertion_keymap;
608 _rl_vi_last_key_before_insert = key;
609 return (0);
610 }
611
612 static void
613 _rl_vi_save_insert (up)
614 UNDO_LIST *up;
615 {
616 int len, start, end;
617
618 if (up == 0)
619 {
620 if (vi_insert_buffer_size >= 1)
621 vi_insert_buffer[0] = '\0';
622 return;
623 }
624
625 start = up->start;
626 end = up->end;
627 len = end - start + 1;
628 if (len >= vi_insert_buffer_size)
629 {
630 vi_insert_buffer_size += (len + 32) - (len % 32);
631 vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
632 }
633 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
634 vi_insert_buffer[len-1] = '\0';
635 }
636
637 void
638 _rl_vi_done_inserting ()
639 {
640 if (_rl_vi_doing_insert)
641 {
642 rl_end_undo_group ();
643 /* Now, the text between rl_undo_list->next->start and
644 rl_undo_list->next->end is what was inserted while in insert
645 mode. It gets copied to VI_INSERT_BUFFER because it depends
646 on absolute indices into the line which may change (though they
647 probably will not). */
648 _rl_vi_doing_insert = 0;
649 _rl_vi_save_insert (rl_undo_list->next);
650 vi_continued_command = 1;
651 }
652 else
653 {
654 if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
655 _rl_vi_save_insert (rl_undo_list);
656 /* XXX - Other keys probably need to be checked. */
657 else if (_rl_vi_last_key_before_insert == 'C')
658 rl_end_undo_group ();
659 while (_rl_undo_group_level > 0)
660 rl_end_undo_group ();
661 vi_continued_command = 0;
662 }
663 }
664
665 int
666 rl_vi_movement_mode (count, key)
667 int count, key;
668 {
669 if (rl_point > 0)
670 rl_backward (1, key);
671
672 _rl_keymap = vi_movement_keymap;
673 _rl_vi_done_inserting ();
674 return (0);
675 }
676
677 int
678 rl_vi_arg_digit (count, c)
679 int count, c;
680 {
681 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
682 return (rl_beg_of_line (1, c));
683 else
684 return (rl_digit_argument (count, c));
685 }
686
687 int
688 rl_vi_change_case (count, ignore)
689 int count, ignore;
690 {
691 char c = 0;
692
693 /* Don't try this on an empty line. */
694 if (rl_point >= rl_end)
695 return (0);
696
697 while (count-- && rl_point < rl_end)
698 {
699 if (_rl_uppercase_p (rl_line_buffer[rl_point]))
700 c = _rl_to_lower (rl_line_buffer[rl_point]);
701 else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
702 c = _rl_to_upper (rl_line_buffer[rl_point]);
703 else
704 {
705 /* Just skip over characters neither upper nor lower case. */
706 rl_forward (1, c);
707 continue;
708 }
709
710 /* Vi is kind of strange here. */
711 if (c)
712 {
713 rl_begin_undo_group ();
714 rl_delete (1, c);
715 rl_insert (1, c);
716 rl_end_undo_group ();
717 rl_vi_check ();
718 }
719 else
720 rl_forward (1, c);
721 }
722 return (0);
723 }
724
725 int
726 rl_vi_put (count, key)
727 int count, key;
728 {
729 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
730 rl_point++;
731
732 rl_yank (1, key);
733 rl_backward (1, key);
734 return (0);
735 }
736
737 int
738 rl_vi_check ()
739 {
740 if (rl_point && rl_point == rl_end)
741 rl_point--;
742 return (0);
743 }
744
745 int
746 rl_vi_column (count, key)
747 int count, key;
748 {
749 if (count > rl_end)
750 rl_end_of_line (1, key);
751 else
752 rl_point = count - 1;
753 return (0);
754 }
755
756 int
757 rl_vi_domove (key, nextkey)
758 int key, *nextkey;
759 {
760 int c, save;
761 int old_end;
762
763 rl_mark = rl_point;
764 c = rl_read_key ();
765 *nextkey = c;
766
767 if (!member (c, vi_motion))
768 {
769 if (_rl_digit_p (c))
770 {
771 save = rl_numeric_arg;
772 rl_numeric_arg = _rl_digit_value (c);
773 rl_digit_loop1 ();
774 rl_numeric_arg *= save;
775 c = rl_read_key (); /* real command */
776 *nextkey = c;
777 }
778 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
779 {
780 rl_mark = rl_end;
781 rl_beg_of_line (1, c);
782 _rl_vi_last_motion = c;
783 return (0);
784 }
785 else
786 return (-1);
787 }
788
789 _rl_vi_last_motion = c;
790
791 /* Append a blank character temporarily so that the motion routines
792 work right at the end of the line. */
793 old_end = rl_end;
794 rl_line_buffer[rl_end++] = ' ';
795 rl_line_buffer[rl_end] = '\0';
796
797 _rl_dispatch (c, _rl_keymap);
798
799 /* Remove the blank that we added. */
800 rl_end = old_end;
801 rl_line_buffer[rl_end] = '\0';
802 if (rl_point > rl_end)
803 rl_point = rl_end;
804
805 /* No change in position means the command failed. */
806 if (rl_mark == rl_point)
807 return (-1);
808
809 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
810 word. If we are not at the end of the line, and we are on a
811 non-whitespace character, move back one (presumably to whitespace). */
812 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
813 !whitespace (rl_line_buffer[rl_point]))
814 rl_point--;
815
816 /* If cw or cW, back up to the end of a word, so the behaviour of ce
817 or cE is the actual result. Brute-force, no subtlety. */
818 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
819 {
820 /* Don't move farther back than where we started. */
821 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
822 rl_point--;
823
824 /* Posix.2 says that if cw or cW moves the cursor towards the end of
825 the line, the character under the cursor should be deleted. */
826 if (rl_point == rl_mark)
827 rl_point++;
828 else
829 {
830 /* Move past the end of the word so that the kill doesn't
831 remove the last letter of the previous word. Only do this
832 if we are not at the end of the line. */
833 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
834 rl_point++;
835 }
836 }
837
838 if (rl_mark < rl_point)
839 exchange (rl_point, rl_mark);
840
841 return (0);
842 }
843
844 /* A simplified loop for vi. Don't dispatch key at end.
845 Don't recognize minus sign? */
846 static int
847 rl_digit_loop1 ()
848 {
849 int key, c;
850
851 while (1)
852 {
853 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
854 key = c = rl_read_key ();
855
856 if (_rl_keymap[c].type == ISFUNC &&
857 _rl_keymap[c].function == rl_universal_argument)
858 {
859 rl_numeric_arg *= 4;
860 continue;
861 }
862
863 c = UNMETA (c);
864 if (_rl_digit_p (c))
865 {
866 if (rl_explicit_arg)
867 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
868 else
869 rl_numeric_arg = _rl_digit_value (c);
870 rl_explicit_arg = 1;
871 }
872 else
873 {
874 rl_clear_message ();
875 rl_stuff_char (key);
876 break;
877 }
878 }
879 return (0);
880 }
881
882 int
883 rl_vi_delete_to (count, key)
884 int count, key;
885 {
886 int c;
887
888 if (_rl_uppercase_p (key))
889 rl_stuff_char ('$');
890 else if (vi_redoing)
891 rl_stuff_char (_rl_vi_last_motion);
892
893 if (rl_vi_domove (key, &c))
894 {
895 ding ();
896 return -1;
897 }
898
899 /* These are the motion commands that do not require adjusting the
900 mark. */
901 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
902 rl_mark++;
903
904 rl_kill_text (rl_point, rl_mark);
905 return (0);
906 }
907
908 int
909 rl_vi_change_to (count, key)
910 int count, key;
911 {
912 int c, start_pos;
913
914 if (_rl_uppercase_p (key))
915 rl_stuff_char ('$');
916 else if (vi_redoing)
917 rl_stuff_char (_rl_vi_last_motion);
918
919 start_pos = rl_point;
920
921 if (rl_vi_domove (key, &c))
922 {
923 ding ();
924 return -1;
925 }
926
927 /* These are the motion commands that do not require adjusting the
928 mark. c[wW] are handled by special-case code in rl_vi_domove(),
929 and already leave the mark at the correct location. */
930 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
931 rl_mark++;
932
933 /* The cursor never moves with c[wW]. */
934 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
935 rl_point = start_pos;
936
937 if (vi_redoing)
938 {
939 if (vi_insert_buffer && *vi_insert_buffer)
940 rl_begin_undo_group ();
941 rl_delete_text (rl_point, rl_mark);
942 if (vi_insert_buffer && *vi_insert_buffer)
943 {
944 rl_insert_text (vi_insert_buffer);
945 rl_end_undo_group ();
946 }
947 }
948 else
949 {
950 rl_begin_undo_group (); /* to make the `u' command work */
951 rl_kill_text (rl_point, rl_mark);
952 /* `C' does not save the text inserted for undoing or redoing. */
953 if (_rl_uppercase_p (key) == 0)
954 _rl_vi_doing_insert = 1;
955 _rl_vi_set_last (key, count, rl_arg_sign);
956 rl_vi_insertion_mode (1, key);
957 }
958
959 return (0);
960 }
961
962 int
963 rl_vi_yank_to (count, key)
964 int count, key;
965 {
966 int c, save = rl_point;
967
968 if (_rl_uppercase_p (key))
969 rl_stuff_char ('$');
970
971 if (rl_vi_domove (key, &c))
972 {
973 ding ();
974 return -1;
975 }
976
977 /* These are the motion commands that do not require adjusting the
978 mark. */
979 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
980 rl_mark++;
981
982 rl_begin_undo_group ();
983 rl_kill_text (rl_point, rl_mark);
984 rl_end_undo_group ();
985 rl_do_undo ();
986 rl_point = save;
987
988 return (0);
989 }
990
991 int
992 rl_vi_delete (count, key)
993 int count, key;
994 {
995 int end;
996
997 if (rl_end == 0)
998 {
999 ding ();
1000 return -1;
1001 }
1002
1003 end = rl_point + count;
1004
1005 if (end >= rl_end)
1006 end = rl_end;
1007
1008 rl_kill_text (rl_point, end);
1009
1010 if (rl_point > 0 && rl_point == rl_end)
1011 rl_backward (1, key);
1012 return (0);
1013 }
1014
1015 int
1016 rl_vi_back_to_indent (count, key)
1017 int count, key;
1018 {
1019 rl_beg_of_line (1, key);
1020 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1021 rl_point++;
1022 return (0);
1023 }
1024
1025 int
1026 rl_vi_first_print (count, key)
1027 int count, key;
1028 {
1029 return (rl_vi_back_to_indent (1, key));
1030 }
1031
1032 int
1033 rl_vi_char_search (count, key)
1034 int count, key;
1035 {
1036 static char target;
1037 static int orig_dir, dir;
1038
1039 if (key == ';' || key == ',')
1040 dir = key == ';' ? orig_dir : -orig_dir;
1041 else
1042 {
1043 if (vi_redoing)
1044 target = _rl_vi_last_search_char;
1045 else
1046 _rl_vi_last_search_char = target = rl_getc (rl_instream);
1047
1048 switch (key)
1049 {
1050 case 't':
1051 orig_dir = dir = FTO;
1052 break;
1053
1054 case 'T':
1055 orig_dir = dir = BTO;
1056 break;
1057
1058 case 'f':
1059 orig_dir = dir = FFIND;
1060 break;
1061
1062 case 'F':
1063 orig_dir = dir = BFIND;
1064 break;
1065 }
1066 }
1067
1068 return (_rl_char_search_internal (count, dir, target));
1069 }
1070
1071 /* Match brackets */
1072 int
1073 rl_vi_match (ignore, key)
1074 int ignore, key;
1075 {
1076 int count = 1, brack, pos;
1077
1078 pos = rl_point;
1079 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1080 {
1081 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1082 rl_point < rl_end - 1)
1083 rl_forward (1, key);
1084
1085 if (brack <= 0)
1086 {
1087 rl_point = pos;
1088 ding ();
1089 return -1;
1090 }
1091 }
1092
1093 pos = rl_point;
1094
1095 if (brack < 0)
1096 {
1097 while (count)
1098 {
1099 if (--pos >= 0)
1100 {
1101 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1102 if (b == -brack)
1103 count--;
1104 else if (b == brack)
1105 count++;
1106 }
1107 else
1108 {
1109 ding ();
1110 return -1;
1111 }
1112 }
1113 }
1114 else
1115 { /* brack > 0 */
1116 while (count)
1117 {
1118 if (++pos < rl_end)
1119 {
1120 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1121 if (b == -brack)
1122 count--;
1123 else if (b == brack)
1124 count++;
1125 }
1126 else
1127 {
1128 ding ();
1129 return -1;
1130 }
1131 }
1132 }
1133 rl_point = pos;
1134 return (0);
1135 }
1136
1137 int
1138 rl_vi_bracktype (c)
1139 int c;
1140 {
1141 switch (c)
1142 {
1143 case '(': return 1;
1144 case ')': return -1;
1145 case '[': return 2;
1146 case ']': return -2;
1147 case '{': return 3;
1148 case '}': return -3;
1149 default: return 0;
1150 }
1151 }
1152
1153 int
1154 rl_vi_change_char (count, key)
1155 int count, key;
1156 {
1157 int c;
1158
1159 if (vi_redoing)
1160 c = _rl_vi_last_replacement;
1161 else
1162 _rl_vi_last_replacement = c = rl_getc (rl_instream);
1163
1164 if (c == '\033' || c == CTRL ('C'))
1165 return -1;
1166
1167 while (count-- && rl_point < rl_end)
1168 {
1169 rl_begin_undo_group ();
1170
1171 rl_delete (1, c);
1172 rl_insert (1, c);
1173 if (count == 0)
1174 rl_backward (1, c);
1175
1176 rl_end_undo_group ();
1177 }
1178 return (0);
1179 }
1180
1181 int
1182 rl_vi_subst (count, key)
1183 int count, key;
1184 {
1185 rl_begin_undo_group ();
1186
1187 if (_rl_uppercase_p (key))
1188 {
1189 rl_beg_of_line (1, key);
1190 rl_kill_line (1, key);
1191 }
1192 else
1193 rl_delete_text (rl_point, rl_point+count);
1194
1195 rl_end_undo_group ();
1196
1197 _rl_vi_set_last (key, count, rl_arg_sign);
1198
1199 if (vi_redoing)
1200 {
1201 int o = _rl_doing_an_undo;
1202
1203 _rl_doing_an_undo = 1;
1204 if (vi_insert_buffer && *vi_insert_buffer)
1205 rl_insert_text (vi_insert_buffer);
1206 _rl_doing_an_undo = o;
1207 }
1208 else
1209 {
1210 rl_begin_undo_group ();
1211 _rl_vi_doing_insert = 1;
1212 rl_vi_insertion_mode (1, key);
1213 }
1214
1215 return (0);
1216 }
1217
1218 int
1219 rl_vi_overstrike (count, key)
1220 int count, key;
1221 {
1222 int i;
1223
1224 if (_rl_vi_doing_insert == 0)
1225 {
1226 _rl_vi_doing_insert = 1;
1227 rl_begin_undo_group ();
1228 }
1229
1230 for (i = 0; i < count; i++)
1231 {
1232 vi_replace_count++;
1233 rl_begin_undo_group ();
1234
1235 if (rl_point < rl_end)
1236 {
1237 rl_delete (1, key);
1238 rl_insert (1, key);
1239 }
1240 else
1241 rl_insert (1, key);
1242
1243 rl_end_undo_group ();
1244 }
1245 return (0);
1246 }
1247
1248 int
1249 rl_vi_overstrike_delete (count, key)
1250 int count, key;
1251 {
1252 int i, s;
1253
1254 for (i = 0; i < count; i++)
1255 {
1256 if (vi_replace_count == 0)
1257 {
1258 ding ();
1259 break;
1260 }
1261 s = rl_point;
1262
1263 if (rl_do_undo ())
1264 vi_replace_count--;
1265
1266 if (rl_point == s)
1267 rl_backward (1, key);
1268 }
1269
1270 if (vi_replace_count == 0 && _rl_vi_doing_insert)
1271 {
1272 rl_end_undo_group ();
1273 rl_do_undo ();
1274 _rl_vi_doing_insert = 0;
1275 }
1276 return (0);
1277 }
1278
1279 int
1280 rl_vi_replace (count, key)
1281 int count, key;
1282 {
1283 int i;
1284
1285 vi_replace_count = 0;
1286
1287 if (!vi_replace_map)
1288 {
1289 vi_replace_map = rl_make_bare_keymap ();
1290
1291 for (i = ' '; i < KEYMAP_SIZE; i++)
1292 vi_replace_map[i].function = rl_vi_overstrike;
1293
1294 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1295 vi_replace_map[ESC].function = rl_vi_movement_mode;
1296 vi_replace_map[RETURN].function = rl_newline;
1297 vi_replace_map[NEWLINE].function = rl_newline;
1298
1299 /* If the normal vi insertion keymap has ^H bound to erase, do the
1300 same here. Probably should remove the assignment to RUBOUT up
1301 there, but I don't think it will make a difference in real life. */
1302 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1303 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1304 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1305
1306 }
1307 _rl_keymap = vi_replace_map;
1308 return (0);
1309 }
1310
1311 #if 0
1312 /* Try to complete the word we are standing on or the word that ends with
1313 the previous character. A space matches everything. Word delimiters are
1314 space and ;. */
1315 int
1316 rl_vi_possible_completions()
1317 {
1318 int save_pos = rl_point;
1319
1320 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1321 {
1322 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1323 rl_line_buffer[rl_point] != ';')
1324 rl_point++;
1325 }
1326 else if (rl_line_buffer[rl_point - 1] == ';')
1327 {
1328 ding ();
1329 return (0);
1330 }
1331
1332 rl_possible_completions ();
1333 rl_point = save_pos;
1334
1335 return (0);
1336 }
1337 #endif
1338
1339 /* Functions to save and restore marks. */
1340 int
1341 rl_vi_set_mark (count, key)
1342 int count, key;
1343 {
1344 int ch;
1345
1346 ch = rl_read_key ();
1347 if (_rl_lowercase_p (ch) == 0)
1348 {
1349 ding ();
1350 return -1;
1351 }
1352 ch -= 'a';
1353 vi_mark_chars[ch] = rl_point;
1354 return 0;
1355 }
1356
1357 int
1358 rl_vi_goto_mark (count, key)
1359 int count, key;
1360 {
1361 int ch;
1362
1363 ch = rl_read_key ();
1364 if (ch == '`')
1365 {
1366 rl_point = rl_mark;
1367 return 0;
1368 }
1369 else if (_rl_lowercase_p (ch) == 0)
1370 {
1371 ding ();
1372 return -1;
1373 }
1374
1375 ch -= 'a';
1376 if (vi_mark_chars[ch] == -1)
1377 {
1378 ding ();
1379 return -1;
1380 }
1381 rl_point = vi_mark_chars[ch];
1382 return 0;
1383 }
1384
1385 #endif /* VI_MODE */