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