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