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