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