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