Annotation of embedaddon/readline/vi_mode.c, revision 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>