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