OSDN Git Service

Add elfedit
[pf3gnuchains/pf3gnuchains3x.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 */