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