* rldefs.h: On Linux, include <termios.h> to fix compile error
[deliverable/binutils-gdb.git] / readline / vi_mode.c
CommitLineData
bd5635a1 1/* vi_mode.c -- A vi emulation mode for Bash.
870ca253 2 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
bd5635a1 3
870ca253
SG
4/* Copyright (C) 1988, 1991 Free Software Foundation, Inc.
5
6 This file is part of the GNU Readline Library (the Library), a set of
7 routines for providing Emacs style line input to programs that ask
8 for it.
9
10 The Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 1, or (at your option)
13 any later version.
bd5635a1 14
870ca253
SG
15 The Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 The GNU General Public License is often shipped with GNU software, and
21 is generally kept in a file called COPYING or LICENSE. If you do not
22 have a copy of the license, write to the Free Software Foundation,
23 675 Mass Ave, Cambridge, MA 02139, USA. */
bd5635a1
RP
24\f
25/* **************************************************************** */
26/* */
27/* VI Emulation Mode */
28/* */
29/* **************************************************************** */
870ca253
SG
30#if defined (VI_MODE)
31
32#include <stdio.h>
33
34#if defined (__GNUC__)
35# define alloca __builtin_alloca
36#else
37# if defined (sparc) || defined (HAVE_ALLOCA_H)
38# include <alloca.h>
39# endif
40#endif
41
42/* Some standard library routines. */
43#include "readline.h"
44#include "history.h"
45
46#ifndef digit
47#define digit(c) ((c) >= '0' && (c) <= '9')
48#endif
49
50#ifndef isletter
51#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
52#endif
53
54#ifndef digit_value
55#define digit_value(c) ((c) - '0')
56#endif
57
58#ifndef member
59#define member(c, s) ((c) ? index ((s), (c)) : 0)
60#endif
61
62#ifndef isident
63#define isident(c) ((isletter(c) || digit(c) || c == '_'))
64#endif
65
66#ifndef exchange
67#define exchange(x, y) {int temp = x; x = y; y = temp;}
68#endif
69
70/* Variables imported from readline.c */
71extern int rl_point, rl_end, rl_mark, rl_done;
72extern FILE *rl_instream;
73extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
74extern Keymap keymap;
75extern char *rl_prompt;
76extern char *rl_line_buffer;
77extern int rl_arg_sign;
78
79extern char *xmalloc (), *xrealloc ();
80extern void rl_extend_line_buffer ();
bd5635a1
RP
81
82/* Last string searched for from `/' or `?'. */
83static char *vi_last_search = (char *)NULL;
84static int vi_histpos;
85
86/* Non-zero means enter insertion mode. */
87int vi_doing_insert = 0;
88
870ca253
SG
89/* String inserted into the line by rl_vi_comment (). */
90char *rl_vi_comment_begin = (char *)NULL;
91
bd5635a1
RP
92/* *** UNCLEAN *** */
93/* Command keys which do movement for xxx_to commands. */
94static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
95
96/* Keymap used for vi replace characters. Created dynamically since
97 rarely used. */
98static Keymap vi_replace_map = (Keymap)NULL;
99
100/* The number of characters inserted in the last replace operation. */
870ca253 101static int vi_replace_count = 0;
bd5635a1
RP
102
103/* Yank the nth arg from the previous line into this line at point. */
104rl_vi_yank_arg (count)
105 int count;
106{
870ca253
SG
107 /* Readline thinks that the first word on a line is the 0th, while vi
108 thinks the first word on a line is the 1st. Compensate. */
109 if (rl_explicit_arg)
110 rl_yank_nth_arg (count - 1, 0);
111 else
112 rl_yank_nth_arg ('$', 0);
113}
114
115/* With an argument, move back that many history lines, else move to the
116 beginning of history. */
117rl_vi_fetch_history (count, c)
118 int count, c;
119{
120 extern int rl_explicit_arg;
121 int current = where_history ();
122
123 /* Giving an argument of n means we want the nth command in the history
124 file. The command number is interpreted the same way that the bash
125 `history' command does it -- that is, giving an argument count of 450
126 to this command would get the command listed as number 450 in the
127 output of `history'. */
128 if (rl_explicit_arg)
129 {
130 int wanted = history_base + current - count;
131 if (wanted <= 0)
132 rl_beginning_of_history (0, 0);
133 else
134 rl_get_previous_history (wanted);
135 }
136 else
137 rl_beginning_of_history (count, 0);
bd5635a1
RP
138}
139
140/* Search again for the last thing searched for. */
141rl_vi_search_again (ignore, key)
142 int ignore, key;
143{
144 switch (key)
145 {
146 case 'n':
147 rl_vi_dosearch (vi_last_search, -1);
148 break;
149
150 case 'N':
151 rl_vi_dosearch (vi_last_search, 1);
152 break;
153 }
154}
155
156/* Do a vi style search. */
157rl_vi_search (count, key)
158 int count, key;
159{
160 int dir, c, save_pos;
161 char *p;
162
163 switch (key)
164 {
165 case '?':
166 dir = 1;
167 break;
168
169 case '/':
170 dir = -1;
171 break;
172
173 default:
174 ding ();
175 return;
176 }
177
178 vi_histpos = where_history ();
179 maybe_save_line ();
180 save_pos = rl_point;
181
182 /* Reuse the line input buffer to read the search string. */
870ca253 183 rl_line_buffer[0] = 0;
bd5635a1
RP
184 rl_end = rl_point = 0;
185 p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
186
187 sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
188
189 rl_message (p, 0, 0);
190
191 while (c = rl_read_key ())
192 {
193 switch (c)
194 {
195 case CTRL('H'):
196 case RUBOUT:
197 if (rl_point == 0)
198 {
199 maybe_unsave_line ();
200 rl_clear_message ();
201 rl_point = save_pos;
202 return;
203 }
204
205 case CTRL('W'):
206 case CTRL('U'):
207 rl_dispatch (c, keymap);
208 break;
209
210 case ESC:
211 case RETURN:
212 case NEWLINE:
213 goto dosearch;
214 break;
215
216 case CTRL('C'):
217 maybe_unsave_line ();
218 rl_clear_message ();
219 rl_point = 0;
220 ding ();
221 return;
222
223 default:
224 rl_insert (1, c);
225 break;
226 }
227 rl_redisplay ();
228 }
229 dosearch:
230 if (vi_last_search)
231 free (vi_last_search);
232
870ca253
SG
233 vi_last_search = savestring (rl_line_buffer);
234 rl_vi_dosearch (rl_line_buffer, dir);
235}
236
237/* Search for STRING in the history list. DIR is < 0 for searching
238 backwards. POS is an absolute index into the history list at
239 which point to begin searching. If the first character of STRING
240 is `^', the string must match a prefix of a history line, otherwise
241 a full substring match is performed. */
242static int
243vi_history_search_pos (string, dir, pos)
244 char *string;
245 int dir, pos;
246{
247 int ret, old = where_history ();
248
249 history_set_pos (pos);
250
251 if (*string == '^')
252 ret = history_search_prefix (string + 1, dir);
253 else
254 ret = history_search (string, dir);
255
256 if (ret == -1)
257 {
258 history_set_pos (old);
259 return (-1);
260 }
261
262 ret = where_history ();
263 history_set_pos (old);
264 return ret;
bd5635a1
RP
265}
266
267rl_vi_dosearch (string, dir)
268 char *string;
269 int dir;
270{
271 int old, save = vi_histpos;
272 HIST_ENTRY *h;
273
274 if (string == 0 || *string == 0 || vi_histpos < 0)
275 {
276 ding ();
277 return;
278 }
279
870ca253 280 if ((save = vi_history_search_pos (string, dir, vi_histpos + dir)) == -1)
bd5635a1
RP
281 {
282 maybe_unsave_line ();
283 rl_clear_message ();
284 rl_point = 0;
285 ding ();
286 return;
287 }
288
289 vi_histpos = save;
290
291 old = where_history ();
292 history_set_pos (vi_histpos);
293 h = current_history ();
294 history_set_pos (old);
295
870ca253
SG
296 {
297 int line_len = strlen (h->line);
298
299 if (line_len >= rl_line_buffer_len)
300 rl_extend_line_buffer (line_len);
301 strcpy (rl_line_buffer, h->line);
302 }
303
bd5635a1 304 rl_undo_list = (UNDO_LIST *)h->data;
870ca253 305 rl_end = strlen (rl_line_buffer);
bd5635a1
RP
306 rl_point = 0;
307 rl_clear_message ();
308}
309
310/* Completion, from vi's point of view. */
311rl_vi_complete (ignore, key)
312 int ignore, key;
313{
870ca253 314 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
bd5635a1 315 {
870ca253 316 if (!whitespace (rl_line_buffer[rl_point + 1]))
bd5635a1
RP
317 rl_vi_end_word (1, 'E');
318 rl_point++;
319 }
320
321 if (key == '*')
870ca253
SG
322 rl_complete_internal ('*'); /* Expansion and replacement. */
323 else if (key == '=')
324 rl_complete_internal ('?'); /* List possible completions. */
325 else if (key == '\\')
326 rl_complete_internal (TAB); /* Standard Readline completion. */
bd5635a1
RP
327 else
328 rl_complete (0, key);
bd5635a1
RP
329}
330
331/* Previous word in vi mode. */
332rl_vi_prev_word (count, key)
333 int count, key;
334{
335 if (count < 0)
336 {
337 rl_vi_next_word (-count, key);
338 return;
339 }
340
870ca253
SG
341 if (rl_point == 0)
342 {
343 ding ();
344 return;
345 }
346
bd5635a1
RP
347 if (uppercase_p (key))
348 rl_vi_bWord (count);
349 else
350 rl_vi_bword (count);
351}
352
353/* Next word in vi mode. */
354rl_vi_next_word (count, key)
355 int count;
356{
357 if (count < 0)
358 {
359 rl_vi_prev_word (-count, key);
360 return;
361 }
362
870ca253
SG
363 if (rl_point >= (rl_end - 1))
364 {
365 ding ();
366 return;
367 }
368
bd5635a1
RP
369 if (uppercase_p (key))
370 rl_vi_fWord (count);
371 else
372 rl_vi_fword (count);
373}
374
375/* Move to the end of the ?next? word. */
376rl_vi_end_word (count, key)
377 int count, key;
378{
379 if (count < 0)
380 {
381 ding ();
382 return;
383 }
384
385 if (uppercase_p (key))
386 rl_vi_eWord (count);
387 else
388 rl_vi_eword (count);
389}
390
391/* Move forward a word the way that 'W' does. */
392rl_vi_fWord (count)
393 int count;
394{
395 while (count-- && rl_point < (rl_end - 1))
396 {
397 /* Skip until whitespace. */
870ca253 398 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
bd5635a1
RP
399 rl_point++;
400
401 /* Now skip whitespace. */
870ca253 402 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
bd5635a1
RP
403 rl_point++;
404 }
405}
406
407rl_vi_bWord (count)
408 int count;
409{
410 while (count-- && rl_point > 0)
411 {
870ca253
SG
412 /* If we are at the start of a word, move back to whitespace so
413 we will go back to the start of the previous word. */
414 if (!whitespace (rl_line_buffer[rl_point]) &&
415 whitespace (rl_line_buffer[rl_point - 1]))
bd5635a1 416 rl_point--;
870ca253
SG
417
418 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
419 rl_point--;
420
421 if (rl_point > 0)
422 {
423 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
424 rl_point++;
425 }
bd5635a1
RP
426 }
427}
428
429rl_vi_eWord (count)
430 int count;
431{
870ca253 432 while (count-- && rl_point < (rl_end - 1))
bd5635a1 433 {
870ca253
SG
434 if (!whitespace (rl_line_buffer[rl_point]))
435 rl_point++;
436
437 /* Move to the next non-whitespace character (to the start of the
438 next word). */
439 while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
440
441 if (rl_point && rl_point < rl_end)
442 {
443 /* Skip whitespace. */
444 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
445 rl_point++;
446
447 /* Skip until whitespace. */
448 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
449 rl_point++;
450
451 /* Move back to the last character of the word. */
452 rl_point--;
453 }
bd5635a1
RP
454 }
455}
456
457rl_vi_fword (count)
458 int count;
459{
870ca253 460 while (count-- && rl_point < (rl_end - 1))
bd5635a1 461 {
870ca253
SG
462 /* Move to white space (really non-identifer). */
463 if (isident (rl_line_buffer[rl_point]))
bd5635a1 464 {
870ca253
SG
465 while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
466 rl_point++;
bd5635a1 467 }
870ca253 468 else /* if (!whitespace (rl_line_buffer[rl_point])) */
bd5635a1 469 {
870ca253
SG
470 while (!isident (rl_line_buffer[rl_point]) &&
471 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
472 rl_point++;
bd5635a1
RP
473 }
474
870ca253
SG
475 /* Move past whitespace. */
476 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
bd5635a1
RP
477 rl_point++;
478 }
479}
480
481rl_vi_bword (count)
482 int count;
483{
870ca253 484 while (count-- && rl_point > 0)
bd5635a1 485 {
870ca253
SG
486 int last_is_ident;
487
488 /* If we are at the start of a word, move back to whitespace
489 so we will go back to the start of the previous word. */
490 if (!whitespace (rl_line_buffer[rl_point]) &&
491 whitespace (rl_line_buffer[rl_point - 1]))
492 rl_point--;
493
494 /* If this character and the previous character are `opposite', move
495 back so we don't get messed up by the rl_point++ down there in
496 the while loop. Without this code, words like `l;' screw up the
497 function. */
498 last_is_ident = isident (rl_line_buffer[rl_point - 1]);
499 if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
500 (!isident (rl_line_buffer[rl_point]) && last_is_ident))
501 rl_point--;
502
503 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
504 rl_point--;
505
bd5635a1
RP
506 if (rl_point > 0)
507 {
870ca253
SG
508 if (isident (rl_line_buffer[rl_point]))
509 while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
bd5635a1 510 else
870ca253
SG
511 while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
512 !whitespace (rl_line_buffer[rl_point]));
bd5635a1
RP
513 rl_point++;
514 }
515 }
516}
517
518rl_vi_eword (count)
519 int count;
520{
870ca253 521 while (count-- && rl_point < rl_end - 1)
bd5635a1 522 {
870ca253
SG
523 if (!whitespace (rl_line_buffer[rl_point]))
524 rl_point++;
525
526 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
527 rl_point++;
bd5635a1
RP
528
529 if (rl_point < rl_end)
530 {
870ca253
SG
531 if (isident (rl_line_buffer[rl_point]))
532 while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
bd5635a1 533 else
870ca253
SG
534 while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
535 && !whitespace (rl_line_buffer[rl_point]));
bd5635a1 536 }
870ca253 537 rl_point--;
bd5635a1
RP
538 }
539}
540
541rl_vi_insert_beg ()
542{
543 rl_beg_of_line ();
544 rl_vi_insertion_mode ();
545 return 0;
546}
547
548rl_vi_append_mode ()
549{
550 if (rl_point < rl_end)
551 rl_point += 1;
552 rl_vi_insertion_mode ();
553 return 0;
554}
555
556rl_vi_append_eol ()
557{
558 rl_end_of_line ();
559 rl_vi_append_mode ();
560 return 0;
561}
562
563/* What to do in the case of C-d. */
564rl_vi_eof_maybe (count, c)
565 int count, c;
566{
567 rl_newline (1, '\n');
568}
569
570/* Insertion mode stuff. */
571
572/* Switching from one mode to the other really just involves
573 switching keymaps. */
574rl_vi_insertion_mode ()
575{
576 keymap = vi_insertion_keymap;
577}
578
579rl_vi_movement_mode ()
580{
581 if (rl_point > 0)
582 rl_backward (1);
583
584 keymap = vi_movement_keymap;
585 vi_done_inserting ();
586}
587
588vi_done_inserting ()
589{
590 if (vi_doing_insert)
591 {
592 rl_end_undo_group ();
593 vi_doing_insert = 0;
594 }
595}
596
597rl_vi_arg_digit (count, c)
598 int count, c;
599{
600 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
601 rl_beg_of_line ();
602 else
603 rl_digit_argument (count, c);
604}
605
870ca253
SG
606rl_vi_change_case (count, ignore)
607 int count, ignore;
bd5635a1
RP
608{
609 char c = 0;
610
870ca253
SG
611 /* Don't try this on an empty line. */
612 if (rl_point >= rl_end)
613 return;
bd5635a1 614
870ca253 615 while (count-- && rl_point < rl_end)
bd5635a1 616 {
870ca253
SG
617 if (uppercase_p (rl_line_buffer[rl_point]))
618 c = to_lower (rl_line_buffer[rl_point]);
619 else if (lowercase_p (rl_line_buffer[rl_point]))
620 c = to_upper (rl_line_buffer[rl_point]);
621
622 /* Vi is kind of strange here. */
623 if (c)
624 {
625 rl_begin_undo_group ();
626 rl_delete (1, c);
627 rl_insert (1, c);
628 rl_end_undo_group ();
629 rl_vi_check ();
630 }
631 else
632 rl_forward (1);
bd5635a1 633 }
bd5635a1
RP
634}
635
636rl_vi_put (count, key)
637 int count, key;
638{
870ca253
SG
639 if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
640 rl_point++;
bd5635a1
RP
641
642 rl_yank ();
643 rl_backward (1);
644}
645
646rl_vi_check ()
647{
648 if (rl_point && rl_point == rl_end)
649 rl_point--;
650}
651
652rl_vi_column (count)
653{
654 if (count > rl_end)
655 rl_end_of_line ();
656 else
657 rl_point = count - 1;
658}
659
660int
661rl_vi_domove (key, nextkey)
662 int key, *nextkey;
663{
664 int c, save;
870ca253
SG
665 int old_end, added_blank;
666
667 added_blank = 0;
bd5635a1
RP
668
669 rl_mark = rl_point;
670 c = rl_read_key ();
671 *nextkey = c;
672
673 if (!member (c, vi_motion))
674 {
675 if (digit (c))
676 {
677 save = rl_numeric_arg;
870ca253 678 rl_numeric_arg = digit_value (c);
bd5635a1
RP
679 rl_digit_loop1 ();
680 rl_numeric_arg *= save;
870ca253
SG
681 c = rl_read_key (); /* real command */
682 *nextkey = c;
bd5635a1
RP
683 }
684 else if ((key == 'd' && c == 'd') ||
870ca253 685 (key == 'y' && c == 'y') ||
bd5635a1
RP
686 (key == 'c' && c == 'c'))
687 {
688 rl_mark = rl_end;
689 rl_beg_of_line ();
690 return (0);
691 }
692 else
693 return (-1);
694 }
695
870ca253
SG
696 /* Append a blank character temporarily so that the motion routines
697 work right at the end of the line. */
698 old_end = rl_end;
699 rl_line_buffer[rl_end++] = ' '; /* This looks pretty bogus to me??? */
700 rl_line_buffer[rl_end] = '\0';
701 added_blank++;
702
bd5635a1
RP
703 rl_dispatch (c, keymap);
704
870ca253
SG
705 /* Remove the blank that we added. */
706 rl_end = old_end;
707 rl_line_buffer[rl_end] = '\0';
708 if (rl_point > rl_end)
709 rl_point = rl_end - 1;
710
bd5635a1
RP
711 /* No change in position means the command failed. */
712 if (rl_mark == rl_point)
713 return (-1);
714
870ca253
SG
715 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
716 word. If we are not at the end of the line, and we are on a
717 non-whitespace character, move back one (presumably to whitespace). */
718 if ((c == 'w' || c == 'W') && (rl_point < rl_end) &&
719 !whitespace (rl_line_buffer[rl_point]))
bd5635a1
RP
720 rl_point--;
721
870ca253
SG
722 /* If cw or cW, back up to the end of a word, so the behaviour of ce
723 or cE is the actual result. Brute-force, no subtlety. Do the same
724 thing for dw or dW. */
725 if (key == 'c' && (to_upper (c) == 'W'))
726 {
727 while (rl_point && whitespace (rl_line_buffer[rl_point]))
728 rl_point--;
729 }
730
bd5635a1
RP
731 if (rl_mark < rl_point)
732 exchange (rl_point, rl_mark);
733
734 return (0);
735}
736
737/* A simplified loop for vi. Don't dispatch key at end.
738 Don't recognize minus sign? */
739rl_digit_loop1 ()
740{
741 int key, c;
742
743 while (1)
744 {
870ca253 745 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
bd5635a1
RP
746 key = c = rl_read_key ();
747
748 if (keymap[c].type == ISFUNC &&
749 keymap[c].function == rl_universal_argument)
750 {
751 rl_numeric_arg *= 4;
752 continue;
753 }
870ca253 754
bd5635a1
RP
755 c = UNMETA (c);
756 if (numeric (c))
757 {
758 if (rl_explicit_arg)
870ca253 759 rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c);
bd5635a1 760 else
870ca253 761 rl_numeric_arg = digit_value (c);
bd5635a1
RP
762 rl_explicit_arg = 1;
763 }
764 else
765 {
766 rl_clear_message ();
767 rl_stuff_char (key);
870ca253 768 break;
bd5635a1
RP
769 }
770 }
771}
772
773rl_vi_delete_to (count, key)
774 int count, key;
775{
776 int c;
777
778 if (uppercase_p (key))
779 rl_stuff_char ('$');
780
781 if (rl_vi_domove (key, &c))
782 {
783 ding ();
784 return;
785 }
786
870ca253 787 if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
bd5635a1
RP
788 rl_mark++;
789
790 rl_kill_text (rl_point, rl_mark);
791}
792
793rl_vi_change_to (count, key)
794 int count, key;
795{
796 int c;
797
798 if (uppercase_p (key))
799 rl_stuff_char ('$');
800
801 if (rl_vi_domove (key, &c))
802 {
803 ding ();
804 return;
805 }
806
870ca253 807 if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
bd5635a1
RP
808 rl_mark++;
809
810 rl_begin_undo_group ();
811 vi_doing_insert = 1;
812 rl_kill_text (rl_point, rl_mark);
813 rl_vi_insertion_mode ();
814}
815
816rl_vi_yank_to (count, key)
817 int count, key;
818{
819 int c, save = rl_point;
820
821 if (uppercase_p (key))
822 rl_stuff_char ('$');
823
824 if (rl_vi_domove (key, &c))
825 {
826 ding ();
827 return;
828 }
829
870ca253
SG
830 if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
831 rl_mark++;
832
bd5635a1
RP
833 rl_begin_undo_group ();
834 rl_kill_text (rl_point, rl_mark);
835 rl_end_undo_group ();
836 rl_do_undo ();
837 rl_point = save;
838}
839
840rl_vi_delete (count)
841{
870ca253
SG
842 int end;
843
844 if (rl_end == 0)
bd5635a1 845 {
870ca253
SG
846 ding ();
847 return;
bd5635a1 848 }
870ca253
SG
849
850 end = rl_point + count;
851
852 if (end >= rl_end)
853 end = rl_end;
854
855 rl_kill_text (rl_point, end);
856
857 if (rl_point > 0 && rl_point == rl_end)
858 rl_backward (1);
bd5635a1
RP
859}
860
870ca253
SG
861/* Turn the current line into a comment in shell history.
862 A K*rn shell style function. */
bd5635a1
RP
863rl_vi_comment ()
864{
865 rl_beg_of_line ();
870ca253
SG
866
867 if (rl_vi_comment_begin != (char *)NULL)
868 rl_insert_text (rl_vi_comment_begin);
869 else
870 rl_insert_text (": "); /* Default. */
871
bd5635a1
RP
872 rl_redisplay ();
873 rl_newline (1, '\010');
874}
875
876rl_vi_first_print ()
877{
878 rl_back_to_indent ();
879}
880
881rl_back_to_indent (ignore1, ignore2)
882 int ignore1, ignore2;
883{
884 rl_beg_of_line ();
870ca253 885 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
bd5635a1
RP
886 rl_point++;
887}
888
889/* NOTE: it is necessary that opposite directions are inverses */
890#define FTO 1 /* forward to */
891#define BTO -1 /* backward to */
892#define FFIND 2 /* forward find */
893#define BFIND -2 /* backward find */
894
895rl_vi_char_search (count, key)
896 int count, key;
897{
898 static char target;
899 static int orig_dir, dir;
900 int pos;
901
902 if (key == ';' || key == ',')
903 dir = (key == ';' ? orig_dir : -orig_dir);
904 else
905 {
870ca253 906 target = rl_getc (rl_instream);
bd5635a1
RP
907
908 switch (key)
870ca253
SG
909 {
910 case 't':
911 orig_dir = dir = FTO;
912 break;
913
914 case 'T':
915 orig_dir = dir = BTO;
916 break;
917
918 case 'f':
919 orig_dir = dir = FFIND;
920 break;
921
922 case 'F':
923 orig_dir = dir = BFIND;
924 break;
925 }
bd5635a1
RP
926 }
927
928 pos = rl_point;
929
870ca253 930 while (count--)
bd5635a1 931 {
870ca253 932 if (dir < 0)
bd5635a1 933 {
870ca253 934 if (pos == 0)
bd5635a1 935 {
870ca253 936 ding ();
bd5635a1
RP
937 return;
938 }
bd5635a1 939
870ca253
SG
940 pos--;
941 do
bd5635a1 942 {
870ca253
SG
943 if (rl_line_buffer[pos] == target)
944 {
945 if (dir == BTO)
946 rl_point = pos + 1;
947 else
948 rl_point = pos;
949 break;
950 }
951 }
952 while (pos--);
953
954 if (pos < 0)
955 {
956 ding ();
bd5635a1
RP
957 return;
958 }
959 }
870ca253
SG
960 else
961 { /* dir > 0 */
962 if (pos >= rl_end)
963 {
964 ding ();
965 return;
966 }
bd5635a1 967
870ca253
SG
968 pos++;
969 do
970 {
971 if (rl_line_buffer[pos] == target)
972 {
973 if (dir == FTO)
974 rl_point = pos - 1;
975 else
976 rl_point = pos;
977 break;
978 }
979 }
980 while (++pos < rl_end);
981
982 if (pos >= (rl_end - 1))
983 {
984 ding ();
985 return;
986 }
987 }
bd5635a1
RP
988 }
989}
990
991/* Match brackets */
992rl_vi_match ()
993{
994 int count = 1, brack, pos;
995
996 pos = rl_point;
870ca253 997 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
bd5635a1 998 {
870ca253 999 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
bd5635a1
RP
1000 rl_point < rl_end - 1)
1001 rl_forward (1);
1002
1003 if (brack <= 0)
1004 {
1005 rl_point = pos;
1006 ding ();
1007 return;
1008 }
1009 }
1010
1011 pos = rl_point;
1012
1013 if (brack < 0)
1014 {
1015 while (count)
1016 {
1017 if (--pos >= 0)
1018 {
870ca253 1019 int b = rl_vi_bracktype (rl_line_buffer[pos]);
bd5635a1
RP
1020 if (b == -brack)
1021 count--;
1022 else if (b == brack)
1023 count++;
1024 }
1025 else
1026 {
1027 ding ();
1028 return;
1029 }
1030 }
1031 }
1032 else
1033 { /* brack > 0 */
1034 while (count)
1035 {
1036 if (++pos < rl_end)
1037 {
870ca253 1038 int b = rl_vi_bracktype (rl_line_buffer[pos]);
bd5635a1
RP
1039 if (b == -brack)
1040 count--;
1041 else if (b == brack)
1042 count++;
1043 }
1044 else
1045 {
1046 ding ();
1047 return;
1048 }
1049 }
1050 }
1051 rl_point = pos;
1052}
1053
1054int
1055rl_vi_bracktype (c)
1056 int c;
1057{
1058 switch (c)
1059 {
1060 case '(': return 1;
1061 case ')': return -1;
1062 case '[': return 2;
1063 case ']': return -2;
1064 case '{': return 3;
1065 case '}': return -3;
1066 default: return 0;
1067 }
1068}
1069
870ca253
SG
1070rl_vi_change_char (count, key)
1071 int count, key;
bd5635a1
RP
1072{
1073 int c;
1074
870ca253 1075 c = rl_getc (rl_instream);
bd5635a1 1076
870ca253
SG
1077 if (c == '\033' || c == CTRL ('C'))
1078 return;
bd5635a1 1079
870ca253
SG
1080 while (count-- && rl_point < rl_end)
1081 {
bd5635a1 1082 rl_begin_undo_group ();
870ca253 1083
bd5635a1
RP
1084 rl_delete (1, c);
1085 rl_insert (1, c);
870ca253
SG
1086 if (count == 0)
1087 rl_backward (1);
1088
bd5635a1 1089 rl_end_undo_group ();
bd5635a1
RP
1090 }
1091}
1092
1093rl_vi_subst (count, key)
1094 int count, key;
1095{
1096 rl_begin_undo_group ();
1097 vi_doing_insert = 1;
1098
1099 if (uppercase_p (key))
1100 {
1101 rl_beg_of_line ();
1102 rl_kill_line (1);
1103 }
1104 else
870ca253 1105 rl_delete (count, key);
bd5635a1
RP
1106
1107 rl_vi_insertion_mode ();
1108}
1109
1110rl_vi_overstrike (count, key)
1111 int count, key;
1112{
1113 int i;
1114
1115 if (vi_doing_insert == 0)
1116 {
1117 vi_doing_insert = 1;
1118 rl_begin_undo_group ();
1119 }
1120
1121 for (i = 0; i < count; i++)
1122 {
1123 vi_replace_count++;
1124 rl_begin_undo_group ();
1125
1126 if (rl_point < rl_end)
1127 {
1128 rl_delete (1, key);
1129 rl_insert (1, key);
1130 }
1131 else
1132 rl_insert (1, key);
1133
1134 rl_end_undo_group ();
1135 }
1136}
1137
1138rl_vi_overstrike_delete (count)
1139 int count;
1140{
1141 int i, s;
1142
1143 for (i = 0; i < count; i++)
1144 {
1145 if (vi_replace_count == 0)
1146 {
1147 ding ();
1148 break;
1149 }
1150 s = rl_point;
1151
1152 if (rl_do_undo ())
1153 vi_replace_count--;
1154
1155 if (rl_point == s)
1156 rl_backward (1);
1157 }
1158
1159 if (vi_replace_count == 0 && vi_doing_insert)
1160 {
1161 rl_end_undo_group ();
1162 rl_do_undo ();
1163 vi_doing_insert = 0;
1164 }
1165}
1166
870ca253
SG
1167rl_vi_replace (count, key)
1168 int count, key;
bd5635a1
RP
1169{
1170 int i;
1171
1172 vi_replace_count = 0;
1173
870ca253
SG
1174 if (!vi_replace_map)
1175 {
1176 vi_replace_map = rl_make_bare_keymap ();
bd5635a1 1177
870ca253
SG
1178 for (i = ' '; i < 127; i++)
1179 vi_replace_map[i].function = rl_vi_overstrike;
bd5635a1 1180
870ca253
SG
1181 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1182 vi_replace_map[ESC].function = rl_vi_movement_mode;
1183 vi_replace_map[RETURN].function = rl_newline;
1184 vi_replace_map[NEWLINE].function = rl_newline;
1185
1186 /* If the normal vi insertion keymap has ^H bound to erase, do the
1187 same here. Probably should remove the assignment to RUBOUT up
1188 there, but I don't think it will make a difference in real life. */
1189 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1190 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1191 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1192
1193 }
bd5635a1
RP
1194 keymap = vi_replace_map;
1195}
1196
1197/*
1198 * Try to complete the word we are standing on or the word that ends with
1199 * the previous character. A space matches everything.
1200 * Word delimiters are space and ;.
1201 */
1202rl_vi_possible_completions()
1203{
1204 int save_pos = rl_point;
1205
870ca253 1206 if (!index (" ;", rl_line_buffer[rl_point]))
bd5635a1 1207 {
870ca253 1208 while (!index(" ;", rl_line_buffer[++rl_point]))
bd5635a1
RP
1209 ;
1210 }
870ca253 1211 else if (rl_line_buffer[rl_point-1] == ';')
bd5635a1
RP
1212 {
1213 ding ();
1214 return (0);
1215 }
1216
1217 rl_possible_completions ();
1218 rl_point = save_pos;
1219
1220 return (0);
1221}
870ca253
SG
1222
1223#endif /* VI_MODE */
This page took 0.230433 seconds and 4 git commands to generate.