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