Commit | Line | Data |
---|---|---|
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 |
81 | int _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 `.' */ |
86 | int _rl_vi_redoing; | |
87 | ||
d60d9f65 SS |
88 | /* Non-zero means enter insertion mode. */ |
89 | static int _rl_vi_doing_insert; | |
90 | ||
91 | /* Command keys which do movement for xxx_to commands. */ | |
cc88a640 | 92 | static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`"; |
d60d9f65 SS |
93 | |
94 | /* Keymap used for vi replace characters. Created dynamically since | |
95 | rarely used. */ | |
96 | static Keymap vi_replace_map; | |
97 | ||
98 | /* The number of characters inserted in the last replace operation. */ | |
99 | static 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 `.'. */ | |
104 | static int vi_continued_command; | |
105 | static char *vi_insert_buffer; | |
106 | static int vi_insert_buffer_size; | |
107 | ||
d60d9f65 SS |
108 | static int _rl_vi_last_repeat = 1; |
109 | static int _rl_vi_last_arg_sign = 1; | |
110 | static int _rl_vi_last_motion; | |
9255ee31 EZ |
111 | #if defined (HANDLE_MULTIBYTE) |
112 | static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; | |
5bdf8622 | 113 | static int _rl_vi_last_search_mblen; |
9255ee31 | 114 | #else |
d60d9f65 | 115 | static int _rl_vi_last_search_char; |
9255ee31 | 116 | #endif |
cb41b9e7 | 117 | static char _rl_vi_last_replacement[MB_LEN_MAX+1]; /* reserve for trailing NULL */ |
d60d9f65 SS |
118 | |
119 | static int _rl_vi_last_key_before_insert; | |
120 | ||
d60d9f65 | 121 | /* Text modification commands. These are the `redoable' commands. */ |
cc88a640 | 122 | static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; |
d60d9f65 SS |
123 | |
124 | /* Arrays for the saved marks. */ | |
9255ee31 | 125 | static int vi_mark_chars['z' - 'a' + 1]; |
d60d9f65 | 126 | |
775e241e TT |
127 | static void _rl_vi_replace_insert PARAMS((int)); |
128 | static void _rl_vi_save_replace PARAMS((void)); | |
9255ee31 EZ |
129 | static void _rl_vi_stuff_insert PARAMS((int)); |
130 | static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); | |
5bdf8622 | 131 | |
775e241e TT |
132 | static void vi_save_insert_buffer PARAMS ((int, int)); |
133 | ||
cb41b9e7 | 134 | static inline void _rl_vi_backup PARAMS((void)); |
cc88a640 | 135 | |
5bdf8622 | 136 | static int _rl_vi_arg_dispatch PARAMS((int)); |
9255ee31 | 137 | static int rl_digit_loop1 PARAMS((void)); |
d60d9f65 | 138 | |
5bdf8622 DJ |
139 | static int _rl_vi_set_mark PARAMS((void)); |
140 | static int _rl_vi_goto_mark PARAMS((void)); | |
141 | ||
cb41b9e7 TT |
142 | static inline int _rl_vi_advance_point PARAMS((void)); |
143 | static inline int _rl_vi_backup_point PARAMS((void)); | |
144 | ||
cc88a640 JK |
145 | static void _rl_vi_append_forward PARAMS((int)); |
146 | ||
5bdf8622 DJ |
147 | static int _rl_vi_callback_getchar PARAMS((char *, int)); |
148 | ||
149 | #if defined (READLINE_CALLBACKS) | |
150 | static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *)); | |
151 | static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *)); | |
152 | static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *)); | |
153 | static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *)); | |
154 | #endif | |
155 | ||
cc88a640 JK |
156 | static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *)); |
157 | static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *)); | |
158 | static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *)); | |
159 | ||
160 | static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *)); | |
161 | static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *)); | |
162 | static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *)); | |
163 | ||
164 | static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *)); | |
165 | ||
d60d9f65 | 166 | void |
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 | ||
178 | void | |
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 | ||
187 | void | |
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. */ | |
197 | void | |
cb41b9e7 | 198 | rl_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? */ |
206 | int | |
cb41b9e7 | 207 | _rl_vi_textmod_command (int c) |
d60d9f65 SS |
208 | { |
209 | return (member (c, vi_textmod)); | |
210 | } | |
211 | ||
775e241e | 212 | int |
cb41b9e7 | 213 | _rl_vi_motion_command (int c) |
775e241e TT |
214 | { |
215 | return (member (c, vi_motion)); | |
216 | } | |
217 | ||
218 | static 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 | 233 | static 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. */ | |
245 | int | |
cb41b9e7 | 246 | rl_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. */ | |
310 | int | |
cb41b9e7 | 311 | rl_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. */ | |
317 | int | |
cb41b9e7 | 318 | rl_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. */ | |
332 | int | |
cb41b9e7 | 333 | rl_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. */ | |
356 | int | |
cb41b9e7 | 357 | rl_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. */ | |
373 | int | |
cb41b9e7 | 374 | rl_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. */ | |
396 | int | |
cb41b9e7 | 397 | rl_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. */ | |
422 | int | |
cb41b9e7 | 423 | rl_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. */ | |
431 | int | |
cb41b9e7 | 432 | rl_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. */ | |
452 | int | |
cb41b9e7 | 453 | rl_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 |
471 | static 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. */ | |
498 | static 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 */ | |
509 | static 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. */ |
535 | int | |
cb41b9e7 | 536 | rl_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. */ | |
552 | int | |
cb41b9e7 | 553 | rl_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 | ||
568 | int | |
cb41b9e7 | 569 | rl_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 | ||
597 | int | |
cb41b9e7 | 598 | rl_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 | ||
631 | int | |
cb41b9e7 | 632 | rl_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 | ||
660 | int | |
cb41b9e7 | 661 | rl_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 | ||
714 | int | |
cb41b9e7 | 715 | rl_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 | ||
749 | int | |
cb41b9e7 | 750 | rl_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 | 757 | static void |
cb41b9e7 | 758 | _rl_vi_append_forward (int key) |
d60d9f65 | 759 | { |
cb41b9e7 | 760 | _rl_vi_advance_point (); |
cc88a640 JK |
761 | } |
762 | ||
763 | int | |
cb41b9e7 | 764 | rl_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 | ||
771 | int | |
cb41b9e7 | 772 | rl_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. */ | |
780 | int | |
cb41b9e7 | 781 | rl_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. */ | |
790 | int | |
cb41b9e7 | 791 | rl_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 | 800 | int |
cb41b9e7 | 801 | rl_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 | 807 | static void |
cb41b9e7 | 808 | vi_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 | ||
820 | static 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 | 843 | static 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 | ||
862 | void | |
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 | ||
897 | int | |
cb41b9e7 | 898 | rl_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 | ||
918 | int | |
cb41b9e7 | 919 | rl_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) | |
929 | static 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 | 982 | int |
cb41b9e7 | 983 | rl_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 | ||
1028 | int | |
cb41b9e7 | 1029 | rl_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 | 1042 | int |
cb41b9e7 | 1043 | rl_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 | 1051 | int |
cb41b9e7 | 1052 | rl_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. */ | |
1067 | static 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? */ | |
1101 | static int | |
cb41b9e7 | 1102 | rl_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 | 1126 | static 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 | ||
1139 | static _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 | ||
1149 | static void | |
cb41b9e7 | 1150 | _rl_mvcxt_dispose (_rl_vimotion_cxt *m) |
cc88a640 JK |
1151 | { |
1152 | xfree (m); | |
1153 | } | |
1154 | ||
1155 | static int | |
cb41b9e7 | 1156 | rl_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 | ||
1188 | int | |
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 | 1250 | static int |
cb41b9e7 | 1251 | rl_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 | 1316 | static int |
cb41b9e7 | 1317 | rl_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) |
1329 | int | |
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 | 1344 | int |
cb41b9e7 | 1345 | rl_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 | ||
1362 | static int | |
cb41b9e7 | 1363 | vi_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 | ||
1375 | int | |
cb41b9e7 | 1376 | rl_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 | ||
1424 | static int | |
cb41b9e7 | 1425 | vi_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 | ||
1463 | int | |
cb41b9e7 | 1464 | rl_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 | ||
1512 | static int | |
cb41b9e7 | 1513 | vi_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 | 1530 | int |
cb41b9e7 | 1531 | rl_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 | ||
1579 | static int | |
cb41b9e7 | 1580 | vidomove_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 | 1605 | int |
cb41b9e7 | 1606 | rl_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 | 1635 | int |
cb41b9e7 | 1636 | rl_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 | ||
1670 | int | |
cb41b9e7 | 1671 | rl_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 | 1720 | int |
cb41b9e7 | 1721 | rl_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 | ||
1729 | int | |
cb41b9e7 | 1730 | rl_vi_first_print (int count, int key) |
d60d9f65 SS |
1731 | { |
1732 | return (rl_vi_back_to_indent (1, key)); | |
1733 | } | |
1734 | ||
5bdf8622 DJ |
1735 | static int _rl_cs_dir, _rl_cs_orig_dir; |
1736 | ||
1737 | #if defined (READLINE_CALLBACKS) | |
1738 | static 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 | 1772 | int |
cb41b9e7 | 1773 | rl_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 */ | |
1865 | int | |
cb41b9e7 | 1866 | rl_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 | ||
1954 | int | |
cb41b9e7 | 1955 | rl_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 | 1969 | static 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 | 2000 | static 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) | |
2021 | static 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 | ||
2045 | int | |
cb41b9e7 | 2046 | rl_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 | 2082 | int |
cb41b9e7 | 2083 | rl_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 | ||
2092 | int | |
cb41b9e7 | 2093 | rl_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 | ||
2110 | int | |
cb41b9e7 | 2111 | rl_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 | ||
2140 | int | |
cb41b9e7 | 2141 | rl_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 ;. */ | |
2189 | int | |
cb41b9e7 | 2190 | rl_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 | 2214 | static 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) |
2234 | static 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 | 2244 | int |
cb41b9e7 | 2245 | rl_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 | ||
2259 | static 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) |
2290 | static 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 | ||
2300 | int | |
cb41b9e7 | 2301 | rl_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 */ |