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