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