1 /* $FreeBSD$ */
2 /* vi_mode.c -- A vi emulation mode for Bash.
3 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
4
5 /* Copyright (C) 1987-2005 Free Software Foundation, Inc.
6
7 This file is part of the GNU Readline Library, a library for
8 reading lines of text with interactive input and history editing.
9
10 The GNU Readline Library is free software; you can redistribute it
11 and/or modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2, or
13 (at your option) any later version.
14
15 The GNU Readline Library is distributed in the hope that it will be
16 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
17 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 The GNU General Public License is often shipped with GNU software, and
21 is generally kept in a file called COPYING or LICENSE. If you do not
22 have a copy of the license, write to the Free Software Foundation,
23 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
24 #define READLINE_LIBRARY
25
26 /* **************************************************************** */
27 /* */
28 /* VI Emulation Mode */
29 /* */
30 /* **************************************************************** */
31 #include "rlconf.h"
32
33 #if defined (VI_MODE)
34
35 #if defined (HAVE_CONFIG_H)
36 # include <config.h>
37 #endif
38
39 #include <sys/types.h>
40
41 #if defined (HAVE_STDLIB_H)
42 # include <stdlib.h>
43 #else
44 # include "ansi_stdlib.h"
45 #endif /* HAVE_STDLIB_H */
46
47 #if defined (HAVE_UNISTD_H)
48 # include <unistd.h>
49 #endif
50
51 #include <stdio.h>
52
53 /* Some standard library routines. */
54 #include "rldefs.h"
55 #include "rlmbutil.h"
56
57 #include "readline.h"
58 #include "history.h"
59
60 #include "rlprivate.h"
61 #include "xmalloc.h"
62
63 #ifndef member
64 #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
65 #endif
66
67 int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
68
69 /* Non-zero means enter insertion mode. */
70 static int _rl_vi_doing_insert;
71
72 /* Command keys which do movement for xxx_to commands. */
73 static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|";
74
75 /* Keymap used for vi replace characters. Created dynamically since
76 rarely used. */
77 static Keymap vi_replace_map;
78
79 /* The number of characters inserted in the last replace operation. */
80 static int vi_replace_count;
81
82 /* If non-zero, we have text inserted after a c[motion] command that put
83 us implicitly into insert mode. Some people want this text to be
84 attached to the command so that it is `redoable' with `.'. */
85 static int vi_continued_command;
86 static char *vi_insert_buffer;
87 static int vi_insert_buffer_size;
88
89 static int _rl_vi_last_repeat = 1;
90 static int _rl_vi_last_arg_sign = 1;
91 static int _rl_vi_last_motion;
92 #if defined (HANDLE_MULTIBYTE)
93 static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
94 static int _rl_vi_last_search_mblen;
95 #else
96 static int _rl_vi_last_search_char;
97 #endif
98 static int _rl_vi_last_replacement;
99
100 static int _rl_vi_last_key_before_insert;
101
102 static int vi_redoing;
103
104 /* Text modification commands. These are the `redoable' commands. */
105 static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
106
107 /* Arrays for the saved marks. */
108 static int vi_mark_chars['z' - 'a' + 1];
109
110 static void _rl_vi_stuff_insert PARAMS((int));
111 static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
112
113 static void _rl_vi_backup PARAMS((void));
114
115 static int _rl_vi_arg_dispatch PARAMS((int));
116 static int rl_digit_loop1 PARAMS((void));
117
118 static int _rl_vi_set_mark PARAMS((void));
119 static int _rl_vi_goto_mark PARAMS((void));
120
121 static void _rl_vi_append_forward PARAMS((int));
122
123 static int _rl_vi_callback_getchar PARAMS((char *, int));
124
125 #if defined (READLINE_CALLBACKS)
126 static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
127 static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
128 static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
129 static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
130 #endif
131
132 void
_rl_vi_initialize_line()133 _rl_vi_initialize_line ()
134 {
135 register int i;
136
137 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
138 vi_mark_chars[i] = -1;
139
140 RL_UNSETSTATE(RL_STATE_VICMDONCE);
141 }
142
143 void
_rl_vi_reset_last()144 _rl_vi_reset_last ()
145 {
146 _rl_vi_last_command = 'i';
147 _rl_vi_last_repeat = 1;
148 _rl_vi_last_arg_sign = 1;
149 _rl_vi_last_motion = 0;
150 }
151
152 void
_rl_vi_set_last(key,repeat,sign)153 _rl_vi_set_last (key, repeat, sign)
154 int key, repeat, sign;
155 {
156 _rl_vi_last_command = key;
157 _rl_vi_last_repeat = repeat;
158 _rl_vi_last_arg_sign = sign;
159 }
160
161 /* A convenience function that calls _rl_vi_set_last to save the last command
162 information and enters insertion mode. */
163 void
rl_vi_start_inserting(key,repeat,sign)164 rl_vi_start_inserting (key, repeat, sign)
165 int key, repeat, sign;
166 {
167 _rl_vi_set_last (key, repeat, sign);
168 rl_vi_insertion_mode (1, key);
169 }
170
171 /* Is the command C a VI mode text modification command? */
172 int
_rl_vi_textmod_command(c)173 _rl_vi_textmod_command (c)
174 int c;
175 {
176 return (member (c, vi_textmod));
177 }
178
179 static void
_rl_vi_stuff_insert(count)180 _rl_vi_stuff_insert (count)
181 int count;
182 {
183 rl_begin_undo_group ();
184 while (count--)
185 rl_insert_text (vi_insert_buffer);
186 rl_end_undo_group ();
187 }
188
189 /* Bound to `.'. Called from command mode, so we know that we have to
190 redo a text modification command. The default for _rl_vi_last_command
191 puts you back into insert mode. */
192 int
rl_vi_redo(count,c)193 rl_vi_redo (count, c)
194 int count, c;
195 {
196 int r;
197
198 if (!rl_explicit_arg)
199 {
200 rl_numeric_arg = _rl_vi_last_repeat;
201 rl_arg_sign = _rl_vi_last_arg_sign;
202 }
203
204 r = 0;
205 vi_redoing = 1;
206 /* If we're redoing an insert with `i', stuff in the inserted text
207 and do not go into insertion mode. */
208 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
209 {
210 _rl_vi_stuff_insert (count);
211 /* And back up point over the last character inserted. */
212 if (rl_point > 0)
213 _rl_vi_backup ();
214 }
215 /* Ditto for redoing an insert with `a', but move forward a character first
216 like the `a' command does. */
217 else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
218 {
219 _rl_vi_append_forward ('a');
220 _rl_vi_stuff_insert (count);
221 if (rl_point > 0)
222 _rl_vi_backup ();
223 }
224 else
225 r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
226 vi_redoing = 0;
227
228 return (r);
229 }
230
231 /* A placeholder for further expansion. */
232 int
rl_vi_undo(count,key)233 rl_vi_undo (count, key)
234 int count, key;
235 {
236 return (rl_undo_command (count, key));
237 }
238
239 /* Yank the nth arg from the previous line into this line at point. */
240 int
rl_vi_yank_arg(count,key)241 rl_vi_yank_arg (count, key)
242 int count, key;
243 {
244 /* Readline thinks that the first word on a line is the 0th, while vi
245 thinks the first word on a line is the 1st. Compensate. */
246 if (rl_explicit_arg)
247 rl_yank_nth_arg (count - 1, 0);
248 else
249 rl_yank_nth_arg ('$', 0);
250
251 return (0);
252 }
253
254 /* With an argument, move back that many history lines, else move to the
255 beginning of history. */
256 int
rl_vi_fetch_history(count,c)257 rl_vi_fetch_history (count, c)
258 int count, c;
259 {
260 int wanted;
261
262 /* Giving an argument of n means we want the nth command in the history
263 file. The command number is interpreted the same way that the bash
264 `history' command does it -- that is, giving an argument count of 450
265 to this command would get the command listed as number 450 in the
266 output of `history'. */
267 if (rl_explicit_arg)
268 {
269 wanted = history_base + where_history () - count;
270 if (wanted <= 0)
271 rl_beginning_of_history (0, 0);
272 else
273 rl_get_previous_history (wanted, c);
274 }
275 else
276 rl_beginning_of_history (count, 0);
277 return (0);
278 }
279
280 /* Search again for the last thing searched for. */
281 int
rl_vi_search_again(count,key)282 rl_vi_search_again (count, key)
283 int count, key;
284 {
285 switch (key)
286 {
287 case 'n':
288 rl_noninc_reverse_search_again (count, key);
289 break;
290
291 case 'N':
292 rl_noninc_forward_search_again (count, key);
293 break;
294 }
295 return (0);
296 }
297
298 /* Do a vi style search. */
299 int
rl_vi_search(count,key)300 rl_vi_search (count, key)
301 int count, key;
302 {
303 switch (key)
304 {
305 case '?':
306 _rl_free_saved_history_line ();
307 rl_noninc_forward_search (count, key);
308 break;
309
310 case '/':
311 _rl_free_saved_history_line ();
312 rl_noninc_reverse_search (count, key);
313 break;
314
315 default:
316 rl_ding ();
317 break;
318 }
319 return (0);
320 }
321
322 /* Completion, from vi's point of view. */
323 int
rl_vi_complete(ignore,key)324 rl_vi_complete (ignore, key)
325 int ignore, key;
326 {
327 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
328 {
329 if (!whitespace (rl_line_buffer[rl_point + 1]))
330 rl_vi_end_word (1, 'E');
331 rl_point++;
332 }
333
334 if (key == '*')
335 rl_complete_internal ('*'); /* Expansion and replacement. */
336 else if (key == '=')
337 rl_complete_internal ('?'); /* List possible completions. */
338 else if (key == '\\')
339 rl_complete_internal (TAB); /* Standard Readline completion. */
340 else
341 rl_complete (0, key);
342
343 if (key == '*' || key == '\\')
344 rl_vi_start_inserting (key, 1, rl_arg_sign);
345
346 return (0);
347 }
348
349 /* Tilde expansion for vi mode. */
350 int
rl_vi_tilde_expand(ignore,key)351 rl_vi_tilde_expand (ignore, key)
352 int ignore, key;
353 {
354 rl_tilde_expand (0, key);
355 rl_vi_start_inserting (key, 1, rl_arg_sign);
356 return (0);
357 }
358
359 /* Previous word in vi mode. */
360 int
rl_vi_prev_word(count,key)361 rl_vi_prev_word (count, key)
362 int count, key;
363 {
364 if (count < 0)
365 return (rl_vi_next_word (-count, key));
366
367 if (rl_point == 0)
368 {
369 rl_ding ();
370 return (0);
371 }
372
373 if (_rl_uppercase_p (key))
374 rl_vi_bWord (count, key);
375 else
376 rl_vi_bword (count, key);
377
378 return (0);
379 }
380
381 /* Next word in vi mode. */
382 int
rl_vi_next_word(count,key)383 rl_vi_next_word (count, key)
384 int count, key;
385 {
386 if (count < 0)
387 return (rl_vi_prev_word (-count, key));
388
389 if (rl_point >= (rl_end - 1))
390 {
391 rl_ding ();
392 return (0);
393 }
394
395 if (_rl_uppercase_p (key))
396 rl_vi_fWord (count, key);
397 else
398 rl_vi_fword (count, key);
399 return (0);
400 }
401
402 /* Move to the end of the ?next? word. */
403 int
rl_vi_end_word(count,key)404 rl_vi_end_word (count, key)
405 int count, key;
406 {
407 if (count < 0)
408 {
409 rl_ding ();
410 return -1;
411 }
412
413 if (_rl_uppercase_p (key))
414 rl_vi_eWord (count, key);
415 else
416 rl_vi_eword (count, key);
417 return (0);
418 }
419
420 /* Move forward a word the way that 'W' does. */
421 int
rl_vi_fWord(count,ignore)422 rl_vi_fWord (count, ignore)
423 int count, ignore;
424 {
425 while (count-- && rl_point < (rl_end - 1))
426 {
427 /* Skip until whitespace. */
428 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
429 rl_point++;
430
431 /* Now skip whitespace. */
432 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
433 rl_point++;
434 }
435 return (0);
436 }
437
438 int
rl_vi_bWord(count,ignore)439 rl_vi_bWord (count, ignore)
440 int count, ignore;
441 {
442 while (count-- && rl_point > 0)
443 {
444 /* If we are at the start of a word, move back to whitespace so
445 we will go back to the start of the previous word. */
446 if (!whitespace (rl_line_buffer[rl_point]) &&
447 whitespace (rl_line_buffer[rl_point - 1]))
448 rl_point--;
449
450 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
451 rl_point--;
452
453 if (rl_point > 0)
454 {
455 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
456 rl_point++;
457 }
458 }
459 return (0);
460 }
461
462 int
rl_vi_eWord(count,ignore)463 rl_vi_eWord (count, ignore)
464 int count, ignore;
465 {
466 while (count-- && rl_point < (rl_end - 1))
467 {
468 if (!whitespace (rl_line_buffer[rl_point]))
469 rl_point++;
470
471 /* Move to the next non-whitespace character (to the start of the
472 next word). */
473 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
474 rl_point++;
475
476 if (rl_point && rl_point < rl_end)
477 {
478 /* Skip whitespace. */
479 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
480 rl_point++;
481
482 /* Skip until whitespace. */
483 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
484 rl_point++;
485
486 /* Move back to the last character of the word. */
487 rl_point--;
488 }
489 }
490 return (0);
491 }
492
493 int
rl_vi_fword(count,ignore)494 rl_vi_fword (count, ignore)
495 int count, ignore;
496 {
497 while (count-- && rl_point < (rl_end - 1))
498 {
499 /* Move to white space (really non-identifer). */
500 if (_rl_isident (rl_line_buffer[rl_point]))
501 {
502 while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
503 rl_point++;
504 }
505 else /* if (!whitespace (rl_line_buffer[rl_point])) */
506 {
507 while (!_rl_isident (rl_line_buffer[rl_point]) &&
508 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
509 rl_point++;
510 }
511
512 /* Move past whitespace. */
513 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
514 rl_point++;
515 }
516 return (0);
517 }
518
519 int
rl_vi_bword(count,ignore)520 rl_vi_bword (count, ignore)
521 int count, ignore;
522 {
523 while (count-- && rl_point > 0)
524 {
525 int last_is_ident;
526
527 /* If we are at the start of a word, move back to whitespace
528 so we will go back to the start of the previous word. */
529 if (!whitespace (rl_line_buffer[rl_point]) &&
530 whitespace (rl_line_buffer[rl_point - 1]))
531 rl_point--;
532
533 /* If this character and the previous character are `opposite', move
534 back so we don't get messed up by the rl_point++ down there in
535 the while loop. Without this code, words like `l;' screw up the
536 function. */
537 last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
538 if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
539 (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
540 rl_point--;
541
542 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
543 rl_point--;
544
545 if (rl_point > 0)
546 {
547 if (_rl_isident (rl_line_buffer[rl_point]))
548 while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
549 else
550 while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
551 !whitespace (rl_line_buffer[rl_point]));
552 rl_point++;
553 }
554 }
555 return (0);
556 }
557
558 int
rl_vi_eword(count,ignore)559 rl_vi_eword (count, ignore)
560 int count, ignore;
561 {
562 while (count-- && rl_point < rl_end - 1)
563 {
564 if (!whitespace (rl_line_buffer[rl_point]))
565 rl_point++;
566
567 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
568 rl_point++;
569
570 if (rl_point < rl_end)
571 {
572 if (_rl_isident (rl_line_buffer[rl_point]))
573 while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
574 else
575 while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
576 && !whitespace (rl_line_buffer[rl_point]));
577 }
578 rl_point--;
579 }
580 return (0);
581 }
582
583 int
rl_vi_insert_beg(count,key)584 rl_vi_insert_beg (count, key)
585 int count, key;
586 {
587 rl_beg_of_line (1, key);
588 rl_vi_insertion_mode (1, key);
589 return (0);
590 }
591
592 static void
_rl_vi_append_forward(key)593 _rl_vi_append_forward (key)
594 int key;
595 {
596 int point;
597
598 if (rl_point < rl_end)
599 {
600 if (MB_CUR_MAX == 1 || rl_byte_oriented)
601 rl_point++;
602 else
603 {
604 point = rl_point;
605 rl_forward_char (1, key);
606 if (point == rl_point)
607 rl_point = rl_end;
608 }
609 }
610 }
611
612 int
rl_vi_append_mode(count,key)613 rl_vi_append_mode (count, key)
614 int count, key;
615 {
616 _rl_vi_append_forward (key);
617 rl_vi_start_inserting (key, 1, rl_arg_sign);
618 return (0);
619 }
620
621 int
rl_vi_append_eol(count,key)622 rl_vi_append_eol (count, key)
623 int count, key;
624 {
625 rl_end_of_line (1, key);
626 rl_vi_append_mode (1, key);
627 return (0);
628 }
629
630 /* What to do in the case of C-d. */
631 int
rl_vi_eof_maybe(count,c)632 rl_vi_eof_maybe (count, c)
633 int count, c;
634 {
635 return (rl_newline (1, '\n'));
636 }
637
638 /* Insertion mode stuff. */
639
640 /* Switching from one mode to the other really just involves
641 switching keymaps. */
642 int
rl_vi_insertion_mode(count,key)643 rl_vi_insertion_mode (count, key)
644 int count, key;
645 {
646 _rl_keymap = vi_insertion_keymap;
647 _rl_vi_last_key_before_insert = key;
648 return (0);
649 }
650
651 static void
_rl_vi_save_insert(up)652 _rl_vi_save_insert (up)
653 UNDO_LIST *up;
654 {
655 int len, start, end;
656
657 if (up == 0 || up->what != UNDO_INSERT)
658 {
659 if (vi_insert_buffer_size >= 1)
660 vi_insert_buffer[0] = '\0';
661 return;
662 }
663
664 start = up->start;
665 end = up->end;
666 len = end - start + 1;
667 if (len >= vi_insert_buffer_size)
668 {
669 vi_insert_buffer_size += (len + 32) - (len % 32);
670 vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
671 }
672 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
673 vi_insert_buffer[len-1] = '\0';
674 }
675
676 void
_rl_vi_done_inserting()677 _rl_vi_done_inserting ()
678 {
679 if (_rl_vi_doing_insert)
680 {
681 /* The `C', `s', and `S' commands set this. */
682 rl_end_undo_group ();
683 /* Now, the text between rl_undo_list->next->start and
684 rl_undo_list->next->end is what was inserted while in insert
685 mode. It gets copied to VI_INSERT_BUFFER because it depends
686 on absolute indices into the line which may change (though they
687 probably will not). */
688 _rl_vi_doing_insert = 0;
689 _rl_vi_save_insert (rl_undo_list->next);
690 vi_continued_command = 1;
691 }
692 else
693 {
694 if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list)
695 _rl_vi_save_insert (rl_undo_list);
696 /* XXX - Other keys probably need to be checked. */
697 else if (_rl_vi_last_key_before_insert == 'C')
698 rl_end_undo_group ();
699 while (_rl_undo_group_level > 0)
700 rl_end_undo_group ();
701 vi_continued_command = 0;
702 }
703 }
704
705 int
rl_vi_movement_mode(count,key)706 rl_vi_movement_mode (count, key)
707 int count, key;
708 {
709 if (rl_point > 0)
710 rl_backward_char (1, key);
711
712 _rl_keymap = vi_movement_keymap;
713 _rl_vi_done_inserting ();
714
715 /* This is how POSIX.2 says `U' should behave -- everything up until the
716 first time you go into command mode should not be undone. */
717 if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
718 rl_free_undo_list ();
719
720 RL_SETSTATE (RL_STATE_VICMDONCE);
721 return (0);
722 }
723
724 int
rl_vi_arg_digit(count,c)725 rl_vi_arg_digit (count, c)
726 int count, c;
727 {
728 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
729 return (rl_beg_of_line (1, c));
730 else
731 return (rl_digit_argument (count, c));
732 }
733
734 /* Change the case of the next COUNT characters. */
735 #if defined (HANDLE_MULTIBYTE)
736 static int
_rl_vi_change_mbchar_case(count)737 _rl_vi_change_mbchar_case (count)
738 int count;
739 {
740 wchar_t wc;
741 char mb[MB_LEN_MAX+1];
742 int mlen, p;
743 mbstate_t ps;
744
745 memset (&ps, 0, sizeof (mbstate_t));
746 if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
747 count--;
748 while (count-- && rl_point < rl_end)
749 {
750 mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
751 if (iswupper (wc))
752 wc = towlower (wc);
753 else if (iswlower (wc))
754 wc = towupper (wc);
755 else
756 {
757 /* Just skip over chars neither upper nor lower case */
758 rl_forward_char (1, 0);
759 continue;
760 }
761
762 /* Vi is kind of strange here. */
763 if (wc)
764 {
765 p = rl_point;
766 mlen = wcrtomb (mb, wc, &ps);
767 if (mlen >= 0)
768 mb[mlen] = '\0';
769 rl_begin_undo_group ();
770 rl_vi_delete (1, 0);
771 if (rl_point < p) /* Did we retreat at EOL? */
772 rl_point++; /* XXX - should we advance more than 1 for mbchar? */
773 rl_insert_text (mb);
774 rl_end_undo_group ();
775 rl_vi_check ();
776 }
777 else
778 rl_forward_char (1, 0);
779 }
780
781 return 0;
782 }
783 #endif
784
785 int
rl_vi_change_case(count,ignore)786 rl_vi_change_case (count, ignore)
787 int count, ignore;
788 {
789 int c, p;
790
791 /* Don't try this on an empty line. */
792 if (rl_point >= rl_end)
793 return (0);
794
795 c = 0;
796 #if defined (HANDLE_MULTIBYTE)
797 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
798 return (_rl_vi_change_mbchar_case (count));
799 #endif
800
801 while (count-- && rl_point < rl_end)
802 {
803 if (_rl_uppercase_p (rl_line_buffer[rl_point]))
804 c = _rl_to_lower (rl_line_buffer[rl_point]);
805 else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
806 c = _rl_to_upper (rl_line_buffer[rl_point]);
807 else
808 {
809 /* Just skip over characters neither upper nor lower case. */
810 rl_forward_char (1, c);
811 continue;
812 }
813
814 /* Vi is kind of strange here. */
815 if (c)
816 {
817 p = rl_point;
818 rl_begin_undo_group ();
819 rl_vi_delete (1, c);
820 if (rl_point < p) /* Did we retreat at EOL? */
821 rl_point++;
822 _rl_insert_char (1, c);
823 rl_end_undo_group ();
824 rl_vi_check ();
825 }
826 else
827 rl_forward_char (1, c);
828 }
829 return (0);
830 }
831
832 int
rl_vi_put(count,key)833 rl_vi_put (count, key)
834 int count, key;
835 {
836 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
837 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
838
839 while (count--)
840 rl_yank (1, key);
841
842 rl_backward_char (1, key);
843 return (0);
844 }
845
846 static void
_rl_vi_backup()847 _rl_vi_backup ()
848 {
849 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
850 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
851 else
852 rl_point--;
853 }
854
855 int
rl_vi_check()856 rl_vi_check ()
857 {
858 if (rl_point && rl_point == rl_end)
859 {
860 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
861 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
862 else
863 rl_point--;
864 }
865 return (0);
866 }
867
868 int
rl_vi_column(count,key)869 rl_vi_column (count, key)
870 int count, key;
871 {
872 if (count > rl_end)
873 rl_end_of_line (1, key);
874 else
875 rl_point = count - 1;
876 return (0);
877 }
878
879 int
rl_vi_domove(key,nextkey)880 rl_vi_domove (key, nextkey)
881 int key, *nextkey;
882 {
883 int c, save;
884 int old_end;
885
886 rl_mark = rl_point;
887 RL_SETSTATE(RL_STATE_MOREINPUT);
888 c = rl_read_key ();
889 RL_UNSETSTATE(RL_STATE_MOREINPUT);
890
891 if (c < 0)
892 {
893 *nextkey = 0;
894 return -1;
895 }
896
897 *nextkey = c;
898
899 if (!member (c, vi_motion))
900 {
901 if (_rl_digit_p (c))
902 {
903 save = rl_numeric_arg;
904 rl_numeric_arg = _rl_digit_value (c);
905 rl_explicit_arg = 1;
906 RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION);
907 rl_digit_loop1 ();
908 RL_UNSETSTATE (RL_STATE_VIMOTION);
909 rl_numeric_arg *= save;
910 RL_SETSTATE(RL_STATE_MOREINPUT);
911 c = rl_read_key (); /* real command */
912 RL_UNSETSTATE(RL_STATE_MOREINPUT);
913 if (c < 0)
914 {
915 *nextkey = 0;
916 return -1;
917 }
918 *nextkey = c;
919 }
920 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
921 {
922 rl_mark = rl_end;
923 rl_beg_of_line (1, c);
924 _rl_vi_last_motion = c;
925 return (0);
926 }
927 else
928 return (-1);
929 }
930
931 _rl_vi_last_motion = c;
932
933 /* Append a blank character temporarily so that the motion routines
934 work right at the end of the line. */
935 old_end = rl_end;
936 rl_line_buffer[rl_end++] = ' ';
937 rl_line_buffer[rl_end] = '\0';
938
939 _rl_dispatch (c, _rl_keymap);
940
941 /* Remove the blank that we added. */
942 rl_end = old_end;
943 rl_line_buffer[rl_end] = '\0';
944 if (rl_point > rl_end)
945 rl_point = rl_end;
946
947 /* No change in position means the command failed. */
948 if (rl_mark == rl_point)
949 return (-1);
950
951 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
952 word. If we are not at the end of the line, and we are on a
953 non-whitespace character, move back one (presumably to whitespace). */
954 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
955 !whitespace (rl_line_buffer[rl_point]))
956 rl_point--;
957
958 /* If cw or cW, back up to the end of a word, so the behaviour of ce
959 or cE is the actual result. Brute-force, no subtlety. */
960 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
961 {
962 /* Don't move farther back than where we started. */
963 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
964 rl_point--;
965
966 /* Posix.2 says that if cw or cW moves the cursor towards the end of
967 the line, the character under the cursor should be deleted. */
968 if (rl_point == rl_mark)
969 rl_point++;
970 else
971 {
972 /* Move past the end of the word so that the kill doesn't
973 remove the last letter of the previous word. Only do this
974 if we are not at the end of the line. */
975 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
976 rl_point++;
977 }
978 }
979
980 if (rl_mark < rl_point)
981 SWAP (rl_point, rl_mark);
982
983 return (0);
984 }
985
986 /* Process C as part of the current numeric argument. Return -1 if the
987 argument should be aborted, 0 if we should not read any more chars, and
988 1 if we should continue to read chars. */
989 static int
_rl_vi_arg_dispatch(c)990 _rl_vi_arg_dispatch (c)
991 int c;
992 {
993 int key;
994
995 key = c;
996 if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
997 {
998 rl_numeric_arg *= 4;
999 return 1;
1000 }
1001
1002 c = UNMETA (c);
1003
1004 if (_rl_digit_p (c))
1005 {
1006 if (rl_explicit_arg)
1007 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
1008 else
1009 rl_numeric_arg = _rl_digit_value (c);
1010 rl_explicit_arg = 1;
1011 return 1;
1012 }
1013 else
1014 {
1015 rl_clear_message ();
1016 rl_stuff_char (key);
1017 return 0;
1018 }
1019 }
1020
1021 /* A simplified loop for vi. Don't dispatch key at end.
1022 Don't recognize minus sign?
1023 Should this do rl_save_prompt/rl_restore_prompt? */
1024 static int
rl_digit_loop1()1025 rl_digit_loop1 ()
1026 {
1027 int c, r;
1028
1029 while (1)
1030 {
1031 if (_rl_arg_overflow ())
1032 return 1;
1033
1034 c = _rl_arg_getchar ();
1035
1036 r = _rl_vi_arg_dispatch (c);
1037 if (r <= 0)
1038 break;
1039 }
1040
1041 RL_UNSETSTATE(RL_STATE_NUMERICARG);
1042 return (0);
1043 }
1044
1045 int
rl_vi_delete_to(count,key)1046 rl_vi_delete_to (count, key)
1047 int count, key;
1048 {
1049 int c;
1050
1051 if (_rl_uppercase_p (key))
1052 rl_stuff_char ('$');
1053 else if (vi_redoing)
1054 rl_stuff_char (_rl_vi_last_motion);
1055
1056 if (rl_vi_domove (key, &c))
1057 {
1058 rl_ding ();
1059 return -1;
1060 }
1061
1062 /* These are the motion commands that do not require adjusting the
1063 mark. */
1064 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
1065 rl_mark++;
1066
1067 rl_kill_text (rl_point, rl_mark);
1068 return (0);
1069 }
1070
1071 int
rl_vi_change_to(count,key)1072 rl_vi_change_to (count, key)
1073 int count, key;
1074 {
1075 int c, start_pos;
1076
1077 if (_rl_uppercase_p (key))
1078 rl_stuff_char ('$');
1079 else if (vi_redoing)
1080 rl_stuff_char (_rl_vi_last_motion);
1081
1082 start_pos = rl_point;
1083
1084 if (rl_vi_domove (key, &c))
1085 {
1086 rl_ding ();
1087 return -1;
1088 }
1089
1090 /* These are the motion commands that do not require adjusting the
1091 mark. c[wW] are handled by special-case code in rl_vi_domove(),
1092 and already leave the mark at the correct location. */
1093 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
1094 rl_mark++;
1095
1096 /* The cursor never moves with c[wW]. */
1097 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
1098 rl_point = start_pos;
1099
1100 if (vi_redoing)
1101 {
1102 if (vi_insert_buffer && *vi_insert_buffer)
1103 rl_begin_undo_group ();
1104 rl_delete_text (rl_point, rl_mark);
1105 if (vi_insert_buffer && *vi_insert_buffer)
1106 {
1107 rl_insert_text (vi_insert_buffer);
1108 rl_end_undo_group ();
1109 }
1110 }
1111 else
1112 {
1113 rl_begin_undo_group (); /* to make the `u' command work */
1114 rl_kill_text (rl_point, rl_mark);
1115 /* `C' does not save the text inserted for undoing or redoing. */
1116 if (_rl_uppercase_p (key) == 0)
1117 _rl_vi_doing_insert = 1;
1118 rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign);
1119 }
1120
1121 return (0);
1122 }
1123
1124 int
rl_vi_yank_to(count,key)1125 rl_vi_yank_to (count, key)
1126 int count, key;
1127 {
1128 int c, save;
1129
1130 save = rl_point;
1131 if (_rl_uppercase_p (key))
1132 rl_stuff_char ('$');
1133
1134 if (rl_vi_domove (key, &c))
1135 {
1136 rl_ding ();
1137 return -1;
1138 }
1139
1140 /* These are the motion commands that do not require adjusting the
1141 mark. */
1142 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
1143 rl_mark++;
1144
1145 rl_begin_undo_group ();
1146 rl_kill_text (rl_point, rl_mark);
1147 rl_end_undo_group ();
1148 rl_do_undo ();
1149 rl_point = save;
1150
1151 return (0);
1152 }
1153
1154 int
rl_vi_rubout(count,key)1155 rl_vi_rubout (count, key)
1156 int count, key;
1157 {
1158 int opoint;
1159
1160 if (count < 0)
1161 return (rl_vi_delete (-count, key));
1162
1163 if (rl_point == 0)
1164 {
1165 rl_ding ();
1166 return -1;
1167 }
1168
1169 opoint = rl_point;
1170 if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1171 rl_backward_char (count, key);
1172 else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1173 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1174 else
1175 rl_point -= count;
1176
1177 if (rl_point < 0)
1178 rl_point = 0;
1179
1180 rl_kill_text (rl_point, opoint);
1181
1182 return (0);
1183 }
1184
1185 int
rl_vi_delete(count,key)1186 rl_vi_delete (count, key)
1187 int count, key;
1188 {
1189 int end;
1190
1191 if (count < 0)
1192 return (rl_vi_rubout (-count, key));
1193
1194 if (rl_end == 0)
1195 {
1196 rl_ding ();
1197 return -1;
1198 }
1199
1200 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1201 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1202 else
1203 end = rl_point + count;
1204
1205 if (end >= rl_end)
1206 end = rl_end;
1207
1208 rl_kill_text (rl_point, end);
1209
1210 if (rl_point > 0 && rl_point == rl_end)
1211 rl_backward_char (1, key);
1212
1213 return (0);
1214 }
1215
1216 int
rl_vi_back_to_indent(count,key)1217 rl_vi_back_to_indent (count, key)
1218 int count, key;
1219 {
1220 rl_beg_of_line (1, key);
1221 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1222 rl_point++;
1223 return (0);
1224 }
1225
1226 int
rl_vi_first_print(count,key)1227 rl_vi_first_print (count, key)
1228 int count, key;
1229 {
1230 return (rl_vi_back_to_indent (1, key));
1231 }
1232
1233 static int _rl_cs_dir, _rl_cs_orig_dir;
1234
1235 #if defined (READLINE_CALLBACKS)
1236 static int
_rl_vi_callback_char_search(data)1237 _rl_vi_callback_char_search (data)
1238 _rl_callback_generic_arg *data;
1239 {
1240 int c;
1241 #if defined (HANDLE_MULTIBYTE)
1242 c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1243 #else
1244 RL_SETSTATE(RL_STATE_MOREINPUT);
1245 c = rl_read_key ();
1246 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1247 #endif
1248
1249 if (c <= 0)
1250 return -1;
1251
1252 #if !defined (HANDLE_MULTIBYTE)
1253 _rl_vi_last_search_char = c;
1254 #endif
1255
1256 _rl_callback_func = 0;
1257 _rl_want_redisplay = 1;
1258
1259 #if defined (HANDLE_MULTIBYTE)
1260 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1261 #else
1262 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1263 #endif
1264 }
1265 #endif
1266
1267 int
rl_vi_char_search(count,key)1268 rl_vi_char_search (count, key)
1269 int count, key;
1270 {
1271 int c;
1272 #if defined (HANDLE_MULTIBYTE)
1273 static char *target;
1274 static int tlen;
1275 #else
1276 static char target;
1277 #endif
1278
1279 if (key == ';' || key == ',')
1280 _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1281 else
1282 {
1283 switch (key)
1284 {
1285 case 't':
1286 _rl_cs_orig_dir = _rl_cs_dir = FTO;
1287 break;
1288
1289 case 'T':
1290 _rl_cs_orig_dir = _rl_cs_dir = BTO;
1291 break;
1292
1293 case 'f':
1294 _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1295 break;
1296
1297 case 'F':
1298 _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1299 break;
1300 }
1301
1302 if (vi_redoing)
1303 {
1304 /* set target and tlen below */
1305 }
1306 #if defined (READLINE_CALLBACKS)
1307 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1308 {
1309 _rl_callback_data = _rl_callback_data_alloc (count);
1310 _rl_callback_data->i1 = _rl_cs_dir;
1311 _rl_callback_func = _rl_vi_callback_char_search;
1312 return (0);
1313 }
1314 #endif
1315 else
1316 {
1317 #if defined (HANDLE_MULTIBYTE)
1318 c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1319 if (c <= 0)
1320 return -1;
1321 _rl_vi_last_search_mblen = c;
1322 #else
1323 RL_SETSTATE(RL_STATE_MOREINPUT);
1324 c = rl_read_key ();
1325 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1326 if (c < 0)
1327 return -1;
1328 _rl_vi_last_search_char = c;
1329 #endif
1330 }
1331 }
1332
1333 #if defined (HANDLE_MULTIBYTE)
1334 target = _rl_vi_last_search_mbchar;
1335 tlen = _rl_vi_last_search_mblen;
1336 #else
1337 target = _rl_vi_last_search_char;
1338 #endif
1339
1340 #if defined (HANDLE_MULTIBYTE)
1341 return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1342 #else
1343 return (_rl_char_search_internal (count, _rl_cs_dir, target));
1344 #endif
1345 }
1346
1347 /* Match brackets */
1348 int
rl_vi_match(ignore,key)1349 rl_vi_match (ignore, key)
1350 int ignore, key;
1351 {
1352 int count = 1, brack, pos, tmp, pre;
1353
1354 pos = rl_point;
1355 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1356 {
1357 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1358 {
1359 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1360 {
1361 pre = rl_point;
1362 rl_forward_char (1, key);
1363 if (pre == rl_point)
1364 break;
1365 }
1366 }
1367 else
1368 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1369 rl_point < rl_end - 1)
1370 rl_forward_char (1, key);
1371
1372 if (brack <= 0)
1373 {
1374 rl_point = pos;
1375 rl_ding ();
1376 return -1;
1377 }
1378 }
1379
1380 pos = rl_point;
1381
1382 if (brack < 0)
1383 {
1384 while (count)
1385 {
1386 tmp = pos;
1387 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1388 pos--;
1389 else
1390 {
1391 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1392 if (tmp == pos)
1393 pos--;
1394 }
1395 if (pos >= 0)
1396 {
1397 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1398 if (b == -brack)
1399 count--;
1400 else if (b == brack)
1401 count++;
1402 }
1403 else
1404 {
1405 rl_ding ();
1406 return -1;
1407 }
1408 }
1409 }
1410 else
1411 { /* brack > 0 */
1412 while (count)
1413 {
1414 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1415 pos++;
1416 else
1417 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1418
1419 if (pos < rl_end)
1420 {
1421 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1422 if (b == -brack)
1423 count--;
1424 else if (b == brack)
1425 count++;
1426 }
1427 else
1428 {
1429 rl_ding ();
1430 return -1;
1431 }
1432 }
1433 }
1434 rl_point = pos;
1435 return (0);
1436 }
1437
1438 int
rl_vi_bracktype(c)1439 rl_vi_bracktype (c)
1440 int c;
1441 {
1442 switch (c)
1443 {
1444 case '(': return 1;
1445 case ')': return -1;
1446 case '[': return 2;
1447 case ']': return -2;
1448 case '{': return 3;
1449 case '}': return -3;
1450 default: return 0;
1451 }
1452 }
1453
1454 static int
_rl_vi_change_char(count,c,mb)1455 _rl_vi_change_char (count, c, mb)
1456 int count, c;
1457 char *mb;
1458 {
1459 int p;
1460
1461 if (c == '\033' || c == CTRL ('C'))
1462 return -1;
1463
1464 rl_begin_undo_group ();
1465 while (count-- && rl_point < rl_end)
1466 {
1467 p = rl_point;
1468 rl_vi_delete (1, c);
1469 if (rl_point < p) /* Did we retreat at EOL? */
1470 rl_point++;
1471 #if defined (HANDLE_MULTIBYTE)
1472 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1473 rl_insert_text (mb);
1474 else
1475 #endif
1476 _rl_insert_char (1, c);
1477 }
1478
1479 /* The cursor shall be left on the last character changed. */
1480 rl_backward_char (1, c);
1481
1482 rl_end_undo_group ();
1483
1484 return (0);
1485 }
1486
1487 static int
_rl_vi_callback_getchar(mb,mlen)1488 _rl_vi_callback_getchar (mb, mlen)
1489 char *mb;
1490 int mlen;
1491 {
1492 int c;
1493
1494 RL_SETSTATE(RL_STATE_MOREINPUT);
1495 c = rl_read_key ();
1496 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1497
1498 if (c < 0)
1499 return -1;
1500
1501 #if defined (HANDLE_MULTIBYTE)
1502 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1503 c = _rl_read_mbstring (c, mb, mlen);
1504 #endif
1505
1506 return c;
1507 }
1508
1509 #if defined (READLINE_CALLBACKS)
1510 static int
_rl_vi_callback_change_char(data)1511 _rl_vi_callback_change_char (data)
1512 _rl_callback_generic_arg *data;
1513 {
1514 int c;
1515 char mb[MB_LEN_MAX];
1516
1517 _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1518
1519 if (c < 0)
1520 return -1;
1521
1522 _rl_callback_func = 0;
1523 _rl_want_redisplay = 1;
1524
1525 return (_rl_vi_change_char (data->count, c, mb));
1526 }
1527 #endif
1528
1529 int
rl_vi_change_char(count,key)1530 rl_vi_change_char (count, key)
1531 int count, key;
1532 {
1533 int c;
1534 char mb[MB_LEN_MAX];
1535
1536 if (vi_redoing)
1537 {
1538 c = _rl_vi_last_replacement;
1539 mb[0] = c;
1540 mb[1] = '\0';
1541 }
1542 #if defined (READLINE_CALLBACKS)
1543 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1544 {
1545 _rl_callback_data = _rl_callback_data_alloc (count);
1546 _rl_callback_func = _rl_vi_callback_change_char;
1547 return (0);
1548 }
1549 #endif
1550 else
1551 _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1552
1553 if (c < 0)
1554 return -1;
1555
1556 return (_rl_vi_change_char (count, c, mb));
1557 }
1558
1559 int
rl_vi_subst(count,key)1560 rl_vi_subst (count, key)
1561 int count, key;
1562 {
1563 /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1564 if (vi_redoing == 0)
1565 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
1566
1567 return (rl_vi_change_to (count, 'c'));
1568 }
1569
1570 int
rl_vi_overstrike(count,key)1571 rl_vi_overstrike (count, key)
1572 int count, key;
1573 {
1574 if (_rl_vi_doing_insert == 0)
1575 {
1576 _rl_vi_doing_insert = 1;
1577 rl_begin_undo_group ();
1578 }
1579
1580 if (count > 0)
1581 {
1582 _rl_overwrite_char (count, key);
1583 vi_replace_count += count;
1584 }
1585
1586 return (0);
1587 }
1588
1589 int
rl_vi_overstrike_delete(count,key)1590 rl_vi_overstrike_delete (count, key)
1591 int count, key;
1592 {
1593 int i, s;
1594
1595 for (i = 0; i < count; i++)
1596 {
1597 if (vi_replace_count == 0)
1598 {
1599 rl_ding ();
1600 break;
1601 }
1602 s = rl_point;
1603
1604 if (rl_do_undo ())
1605 vi_replace_count--;
1606
1607 if (rl_point == s)
1608 rl_backward_char (1, key);
1609 }
1610
1611 if (vi_replace_count == 0 && _rl_vi_doing_insert)
1612 {
1613 rl_end_undo_group ();
1614 rl_do_undo ();
1615 _rl_vi_doing_insert = 0;
1616 }
1617 return (0);
1618 }
1619
1620 int
rl_vi_replace(count,key)1621 rl_vi_replace (count, key)
1622 int count, key;
1623 {
1624 int i;
1625
1626 vi_replace_count = 0;
1627
1628 if (!vi_replace_map)
1629 {
1630 vi_replace_map = rl_make_bare_keymap ();
1631
1632 for (i = ' '; i < KEYMAP_SIZE; i++)
1633 vi_replace_map[i].function = rl_vi_overstrike;
1634
1635 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1636 vi_replace_map[ESC].function = rl_vi_movement_mode;
1637 vi_replace_map[RETURN].function = rl_newline;
1638 vi_replace_map[NEWLINE].function = rl_newline;
1639
1640 /* If the normal vi insertion keymap has ^H bound to erase, do the
1641 same here. Probably should remove the assignment to RUBOUT up
1642 there, but I don't think it will make a difference in real life. */
1643 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1644 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1645 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1646
1647 }
1648 _rl_keymap = vi_replace_map;
1649 return (0);
1650 }
1651
1652 #if 0
1653 /* Try to complete the word we are standing on or the word that ends with
1654 the previous character. A space matches everything. Word delimiters are
1655 space and ;. */
1656 int
1657 rl_vi_possible_completions()
1658 {
1659 int save_pos = rl_point;
1660
1661 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1662 {
1663 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1664 rl_line_buffer[rl_point] != ';')
1665 rl_point++;
1666 }
1667 else if (rl_line_buffer[rl_point - 1] == ';')
1668 {
1669 rl_ding ();
1670 return (0);
1671 }
1672
1673 rl_possible_completions ();
1674 rl_point = save_pos;
1675
1676 return (0);
1677 }
1678 #endif
1679
1680 /* Functions to save and restore marks. */
1681 static int
_rl_vi_set_mark()1682 _rl_vi_set_mark ()
1683 {
1684 int ch;
1685
1686 RL_SETSTATE(RL_STATE_MOREINPUT);
1687 ch = rl_read_key ();
1688 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1689
1690 if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
1691 {
1692 rl_ding ();
1693 return -1;
1694 }
1695 ch -= 'a';
1696 vi_mark_chars[ch] = rl_point;
1697 return 0;
1698 }
1699
1700 #if defined (READLINE_CALLBACKS)
1701 static int
_rl_vi_callback_set_mark(data)1702 _rl_vi_callback_set_mark (data)
1703 _rl_callback_generic_arg *data;
1704 {
1705 _rl_callback_func = 0;
1706 _rl_want_redisplay = 1;
1707
1708 return (_rl_vi_set_mark ());
1709 }
1710 #endif
1711
1712 int
rl_vi_set_mark(count,key)1713 rl_vi_set_mark (count, key)
1714 int count, key;
1715 {
1716 #if defined (READLINE_CALLBACKS)
1717 if (RL_ISSTATE (RL_STATE_CALLBACK))
1718 {
1719 _rl_callback_data = 0;
1720 _rl_callback_func = _rl_vi_callback_set_mark;
1721 return (0);
1722 }
1723 #endif
1724
1725 return (_rl_vi_set_mark ());
1726 }
1727
1728 static int
_rl_vi_goto_mark()1729 _rl_vi_goto_mark ()
1730 {
1731 int ch;
1732
1733 RL_SETSTATE(RL_STATE_MOREINPUT);
1734 ch = rl_read_key ();
1735 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1736
1737 if (ch == '`')
1738 {
1739 rl_point = rl_mark;
1740 return 0;
1741 }
1742 else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
1743 {
1744 rl_ding ();
1745 return -1;
1746 }
1747
1748 ch -= 'a';
1749 if (vi_mark_chars[ch] == -1)
1750 {
1751 rl_ding ();
1752 return -1;
1753 }
1754 rl_point = vi_mark_chars[ch];
1755 return 0;
1756 }
1757
1758 #if defined (READLINE_CALLBACKS)
1759 static int
_rl_vi_callback_goto_mark(data)1760 _rl_vi_callback_goto_mark (data)
1761 _rl_callback_generic_arg *data;
1762 {
1763 _rl_callback_func = 0;
1764 _rl_want_redisplay = 1;
1765
1766 return (_rl_vi_goto_mark ());
1767 }
1768 #endif
1769
1770 int
rl_vi_goto_mark(count,key)1771 rl_vi_goto_mark (count, key)
1772 int count, key;
1773 {
1774 #if defined (READLINE_CALLBACKS)
1775 if (RL_ISSTATE (RL_STATE_CALLBACK))
1776 {
1777 _rl_callback_data = 0;
1778 _rl_callback_func = _rl_vi_callback_goto_mark;
1779 return (0);
1780 }
1781 #endif
1782
1783 return (_rl_vi_goto_mark ());
1784 }
1785 #endif /* VI_MODE */
1786