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