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