[readline] Fix compilation on MinGW
[deliverable/binutils-gdb.git] / readline / vi_mode.c
CommitLineData
d60d9f65
SS
1/* vi_mode.c -- A vi emulation mode for Bash.
2 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
3
cb41b9e7 4/* Copyright (C) 1987-2018 Free Software Foundation, Inc.
d60d9f65 5
cc88a640
JK
6 This file is part of the GNU Readline Library (Readline), a library
7 for reading lines of text with interactive input and history editing.
d60d9f65 8
cc88a640
JK
9 Readline is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
d60d9f65
SS
12 (at your option) any later version.
13
cc88a640
JK
14 Readline is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
d60d9f65
SS
17 GNU General Public License for more details.
18
cc88a640
JK
19 You should have received a copy of the GNU General Public License
20 along with Readline. If not, see <http://www.gnu.org/licenses/>.
21*/
22
d60d9f65
SS
23#define READLINE_LIBRARY
24
25/* **************************************************************** */
26/* */
27/* VI Emulation Mode */
28/* */
29/* **************************************************************** */
30#include "rlconf.h"
31
32#if defined (VI_MODE)
33
34#if defined (HAVE_CONFIG_H)
35# include <config.h>
36#endif
37
38#include <sys/types.h>
39
40#if defined (HAVE_STDLIB_H)
41# include <stdlib.h>
42#else
43# include "ansi_stdlib.h"
44#endif /* HAVE_STDLIB_H */
45
46#if defined (HAVE_UNISTD_H)
47# include <unistd.h>
48#endif
49
50#include <stdio.h>
51
52/* Some standard library routines. */
53#include "rldefs.h"
9255ee31
EZ
54#include "rlmbutil.h"
55
d60d9f65
SS
56#include "readline.h"
57#include "history.h"
58
1b17e766
EZ
59#include "rlprivate.h"
60#include "xmalloc.h"
61
d60d9f65
SS
62#ifndef member
63#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
64#endif
65
cb41b9e7
TT
66/* Increment START to the next character in RL_LINE_BUFFER, handling multibyte chars */
67#if defined (HANDLE_MULTIBYTE)
68#define INCREMENT_POS(start) \
69 do { \
70 if (MB_CUR_MAX == 1 || rl_byte_oriented) \
71 start++; \
72 else \
73 start = _rl_find_next_mbchar (rl_line_buffer, start, 1, MB_FIND_ANY); \
74 } while (0)
75#else /* !HANDLE_MULTIBYTE */
76#define INCREMENT_POS(start) (start)++
77#endif /* !HANDLE_MULTIBYTE */
78
79/* This is global so other parts of the code can check whether the last
80 command was a text modification command. */
5bdf8622
DJ
81int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
82
cc88a640
JK
83_rl_vimotion_cxt *_rl_vimvcxt = 0;
84
775e241e
TT
85/* Non-zero indicates we are redoing a vi-mode command with `.' */
86int _rl_vi_redoing;
87
d60d9f65
SS
88/* Non-zero means enter insertion mode. */
89static int _rl_vi_doing_insert;
90
91/* Command keys which do movement for xxx_to commands. */
cc88a640 92static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`";
d60d9f65
SS
93
94/* Keymap used for vi replace characters. Created dynamically since
95 rarely used. */
96static Keymap vi_replace_map;
97
98/* The number of characters inserted in the last replace operation. */
99static int vi_replace_count;
100
101/* If non-zero, we have text inserted after a c[motion] command that put
102 us implicitly into insert mode. Some people want this text to be
103 attached to the command so that it is `redoable' with `.'. */
104static int vi_continued_command;
105static char *vi_insert_buffer;
106static int vi_insert_buffer_size;
107
d60d9f65
SS
108static int _rl_vi_last_repeat = 1;
109static int _rl_vi_last_arg_sign = 1;
110static int _rl_vi_last_motion;
9255ee31
EZ
111#if defined (HANDLE_MULTIBYTE)
112static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
5bdf8622 113static int _rl_vi_last_search_mblen;
9255ee31 114#else
d60d9f65 115static int _rl_vi_last_search_char;
9255ee31 116#endif
cb41b9e7 117static char _rl_vi_last_replacement[MB_LEN_MAX+1]; /* reserve for trailing NULL */
d60d9f65
SS
118
119static int _rl_vi_last_key_before_insert;
120
d60d9f65 121/* Text modification commands. These are the `redoable' commands. */
cc88a640 122static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
d60d9f65
SS
123
124/* Arrays for the saved marks. */
9255ee31 125static int vi_mark_chars['z' - 'a' + 1];
d60d9f65 126
775e241e
TT
127static void _rl_vi_replace_insert PARAMS((int));
128static void _rl_vi_save_replace PARAMS((void));
9255ee31
EZ
129static void _rl_vi_stuff_insert PARAMS((int));
130static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
5bdf8622 131
775e241e
TT
132static void vi_save_insert_buffer PARAMS ((int, int));
133
cb41b9e7 134static inline void _rl_vi_backup PARAMS((void));
cc88a640 135
5bdf8622 136static int _rl_vi_arg_dispatch PARAMS((int));
9255ee31 137static int rl_digit_loop1 PARAMS((void));
d60d9f65 138
5bdf8622
DJ
139static int _rl_vi_set_mark PARAMS((void));
140static int _rl_vi_goto_mark PARAMS((void));
141
cb41b9e7
TT
142static inline int _rl_vi_advance_point PARAMS((void));
143static inline int _rl_vi_backup_point PARAMS((void));
144
cc88a640
JK
145static void _rl_vi_append_forward PARAMS((int));
146
5bdf8622
DJ
147static int _rl_vi_callback_getchar PARAMS((char *, int));
148
149#if defined (READLINE_CALLBACKS)
150static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
151static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
152static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
153static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
154#endif
155
cc88a640
JK
156static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *));
157static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *));
158static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *));
159
160static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *));
161static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *));
162static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *));
163
164static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *));
165
d60d9f65 166void
cb41b9e7 167_rl_vi_initialize_line (void)
d60d9f65 168{
cc88a640 169 register int i, n;
d60d9f65 170
cc88a640
JK
171 n = sizeof (vi_mark_chars) / sizeof (vi_mark_chars[0]);
172 for (i = 0; i < n; i++)
d60d9f65 173 vi_mark_chars[i] = -1;
5bdf8622
DJ
174
175 RL_UNSETSTATE(RL_STATE_VICMDONCE);
d60d9f65
SS
176}
177
178void
cb41b9e7 179_rl_vi_reset_last (void)
d60d9f65
SS
180{
181 _rl_vi_last_command = 'i';
182 _rl_vi_last_repeat = 1;
183 _rl_vi_last_arg_sign = 1;
184 _rl_vi_last_motion = 0;
185}
186
187void
cb41b9e7 188_rl_vi_set_last (int key, int repeat, int sign)
d60d9f65
SS
189{
190 _rl_vi_last_command = key;
191 _rl_vi_last_repeat = repeat;
192 _rl_vi_last_arg_sign = sign;
193}
194
5bdf8622
DJ
195/* A convenience function that calls _rl_vi_set_last to save the last command
196 information and enters insertion mode. */
197void
cb41b9e7 198rl_vi_start_inserting (int key, int repeat, int sign)
5bdf8622
DJ
199{
200 _rl_vi_set_last (key, repeat, sign);
cb41b9e7 201 rl_begin_undo_group (); /* ensure inserts aren't concatenated */
5bdf8622
DJ
202 rl_vi_insertion_mode (1, key);
203}
204
d60d9f65
SS
205/* Is the command C a VI mode text modification command? */
206int
cb41b9e7 207_rl_vi_textmod_command (int c)
d60d9f65
SS
208{
209 return (member (c, vi_textmod));
210}
211
775e241e 212int
cb41b9e7 213_rl_vi_motion_command (int c)
775e241e
TT
214{
215 return (member (c, vi_motion));
216}
217
218static void
cb41b9e7 219_rl_vi_replace_insert (int count)
775e241e
TT
220{
221 int nchars;
222
223 nchars = strlen (vi_insert_buffer);
224
225 rl_begin_undo_group ();
226 while (count--)
227 /* nchars-1 to compensate for _rl_replace_text using `end+1' in call
228 to rl_delete_text */
229 _rl_replace_text (vi_insert_buffer, rl_point, rl_point+nchars-1);
230 rl_end_undo_group ();
231}
232
d60d9f65 233static void
cb41b9e7 234_rl_vi_stuff_insert (int count)
d60d9f65
SS
235{
236 rl_begin_undo_group ();
237 while (count--)
238 rl_insert_text (vi_insert_buffer);
239 rl_end_undo_group ();
240}
241
242/* Bound to `.'. Called from command mode, so we know that we have to
243 redo a text modification command. The default for _rl_vi_last_command
244 puts you back into insert mode. */
245int
cb41b9e7 246rl_vi_redo (int count, int c)
d60d9f65 247{
9255ee31
EZ
248 int r;
249
775e241e 250 if (rl_explicit_arg == 0)
d60d9f65
SS
251 {
252 rl_numeric_arg = _rl_vi_last_repeat;
253 rl_arg_sign = _rl_vi_last_arg_sign;
254 }
255
9255ee31 256 r = 0;
775e241e 257 _rl_vi_redoing = 1;
d60d9f65
SS
258 /* If we're redoing an insert with `i', stuff in the inserted text
259 and do not go into insertion mode. */
260 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
261 {
262 _rl_vi_stuff_insert (count);
263 /* And back up point over the last character inserted. */
264 if (rl_point > 0)
cc88a640
JK
265 _rl_vi_backup ();
266 }
775e241e
TT
267 else if (_rl_vi_last_command == 'R' && vi_insert_buffer && *vi_insert_buffer)
268 {
269 _rl_vi_replace_insert (count);
270 /* And back up point over the last character inserted. */
271 if (rl_point > 0)
272 _rl_vi_backup ();
273 }
cc88a640
JK
274 /* Ditto for redoing an insert with `I', but move to the beginning of the
275 line like the `I' command does. */
276 else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer)
277 {
278 rl_beg_of_line (1, 'I');
279 _rl_vi_stuff_insert (count);
280 if (rl_point > 0)
281 _rl_vi_backup ();
282 }
283 /* Ditto for redoing an insert with `a', but move forward a character first
284 like the `a' command does. */
285 else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
286 {
287 _rl_vi_append_forward ('a');
288 _rl_vi_stuff_insert (count);
289 if (rl_point > 0)
290 _rl_vi_backup ();
291 }
292 /* Ditto for redoing an insert with `A', but move to the end of the line
293 like the `A' command does. */
294 else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer)
295 {
296 rl_end_of_line (1, 'A');
297 _rl_vi_stuff_insert (count);
298 if (rl_point > 0)
299 _rl_vi_backup ();
d60d9f65
SS
300 }
301 else
9255ee31 302 r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
775e241e
TT
303
304 _rl_vi_redoing = 0;
d60d9f65 305
9255ee31 306 return (r);
d60d9f65
SS
307}
308
309/* A placeholder for further expansion. */
310int
cb41b9e7 311rl_vi_undo (int count, int key)
d60d9f65
SS
312{
313 return (rl_undo_command (count, key));
314}
315
316/* Yank the nth arg from the previous line into this line at point. */
317int
cb41b9e7 318rl_vi_yank_arg (int count, int key)
d60d9f65
SS
319{
320 /* Readline thinks that the first word on a line is the 0th, while vi
321 thinks the first word on a line is the 1st. Compensate. */
322 if (rl_explicit_arg)
323 rl_yank_nth_arg (count - 1, 0);
324 else
325 rl_yank_nth_arg ('$', 0);
326
327 return (0);
328}
329
330/* With an argument, move back that many history lines, else move to the
331 beginning of history. */
332int
cb41b9e7 333rl_vi_fetch_history (int count, int c)
d60d9f65
SS
334{
335 int wanted;
336
337 /* Giving an argument of n means we want the nth command in the history
338 file. The command number is interpreted the same way that the bash
339 `history' command does it -- that is, giving an argument count of 450
340 to this command would get the command listed as number 450 in the
341 output of `history'. */
342 if (rl_explicit_arg)
343 {
344 wanted = history_base + where_history () - count;
345 if (wanted <= 0)
346 rl_beginning_of_history (0, 0);
347 else
348 rl_get_previous_history (wanted, c);
349 }
350 else
351 rl_beginning_of_history (count, 0);
352 return (0);
353}
354
355/* Search again for the last thing searched for. */
356int
cb41b9e7 357rl_vi_search_again (int count, int key)
d60d9f65
SS
358{
359 switch (key)
360 {
361 case 'n':
362 rl_noninc_reverse_search_again (count, key);
363 break;
364
365 case 'N':
366 rl_noninc_forward_search_again (count, key);
367 break;
368 }
369 return (0);
370}
371
372/* Do a vi style search. */
373int
cb41b9e7 374rl_vi_search (int count, int key)
d60d9f65
SS
375{
376 switch (key)
377 {
378 case '?':
5bdf8622 379 _rl_free_saved_history_line ();
d60d9f65
SS
380 rl_noninc_forward_search (count, key);
381 break;
382
383 case '/':
5bdf8622 384 _rl_free_saved_history_line ();
d60d9f65
SS
385 rl_noninc_reverse_search (count, key);
386 break;
387
388 default:
9255ee31 389 rl_ding ();
d60d9f65
SS
390 break;
391 }
392 return (0);
393}
394
395/* Completion, from vi's point of view. */
396int
cb41b9e7 397rl_vi_complete (int ignore, int key)
d60d9f65
SS
398{
399 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
400 {
401 if (!whitespace (rl_line_buffer[rl_point + 1]))
402 rl_vi_end_word (1, 'E');
cb41b9e7 403 _rl_vi_advance_point ();
d60d9f65
SS
404 }
405
406 if (key == '*')
407 rl_complete_internal ('*'); /* Expansion and replacement. */
408 else if (key == '=')
409 rl_complete_internal ('?'); /* List possible completions. */
410 else if (key == '\\')
411 rl_complete_internal (TAB); /* Standard Readline completion. */
412 else
413 rl_complete (0, key);
414
415 if (key == '*' || key == '\\')
5bdf8622
DJ
416 rl_vi_start_inserting (key, 1, rl_arg_sign);
417
d60d9f65
SS
418 return (0);
419}
420
421/* Tilde expansion for vi mode. */
422int
cb41b9e7 423rl_vi_tilde_expand (int ignore, int key)
d60d9f65
SS
424{
425 rl_tilde_expand (0, key);
5bdf8622 426 rl_vi_start_inserting (key, 1, rl_arg_sign);
d60d9f65
SS
427 return (0);
428}
429
430/* Previous word in vi mode. */
431int
cb41b9e7 432rl_vi_prev_word (int count, int key)
d60d9f65
SS
433{
434 if (count < 0)
435 return (rl_vi_next_word (-count, key));
436
437 if (rl_point == 0)
438 {
9255ee31 439 rl_ding ();
d60d9f65
SS
440 return (0);
441 }
442
443 if (_rl_uppercase_p (key))
c862e87b 444 rl_vi_bWord (count, key);
d60d9f65 445 else
c862e87b 446 rl_vi_bword (count, key);
d60d9f65
SS
447
448 return (0);
449}
450
451/* Next word in vi mode. */
452int
cb41b9e7 453rl_vi_next_word (int count, int key)
d60d9f65
SS
454{
455 if (count < 0)
456 return (rl_vi_prev_word (-count, key));
457
458 if (rl_point >= (rl_end - 1))
459 {
9255ee31 460 rl_ding ();
d60d9f65
SS
461 return (0);
462 }
463
464 if (_rl_uppercase_p (key))
c862e87b 465 rl_vi_fWord (count, key);
d60d9f65 466 else
c862e87b 467 rl_vi_fword (count, key);
d60d9f65
SS
468 return (0);
469}
470
cb41b9e7
TT
471static inline int
472_rl_vi_advance_point (void)
473{
474 int point;
475
476 point = rl_point;
477 if (rl_point < rl_end)
478#if defined (HANDLE_MULTIBYTE)
479 {
480 if (MB_CUR_MAX == 1 || rl_byte_oriented)
481 rl_point++;
482 else
483 {
484 point = rl_point;
485 rl_point = _rl_forward_char_internal (1);
486 if (point == rl_point || rl_point > rl_end)
487 rl_point = rl_end;
488 }
489 }
490#else
491 rl_point++;
492#endif
493
494 return point;
495}
496
497/* Move the cursor back one character. */
498static inline void
499_rl_vi_backup (void)
500{
501 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
502 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
503 else
504 rl_point--;
505}
506
507/* Move the point back one character, returning the starting value and not
508 doing anything at the beginning of the line */
509static inline int
510_rl_vi_backup_point (void)
511{
512 int point;
513
514 point = rl_point;
515 if (rl_point > 0)
516#if defined (HANDLE_MULTIBYTE)
517 {
518 if (MB_CUR_MAX == 1 || rl_byte_oriented)
519 rl_point--;
520 else
521 {
522 point = rl_point;
523 rl_point = _rl_backward_char_internal (1);
524 if (rl_point < 0)
525 rl_point = 0; /* XXX - not really necessary */
526 }
527 }
528#else
529 rl_point--;
530#endif
531 return point;
532}
533
d60d9f65
SS
534/* Move to the end of the ?next? word. */
535int
cb41b9e7 536rl_vi_end_word (int count, int key)
d60d9f65
SS
537{
538 if (count < 0)
539 {
9255ee31 540 rl_ding ();
775e241e 541 return 1;
d60d9f65
SS
542 }
543
544 if (_rl_uppercase_p (key))
c862e87b 545 rl_vi_eWord (count, key);
d60d9f65 546 else
c862e87b 547 rl_vi_eword (count, key);
d60d9f65
SS
548 return (0);
549}
550
551/* Move forward a word the way that 'W' does. */
552int
cb41b9e7 553rl_vi_fWord (int count, int ignore)
d60d9f65
SS
554{
555 while (count-- && rl_point < (rl_end - 1))
556 {
557 /* Skip until whitespace. */
558 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
cb41b9e7 559 _rl_vi_advance_point ();
d60d9f65
SS
560
561 /* Now skip whitespace. */
562 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
cb41b9e7 563 _rl_vi_advance_point ();
d60d9f65
SS
564 }
565 return (0);
566}
567
568int
cb41b9e7 569rl_vi_bWord (int count, int ignore)
d60d9f65
SS
570{
571 while (count-- && rl_point > 0)
572 {
573 /* If we are at the start of a word, move back to whitespace so
574 we will go back to the start of the previous word. */
575 if (!whitespace (rl_line_buffer[rl_point]) &&
576 whitespace (rl_line_buffer[rl_point - 1]))
577 rl_point--;
578
579 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
cb41b9e7 580 _rl_vi_backup_point ();
d60d9f65
SS
581
582 if (rl_point > 0)
583 {
cb41b9e7
TT
584 do
585 _rl_vi_backup_point ();
586 while (rl_point > 0 && !whitespace (rl_line_buffer[rl_point]));
587 if (rl_point > 0) /* hit whitespace */
588 rl_point++;
589
590 if (rl_point < 0)
591 rl_point = 0;
d60d9f65
SS
592 }
593 }
594 return (0);
595}
596
597int
cb41b9e7 598rl_vi_eWord (int count, int ignore)
d60d9f65 599{
cb41b9e7
TT
600 int opoint;
601
d60d9f65
SS
602 while (count-- && rl_point < (rl_end - 1))
603 {
cb41b9e7
TT
604 if (whitespace (rl_line_buffer[rl_point]) == 0)
605 _rl_vi_advance_point ();
d60d9f65
SS
606
607 /* Move to the next non-whitespace character (to the start of the
608 next word). */
5bdf8622 609 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
cb41b9e7 610 _rl_vi_advance_point ();
d60d9f65
SS
611
612 if (rl_point && rl_point < rl_end)
613 {
cb41b9e7
TT
614 opoint = rl_point;
615
d60d9f65
SS
616 /* Skip whitespace. */
617 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
cb41b9e7 618 opoint = _rl_vi_advance_point (); /* XXX - why? */
d60d9f65
SS
619
620 /* Skip until whitespace. */
621 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
cb41b9e7 622 opoint = _rl_vi_advance_point ();
d60d9f65
SS
623
624 /* Move back to the last character of the word. */
cb41b9e7 625 rl_point = opoint;
d60d9f65
SS
626 }
627 }
628 return (0);
629}
630
631int
cb41b9e7 632rl_vi_fword (int count, int ignore)
d60d9f65 633{
cb41b9e7
TT
634 int opoint;
635
d60d9f65
SS
636 while (count-- && rl_point < (rl_end - 1))
637 {
638 /* Move to white space (really non-identifer). */
9255ee31 639 if (_rl_isident (rl_line_buffer[rl_point]))
d60d9f65 640 {
9255ee31 641 while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
cb41b9e7 642 _rl_vi_advance_point ();
d60d9f65
SS
643 }
644 else /* if (!whitespace (rl_line_buffer[rl_point])) */
645 {
9255ee31 646 while (!_rl_isident (rl_line_buffer[rl_point]) &&
d60d9f65 647 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
cb41b9e7 648 _rl_vi_advance_point ();
d60d9f65
SS
649 }
650
cb41b9e7
TT
651 opoint = rl_point;
652
d60d9f65
SS
653 /* Move past whitespace. */
654 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
cb41b9e7 655 opoint = _rl_vi_advance_point ();
d60d9f65
SS
656 }
657 return (0);
658}
659
660int
cb41b9e7 661rl_vi_bword (int count, int ignore)
d60d9f65 662{
cb41b9e7
TT
663 int opoint;
664
d60d9f65
SS
665 while (count-- && rl_point > 0)
666 {
cb41b9e7 667 int prev_is_ident, cur_is_ident;
d60d9f65
SS
668
669 /* If we are at the start of a word, move back to whitespace
670 so we will go back to the start of the previous word. */
671 if (!whitespace (rl_line_buffer[rl_point]) &&
672 whitespace (rl_line_buffer[rl_point - 1]))
cb41b9e7
TT
673 if (--rl_point == 0)
674 break;
d60d9f65
SS
675
676 /* If this character and the previous character are `opposite', move
677 back so we don't get messed up by the rl_point++ down there in
678 the while loop. Without this code, words like `l;' screw up the
679 function. */
cb41b9e7
TT
680 cur_is_ident = _rl_isident (rl_line_buffer[rl_point]);
681 opoint = _rl_vi_backup_point ();
682 prev_is_ident = _rl_isident (rl_line_buffer[rl_point]);
683 if ((cur_is_ident && !prev_is_ident) || (!cur_is_ident && prev_is_ident))
684 ; /* leave point alone, we backed it up one character */
685 else
686 rl_point = opoint;
d60d9f65
SS
687
688 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
cb41b9e7 689 _rl_vi_backup_point ();
d60d9f65
SS
690
691 if (rl_point > 0)
692 {
cb41b9e7 693 opoint = rl_point;
9255ee31 694 if (_rl_isident (rl_line_buffer[rl_point]))
cb41b9e7
TT
695 do
696 opoint = _rl_vi_backup_point ();
697 while (rl_point > 0 && _rl_isident (rl_line_buffer[rl_point]));
d60d9f65 698 else
cb41b9e7
TT
699 do
700 opoint = _rl_vi_backup_point ();
701 while (rl_point > 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
d60d9f65 702 !whitespace (rl_line_buffer[rl_point]));
cb41b9e7
TT
703
704 if (rl_point > 0)
705 rl_point = opoint;
706
707 if (rl_point < 0)
708 rl_point = 0;
d60d9f65
SS
709 }
710 }
711 return (0);
712}
713
714int
cb41b9e7 715rl_vi_eword (int count, int ignore)
d60d9f65 716{
cb41b9e7
TT
717 int opoint;
718
719 while (count-- && rl_point < (rl_end - 1))
d60d9f65 720 {
cb41b9e7
TT
721 if (whitespace (rl_line_buffer[rl_point]) == 0)
722 _rl_vi_advance_point ();
d60d9f65
SS
723
724 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
cb41b9e7 725 _rl_vi_advance_point ();
d60d9f65 726
cb41b9e7 727 opoint = rl_point;
d60d9f65
SS
728 if (rl_point < rl_end)
729 {
9255ee31 730 if (_rl_isident (rl_line_buffer[rl_point]))
cb41b9e7
TT
731 do
732 {
733 opoint = _rl_vi_advance_point ();
734 }
735 while (rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
d60d9f65 736 else
cb41b9e7
TT
737 do
738 {
739 opoint = _rl_vi_advance_point ();
740 }
741 while (rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
d60d9f65
SS
742 && !whitespace (rl_line_buffer[rl_point]));
743 }
cb41b9e7 744 rl_point = opoint;
d60d9f65
SS
745 }
746 return (0);
747}
748
749int
cb41b9e7 750rl_vi_insert_beg (int count, int key)
d60d9f65
SS
751{
752 rl_beg_of_line (1, key);
cc88a640 753 rl_vi_insert_mode (1, key);
d60d9f65
SS
754 return (0);
755}
756
cc88a640 757static void
cb41b9e7 758_rl_vi_append_forward (int key)
d60d9f65 759{
cb41b9e7 760 _rl_vi_advance_point ();
cc88a640
JK
761}
762
763int
cb41b9e7 764rl_vi_append_mode (int count, int key)
cc88a640
JK
765{
766 _rl_vi_append_forward (key);
767 rl_vi_start_inserting (key, 1, rl_arg_sign);
d60d9f65
SS
768 return (0);
769}
770
771int
cb41b9e7 772rl_vi_append_eol (int count, int key)
d60d9f65
SS
773{
774 rl_end_of_line (1, key);
775 rl_vi_append_mode (1, key);
776 return (0);
777}
778
779/* What to do in the case of C-d. */
780int
cb41b9e7 781rl_vi_eof_maybe (int count, int c)
d60d9f65
SS
782{
783 return (rl_newline (1, '\n'));
784}
785
786/* Insertion mode stuff. */
787
788/* Switching from one mode to the other really just involves
789 switching keymaps. */
790int
cb41b9e7 791rl_vi_insertion_mode (int count, int key)
d60d9f65
SS
792{
793 _rl_keymap = vi_insertion_keymap;
794 _rl_vi_last_key_before_insert = key;
775e241e
TT
795 if (_rl_show_mode_in_prompt)
796 _rl_reset_prompt ();
d60d9f65
SS
797 return (0);
798}
799
cc88a640 800int
cb41b9e7 801rl_vi_insert_mode (int count, int key)
cc88a640
JK
802{
803 rl_vi_start_inserting (key, 1, rl_arg_sign);
804 return (0);
805}
806
775e241e 807static void
cb41b9e7 808vi_save_insert_buffer (int start, int len)
775e241e
TT
809{
810 /* Same code as _rl_vi_save_insert below */
811 if (len >= vi_insert_buffer_size)
812 {
813 vi_insert_buffer_size += (len + 32) - (len % 32);
814 vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
815 }
816 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
817 vi_insert_buffer[len-1] = '\0';
818}
819
820static void
cb41b9e7 821_rl_vi_save_replace (void)
775e241e
TT
822{
823 int len, start, end;
824 UNDO_LIST *up;
825
826 up = rl_undo_list;
827 if (up == 0 || up->what != UNDO_END || vi_replace_count <= 0)
828 {
829 if (vi_insert_buffer_size >= 1)
830 vi_insert_buffer[0] = '\0';
831 return;
832 }
833 /* Let's try it the quick and easy way for now. This should essentially
834 accommodate every UNDO_INSERT and save the inserted text to
835 vi_insert_buffer */
836 end = rl_point;
837 start = end - vi_replace_count + 1;
838 len = vi_replace_count + 1;
839
840 vi_save_insert_buffer (start, len);
841}
842
d60d9f65 843static void
cb41b9e7 844_rl_vi_save_insert (UNDO_LIST *up)
d60d9f65
SS
845{
846 int len, start, end;
847
cc88a640 848 if (up == 0 || up->what != UNDO_INSERT)
d60d9f65
SS
849 {
850 if (vi_insert_buffer_size >= 1)
851 vi_insert_buffer[0] = '\0';
852 return;
853 }
854
855 start = up->start;
856 end = up->end;
857 len = end - start + 1;
775e241e
TT
858
859 vi_save_insert_buffer (start, len);
d60d9f65
SS
860}
861
862void
cb41b9e7 863_rl_vi_done_inserting (void)
d60d9f65
SS
864{
865 if (_rl_vi_doing_insert)
866 {
9255ee31 867 /* The `C', `s', and `S' commands set this. */
d60d9f65
SS
868 rl_end_undo_group ();
869 /* Now, the text between rl_undo_list->next->start and
870 rl_undo_list->next->end is what was inserted while in insert
871 mode. It gets copied to VI_INSERT_BUFFER because it depends
872 on absolute indices into the line which may change (though they
873 probably will not). */
874 _rl_vi_doing_insert = 0;
775e241e
TT
875 if (_rl_vi_last_key_before_insert == 'R')
876 _rl_vi_save_replace (); /* Half the battle */
877 else
878 _rl_vi_save_insert (rl_undo_list->next);
d60d9f65
SS
879 vi_continued_command = 1;
880 }
881 else
882 {
cc88a640
JK
883 if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' ||
884 _rl_vi_last_key_before_insert == 'a' ||
885 _rl_vi_last_key_before_insert == 'I' ||
886 _rl_vi_last_key_before_insert == 'A'))
887 _rl_vi_save_insert (rl_undo_list);
d60d9f65
SS
888 /* XXX - Other keys probably need to be checked. */
889 else if (_rl_vi_last_key_before_insert == 'C')
890 rl_end_undo_group ();
891 while (_rl_undo_group_level > 0)
892 rl_end_undo_group ();
893 vi_continued_command = 0;
894 }
895}
896
897int
cb41b9e7 898rl_vi_movement_mode (int count, int key)
d60d9f65
SS
899{
900 if (rl_point > 0)
9255ee31 901 rl_backward_char (1, key);
d60d9f65
SS
902
903 _rl_keymap = vi_movement_keymap;
904 _rl_vi_done_inserting ();
5bdf8622
DJ
905
906 /* This is how POSIX.2 says `U' should behave -- everything up until the
907 first time you go into command mode should not be undone. */
908 if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
909 rl_free_undo_list ();
910
775e241e
TT
911 if (_rl_show_mode_in_prompt)
912 _rl_reset_prompt ();
913
5bdf8622 914 RL_SETSTATE (RL_STATE_VICMDONCE);
d60d9f65
SS
915 return (0);
916}
917
918int
cb41b9e7 919rl_vi_arg_digit (int count, int c)
d60d9f65
SS
920{
921 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
922 return (rl_beg_of_line (1, c));
923 else
924 return (rl_digit_argument (count, c));
925}
926
9255ee31
EZ
927/* Change the case of the next COUNT characters. */
928#if defined (HANDLE_MULTIBYTE)
929static int
cb41b9e7 930_rl_vi_change_mbchar_case (int count)
9255ee31
EZ
931{
932 wchar_t wc;
5af408ce 933 char mb[MB_LEN_MAX+1];
cc88a640
JK
934 int mlen, p;
935 size_t m;
9255ee31
EZ
936 mbstate_t ps;
937
938 memset (&ps, 0, sizeof (mbstate_t));
939 if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
940 count--;
941 while (count-- && rl_point < rl_end)
942 {
cc88a640
JK
943 m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
944 if (MB_INVALIDCH (m))
945 wc = (wchar_t)rl_line_buffer[rl_point];
946 else if (MB_NULLWCH (m))
947 wc = L'\0';
9255ee31
EZ
948 if (iswupper (wc))
949 wc = towlower (wc);
950 else if (iswlower (wc))
951 wc = towupper (wc);
952 else
953 {
954 /* Just skip over chars neither upper nor lower case */
955 rl_forward_char (1, 0);
956 continue;
957 }
958
959 /* Vi is kind of strange here. */
960 if (wc)
961 {
5bdf8622 962 p = rl_point;
cc88a640
JK
963 mlen = wcrtomb (mb, wc, &ps);
964 if (mlen >= 0)
965 mb[mlen] = '\0';
9255ee31 966 rl_begin_undo_group ();
5bdf8622
DJ
967 rl_vi_delete (1, 0);
968 if (rl_point < p) /* Did we retreat at EOL? */
cb41b9e7 969 _rl_vi_advance_point ();
9255ee31
EZ
970 rl_insert_text (mb);
971 rl_end_undo_group ();
972 rl_vi_check ();
973 }
974 else
cc88a640 975 rl_forward_char (1, 0);
9255ee31
EZ
976 }
977
978 return 0;
979}
980#endif
981
d60d9f65 982int
cb41b9e7 983rl_vi_change_case (int count, int ignore)
d60d9f65 984{
5bdf8622 985 int c, p;
d60d9f65
SS
986
987 /* Don't try this on an empty line. */
988 if (rl_point >= rl_end)
989 return (0);
990
5bdf8622 991 c = 0;
9255ee31
EZ
992#if defined (HANDLE_MULTIBYTE)
993 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
994 return (_rl_vi_change_mbchar_case (count));
995#endif
996
d60d9f65
SS
997 while (count-- && rl_point < rl_end)
998 {
999 if (_rl_uppercase_p (rl_line_buffer[rl_point]))
1000 c = _rl_to_lower (rl_line_buffer[rl_point]);
1001 else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
1002 c = _rl_to_upper (rl_line_buffer[rl_point]);
1003 else
1004 {
1005 /* Just skip over characters neither upper nor lower case. */
9255ee31 1006 rl_forward_char (1, c);
d60d9f65
SS
1007 continue;
1008 }
1009
1010 /* Vi is kind of strange here. */
1011 if (c)
1012 {
5bdf8622 1013 p = rl_point;
d60d9f65 1014 rl_begin_undo_group ();
5bdf8622
DJ
1015 rl_vi_delete (1, c);
1016 if (rl_point < p) /* Did we retreat at EOL? */
1017 rl_point++;
9255ee31 1018 _rl_insert_char (1, c);
d60d9f65
SS
1019 rl_end_undo_group ();
1020 rl_vi_check ();
cc88a640 1021 }
d60d9f65 1022 else
9255ee31 1023 rl_forward_char (1, c);
d60d9f65
SS
1024 }
1025 return (0);
1026}
1027
1028int
cb41b9e7 1029rl_vi_put (int count, int key)
d60d9f65
SS
1030{
1031 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
9255ee31 1032 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
d60d9f65 1033
5bdf8622
DJ
1034 while (count--)
1035 rl_yank (1, key);
1036
9255ee31 1037 rl_backward_char (1, key);
d60d9f65
SS
1038 return (0);
1039}
1040
cb41b9e7 1041/* Move the cursor back one character if you're at the end of the line */
d60d9f65 1042int
cb41b9e7 1043rl_vi_check (void)
d60d9f65
SS
1044{
1045 if (rl_point && rl_point == rl_end)
cb41b9e7 1046 _rl_vi_backup ();
d60d9f65
SS
1047 return (0);
1048}
1049
cb41b9e7 1050/* Move to the character position specified by COUNT */
d60d9f65 1051int
cb41b9e7 1052rl_vi_column (int count, int key)
d60d9f65
SS
1053{
1054 if (count > rl_end)
1055 rl_end_of_line (1, key);
1056 else
cb41b9e7
TT
1057 {
1058 rl_point = 0;
1059 rl_point = _rl_forward_char_internal (count - 1);
1060 }
d60d9f65
SS
1061 return (0);
1062}
1063
cc88a640
JK
1064/* Process C as part of the current numeric argument. Return -1 if the
1065 argument should be aborted, 0 if we should not read any more chars, and
1066 1 if we should continue to read chars. */
1067static int
cb41b9e7 1068_rl_vi_arg_dispatch (int c)
d60d9f65 1069{
cc88a640 1070 int key;
d60d9f65 1071
cc88a640
JK
1072 key = c;
1073 if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
1074 {
1075 rl_numeric_arg *= 4;
1076 return 1;
1077 }
1078
1079 c = UNMETA (c);
d60d9f65 1080
cc88a640 1081 if (_rl_digit_p (c))
d60d9f65 1082 {
cc88a640
JK
1083 if (rl_explicit_arg)
1084 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
d60d9f65 1085 else
cc88a640
JK
1086 rl_numeric_arg = _rl_digit_value (c);
1087 rl_explicit_arg = 1;
1088 return 1; /* keep going */
1089 }
1090 else
1091 {
1092 rl_clear_message ();
1093 rl_stuff_char (key);
1094 return 0; /* done */
1095 }
1096}
1097
1098/* A simplified loop for vi. Don't dispatch key at end.
1099 Don't recognize minus sign?
1100 Should this do rl_save_prompt/rl_restore_prompt? */
1101static int
cb41b9e7 1102rl_digit_loop1 (void)
cc88a640
JK
1103{
1104 int c, r;
1105
1106 while (1)
1107 {
1108 if (_rl_arg_overflow ())
1109 return 1;
1110
1111 c = _rl_arg_getchar ();
1112
1113 r = _rl_vi_arg_dispatch (c);
1114 if (r <= 0)
1115 break;
d60d9f65
SS
1116 }
1117
cc88a640
JK
1118 RL_UNSETSTATE(RL_STATE_NUMERICARG);
1119 return (0);
1120}
1121
cb41b9e7
TT
1122/* This set of functions is basically to handle the commands that take a
1123 motion argument while in callback mode: read the command, read the motion
1124 command modifier, find the extent of the text to affect, and dispatch the
1125 command for execution. */
cc88a640 1126static void
cb41b9e7 1127_rl_mvcxt_init (_rl_vimotion_cxt *m, int op, int key)
cc88a640
JK
1128{
1129 m->op = op;
1130 m->state = m->flags = 0;
1131 m->ncxt = 0;
1132 m->numeric_arg = -1;
1133 m->start = rl_point;
1134 m->end = rl_end;
1135 m->key = key;
1136 m->motion = -1;
1137}
1138
1139static _rl_vimotion_cxt *
cb41b9e7 1140_rl_mvcxt_alloc (int op, int key)
cc88a640
JK
1141{
1142 _rl_vimotion_cxt *m;
1143
1144 m = xmalloc (sizeof (_rl_vimotion_cxt));
1145 _rl_mvcxt_init (m, op, key);
1146 return m;
1147}
1148
1149static void
cb41b9e7 1150_rl_mvcxt_dispose (_rl_vimotion_cxt *m)
cc88a640
JK
1151{
1152 xfree (m);
1153}
1154
1155static int
cb41b9e7 1156rl_domove_motion_callback (_rl_vimotion_cxt *m)
cc88a640 1157{
775e241e 1158 int c;
cc88a640
JK
1159
1160 _rl_vi_last_motion = c = m->motion;
d60d9f65
SS
1161
1162 /* Append a blank character temporarily so that the motion routines
775e241e
TT
1163 work right at the end of the line. Original value of rl_end is saved
1164 as m->end. */
d60d9f65
SS
1165 rl_line_buffer[rl_end++] = ' ';
1166 rl_line_buffer[rl_end] = '\0';
1167
1168 _rl_dispatch (c, _rl_keymap);
1169
775e241e
TT
1170#if defined (READLINE_CALLBACKS)
1171 if (RL_ISSTATE (RL_STATE_CALLBACK))
1172 {
1173 /* Messy case where char search can be vi motion command; see rest of
1174 details in callback.c. vi_char_search and callback_char_search just
1175 set and unset the CHARSEARCH state. This is where any vi motion
1176 command that needs to set its own state should be handled, with any
1177 corresponding code to manage that state in callback.c */
1178 if (RL_ISSTATE (RL_STATE_CHARSEARCH))
1179 return 0;
1180 else
1181 return (_rl_vi_domove_motion_cleanup (c, m));
1182 }
1183#endif
1184
1185 return (_rl_vi_domove_motion_cleanup (c, m));
1186}
1187
1188int
cb41b9e7 1189_rl_vi_domove_motion_cleanup (int c, _rl_vimotion_cxt *m)
775e241e
TT
1190{
1191 int r;
1192
1193 /* Remove the blank that we added in rl_domove_motion_callback. */
1194 rl_end = m->end;
d60d9f65
SS
1195 rl_line_buffer[rl_end] = '\0';
1196 if (rl_point > rl_end)
1197 rl_point = rl_end;
1198
1199 /* No change in position means the command failed. */
1200 if (rl_mark == rl_point)
775e241e
TT
1201 {
1202 RL_UNSETSTATE (RL_STATE_VIMOTION);
1203 return (-1);
1204 }
d60d9f65
SS
1205
1206 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
1207 word. If we are not at the end of the line, and we are on a
1208 non-whitespace character, move back one (presumably to whitespace). */
1209 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
1210 !whitespace (rl_line_buffer[rl_point]))
cb41b9e7 1211 rl_point--; /* XXX */
d60d9f65
SS
1212
1213 /* If cw or cW, back up to the end of a word, so the behaviour of ce
1214 or cE is the actual result. Brute-force, no subtlety. */
cc88a640 1215 if (m->key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
d60d9f65
SS
1216 {
1217 /* Don't move farther back than where we started. */
1218 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
1219 rl_point--;
1220
1221 /* Posix.2 says that if cw or cW moves the cursor towards the end of
1222 the line, the character under the cursor should be deleted. */
1223 if (rl_point == rl_mark)
cb41b9e7 1224 _rl_vi_advance_point ();
d60d9f65
SS
1225 else
1226 {
1227 /* Move past the end of the word so that the kill doesn't
1228 remove the last letter of the previous word. Only do this
1229 if we are not at the end of the line. */
1230 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
cb41b9e7 1231 _rl_vi_advance_point ();
d60d9f65
SS
1232 }
1233 }
1234
1235 if (rl_mark < rl_point)
9255ee31 1236 SWAP (rl_point, rl_mark);
d60d9f65 1237
cc88a640
JK
1238#if defined (READLINE_CALLBACKS)
1239 if (RL_ISSTATE (RL_STATE_CALLBACK))
1240 (*rl_redisplay_function)(); /* make sure motion is displayed */
1241#endif
1242
1243 r = vidomove_dispatch (m);
1244
1245 return (r);
d60d9f65
SS
1246}
1247
cc88a640
JK
1248#define RL_VIMOVENUMARG() (RL_ISSTATE (RL_STATE_VIMOTION) && RL_ISSTATE (RL_STATE_NUMERICARG))
1249
5bdf8622 1250static int
cb41b9e7 1251rl_domove_read_callback (_rl_vimotion_cxt *m)
5bdf8622 1252{
cc88a640 1253 int c, save;
5bdf8622 1254
cc88a640
JK
1255 c = m->motion;
1256
1257 if (member (c, vi_motion))
5bdf8622 1258 {
cc88a640
JK
1259#if defined (READLINE_CALLBACKS)
1260 /* If we just read a vi-mode motion command numeric argument, turn off
1261 the `reading numeric arg' state */
1262 if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1263 RL_UNSETSTATE (RL_STATE_NUMERICARG);
1264#endif
1265 /* Should do everything, including turning off RL_STATE_VIMOTION */
1266 return (rl_domove_motion_callback (m));
5bdf8622 1267 }
cc88a640 1268 else if (m->key == c && (m->key == 'd' || m->key == 'y' || m->key == 'c'))
5bdf8622 1269 {
cc88a640
JK
1270 rl_mark = rl_end;
1271 rl_beg_of_line (1, c);
1272 _rl_vi_last_motion = c;
1273 RL_UNSETSTATE (RL_STATE_VIMOTION);
1274 return (vidomove_dispatch (m));
1275 }
1276#if defined (READLINE_CALLBACKS)
1277 /* XXX - these need to handle rl_universal_argument bindings */
1278 /* Reading vi motion char continuing numeric argument */
1279 else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1280 {
1281 return (_rl_vi_arg_dispatch (c));
1282 }
1283 /* Readine vi motion char starting numeric argument */
1284 else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_VIMOTION) && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
1285 {
1286 RL_SETSTATE (RL_STATE_NUMERICARG);
1287 return (_rl_vi_arg_dispatch (c));
1288 }
1289#endif
1290 else if (_rl_digit_p (c))
1291 {
1292 /* This code path taken when not in callback mode */
1293 save = rl_numeric_arg;
1294 rl_numeric_arg = _rl_digit_value (c);
5bdf8622 1295 rl_explicit_arg = 1;
cc88a640
JK
1296 RL_SETSTATE (RL_STATE_NUMERICARG);
1297 rl_digit_loop1 ();
1298 rl_numeric_arg *= save;
1299 c = rl_vi_domove_getchar (m);
1300 if (c < 0)
1301 {
1302 m->motion = 0;
1303 return -1;
1304 }
1305 m->motion = c;
1306 return (rl_domove_motion_callback (m));
5bdf8622
DJ
1307 }
1308 else
1309 {
cc88a640
JK
1310 RL_UNSETSTATE (RL_STATE_VIMOTION);
1311 RL_UNSETSTATE (RL_STATE_NUMERICARG);
1312 return (1);
5bdf8622
DJ
1313 }
1314}
1315
d60d9f65 1316static int
cb41b9e7 1317rl_vi_domove_getchar (_rl_vimotion_cxt *m)
d60d9f65 1318{
cc88a640 1319 int c;
d60d9f65 1320
cc88a640
JK
1321 RL_SETSTATE(RL_STATE_MOREINPUT);
1322 c = rl_read_key ();
1323 RL_UNSETSTATE(RL_STATE_MOREINPUT);
d60d9f65 1324
cc88a640
JK
1325 return c;
1326}
d60d9f65 1327
cc88a640
JK
1328#if defined (READLINE_CALLBACKS)
1329int
cb41b9e7 1330_rl_vi_domove_callback (_rl_vimotion_cxt *m)
cc88a640
JK
1331{
1332 int c, r;
9255ee31 1333
cc88a640 1334 m->motion = c = rl_vi_domove_getchar (m);
775e241e
TT
1335 if (c < 0)
1336 return 1; /* EOF */
cc88a640
JK
1337 r = rl_domove_read_callback (m);
1338
1339 return ((r == 0) ? r : 1); /* normalize return values */
d60d9f65 1340}
cc88a640 1341#endif
d60d9f65 1342
cb41b9e7 1343/* This code path is taken when not in callback mode. */
d60d9f65 1344int
cb41b9e7 1345rl_vi_domove (int x, int *ignore)
d60d9f65 1346{
cc88a640
JK
1347 int r;
1348 _rl_vimotion_cxt *m;
d60d9f65 1349
cc88a640
JK
1350 m = _rl_vimvcxt;
1351 *ignore = m->motion = rl_vi_domove_getchar (m);
d60d9f65 1352
cc88a640 1353 if (m->motion < 0)
d60d9f65 1354 {
cc88a640 1355 m->motion = 0;
d60d9f65
SS
1356 return -1;
1357 }
1358
cc88a640
JK
1359 return (rl_domove_read_callback (m));
1360}
1361
1362static int
cb41b9e7 1363vi_delete_dispatch (_rl_vimotion_cxt *m)
cc88a640 1364{
d60d9f65
SS
1365 /* These are the motion commands that do not require adjusting the
1366 mark. */
cc88a640
JK
1367 if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1368 (rl_mark < rl_end))
cb41b9e7 1369 INCREMENT_POS (rl_mark);
d60d9f65
SS
1370
1371 rl_kill_text (rl_point, rl_mark);
1372 return (0);
1373}
1374
1375int
cb41b9e7 1376rl_vi_delete_to (int count, int key)
d60d9f65 1377{
cc88a640
JK
1378 int c, r;
1379
1380 _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
1381 _rl_vimvcxt->start = rl_point;
d60d9f65 1382
cc88a640 1383 rl_mark = rl_point;
d60d9f65 1384 if (_rl_uppercase_p (key))
cc88a640
JK
1385 {
1386 _rl_vimvcxt->motion = '$';
1387 r = rl_domove_motion_callback (_rl_vimvcxt);
1388 }
775e241e 1389 else if (_rl_vi_redoing && _rl_vi_last_motion != 'd') /* `dd' is special */
cc88a640
JK
1390 {
1391 _rl_vimvcxt->motion = _rl_vi_last_motion;
1392 r = rl_domove_motion_callback (_rl_vimvcxt);
1393 }
775e241e
TT
1394 else if (_rl_vi_redoing) /* handle redoing `dd' here */
1395 {
1396 _rl_vimvcxt->motion = _rl_vi_last_motion;
1397 rl_mark = rl_end;
1398 rl_beg_of_line (1, key);
1399 RL_UNSETSTATE (RL_STATE_VIMOTION);
1400 r = vidomove_dispatch (_rl_vimvcxt);
1401 }
cc88a640
JK
1402#if defined (READLINE_CALLBACKS)
1403 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1404 {
1405 RL_SETSTATE (RL_STATE_VIMOTION);
1406 return (0);
1407 }
1408#endif
1409 else
1410 r = rl_vi_domove (key, &c);
d60d9f65 1411
cc88a640 1412 if (r < 0)
d60d9f65 1413 {
9255ee31 1414 rl_ding ();
cc88a640 1415 r = -1;
d60d9f65
SS
1416 }
1417
cc88a640
JK
1418 _rl_mvcxt_dispose (_rl_vimvcxt);
1419 _rl_vimvcxt = 0;
1420
1421 return r;
1422}
1423
1424static int
cb41b9e7 1425vi_change_dispatch (_rl_vimotion_cxt *m)
cc88a640 1426{
d60d9f65
SS
1427 /* These are the motion commands that do not require adjusting the
1428 mark. c[wW] are handled by special-case code in rl_vi_domove(),
1429 and already leave the mark at the correct location. */
cc88a640
JK
1430 if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1431 (rl_mark < rl_end))
cb41b9e7 1432 INCREMENT_POS (rl_mark);
d60d9f65
SS
1433
1434 /* The cursor never moves with c[wW]. */
cc88a640
JK
1435 if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
1436 rl_point = m->start;
d60d9f65 1437
775e241e 1438 if (_rl_vi_redoing)
d60d9f65
SS
1439 {
1440 if (vi_insert_buffer && *vi_insert_buffer)
1441 rl_begin_undo_group ();
1442 rl_delete_text (rl_point, rl_mark);
1443 if (vi_insert_buffer && *vi_insert_buffer)
1444 {
1445 rl_insert_text (vi_insert_buffer);
1446 rl_end_undo_group ();
1447 }
1448 }
1449 else
1450 {
1451 rl_begin_undo_group (); /* to make the `u' command work */
1452 rl_kill_text (rl_point, rl_mark);
1453 /* `C' does not save the text inserted for undoing or redoing. */
cc88a640
JK
1454 if (_rl_uppercase_p (m->key) == 0)
1455 _rl_vi_doing_insert = 1;
1456 /* XXX -- TODO -- use m->numericarg? */
1457 rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign);
d60d9f65
SS
1458 }
1459
1460 return (0);
1461}
1462
1463int
cb41b9e7 1464rl_vi_change_to (int count, int key)
d60d9f65 1465{
cc88a640
JK
1466 int c, r;
1467
1468 _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
1469 _rl_vimvcxt->start = rl_point;
d60d9f65 1470
cc88a640 1471 rl_mark = rl_point;
d60d9f65 1472 if (_rl_uppercase_p (key))
cc88a640
JK
1473 {
1474 _rl_vimvcxt->motion = '$';
1475 r = rl_domove_motion_callback (_rl_vimvcxt);
1476 }
775e241e 1477 else if (_rl_vi_redoing && _rl_vi_last_motion != 'c') /* `cc' is special */
cc88a640
JK
1478 {
1479 _rl_vimvcxt->motion = _rl_vi_last_motion;
1480 r = rl_domove_motion_callback (_rl_vimvcxt);
1481 }
775e241e
TT
1482 else if (_rl_vi_redoing) /* handle redoing `cc' here */
1483 {
1484 _rl_vimvcxt->motion = _rl_vi_last_motion;
1485 rl_mark = rl_end;
1486 rl_beg_of_line (1, key);
1487 RL_UNSETSTATE (RL_STATE_VIMOTION);
1488 r = vidomove_dispatch (_rl_vimvcxt);
1489 }
cc88a640
JK
1490#if defined (READLINE_CALLBACKS)
1491 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1492 {
1493 RL_SETSTATE (RL_STATE_VIMOTION);
1494 return (0);
1495 }
1496#endif
1497 else
1498 r = rl_vi_domove (key, &c);
d60d9f65 1499
cc88a640 1500 if (r < 0)
d60d9f65 1501 {
9255ee31 1502 rl_ding ();
cc88a640 1503 r = -1; /* normalize return value */
d60d9f65
SS
1504 }
1505
cc88a640
JK
1506 _rl_mvcxt_dispose (_rl_vimvcxt);
1507 _rl_vimvcxt = 0;
1508
1509 return r;
1510}
1511
1512static int
cb41b9e7 1513vi_yank_dispatch (_rl_vimotion_cxt *m)
cc88a640 1514{
d60d9f65
SS
1515 /* These are the motion commands that do not require adjusting the
1516 mark. */
cc88a640
JK
1517 if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1518 (rl_mark < rl_end))
cb41b9e7 1519 INCREMENT_POS (rl_mark);
d60d9f65
SS
1520
1521 rl_begin_undo_group ();
1522 rl_kill_text (rl_point, rl_mark);
1523 rl_end_undo_group ();
1524 rl_do_undo ();
cc88a640 1525 rl_point = m->start;
d60d9f65
SS
1526
1527 return (0);
1528}
1529
cc88a640 1530int
cb41b9e7 1531rl_vi_yank_to (int count, int key)
cc88a640
JK
1532{
1533 int c, r;
1534
1535 _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
1536 _rl_vimvcxt->start = rl_point;
1537
1538 rl_mark = rl_point;
1539 if (_rl_uppercase_p (key))
1540 {
1541 _rl_vimvcxt->motion = '$';
1542 r = rl_domove_motion_callback (_rl_vimvcxt);
1543 }
775e241e
TT
1544 else if (_rl_vi_redoing && _rl_vi_last_motion != 'y') /* `yy' is special */
1545 {
1546 _rl_vimvcxt->motion = _rl_vi_last_motion;
1547 r = rl_domove_motion_callback (_rl_vimvcxt);
1548 }
1549 else if (_rl_vi_redoing) /* handle redoing `yy' here */
1550 {
1551 _rl_vimvcxt->motion = _rl_vi_last_motion;
1552 rl_mark = rl_end;
1553 rl_beg_of_line (1, key);
1554 RL_UNSETSTATE (RL_STATE_VIMOTION);
1555 r = vidomove_dispatch (_rl_vimvcxt);
1556 }
cc88a640
JK
1557#if defined (READLINE_CALLBACKS)
1558 else if (RL_ISSTATE (RL_STATE_CALLBACK))
1559 {
1560 RL_SETSTATE (RL_STATE_VIMOTION);
1561 return (0);
1562 }
1563#endif
1564 else
1565 r = rl_vi_domove (key, &c);
1566
1567 if (r < 0)
1568 {
1569 rl_ding ();
1570 r = -1;
1571 }
1572
1573 _rl_mvcxt_dispose (_rl_vimvcxt);
1574 _rl_vimvcxt = 0;
1575
1576 return r;
1577}
1578
1579static int
cb41b9e7 1580vidomove_dispatch (_rl_vimotion_cxt *m)
cc88a640
JK
1581{
1582 int r;
1583
1584 switch (m->op)
1585 {
1586 case VIM_DELETE:
1587 r = vi_delete_dispatch (m);
1588 break;
1589 case VIM_CHANGE:
1590 r = vi_change_dispatch (m);
1591 break;
1592 case VIM_YANK:
1593 r = vi_yank_dispatch (m);
1594 break;
1595 default:
1596 _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op);
1597 r = 1;
1598 break;
1599 }
1600
1601 RL_UNSETSTATE (RL_STATE_VIMOTION);
1602 return r;
1603}
1604
5bdf8622 1605int
cb41b9e7 1606rl_vi_rubout (int count, int key)
5bdf8622 1607{
cc88a640 1608 int opoint;
5bdf8622
DJ
1609
1610 if (count < 0)
1611 return (rl_vi_delete (-count, key));
1612
1613 if (rl_point == 0)
1614 {
1615 rl_ding ();
775e241e 1616 return 1;
5bdf8622
DJ
1617 }
1618
1619 opoint = rl_point;
1620 if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1621 rl_backward_char (count, key);
1622 else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1623 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1624 else
1625 rl_point -= count;
1626
1627 if (rl_point < 0)
1628 rl_point = 0;
1629
1630 rl_kill_text (rl_point, opoint);
1631
1632 return (0);
1633}
1634
d60d9f65 1635int
cb41b9e7 1636rl_vi_delete (int count, int key)
d60d9f65
SS
1637{
1638 int end;
1639
5bdf8622
DJ
1640 if (count < 0)
1641 return (rl_vi_rubout (-count, key));
1642
d60d9f65
SS
1643 if (rl_end == 0)
1644 {
9255ee31 1645 rl_ding ();
775e241e 1646 return 1;
d60d9f65
SS
1647 }
1648
9255ee31
EZ
1649 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1650 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1651 else
1652 end = rl_point + count;
d60d9f65
SS
1653
1654 if (end >= rl_end)
1655 end = rl_end;
1656
1657 rl_kill_text (rl_point, end);
1658
1659 if (rl_point > 0 && rl_point == rl_end)
9255ee31 1660 rl_backward_char (1, key);
5bdf8622 1661
d60d9f65
SS
1662 return (0);
1663}
1664
775e241e
TT
1665/* This does what Posix specifies vi-mode C-w to do: using whitespace and
1666 punctuation characters as the word boundaries. */
1667
1668#define vi_unix_word_boundary(c) (whitespace(c) || ispunct(c))
1669
1670int
cb41b9e7 1671rl_vi_unix_word_rubout (int count, int key)
775e241e
TT
1672{
1673 int orig_point;
1674
1675 if (rl_point == 0)
1676 rl_ding ();
1677 else
1678 {
1679 orig_point = rl_point;
1680 if (count <= 0)
1681 count = 1;
1682
1683 while (count--)
1684 {
1685 /* This isn't quite what ksh93 does but it seems to match what the
1686 Posix description of sh specifies, with a few accommodations
1687 for sequences of whitespace characters between words and at
1688 the end of the line. */
1689
1690 /* Skip over whitespace at the end of the line as a special case */
1691 if (rl_point > 0 && (rl_line_buffer[rl_point] == 0) &&
1692 whitespace (rl_line_buffer[rl_point - 1]))
1693 while (--rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
1694 ;
1695
1696 /* If we're at the start of a word, move back to word boundary so we
1697 move back to the `preceding' word */
1698 if (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0) &&
1699 vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
1700 rl_point--;
1701
1702 /* If we are at a word boundary (whitespace/punct), move backward
1703 past a sequence of word boundary characters. If we are at the
1704 end of a word (non-word boundary), move back to a word boundary */
1705 if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]))
1706 while (rl_point && vi_unix_word_boundary (rl_line_buffer[rl_point - 1]))
1707 rl_point--;
1708 else if (rl_point > 0 && vi_unix_word_boundary (rl_line_buffer[rl_point]) == 0)
cb41b9e7
TT
1709 while (rl_point > 0 && (vi_unix_word_boundary (rl_line_buffer[rl_point - 1]) == 0))
1710 _rl_vi_backup_point ();
775e241e
TT
1711 }
1712
1713 rl_kill_text (orig_point, rl_point);
1714 }
1715
1716 return 0;
1717}
1718
1719
d60d9f65 1720int
cb41b9e7 1721rl_vi_back_to_indent (int count, int key)
d60d9f65
SS
1722{
1723 rl_beg_of_line (1, key);
1724 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1725 rl_point++;
1726 return (0);
1727}
1728
1729int
cb41b9e7 1730rl_vi_first_print (int count, int key)
d60d9f65
SS
1731{
1732 return (rl_vi_back_to_indent (1, key));
1733}
1734
5bdf8622
DJ
1735static int _rl_cs_dir, _rl_cs_orig_dir;
1736
1737#if defined (READLINE_CALLBACKS)
1738static int
cb41b9e7 1739_rl_vi_callback_char_search (_rl_callback_generic_arg *data)
5bdf8622 1740{
cc88a640 1741 int c;
5bdf8622 1742#if defined (HANDLE_MULTIBYTE)
cc88a640 1743 c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
5bdf8622
DJ
1744#else
1745 RL_SETSTATE(RL_STATE_MOREINPUT);
cc88a640 1746 c = rl_read_key ();
5bdf8622
DJ
1747 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1748#endif
1749
cc88a640 1750 if (c <= 0)
775e241e
TT
1751 {
1752 RL_UNSETSTATE (RL_STATE_CHARSEARCH);
1753 return -1;
1754 }
cc88a640
JK
1755
1756#if !defined (HANDLE_MULTIBYTE)
1757 _rl_vi_last_search_char = c;
1758#endif
1759
5bdf8622
DJ
1760 _rl_callback_func = 0;
1761 _rl_want_redisplay = 1;
775e241e 1762 RL_UNSETSTATE (RL_STATE_CHARSEARCH);
5bdf8622
DJ
1763
1764#if defined (HANDLE_MULTIBYTE)
1765 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1766#else
1767 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1768#endif
1769}
1770#endif
1771
d60d9f65 1772int
cb41b9e7 1773rl_vi_char_search (int count, int key)
d60d9f65 1774{
cc88a640 1775 int c;
9255ee31
EZ
1776#if defined (HANDLE_MULTIBYTE)
1777 static char *target;
5bdf8622 1778 static int tlen;
9255ee31 1779#else
d60d9f65 1780 static char target;
9255ee31 1781#endif
d60d9f65
SS
1782
1783 if (key == ';' || key == ',')
cc88a640
JK
1784 {
1785 if (_rl_cs_orig_dir == 0)
775e241e 1786 return 1;
cc88a640
JK
1787#if defined (HANDLE_MULTIBYTE)
1788 if (_rl_vi_last_search_mblen == 0)
775e241e 1789 return 1;
cc88a640
JK
1790#else
1791 if (_rl_vi_last_search_char == 0)
775e241e 1792 return 1;
cc88a640
JK
1793#endif
1794 _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1795 }
d60d9f65
SS
1796 else
1797 {
d60d9f65 1798 switch (key)
cc88a640
JK
1799 {
1800 case 't':
1801 _rl_cs_orig_dir = _rl_cs_dir = FTO;
1802 break;
d60d9f65 1803
cc88a640
JK
1804 case 'T':
1805 _rl_cs_orig_dir = _rl_cs_dir = BTO;
1806 break;
d60d9f65 1807
cc88a640
JK
1808 case 'f':
1809 _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1810 break;
d60d9f65 1811
cc88a640
JK
1812 case 'F':
1813 _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1814 break;
1815 }
5bdf8622 1816
775e241e 1817 if (_rl_vi_redoing)
5bdf8622
DJ
1818 {
1819 /* set target and tlen below */
1820 }
1821#if defined (READLINE_CALLBACKS)
1822 else if (RL_ISSTATE (RL_STATE_CALLBACK))
cc88a640
JK
1823 {
1824 _rl_callback_data = _rl_callback_data_alloc (count);
1825 _rl_callback_data->i1 = _rl_cs_dir;
775e241e 1826 _rl_callback_data->i2 = key;
cc88a640 1827 _rl_callback_func = _rl_vi_callback_char_search;
775e241e 1828 RL_SETSTATE (RL_STATE_CHARSEARCH);
cc88a640
JK
1829 return (0);
1830 }
5bdf8622
DJ
1831#endif
1832 else
1833 {
1834#if defined (HANDLE_MULTIBYTE)
cc88a640
JK
1835 c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1836 if (c <= 0)
1837 return -1;
1838 _rl_vi_last_search_mblen = c;
5bdf8622
DJ
1839#else
1840 RL_SETSTATE(RL_STATE_MOREINPUT);
cc88a640 1841 c = rl_read_key ();
5bdf8622 1842 RL_UNSETSTATE(RL_STATE_MOREINPUT);
cc88a640
JK
1843 if (c < 0)
1844 return -1;
1845 _rl_vi_last_search_char = c;
5bdf8622
DJ
1846#endif
1847 }
d60d9f65
SS
1848 }
1849
9255ee31 1850#if defined (HANDLE_MULTIBYTE)
5bdf8622
DJ
1851 target = _rl_vi_last_search_mbchar;
1852 tlen = _rl_vi_last_search_mblen;
1853#else
1854 target = _rl_vi_last_search_char;
1855#endif
1856
1857#if defined (HANDLE_MULTIBYTE)
1858 return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
9255ee31 1859#else
5bdf8622 1860 return (_rl_char_search_internal (count, _rl_cs_dir, target));
9255ee31 1861#endif
d60d9f65
SS
1862}
1863
1864/* Match brackets */
1865int
cb41b9e7 1866rl_vi_match (int ignore, int key)
d60d9f65 1867{
9255ee31 1868 int count = 1, brack, pos, tmp, pre;
d60d9f65
SS
1869
1870 pos = rl_point;
1871 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1872 {
9255ee31
EZ
1873 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1874 {
1875 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1876 {
1877 pre = rl_point;
1878 rl_forward_char (1, key);
1879 if (pre == rl_point)
cc88a640 1880 break;
9255ee31
EZ
1881 }
1882 }
1883 else
1884 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1885 rl_point < rl_end - 1)
1886 rl_forward_char (1, key);
d60d9f65
SS
1887
1888 if (brack <= 0)
1889 {
1890 rl_point = pos;
9255ee31 1891 rl_ding ();
775e241e 1892 return 1;
d60d9f65
SS
1893 }
1894 }
1895
1896 pos = rl_point;
1897
1898 if (brack < 0)
1899 {
1900 while (count)
1901 {
9255ee31
EZ
1902 tmp = pos;
1903 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1904 pos--;
1905 else
1906 {
1907 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1908 if (tmp == pos)
cc88a640 1909 pos--;
9255ee31
EZ
1910 }
1911 if (pos >= 0)
d60d9f65
SS
1912 {
1913 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1914 if (b == -brack)
1915 count--;
1916 else if (b == brack)
1917 count++;
1918 }
1919 else
1920 {
9255ee31 1921 rl_ding ();
775e241e 1922 return 1;
d60d9f65
SS
1923 }
1924 }
1925 }
1926 else
1927 { /* brack > 0 */
1928 while (count)
1929 {
9255ee31
EZ
1930 if (MB_CUR_MAX == 1 || rl_byte_oriented)
1931 pos++;
1932 else
1933 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1934
1935 if (pos < rl_end)
d60d9f65
SS
1936 {
1937 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1938 if (b == -brack)
1939 count--;
1940 else if (b == brack)
1941 count++;
1942 }
1943 else
1944 {
9255ee31 1945 rl_ding ();
775e241e 1946 return 1;
d60d9f65
SS
1947 }
1948 }
1949 }
1950 rl_point = pos;
1951 return (0);
1952}
1953
1954int
cb41b9e7 1955rl_vi_bracktype (int c)
d60d9f65
SS
1956{
1957 switch (c)
1958 {
1959 case '(': return 1;
1960 case ')': return -1;
1961 case '[': return 2;
1962 case ']': return -2;
1963 case '{': return 3;
1964 case '}': return -3;
1965 default: return 0;
1966 }
1967}
1968
5bdf8622 1969static int
cb41b9e7 1970_rl_vi_change_char (int count, int c, char *mb)
d60d9f65 1971{
5bdf8622 1972 int p;
d60d9f65
SS
1973
1974 if (c == '\033' || c == CTRL ('C'))
1975 return -1;
1976
5bdf8622 1977 rl_begin_undo_group ();
d60d9f65
SS
1978 while (count-- && rl_point < rl_end)
1979 {
5bdf8622
DJ
1980 p = rl_point;
1981 rl_vi_delete (1, c);
1982 if (rl_point < p) /* Did we retreat at EOL? */
cb41b9e7 1983 _rl_vi_append_forward (c);
9255ee31
EZ
1984#if defined (HANDLE_MULTIBYTE)
1985 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
5bdf8622 1986 rl_insert_text (mb);
9255ee31
EZ
1987 else
1988#endif
1989 _rl_insert_char (1, c);
d60d9f65 1990 }
5bdf8622
DJ
1991
1992 /* The cursor shall be left on the last character changed. */
1993 rl_backward_char (1, c);
1994
1995 rl_end_undo_group ();
1996
d60d9f65
SS
1997 return (0);
1998}
1999
5bdf8622 2000static int
cb41b9e7 2001_rl_vi_callback_getchar (char *mb, int mlen)
5bdf8622
DJ
2002{
2003 int c;
2004
2005 RL_SETSTATE(RL_STATE_MOREINPUT);
2006 c = rl_read_key ();
2007 RL_UNSETSTATE(RL_STATE_MOREINPUT);
2008
cc88a640
JK
2009 if (c < 0)
2010 return -1;
2011
5bdf8622
DJ
2012#if defined (HANDLE_MULTIBYTE)
2013 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
cc88a640 2014 c = _rl_read_mbstring (c, mb, mlen);
5bdf8622
DJ
2015#endif
2016
2017 return c;
2018}
2019
2020#if defined (READLINE_CALLBACKS)
2021static int
cb41b9e7 2022_rl_vi_callback_change_char (_rl_callback_generic_arg *data)
5bdf8622
DJ
2023{
2024 int c;
cb41b9e7 2025 char mb[MB_LEN_MAX+1];
5bdf8622 2026
cb41b9e7
TT
2027 c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
2028#if defined (HANDLE_MULTIBYTE)
2029 strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX);
2030#else
2031 _rl_vi_last_replacement[0] = c;
2032#endif
2033 _rl_vi_last_replacement[MB_LEN_MAX] = '\0'; /* XXX */
5bdf8622 2034
cc88a640
JK
2035 if (c < 0)
2036 return -1;
2037
5bdf8622
DJ
2038 _rl_callback_func = 0;
2039 _rl_want_redisplay = 1;
2040
2041 return (_rl_vi_change_char (data->count, c, mb));
2042}
2043#endif
2044
2045int
cb41b9e7 2046rl_vi_change_char (int count, int key)
5bdf8622
DJ
2047{
2048 int c;
cb41b9e7 2049 char mb[MB_LEN_MAX+1];
5bdf8622 2050
775e241e 2051 if (_rl_vi_redoing)
5bdf8622 2052 {
cb41b9e7
TT
2053 strncpy (mb, _rl_vi_last_replacement, MB_LEN_MAX);
2054 c = (unsigned char)_rl_vi_last_replacement[0]; /* XXX */
2055 mb[MB_LEN_MAX] = '\0';
5bdf8622
DJ
2056 }
2057#if defined (READLINE_CALLBACKS)
2058 else if (RL_ISSTATE (RL_STATE_CALLBACK))
2059 {
2060 _rl_callback_data = _rl_callback_data_alloc (count);
2061 _rl_callback_func = _rl_vi_callback_change_char;
2062 return (0);
2063 }
2064#endif
2065 else
cb41b9e7
TT
2066 {
2067 c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
2068#ifdef HANDLE_MULTIBYTE
2069 strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX);
2070#else
2071 _rl_vi_last_replacement[0] = c;
2072#endif
2073 _rl_vi_last_replacement[MB_LEN_MAX] = '\0'; /* just in case */
2074 }
5bdf8622 2075
cc88a640
JK
2076 if (c < 0)
2077 return -1;
2078
5bdf8622
DJ
2079 return (_rl_vi_change_char (count, c, mb));
2080}
2081
d60d9f65 2082int
cb41b9e7 2083rl_vi_subst (int count, int key)
d60d9f65 2084{
9255ee31 2085 /* If we are redoing, rl_vi_change_to will stuff the last motion char */
775e241e 2086 if (_rl_vi_redoing == 0)
5bdf8622 2087 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
d60d9f65 2088
9255ee31 2089 return (rl_vi_change_to (count, 'c'));
d60d9f65
SS
2090}
2091
2092int
cb41b9e7 2093rl_vi_overstrike (int count, int key)
d60d9f65 2094{
d60d9f65
SS
2095 if (_rl_vi_doing_insert == 0)
2096 {
2097 _rl_vi_doing_insert = 1;
2098 rl_begin_undo_group ();
2099 }
2100
9255ee31 2101 if (count > 0)
d60d9f65 2102 {
9255ee31
EZ
2103 _rl_overwrite_char (count, key);
2104 vi_replace_count += count;
d60d9f65 2105 }
9255ee31 2106
d60d9f65
SS
2107 return (0);
2108}
2109
2110int
cb41b9e7 2111rl_vi_overstrike_delete (int count, int key)
d60d9f65
SS
2112{
2113 int i, s;
2114
2115 for (i = 0; i < count; i++)
2116 {
2117 if (vi_replace_count == 0)
2118 {
9255ee31 2119 rl_ding ();
d60d9f65
SS
2120 break;
2121 }
2122 s = rl_point;
2123
2124 if (rl_do_undo ())
2125 vi_replace_count--;
2126
2127 if (rl_point == s)
9255ee31 2128 rl_backward_char (1, key);
d60d9f65
SS
2129 }
2130
2131 if (vi_replace_count == 0 && _rl_vi_doing_insert)
2132 {
2133 rl_end_undo_group ();
2134 rl_do_undo ();
2135 _rl_vi_doing_insert = 0;
2136 }
2137 return (0);
2138}
2139
2140int
cb41b9e7 2141rl_vi_replace (int count, int key)
d60d9f65
SS
2142{
2143 int i;
2144
2145 vi_replace_count = 0;
2146
775e241e 2147 if (vi_replace_map == 0)
d60d9f65
SS
2148 {
2149 vi_replace_map = rl_make_bare_keymap ();
2150
775e241e
TT
2151 for (i = 0; i < ' '; i++)
2152 if (vi_insertion_keymap[i].type == ISFUNC)
2153 vi_replace_map[i].function = vi_insertion_keymap[i].function;
2154
d60d9f65
SS
2155 for (i = ' '; i < KEYMAP_SIZE; i++)
2156 vi_replace_map[i].function = rl_vi_overstrike;
2157
2158 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
775e241e
TT
2159
2160 /* Make sure these are what we want. */
d60d9f65
SS
2161 vi_replace_map[ESC].function = rl_vi_movement_mode;
2162 vi_replace_map[RETURN].function = rl_newline;
2163 vi_replace_map[NEWLINE].function = rl_newline;
2164
2165 /* If the normal vi insertion keymap has ^H bound to erase, do the
cc88a640
JK
2166 same here. Probably should remove the assignment to RUBOUT up
2167 there, but I don't think it will make a difference in real life. */
d60d9f65
SS
2168 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
2169 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
2170 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
2171
cb41b9e7
TT
2172 /* Make sure this is the value we need. */
2173 vi_replace_map[ANYOTHERKEY].type = ISFUNC;
2174 vi_replace_map[ANYOTHERKEY].function = (rl_command_func_t *)NULL;
d60d9f65 2175 }
775e241e
TT
2176
2177 rl_vi_start_inserting (key, 1, rl_arg_sign);
2178
2179 _rl_vi_last_key_before_insert = key;
d60d9f65 2180 _rl_keymap = vi_replace_map;
775e241e 2181
d60d9f65
SS
2182 return (0);
2183}
2184
2185#if 0
2186/* Try to complete the word we are standing on or the word that ends with
2187 the previous character. A space matches everything. Word delimiters are
2188 space and ;. */
2189int
cb41b9e7 2190rl_vi_possible_completions (void)
d60d9f65
SS
2191{
2192 int save_pos = rl_point;
2193
2194 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
2195 {
2196 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
2197 rl_line_buffer[rl_point] != ';')
cb41b9e7 2198 _rl_vi_advance_point ();
d60d9f65
SS
2199 }
2200 else if (rl_line_buffer[rl_point - 1] == ';')
2201 {
9255ee31 2202 rl_ding ();
d60d9f65
SS
2203 return (0);
2204 }
2205
2206 rl_possible_completions ();
2207 rl_point = save_pos;
2208
2209 return (0);
2210}
2211#endif
2212
2213/* Functions to save and restore marks. */
5bdf8622 2214static int
cb41b9e7 2215_rl_vi_set_mark (void)
d60d9f65
SS
2216{
2217 int ch;
2218
9255ee31 2219 RL_SETSTATE(RL_STATE_MOREINPUT);
d60d9f65 2220 ch = rl_read_key ();
9255ee31
EZ
2221 RL_UNSETSTATE(RL_STATE_MOREINPUT);
2222
cc88a640 2223 if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
d60d9f65 2224 {
9255ee31 2225 rl_ding ();
775e241e 2226 return 1;
d60d9f65
SS
2227 }
2228 ch -= 'a';
2229 vi_mark_chars[ch] = rl_point;
2230 return 0;
2231}
2232
5bdf8622
DJ
2233#if defined (READLINE_CALLBACKS)
2234static int
cb41b9e7 2235_rl_vi_callback_set_mark (_rl_callback_generic_arg *data)
5bdf8622
DJ
2236{
2237 _rl_callback_func = 0;
2238 _rl_want_redisplay = 1;
2239
2240 return (_rl_vi_set_mark ());
2241}
2242#endif
2243
d60d9f65 2244int
cb41b9e7 2245rl_vi_set_mark (int count, int key)
5bdf8622
DJ
2246{
2247#if defined (READLINE_CALLBACKS)
2248 if (RL_ISSTATE (RL_STATE_CALLBACK))
2249 {
2250 _rl_callback_data = 0;
2251 _rl_callback_func = _rl_vi_callback_set_mark;
2252 return (0);
2253 }
2254#endif
2255
2256 return (_rl_vi_set_mark ());
2257}
2258
2259static int
cb41b9e7 2260_rl_vi_goto_mark (void)
d60d9f65
SS
2261{
2262 int ch;
2263
9255ee31 2264 RL_SETSTATE(RL_STATE_MOREINPUT);
d60d9f65 2265 ch = rl_read_key ();
9255ee31
EZ
2266 RL_UNSETSTATE(RL_STATE_MOREINPUT);
2267
d60d9f65
SS
2268 if (ch == '`')
2269 {
2270 rl_point = rl_mark;
2271 return 0;
2272 }
cc88a640 2273 else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
d60d9f65 2274 {
9255ee31 2275 rl_ding ();
775e241e 2276 return 1;
d60d9f65
SS
2277 }
2278
2279 ch -= 'a';
2280 if (vi_mark_chars[ch] == -1)
2281 {
9255ee31 2282 rl_ding ();
775e241e 2283 return 1;
d60d9f65
SS
2284 }
2285 rl_point = vi_mark_chars[ch];
2286 return 0;
2287}
2288
5bdf8622
DJ
2289#if defined (READLINE_CALLBACKS)
2290static int
cb41b9e7 2291_rl_vi_callback_goto_mark (_rl_callback_generic_arg *data)
5bdf8622
DJ
2292{
2293 _rl_callback_func = 0;
2294 _rl_want_redisplay = 1;
2295
2296 return (_rl_vi_goto_mark ());
2297}
2298#endif
2299
2300int
cb41b9e7 2301rl_vi_goto_mark (int count, int key)
5bdf8622
DJ
2302{
2303#if defined (READLINE_CALLBACKS)
2304 if (RL_ISSTATE (RL_STATE_CALLBACK))
2305 {
2306 _rl_callback_data = 0;
2307 _rl_callback_func = _rl_vi_callback_goto_mark;
2308 return (0);
2309 }
2310#endif
2311
2312 return (_rl_vi_goto_mark ());
2313}
d60d9f65 2314#endif /* VI_MODE */
This page took 0.992369 seconds and 4 git commands to generate.