]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/vi_mode.c
Imported from ../bash-2.05.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
4/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
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"
54#include "readline.h"
55#include "history.h"
56
bb70624e
JA
57#include "rlprivate.h"
58#include "xmalloc.h"
59
ccc6cda3
JA
60#ifndef _rl_digit_p
61#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9')
726f6388
JA
62#endif
63
ccc6cda3
JA
64#ifndef _rl_digit_value
65#define _rl_digit_value(c) ((c) - '0')
726f6388
JA
66#endif
67
68#ifndef member
69#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
70#endif
71
72#ifndef isident
ccc6cda3 73#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
726f6388
JA
74#endif
75
76#ifndef exchange
77#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
78#endif
79
726f6388 80/* Non-zero means enter insertion mode. */
ccc6cda3 81static int _rl_vi_doing_insert;
726f6388 82
726f6388 83/* Command keys which do movement for xxx_to commands. */
28ef6c31 84static const char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
726f6388
JA
85
86/* Keymap used for vi replace characters. Created dynamically since
87 rarely used. */
ccc6cda3 88static Keymap vi_replace_map;
726f6388
JA
89
90/* The number of characters inserted in the last replace operation. */
ccc6cda3 91static int vi_replace_count;
726f6388
JA
92
93/* If non-zero, we have text inserted after a c[motion] command that put
94 us implicitly into insert mode. Some people want this text to be
95 attached to the command so that it is `redoable' with `.'. */
ccc6cda3
JA
96static int vi_continued_command;
97static char *vi_insert_buffer;
98static int vi_insert_buffer_size;
726f6388
JA
99
100static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
101static int _rl_vi_last_repeat = 1;
102static int _rl_vi_last_arg_sign = 1;
ccc6cda3
JA
103static int _rl_vi_last_motion;
104static int _rl_vi_last_search_char;
105static int _rl_vi_last_replacement;
106
107static int _rl_vi_last_key_before_insert;
726f6388 108
ccc6cda3 109static int vi_redoing;
726f6388
JA
110
111/* Text modification commands. These are the `redoable' commands. */
28ef6c31 112static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
726f6388 113
ccc6cda3
JA
114/* Arrays for the saved marks. */
115static int vi_mark_chars[27];
116
bb70624e 117static int rl_digit_loop1 __P((void));
726f6388 118
ccc6cda3
JA
119void
120_rl_vi_initialize_line ()
121{
122 register int i;
123
124 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
125 vi_mark_chars[i] = -1;
126}
127
726f6388
JA
128void
129_rl_vi_reset_last ()
130{
131 _rl_vi_last_command = 'i';
132 _rl_vi_last_repeat = 1;
133 _rl_vi_last_arg_sign = 1;
134 _rl_vi_last_motion = 0;
135}
136
137void
138_rl_vi_set_last (key, repeat, sign)
139 int key, repeat, sign;
140{
141 _rl_vi_last_command = key;
142 _rl_vi_last_repeat = repeat;
143 _rl_vi_last_arg_sign = sign;
144}
145
146/* Is the command C a VI mode text modification command? */
147int
ccc6cda3 148_rl_vi_textmod_command (c)
726f6388
JA
149 int c;
150{
151 return (member (c, vi_textmod));
152}
153
ccc6cda3
JA
154static void
155_rl_vi_stuff_insert (count)
156 int count;
157{
158 rl_begin_undo_group ();
159 while (count--)
160 rl_insert_text (vi_insert_buffer);
161 rl_end_undo_group ();
162}
163
726f6388
JA
164/* Bound to `.'. Called from command mode, so we know that we have to
165 redo a text modification command. The default for _rl_vi_last_command
166 puts you back into insert mode. */
ccc6cda3 167int
726f6388
JA
168rl_vi_redo (count, c)
169 int count, c;
170{
171 if (!rl_explicit_arg)
172 {
173 rl_numeric_arg = _rl_vi_last_repeat;
174 rl_arg_sign = _rl_vi_last_arg_sign;
175 }
176
177 vi_redoing = 1;
ccc6cda3
JA
178 /* If we're redoing an insert with `i', stuff in the inserted text
179 and do not go into insertion mode. */
180 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
181 {
182 _rl_vi_stuff_insert (count);
183 /* And back up point over the last character inserted. */
184 if (rl_point > 0)
185 rl_point--;
186 }
187 else
188 _rl_dispatch (_rl_vi_last_command, _rl_keymap);
726f6388
JA
189 vi_redoing = 0;
190
191 return (0);
192}
ccc6cda3
JA
193
194/* A placeholder for further expansion. */
195int
196rl_vi_undo (count, key)
197 int count, key;
198{
199 return (rl_undo_command (count, key));
200}
726f6388
JA
201
202/* Yank the nth arg from the previous line into this line at point. */
ccc6cda3 203int
726f6388
JA
204rl_vi_yank_arg (count, key)
205 int count, key;
206{
207 /* Readline thinks that the first word on a line is the 0th, while vi
208 thinks the first word on a line is the 1st. Compensate. */
209 if (rl_explicit_arg)
210 rl_yank_nth_arg (count - 1, 0);
211 else
212 rl_yank_nth_arg ('$', 0);
213
214 return (0);
215}
216
217/* With an argument, move back that many history lines, else move to the
218 beginning of history. */
ccc6cda3 219int
726f6388
JA
220rl_vi_fetch_history (count, c)
221 int count, c;
222{
ccc6cda3 223 int wanted;
726f6388
JA
224
225 /* Giving an argument of n means we want the nth command in the history
226 file. The command number is interpreted the same way that the bash
227 `history' command does it -- that is, giving an argument count of 450
228 to this command would get the command listed as number 450 in the
229 output of `history'. */
230 if (rl_explicit_arg)
231 {
ccc6cda3 232 wanted = history_base + where_history () - count;
726f6388
JA
233 if (wanted <= 0)
234 rl_beginning_of_history (0, 0);
235 else
ccc6cda3 236 rl_get_previous_history (wanted, c);
726f6388
JA
237 }
238 else
239 rl_beginning_of_history (count, 0);
240 return (0);
241}
242
243/* Search again for the last thing searched for. */
ccc6cda3 244int
726f6388
JA
245rl_vi_search_again (count, key)
246 int count, key;
247{
248 switch (key)
249 {
250 case 'n':
251 rl_noninc_reverse_search_again (count, key);
252 break;
253
254 case 'N':
255 rl_noninc_forward_search_again (count, key);
256 break;
257 }
258 return (0);
259}
260
261/* Do a vi style search. */
ccc6cda3 262int
726f6388
JA
263rl_vi_search (count, key)
264 int count, key;
265{
266 switch (key)
267 {
268 case '?':
269 rl_noninc_forward_search (count, key);
270 break;
271
272 case '/':
273 rl_noninc_reverse_search (count, key);
274 break;
275
276 default:
28ef6c31 277 rl_ding ();
726f6388
JA
278 break;
279 }
280 return (0);
281}
282
283/* Completion, from vi's point of view. */
ccc6cda3 284int
726f6388
JA
285rl_vi_complete (ignore, key)
286 int ignore, key;
287{
288 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
289 {
290 if (!whitespace (rl_line_buffer[rl_point + 1]))
291 rl_vi_end_word (1, 'E');
292 rl_point++;
293 }
294
295 if (key == '*')
296 rl_complete_internal ('*'); /* Expansion and replacement. */
297 else if (key == '=')
298 rl_complete_internal ('?'); /* List possible completions. */
299 else if (key == '\\')
300 rl_complete_internal (TAB); /* Standard Readline completion. */
301 else
302 rl_complete (0, key);
303
304 if (key == '*' || key == '\\')
305 {
306 _rl_vi_set_last (key, 1, rl_arg_sign);
307 rl_vi_insertion_mode (1, key);
308 }
309 return (0);
310}
311
312/* Tilde expansion for vi mode. */
ccc6cda3 313int
726f6388
JA
314rl_vi_tilde_expand (ignore, key)
315 int ignore, key;
316{
317 rl_tilde_expand (0, key);
318 _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */
319 rl_vi_insertion_mode (1, key);
320 return (0);
321}
322
323/* Previous word in vi mode. */
ccc6cda3 324int
726f6388
JA
325rl_vi_prev_word (count, key)
326 int count, key;
327{
328 if (count < 0)
329 return (rl_vi_next_word (-count, key));
330
331 if (rl_point == 0)
332 {
28ef6c31 333 rl_ding ();
726f6388
JA
334 return (0);
335 }
336
ccc6cda3 337 if (_rl_uppercase_p (key))
b72432fd 338 rl_vi_bWord (count, key);
726f6388 339 else
b72432fd 340 rl_vi_bword (count, key);
726f6388
JA
341
342 return (0);
343}
344
345/* Next word in vi mode. */
ccc6cda3 346int
726f6388
JA
347rl_vi_next_word (count, key)
348 int count, key;
349{
350 if (count < 0)
351 return (rl_vi_prev_word (-count, key));
352
353 if (rl_point >= (rl_end - 1))
354 {
28ef6c31 355 rl_ding ();
726f6388
JA
356 return (0);
357 }
358
ccc6cda3 359 if (_rl_uppercase_p (key))
b72432fd 360 rl_vi_fWord (count, key);
726f6388 361 else
b72432fd 362 rl_vi_fword (count, key);
726f6388
JA
363 return (0);
364}
365
366/* Move to the end of the ?next? word. */
ccc6cda3 367int
726f6388
JA
368rl_vi_end_word (count, key)
369 int count, key;
370{
371 if (count < 0)
372 {
28ef6c31 373 rl_ding ();
726f6388
JA
374 return -1;
375 }
376
ccc6cda3 377 if (_rl_uppercase_p (key))
b72432fd 378 rl_vi_eWord (count, key);
726f6388 379 else
b72432fd 380 rl_vi_eword (count, key);
726f6388
JA
381 return (0);
382}
383
384/* Move forward a word the way that 'W' does. */
ccc6cda3 385int
b72432fd
JA
386rl_vi_fWord (count, ignore)
387 int count, ignore;
726f6388
JA
388{
389 while (count-- && rl_point < (rl_end - 1))
390 {
391 /* Skip until whitespace. */
392 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
393 rl_point++;
394
395 /* Now skip whitespace. */
396 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
397 rl_point++;
398 }
399 return (0);
400}
401
ccc6cda3 402int
b72432fd
JA
403rl_vi_bWord (count, ignore)
404 int count, ignore;
726f6388
JA
405{
406 while (count-- && rl_point > 0)
407 {
408 /* If we are at the start of a word, move back to whitespace so
409 we will go back to the start of the previous word. */
410 if (!whitespace (rl_line_buffer[rl_point]) &&
411 whitespace (rl_line_buffer[rl_point - 1]))
412 rl_point--;
413
414 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
415 rl_point--;
416
417 if (rl_point > 0)
418 {
419 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
420 rl_point++;
421 }
422 }
423 return (0);
424}
425
ccc6cda3 426int
b72432fd
JA
427rl_vi_eWord (count, ignore)
428 int count, ignore;
726f6388
JA
429{
430 while (count-- && rl_point < (rl_end - 1))
431 {
432 if (!whitespace (rl_line_buffer[rl_point]))
433 rl_point++;
434
435 /* Move to the next non-whitespace character (to the start of the
436 next word). */
437 while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
438
439 if (rl_point && rl_point < rl_end)
440 {
441 /* Skip whitespace. */
442 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
443 rl_point++;
444
445 /* Skip until whitespace. */
446 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
447 rl_point++;
448
449 /* Move back to the last character of the word. */
450 rl_point--;
451 }
452 }
453 return (0);
454}
455
ccc6cda3 456int
b72432fd
JA
457rl_vi_fword (count, ignore)
458 int count, ignore;
726f6388
JA
459{
460 while (count-- && rl_point < (rl_end - 1))
461 {
462 /* Move to white space (really non-identifer). */
463 if (isident (rl_line_buffer[rl_point]))
464 {
465 while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
466 rl_point++;
467 }
468 else /* if (!whitespace (rl_line_buffer[rl_point])) */
469 {
470 while (!isident (rl_line_buffer[rl_point]) &&
471 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
472 rl_point++;
473 }
474
475 /* Move past whitespace. */
476 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
477 rl_point++;
478 }
479 return (0);
480}
481
ccc6cda3 482int
b72432fd
JA
483rl_vi_bword (count, ignore)
484 int count, ignore;
726f6388
JA
485{
486 while (count-- && rl_point > 0)
487 {
488 int last_is_ident;
489
490 /* If we are at the start of a word, move back to whitespace
491 so we will go back to the start of the previous word. */
492 if (!whitespace (rl_line_buffer[rl_point]) &&
493 whitespace (rl_line_buffer[rl_point - 1]))
494 rl_point--;
495
496 /* If this character and the previous character are `opposite', move
497 back so we don't get messed up by the rl_point++ down there in
498 the while loop. Without this code, words like `l;' screw up the
499 function. */
500 last_is_ident = isident (rl_line_buffer[rl_point - 1]);
501 if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
502 (!isident (rl_line_buffer[rl_point]) && last_is_ident))
503 rl_point--;
504
505 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
506 rl_point--;
507
508 if (rl_point > 0)
509 {
510 if (isident (rl_line_buffer[rl_point]))
511 while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
512 else
513 while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
514 !whitespace (rl_line_buffer[rl_point]));
515 rl_point++;
516 }
517 }
518 return (0);
519}
520
ccc6cda3 521int
b72432fd
JA
522rl_vi_eword (count, ignore)
523 int count, ignore;
726f6388
JA
524{
525 while (count-- && rl_point < rl_end - 1)
526 {
527 if (!whitespace (rl_line_buffer[rl_point]))
528 rl_point++;
529
530 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
531 rl_point++;
532
533 if (rl_point < rl_end)
534 {
535 if (isident (rl_line_buffer[rl_point]))
536 while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
537 else
538 while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
539 && !whitespace (rl_line_buffer[rl_point]));
540 }
541 rl_point--;
542 }
543 return (0);
544}
545
ccc6cda3 546int
726f6388
JA
547rl_vi_insert_beg (count, key)
548 int count, key;
549{
550 rl_beg_of_line (1, key);
551 rl_vi_insertion_mode (1, key);
552 return (0);
553}
554
ccc6cda3 555int
726f6388
JA
556rl_vi_append_mode (count, key)
557 int count, key;
558{
559 if (rl_point < rl_end)
560 rl_point++;
561 rl_vi_insertion_mode (1, key);
562 return (0);
563}
564
ccc6cda3 565int
726f6388
JA
566rl_vi_append_eol (count, key)
567 int count, key;
568{
569 rl_end_of_line (1, key);
570 rl_vi_append_mode (1, key);
571 return (0);
572}
573
574/* What to do in the case of C-d. */
ccc6cda3 575int
726f6388
JA
576rl_vi_eof_maybe (count, c)
577 int count, c;
578{
579 return (rl_newline (1, '\n'));
580}
581
582/* Insertion mode stuff. */
583
584/* Switching from one mode to the other really just involves
585 switching keymaps. */
ccc6cda3 586int
726f6388
JA
587rl_vi_insertion_mode (count, key)
588 int count, key;
589{
590 _rl_keymap = vi_insertion_keymap;
ccc6cda3 591 _rl_vi_last_key_before_insert = key;
726f6388
JA
592 return (0);
593}
594
ccc6cda3
JA
595static void
596_rl_vi_save_insert (up)
597 UNDO_LIST *up;
598{
599 int len, start, end;
600
cce855bc
JA
601 if (up == 0)
602 {
603 if (vi_insert_buffer_size >= 1)
604 vi_insert_buffer[0] = '\0';
605 return;
606 }
607
ccc6cda3
JA
608 start = up->start;
609 end = up->end;
610 len = end - start + 1;
611 if (len >= vi_insert_buffer_size)
612 {
613 vi_insert_buffer_size += (len + 32) - (len % 32);
614 vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
615 }
616 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
617 vi_insert_buffer[len-1] = '\0';
618}
619
726f6388
JA
620void
621_rl_vi_done_inserting ()
622{
623 if (_rl_vi_doing_insert)
624 {
625 rl_end_undo_group ();
626 /* Now, the text between rl_undo_list->next->start and
627 rl_undo_list->next->end is what was inserted while in insert
ccc6cda3
JA
628 mode. It gets copied to VI_INSERT_BUFFER because it depends
629 on absolute indices into the line which may change (though they
630 probably will not). */
726f6388 631 _rl_vi_doing_insert = 0;
ccc6cda3 632 _rl_vi_save_insert (rl_undo_list->next);
726f6388
JA
633 vi_continued_command = 1;
634 }
635 else
ccc6cda3
JA
636 {
637 if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
638 _rl_vi_save_insert (rl_undo_list);
639 /* XXX - Other keys probably need to be checked. */
640 else if (_rl_vi_last_key_before_insert == 'C')
641 rl_end_undo_group ();
642 while (_rl_undo_group_level > 0)
643 rl_end_undo_group ();
644 vi_continued_command = 0;
645 }
726f6388
JA
646}
647
ccc6cda3 648int
726f6388
JA
649rl_vi_movement_mode (count, key)
650 int count, key;
651{
652 if (rl_point > 0)
ccc6cda3 653 rl_backward (1, key);
726f6388
JA
654
655 _rl_keymap = vi_movement_keymap;
656 _rl_vi_done_inserting ();
657 return (0);
658}
659
ccc6cda3 660int
726f6388
JA
661rl_vi_arg_digit (count, c)
662 int count, c;
663{
664 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
ccc6cda3 665 return (rl_beg_of_line (1, c));
726f6388
JA
666 else
667 return (rl_digit_argument (count, c));
668}
669
ccc6cda3 670int
726f6388
JA
671rl_vi_change_case (count, ignore)
672 int count, ignore;
673{
674 char c = 0;
675
676 /* Don't try this on an empty line. */
677 if (rl_point >= rl_end)
678 return (0);
679
680 while (count-- && rl_point < rl_end)
681 {
ccc6cda3
JA
682 if (_rl_uppercase_p (rl_line_buffer[rl_point]))
683 c = _rl_to_lower (rl_line_buffer[rl_point]);
684 else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
685 c = _rl_to_upper (rl_line_buffer[rl_point]);
726f6388
JA
686 else
687 {
688 /* Just skip over characters neither upper nor lower case. */
ccc6cda3 689 rl_forward (1, c);
726f6388
JA
690 continue;
691 }
692
693 /* Vi is kind of strange here. */
694 if (c)
695 {
696 rl_begin_undo_group ();
697 rl_delete (1, c);
698 rl_insert (1, c);
699 rl_end_undo_group ();
700 rl_vi_check ();
701 }
702 else
ccc6cda3 703 rl_forward (1, c);
726f6388
JA
704 }
705 return (0);
706}
707
ccc6cda3 708int
726f6388
JA
709rl_vi_put (count, key)
710 int count, key;
711{
ccc6cda3 712 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
726f6388
JA
713 rl_point++;
714
b72432fd 715 rl_yank (1, key);
ccc6cda3 716 rl_backward (1, key);
726f6388
JA
717 return (0);
718}
719
ccc6cda3 720int
726f6388
JA
721rl_vi_check ()
722{
723 if (rl_point && rl_point == rl_end)
724 rl_point--;
725 return (0);
726}
727
ccc6cda3 728int
726f6388
JA
729rl_vi_column (count, key)
730 int count, key;
731{
732 if (count > rl_end)
ccc6cda3 733 rl_end_of_line (1, key);
726f6388
JA
734 else
735 rl_point = count - 1;
736 return (0);
737}
738
739int
740rl_vi_domove (key, nextkey)
741 int key, *nextkey;
742{
743 int c, save;
744 int old_end;
745
746 rl_mark = rl_point;
28ef6c31 747 RL_SETSTATE(RL_STATE_MOREINPUT);
726f6388 748 c = rl_read_key ();
28ef6c31 749 RL_UNSETSTATE(RL_STATE_MOREINPUT);
726f6388
JA
750 *nextkey = c;
751
752 if (!member (c, vi_motion))
753 {
ccc6cda3 754 if (_rl_digit_p (c))
726f6388
JA
755 {
756 save = rl_numeric_arg;
ccc6cda3 757 rl_numeric_arg = _rl_digit_value (c);
726f6388
JA
758 rl_digit_loop1 ();
759 rl_numeric_arg *= save;
28ef6c31 760 RL_SETSTATE(RL_STATE_MOREINPUT);
726f6388 761 c = rl_read_key (); /* real command */
28ef6c31 762 RL_UNSETSTATE(RL_STATE_MOREINPUT);
726f6388
JA
763 *nextkey = c;
764 }
765 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
766 {
767 rl_mark = rl_end;
ccc6cda3 768 rl_beg_of_line (1, c);
726f6388
JA
769 _rl_vi_last_motion = c;
770 return (0);
771 }
772 else
773 return (-1);
774 }
775
776 _rl_vi_last_motion = c;
777
778 /* Append a blank character temporarily so that the motion routines
779 work right at the end of the line. */
780 old_end = rl_end;
781 rl_line_buffer[rl_end++] = ' ';
782 rl_line_buffer[rl_end] = '\0';
783
784 _rl_dispatch (c, _rl_keymap);
785
786 /* Remove the blank that we added. */
787 rl_end = old_end;
788 rl_line_buffer[rl_end] = '\0';
789 if (rl_point > rl_end)
790 rl_point = rl_end;
791
792 /* No change in position means the command failed. */
793 if (rl_mark == rl_point)
794 return (-1);
795
796 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
797 word. If we are not at the end of the line, and we are on a
798 non-whitespace character, move back one (presumably to whitespace). */
ccc6cda3 799 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
726f6388
JA
800 !whitespace (rl_line_buffer[rl_point]))
801 rl_point--;
802
803 /* If cw or cW, back up to the end of a word, so the behaviour of ce
804 or cE is the actual result. Brute-force, no subtlety. */
ccc6cda3 805 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
726f6388
JA
806 {
807 /* Don't move farther back than where we started. */
808 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
809 rl_point--;
810
811 /* Posix.2 says that if cw or cW moves the cursor towards the end of
812 the line, the character under the cursor should be deleted. */
813 if (rl_point == rl_mark)
814 rl_point++;
815 else
816 {
817 /* Move past the end of the word so that the kill doesn't
818 remove the last letter of the previous word. Only do this
819 if we are not at the end of the line. */
820 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
821 rl_point++;
822 }
823 }
824
825 if (rl_mark < rl_point)
826 exchange (rl_point, rl_mark);
827
828 return (0);
829}
830
831/* A simplified loop for vi. Don't dispatch key at end.
28ef6c31
JA
832 Don't recognize minus sign?
833 Should this do rl_save_prompt/rl_restore_prompt? */
726f6388
JA
834static int
835rl_digit_loop1 ()
836{
837 int key, c;
838
28ef6c31 839 RL_SETSTATE(RL_STATE_NUMERICARG);
726f6388
JA
840 while (1)
841 {
28ef6c31
JA
842 if (rl_numeric_arg > 1000000)
843 {
844 rl_explicit_arg = rl_numeric_arg = 0;
845 rl_ding ();
846 rl_clear_message ();
847 RL_UNSETSTATE(RL_STATE_NUMERICARG);
848 return 1;
849 }
726f6388 850 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
28ef6c31 851 RL_SETSTATE(RL_STATE_MOREINPUT);
726f6388 852 key = c = rl_read_key ();
28ef6c31 853 RL_UNSETSTATE(RL_STATE_MOREINPUT);
726f6388
JA
854
855 if (_rl_keymap[c].type == ISFUNC &&
856 _rl_keymap[c].function == rl_universal_argument)
857 {
858 rl_numeric_arg *= 4;
859 continue;
860 }
861
862 c = UNMETA (c);
ccc6cda3 863 if (_rl_digit_p (c))
726f6388
JA
864 {
865 if (rl_explicit_arg)
ccc6cda3 866 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
726f6388 867 else
ccc6cda3 868 rl_numeric_arg = _rl_digit_value (c);
726f6388
JA
869 rl_explicit_arg = 1;
870 }
871 else
872 {
873 rl_clear_message ();
874 rl_stuff_char (key);
875 break;
876 }
877 }
28ef6c31
JA
878
879 RL_UNSETSTATE(RL_STATE_NUMERICARG);
726f6388
JA
880 return (0);
881}
882
ccc6cda3 883int
726f6388
JA
884rl_vi_delete_to (count, key)
885 int count, key;
886{
887 int c;
888
ccc6cda3 889 if (_rl_uppercase_p (key))
726f6388
JA
890 rl_stuff_char ('$');
891 else if (vi_redoing)
892 rl_stuff_char (_rl_vi_last_motion);
893
894 if (rl_vi_domove (key, &c))
895 {
28ef6c31 896 rl_ding ();
726f6388
JA
897 return -1;
898 }
899
900 /* These are the motion commands that do not require adjusting the
901 mark. */
902 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
903 rl_mark++;
904
905 rl_kill_text (rl_point, rl_mark);
906 return (0);
907}
908
ccc6cda3 909int
726f6388
JA
910rl_vi_change_to (count, key)
911 int count, key;
912{
913 int c, start_pos;
914
ccc6cda3 915 if (_rl_uppercase_p (key))
726f6388
JA
916 rl_stuff_char ('$');
917 else if (vi_redoing)
918 rl_stuff_char (_rl_vi_last_motion);
919
920 start_pos = rl_point;
921
922 if (rl_vi_domove (key, &c))
923 {
28ef6c31 924 rl_ding ();
726f6388
JA
925 return -1;
926 }
927
928 /* These are the motion commands that do not require adjusting the
929 mark. c[wW] are handled by special-case code in rl_vi_domove(),
930 and already leave the mark at the correct location. */
931 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
932 rl_mark++;
933
934 /* The cursor never moves with c[wW]. */
ccc6cda3 935 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
726f6388
JA
936 rl_point = start_pos;
937
ccc6cda3
JA
938 if (vi_redoing)
939 {
940 if (vi_insert_buffer && *vi_insert_buffer)
941 rl_begin_undo_group ();
942 rl_delete_text (rl_point, rl_mark);
943 if (vi_insert_buffer && *vi_insert_buffer)
944 {
945 rl_insert_text (vi_insert_buffer);
946 rl_end_undo_group ();
947 }
948 }
949 else
950 {
951 rl_begin_undo_group (); /* to make the `u' command work */
952 rl_kill_text (rl_point, rl_mark);
953 /* `C' does not save the text inserted for undoing or redoing. */
954 if (_rl_uppercase_p (key) == 0)
955 _rl_vi_doing_insert = 1;
956 _rl_vi_set_last (key, count, rl_arg_sign);
957 rl_vi_insertion_mode (1, key);
958 }
726f6388
JA
959
960 return (0);
961}
962
ccc6cda3 963int
726f6388
JA
964rl_vi_yank_to (count, key)
965 int count, key;
966{
967 int c, save = rl_point;
968
ccc6cda3 969 if (_rl_uppercase_p (key))
726f6388
JA
970 rl_stuff_char ('$');
971
972 if (rl_vi_domove (key, &c))
973 {
28ef6c31 974 rl_ding ();
726f6388
JA
975 return -1;
976 }
977
978 /* These are the motion commands that do not require adjusting the
979 mark. */
980 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
981 rl_mark++;
982
983 rl_begin_undo_group ();
984 rl_kill_text (rl_point, rl_mark);
985 rl_end_undo_group ();
986 rl_do_undo ();
987 rl_point = save;
988
989 return (0);
990}
991
ccc6cda3 992int
726f6388
JA
993rl_vi_delete (count, key)
994 int count, key;
995{
996 int end;
997
998 if (rl_end == 0)
999 {
28ef6c31 1000 rl_ding ();
726f6388
JA
1001 return -1;
1002 }
1003
1004 end = rl_point + count;
1005
1006 if (end >= rl_end)
1007 end = rl_end;
1008
1009 rl_kill_text (rl_point, end);
1010
1011 if (rl_point > 0 && rl_point == rl_end)
ccc6cda3 1012 rl_backward (1, key);
726f6388
JA
1013 return (0);
1014}
1015
ccc6cda3
JA
1016int
1017rl_vi_back_to_indent (count, key)
726f6388
JA
1018 int count, key;
1019{
ccc6cda3
JA
1020 rl_beg_of_line (1, key);
1021 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1022 rl_point++;
726f6388
JA
1023 return (0);
1024}
1025
ccc6cda3 1026int
726f6388
JA
1027rl_vi_first_print (count, key)
1028 int count, key;
1029{
ccc6cda3 1030 return (rl_vi_back_to_indent (1, key));
726f6388
JA
1031}
1032
ccc6cda3 1033int
726f6388
JA
1034rl_vi_char_search (count, key)
1035 int count, key;
1036{
1037 static char target;
1038 static int orig_dir, dir;
726f6388
JA
1039
1040 if (key == ';' || key == ',')
ccc6cda3 1041 dir = key == ';' ? orig_dir : -orig_dir;
726f6388
JA
1042 else
1043 {
1044 if (vi_redoing)
1045 target = _rl_vi_last_search_char;
1046 else
28ef6c31
JA
1047 {
1048 RL_SETSTATE(RL_STATE_MOREINPUT);
1049 _rl_vi_last_search_char = target = rl_read_key ();
1050 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1051 }
726f6388
JA
1052
1053 switch (key)
1054 {
1055 case 't':
1056 orig_dir = dir = FTO;
1057 break;
1058
1059 case 'T':
1060 orig_dir = dir = BTO;
1061 break;
1062
1063 case 'f':
1064 orig_dir = dir = FFIND;
1065 break;
1066
1067 case 'F':
1068 orig_dir = dir = BFIND;
1069 break;
1070 }
1071 }
1072
ccc6cda3 1073 return (_rl_char_search_internal (count, dir, target));
726f6388
JA
1074}
1075
1076/* Match brackets */
ccc6cda3 1077int
726f6388
JA
1078rl_vi_match (ignore, key)
1079 int ignore, key;
1080{
1081 int count = 1, brack, pos;
1082
1083 pos = rl_point;
1084 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1085 {
1086 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1087 rl_point < rl_end - 1)
ccc6cda3 1088 rl_forward (1, key);
726f6388
JA
1089
1090 if (brack <= 0)
1091 {
1092 rl_point = pos;
28ef6c31 1093 rl_ding ();
726f6388
JA
1094 return -1;
1095 }
1096 }
1097
1098 pos = rl_point;
1099
1100 if (brack < 0)
1101 {
1102 while (count)
1103 {
1104 if (--pos >= 0)
1105 {
1106 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1107 if (b == -brack)
1108 count--;
1109 else if (b == brack)
1110 count++;
1111 }
1112 else
1113 {
28ef6c31 1114 rl_ding ();
726f6388
JA
1115 return -1;
1116 }
1117 }
1118 }
1119 else
1120 { /* brack > 0 */
1121 while (count)
1122 {
1123 if (++pos < rl_end)
1124 {
1125 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1126 if (b == -brack)
1127 count--;
1128 else if (b == brack)
1129 count++;
1130 }
1131 else
1132 {
28ef6c31 1133 rl_ding ();
726f6388
JA
1134 return -1;
1135 }
1136 }
1137 }
1138 rl_point = pos;
1139 return (0);
1140}
1141
1142int
1143rl_vi_bracktype (c)
1144 int c;
1145{
1146 switch (c)
1147 {
1148 case '(': return 1;
1149 case ')': return -1;
1150 case '[': return 2;
1151 case ']': return -2;
1152 case '{': return 3;
1153 case '}': return -3;
1154 default: return 0;
1155 }
1156}
1157
ccc6cda3 1158int
726f6388
JA
1159rl_vi_change_char (count, key)
1160 int count, key;
1161{
1162 int c;
1163
1164 if (vi_redoing)
1165 c = _rl_vi_last_replacement;
1166 else
28ef6c31
JA
1167 {
1168 RL_SETSTATE(RL_STATE_MOREINPUT);
1169 _rl_vi_last_replacement = c = rl_read_key ();
1170 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1171 }
726f6388
JA
1172
1173 if (c == '\033' || c == CTRL ('C'))
1174 return -1;
1175
1176 while (count-- && rl_point < rl_end)
1177 {
1178 rl_begin_undo_group ();
1179
1180 rl_delete (1, c);
1181 rl_insert (1, c);
1182 if (count == 0)
ccc6cda3 1183 rl_backward (1, c);
726f6388
JA
1184
1185 rl_end_undo_group ();
1186 }
1187 return (0);
1188}
1189
ccc6cda3 1190int
726f6388
JA
1191rl_vi_subst (count, key)
1192 int count, key;
1193{
1194 rl_begin_undo_group ();
1195
ccc6cda3 1196 if (_rl_uppercase_p (key))
726f6388 1197 {
ccc6cda3
JA
1198 rl_beg_of_line (1, key);
1199 rl_kill_line (1, key);
726f6388
JA
1200 }
1201 else
1202 rl_delete_text (rl_point, rl_point+count);
1203
1204 rl_end_undo_group ();
1205
1206 _rl_vi_set_last (key, count, rl_arg_sign);
1207
ccc6cda3
JA
1208 if (vi_redoing)
1209 {
1210 int o = _rl_doing_an_undo;
1211
1212 _rl_doing_an_undo = 1;
1213 if (vi_insert_buffer && *vi_insert_buffer)
1214 rl_insert_text (vi_insert_buffer);
1215 _rl_doing_an_undo = o;
1216 }
1217 else
1218 {
1219 rl_begin_undo_group ();
1220 _rl_vi_doing_insert = 1;
1221 rl_vi_insertion_mode (1, key);
1222 }
726f6388
JA
1223
1224 return (0);
1225}
1226
ccc6cda3 1227int
726f6388
JA
1228rl_vi_overstrike (count, key)
1229 int count, key;
1230{
1231 int i;
1232
1233 if (_rl_vi_doing_insert == 0)
1234 {
1235 _rl_vi_doing_insert = 1;
1236 rl_begin_undo_group ();
1237 }
1238
1239 for (i = 0; i < count; i++)
1240 {
1241 vi_replace_count++;
1242 rl_begin_undo_group ();
1243
1244 if (rl_point < rl_end)
1245 {
1246 rl_delete (1, key);
1247 rl_insert (1, key);
1248 }
1249 else
1250 rl_insert (1, key);
1251
1252 rl_end_undo_group ();
1253 }
1254 return (0);
1255}
1256
ccc6cda3
JA
1257int
1258rl_vi_overstrike_delete (count, key)
1259 int count, key;
726f6388
JA
1260{
1261 int i, s;
1262
1263 for (i = 0; i < count; i++)
1264 {
1265 if (vi_replace_count == 0)
1266 {
28ef6c31 1267 rl_ding ();
726f6388
JA
1268 break;
1269 }
1270 s = rl_point;
1271
1272 if (rl_do_undo ())
1273 vi_replace_count--;
1274
1275 if (rl_point == s)
ccc6cda3 1276 rl_backward (1, key);
726f6388
JA
1277 }
1278
1279 if (vi_replace_count == 0 && _rl_vi_doing_insert)
1280 {
1281 rl_end_undo_group ();
1282 rl_do_undo ();
1283 _rl_vi_doing_insert = 0;
1284 }
1285 return (0);
1286}
1287
ccc6cda3 1288int
726f6388
JA
1289rl_vi_replace (count, key)
1290 int count, key;
1291{
1292 int i;
1293
1294 vi_replace_count = 0;
1295
1296 if (!vi_replace_map)
1297 {
1298 vi_replace_map = rl_make_bare_keymap ();
1299
1300 for (i = ' '; i < KEYMAP_SIZE; i++)
1301 vi_replace_map[i].function = rl_vi_overstrike;
1302
1303 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1304 vi_replace_map[ESC].function = rl_vi_movement_mode;
1305 vi_replace_map[RETURN].function = rl_newline;
1306 vi_replace_map[NEWLINE].function = rl_newline;
1307
1308 /* If the normal vi insertion keymap has ^H bound to erase, do the
1309 same here. Probably should remove the assignment to RUBOUT up
1310 there, but I don't think it will make a difference in real life. */
1311 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1312 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1313 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1314
1315 }
1316 _rl_keymap = vi_replace_map;
1317 return (0);
1318}
1319
1320#if 0
1321/* Try to complete the word we are standing on or the word that ends with
1322 the previous character. A space matches everything. Word delimiters are
1323 space and ;. */
ccc6cda3 1324int
726f6388
JA
1325rl_vi_possible_completions()
1326{
1327 int save_pos = rl_point;
1328
1329 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1330 {
1331 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1332 rl_line_buffer[rl_point] != ';')
1333 rl_point++;
1334 }
1335 else if (rl_line_buffer[rl_point - 1] == ';')
1336 {
28ef6c31 1337 rl_ding ();
726f6388
JA
1338 return (0);
1339 }
1340
1341 rl_possible_completions ();
1342 rl_point = save_pos;
1343
1344 return (0);
1345}
1346#endif
1347
ccc6cda3
JA
1348/* Functions to save and restore marks. */
1349int
1350rl_vi_set_mark (count, key)
1351 int count, key;
726f6388 1352{
ccc6cda3 1353 int ch;
726f6388 1354
28ef6c31 1355 RL_SETSTATE(RL_STATE_MOREINPUT);
ccc6cda3 1356 ch = rl_read_key ();
28ef6c31
JA
1357 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1358
ccc6cda3
JA
1359 if (_rl_lowercase_p (ch) == 0)
1360 {
28ef6c31 1361 rl_ding ();
ccc6cda3
JA
1362 return -1;
1363 }
1364 ch -= 'a';
1365 vi_mark_chars[ch] = rl_point;
1366 return 0;
726f6388
JA
1367}
1368
ccc6cda3
JA
1369int
1370rl_vi_goto_mark (count, key)
1371 int count, key;
726f6388 1372{
ccc6cda3 1373 int ch;
726f6388 1374
28ef6c31 1375 RL_SETSTATE(RL_STATE_MOREINPUT);
ccc6cda3 1376 ch = rl_read_key ();
28ef6c31
JA
1377 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1378
ccc6cda3
JA
1379 if (ch == '`')
1380 {
1381 rl_point = rl_mark;
1382 return 0;
1383 }
1384 else if (_rl_lowercase_p (ch) == 0)
1385 {
28ef6c31 1386 rl_ding ();
ccc6cda3
JA
1387 return -1;
1388 }
726f6388 1389
ccc6cda3
JA
1390 ch -= 'a';
1391 if (vi_mark_chars[ch] == -1)
1392 {
28ef6c31 1393 rl_ding ();
ccc6cda3
JA
1394 return -1;
1395 }
1396 rl_point = vi_mark_chars[ch];
1397 return 0;
726f6388 1398}
726f6388
JA
1399
1400#endif /* VI_MODE */