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