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