]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/vi_mode.c
Imported from ../bash-2.04.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
JA
83/* Command keys which do movement for xxx_to commands. */
84static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
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. */
112static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
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:
277 ding ();
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 {
333 ding ();
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 {
355 ding ();
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 {
373 ding ();
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;
747 c = rl_read_key ();
748 *nextkey = c;
749
750 if (!member (c, vi_motion))
751 {
ccc6cda3 752 if (_rl_digit_p (c))
726f6388
JA
753 {
754 save = rl_numeric_arg;
ccc6cda3 755 rl_numeric_arg = _rl_digit_value (c);
726f6388
JA
756 rl_digit_loop1 ();
757 rl_numeric_arg *= save;
758 c = rl_read_key (); /* real command */
759 *nextkey = c;
760 }
761 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
762 {
763 rl_mark = rl_end;
ccc6cda3 764 rl_beg_of_line (1, c);
726f6388
JA
765 _rl_vi_last_motion = c;
766 return (0);
767 }
768 else
769 return (-1);
770 }
771
772 _rl_vi_last_motion = c;
773
774 /* Append a blank character temporarily so that the motion routines
775 work right at the end of the line. */
776 old_end = rl_end;
777 rl_line_buffer[rl_end++] = ' ';
778 rl_line_buffer[rl_end] = '\0';
779
780 _rl_dispatch (c, _rl_keymap);
781
782 /* Remove the blank that we added. */
783 rl_end = old_end;
784 rl_line_buffer[rl_end] = '\0';
785 if (rl_point > rl_end)
786 rl_point = rl_end;
787
788 /* No change in position means the command failed. */
789 if (rl_mark == rl_point)
790 return (-1);
791
792 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
793 word. If we are not at the end of the line, and we are on a
794 non-whitespace character, move back one (presumably to whitespace). */
ccc6cda3 795 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
726f6388
JA
796 !whitespace (rl_line_buffer[rl_point]))
797 rl_point--;
798
799 /* If cw or cW, back up to the end of a word, so the behaviour of ce
800 or cE is the actual result. Brute-force, no subtlety. */
ccc6cda3 801 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
726f6388
JA
802 {
803 /* Don't move farther back than where we started. */
804 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
805 rl_point--;
806
807 /* Posix.2 says that if cw or cW moves the cursor towards the end of
808 the line, the character under the cursor should be deleted. */
809 if (rl_point == rl_mark)
810 rl_point++;
811 else
812 {
813 /* Move past the end of the word so that the kill doesn't
814 remove the last letter of the previous word. Only do this
815 if we are not at the end of the line. */
816 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
817 rl_point++;
818 }
819 }
820
821 if (rl_mark < rl_point)
822 exchange (rl_point, rl_mark);
823
824 return (0);
825}
826
827/* A simplified loop for vi. Don't dispatch key at end.
828 Don't recognize minus sign? */
829static int
830rl_digit_loop1 ()
831{
832 int key, c;
833
834 while (1)
835 {
836 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
837 key = c = rl_read_key ();
838
839 if (_rl_keymap[c].type == ISFUNC &&
840 _rl_keymap[c].function == rl_universal_argument)
841 {
842 rl_numeric_arg *= 4;
843 continue;
844 }
845
846 c = UNMETA (c);
ccc6cda3 847 if (_rl_digit_p (c))
726f6388
JA
848 {
849 if (rl_explicit_arg)
ccc6cda3 850 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
726f6388 851 else
ccc6cda3 852 rl_numeric_arg = _rl_digit_value (c);
726f6388
JA
853 rl_explicit_arg = 1;
854 }
855 else
856 {
857 rl_clear_message ();
858 rl_stuff_char (key);
859 break;
860 }
861 }
862 return (0);
863}
864
ccc6cda3 865int
726f6388
JA
866rl_vi_delete_to (count, key)
867 int count, key;
868{
869 int c;
870
ccc6cda3 871 if (_rl_uppercase_p (key))
726f6388
JA
872 rl_stuff_char ('$');
873 else if (vi_redoing)
874 rl_stuff_char (_rl_vi_last_motion);
875
876 if (rl_vi_domove (key, &c))
877 {
878 ding ();
879 return -1;
880 }
881
882 /* These are the motion commands that do not require adjusting the
883 mark. */
884 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
885 rl_mark++;
886
887 rl_kill_text (rl_point, rl_mark);
888 return (0);
889}
890
ccc6cda3 891int
726f6388
JA
892rl_vi_change_to (count, key)
893 int count, key;
894{
895 int c, start_pos;
896
ccc6cda3 897 if (_rl_uppercase_p (key))
726f6388
JA
898 rl_stuff_char ('$');
899 else if (vi_redoing)
900 rl_stuff_char (_rl_vi_last_motion);
901
902 start_pos = rl_point;
903
904 if (rl_vi_domove (key, &c))
905 {
906 ding ();
907 return -1;
908 }
909
910 /* These are the motion commands that do not require adjusting the
911 mark. c[wW] are handled by special-case code in rl_vi_domove(),
912 and already leave the mark at the correct location. */
913 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
914 rl_mark++;
915
916 /* The cursor never moves with c[wW]. */
ccc6cda3 917 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
726f6388
JA
918 rl_point = start_pos;
919
ccc6cda3
JA
920 if (vi_redoing)
921 {
922 if (vi_insert_buffer && *vi_insert_buffer)
923 rl_begin_undo_group ();
924 rl_delete_text (rl_point, rl_mark);
925 if (vi_insert_buffer && *vi_insert_buffer)
926 {
927 rl_insert_text (vi_insert_buffer);
928 rl_end_undo_group ();
929 }
930 }
931 else
932 {
933 rl_begin_undo_group (); /* to make the `u' command work */
934 rl_kill_text (rl_point, rl_mark);
935 /* `C' does not save the text inserted for undoing or redoing. */
936 if (_rl_uppercase_p (key) == 0)
937 _rl_vi_doing_insert = 1;
938 _rl_vi_set_last (key, count, rl_arg_sign);
939 rl_vi_insertion_mode (1, key);
940 }
726f6388
JA
941
942 return (0);
943}
944
ccc6cda3 945int
726f6388
JA
946rl_vi_yank_to (count, key)
947 int count, key;
948{
949 int c, save = rl_point;
950
ccc6cda3 951 if (_rl_uppercase_p (key))
726f6388
JA
952 rl_stuff_char ('$');
953
954 if (rl_vi_domove (key, &c))
955 {
956 ding ();
957 return -1;
958 }
959
960 /* These are the motion commands that do not require adjusting the
961 mark. */
962 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
963 rl_mark++;
964
965 rl_begin_undo_group ();
966 rl_kill_text (rl_point, rl_mark);
967 rl_end_undo_group ();
968 rl_do_undo ();
969 rl_point = save;
970
971 return (0);
972}
973
ccc6cda3 974int
726f6388
JA
975rl_vi_delete (count, key)
976 int count, key;
977{
978 int end;
979
980 if (rl_end == 0)
981 {
982 ding ();
983 return -1;
984 }
985
986 end = rl_point + count;
987
988 if (end >= rl_end)
989 end = rl_end;
990
991 rl_kill_text (rl_point, end);
992
993 if (rl_point > 0 && rl_point == rl_end)
ccc6cda3 994 rl_backward (1, key);
726f6388
JA
995 return (0);
996}
997
ccc6cda3
JA
998int
999rl_vi_back_to_indent (count, key)
726f6388
JA
1000 int count, key;
1001{
ccc6cda3
JA
1002 rl_beg_of_line (1, key);
1003 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1004 rl_point++;
726f6388
JA
1005 return (0);
1006}
1007
ccc6cda3 1008int
726f6388
JA
1009rl_vi_first_print (count, key)
1010 int count, key;
1011{
ccc6cda3 1012 return (rl_vi_back_to_indent (1, key));
726f6388
JA
1013}
1014
ccc6cda3 1015int
726f6388
JA
1016rl_vi_char_search (count, key)
1017 int count, key;
1018{
1019 static char target;
1020 static int orig_dir, dir;
726f6388
JA
1021
1022 if (key == ';' || key == ',')
ccc6cda3 1023 dir = key == ';' ? orig_dir : -orig_dir;
726f6388
JA
1024 else
1025 {
1026 if (vi_redoing)
1027 target = _rl_vi_last_search_char;
1028 else
bb70624e 1029 _rl_vi_last_search_char = target = (*rl_getc_function) (rl_instream);
726f6388
JA
1030
1031 switch (key)
1032 {
1033 case 't':
1034 orig_dir = dir = FTO;
1035 break;
1036
1037 case 'T':
1038 orig_dir = dir = BTO;
1039 break;
1040
1041 case 'f':
1042 orig_dir = dir = FFIND;
1043 break;
1044
1045 case 'F':
1046 orig_dir = dir = BFIND;
1047 break;
1048 }
1049 }
1050
ccc6cda3 1051 return (_rl_char_search_internal (count, dir, target));
726f6388
JA
1052}
1053
1054/* Match brackets */
ccc6cda3 1055int
726f6388
JA
1056rl_vi_match (ignore, key)
1057 int ignore, key;
1058{
1059 int count = 1, brack, pos;
1060
1061 pos = rl_point;
1062 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1063 {
1064 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1065 rl_point < rl_end - 1)
ccc6cda3 1066 rl_forward (1, key);
726f6388
JA
1067
1068 if (brack <= 0)
1069 {
1070 rl_point = pos;
1071 ding ();
1072 return -1;
1073 }
1074 }
1075
1076 pos = rl_point;
1077
1078 if (brack < 0)
1079 {
1080 while (count)
1081 {
1082 if (--pos >= 0)
1083 {
1084 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1085 if (b == -brack)
1086 count--;
1087 else if (b == brack)
1088 count++;
1089 }
1090 else
1091 {
1092 ding ();
1093 return -1;
1094 }
1095 }
1096 }
1097 else
1098 { /* brack > 0 */
1099 while (count)
1100 {
1101 if (++pos < rl_end)
1102 {
1103 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1104 if (b == -brack)
1105 count--;
1106 else if (b == brack)
1107 count++;
1108 }
1109 else
1110 {
1111 ding ();
1112 return -1;
1113 }
1114 }
1115 }
1116 rl_point = pos;
1117 return (0);
1118}
1119
1120int
1121rl_vi_bracktype (c)
1122 int c;
1123{
1124 switch (c)
1125 {
1126 case '(': return 1;
1127 case ')': return -1;
1128 case '[': return 2;
1129 case ']': return -2;
1130 case '{': return 3;
1131 case '}': return -3;
1132 default: return 0;
1133 }
1134}
1135
ccc6cda3 1136int
726f6388
JA
1137rl_vi_change_char (count, key)
1138 int count, key;
1139{
1140 int c;
1141
1142 if (vi_redoing)
1143 c = _rl_vi_last_replacement;
1144 else
bb70624e 1145 _rl_vi_last_replacement = c = (*rl_getc_function) (rl_instream);
726f6388
JA
1146
1147 if (c == '\033' || c == CTRL ('C'))
1148 return -1;
1149
1150 while (count-- && rl_point < rl_end)
1151 {
1152 rl_begin_undo_group ();
1153
1154 rl_delete (1, c);
1155 rl_insert (1, c);
1156 if (count == 0)
ccc6cda3 1157 rl_backward (1, c);
726f6388
JA
1158
1159 rl_end_undo_group ();
1160 }
1161 return (0);
1162}
1163
ccc6cda3 1164int
726f6388
JA
1165rl_vi_subst (count, key)
1166 int count, key;
1167{
1168 rl_begin_undo_group ();
1169
ccc6cda3 1170 if (_rl_uppercase_p (key))
726f6388 1171 {
ccc6cda3
JA
1172 rl_beg_of_line (1, key);
1173 rl_kill_line (1, key);
726f6388
JA
1174 }
1175 else
1176 rl_delete_text (rl_point, rl_point+count);
1177
1178 rl_end_undo_group ();
1179
1180 _rl_vi_set_last (key, count, rl_arg_sign);
1181
ccc6cda3
JA
1182 if (vi_redoing)
1183 {
1184 int o = _rl_doing_an_undo;
1185
1186 _rl_doing_an_undo = 1;
1187 if (vi_insert_buffer && *vi_insert_buffer)
1188 rl_insert_text (vi_insert_buffer);
1189 _rl_doing_an_undo = o;
1190 }
1191 else
1192 {
1193 rl_begin_undo_group ();
1194 _rl_vi_doing_insert = 1;
1195 rl_vi_insertion_mode (1, key);
1196 }
726f6388
JA
1197
1198 return (0);
1199}
1200
ccc6cda3 1201int
726f6388
JA
1202rl_vi_overstrike (count, key)
1203 int count, key;
1204{
1205 int i;
1206
1207 if (_rl_vi_doing_insert == 0)
1208 {
1209 _rl_vi_doing_insert = 1;
1210 rl_begin_undo_group ();
1211 }
1212
1213 for (i = 0; i < count; i++)
1214 {
1215 vi_replace_count++;
1216 rl_begin_undo_group ();
1217
1218 if (rl_point < rl_end)
1219 {
1220 rl_delete (1, key);
1221 rl_insert (1, key);
1222 }
1223 else
1224 rl_insert (1, key);
1225
1226 rl_end_undo_group ();
1227 }
1228 return (0);
1229}
1230
ccc6cda3
JA
1231int
1232rl_vi_overstrike_delete (count, key)
1233 int count, key;
726f6388
JA
1234{
1235 int i, s;
1236
1237 for (i = 0; i < count; i++)
1238 {
1239 if (vi_replace_count == 0)
1240 {
1241 ding ();
1242 break;
1243 }
1244 s = rl_point;
1245
1246 if (rl_do_undo ())
1247 vi_replace_count--;
1248
1249 if (rl_point == s)
ccc6cda3 1250 rl_backward (1, key);
726f6388
JA
1251 }
1252
1253 if (vi_replace_count == 0 && _rl_vi_doing_insert)
1254 {
1255 rl_end_undo_group ();
1256 rl_do_undo ();
1257 _rl_vi_doing_insert = 0;
1258 }
1259 return (0);
1260}
1261
ccc6cda3 1262int
726f6388
JA
1263rl_vi_replace (count, key)
1264 int count, key;
1265{
1266 int i;
1267
1268 vi_replace_count = 0;
1269
1270 if (!vi_replace_map)
1271 {
1272 vi_replace_map = rl_make_bare_keymap ();
1273
1274 for (i = ' '; i < KEYMAP_SIZE; i++)
1275 vi_replace_map[i].function = rl_vi_overstrike;
1276
1277 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1278 vi_replace_map[ESC].function = rl_vi_movement_mode;
1279 vi_replace_map[RETURN].function = rl_newline;
1280 vi_replace_map[NEWLINE].function = rl_newline;
1281
1282 /* If the normal vi insertion keymap has ^H bound to erase, do the
1283 same here. Probably should remove the assignment to RUBOUT up
1284 there, but I don't think it will make a difference in real life. */
1285 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1286 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1287 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1288
1289 }
1290 _rl_keymap = vi_replace_map;
1291 return (0);
1292}
1293
1294#if 0
1295/* Try to complete the word we are standing on or the word that ends with
1296 the previous character. A space matches everything. Word delimiters are
1297 space and ;. */
ccc6cda3 1298int
726f6388
JA
1299rl_vi_possible_completions()
1300{
1301 int save_pos = rl_point;
1302
1303 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1304 {
1305 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1306 rl_line_buffer[rl_point] != ';')
1307 rl_point++;
1308 }
1309 else if (rl_line_buffer[rl_point - 1] == ';')
1310 {
1311 ding ();
1312 return (0);
1313 }
1314
1315 rl_possible_completions ();
1316 rl_point = save_pos;
1317
1318 return (0);
1319}
1320#endif
1321
ccc6cda3
JA
1322/* Functions to save and restore marks. */
1323int
1324rl_vi_set_mark (count, key)
1325 int count, key;
726f6388 1326{
ccc6cda3 1327 int ch;
726f6388 1328
ccc6cda3
JA
1329 ch = rl_read_key ();
1330 if (_rl_lowercase_p (ch) == 0)
1331 {
1332 ding ();
1333 return -1;
1334 }
1335 ch -= 'a';
1336 vi_mark_chars[ch] = rl_point;
1337 return 0;
726f6388
JA
1338}
1339
ccc6cda3
JA
1340int
1341rl_vi_goto_mark (count, key)
1342 int count, key;
726f6388 1343{
ccc6cda3 1344 int ch;
726f6388 1345
ccc6cda3
JA
1346 ch = rl_read_key ();
1347 if (ch == '`')
1348 {
1349 rl_point = rl_mark;
1350 return 0;
1351 }
1352 else if (_rl_lowercase_p (ch) == 0)
1353 {
1354 ding ();
1355 return -1;
1356 }
726f6388 1357
ccc6cda3
JA
1358 ch -= 'a';
1359 if (vi_mark_chars[ch] == -1)
1360 {
1361 ding ();
1362 return -1;
1363 }
1364 rl_point = vi_mark_chars[ch];
1365 return 0;
726f6388 1366}
726f6388
JA
1367
1368#endif /* VI_MODE */