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