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