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, 1989, 1992 Free Software Foundation, Inc. 5 6 This file is part of the GNU Readline Library, a library for 7 reading lines of text with interactive input and history editing. 8 9 The GNU Readline Library is free software; you can redistribute it 10 and/or modify it under the terms of the GNU General Public License 11 as published by the Free Software Foundation; either version 2, or 12 (at your option) any later version. 13 14 The GNU Readline Library is distributed in the hope that it will be 15 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 The GNU General Public License is often shipped with GNU software, and 20 is generally kept in a file called COPYING or LICENSE. If you do not 21 have a copy of the license, write to the Free Software Foundation, 22 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 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 /* Non-zero means enter insertion mode. */ 67 static int _rl_vi_doing_insert; 68 69 /* Command keys which do movement for xxx_to commands. */ 70 static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; 71 72 /* Keymap used for vi replace characters. Created dynamically since 73 rarely used. */ 74 static Keymap vi_replace_map; 75 76 /* The number of characters inserted in the last replace operation. */ 77 static int vi_replace_count; 78 79 /* If non-zero, we have text inserted after a c[motion] command that put 80 us implicitly into insert mode. Some people want this text to be 81 attached to the command so that it is `redoable' with `.'. */ 82 static int vi_continued_command; 83 static char *vi_insert_buffer; 84 static int vi_insert_buffer_size; 85 86 static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 87 static int _rl_vi_last_repeat = 1; 88 static int _rl_vi_last_arg_sign = 1; 89 static int _rl_vi_last_motion; 90 #if defined (HANDLE_MULTIBYTE) 91 static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; 92 #else 93 static int _rl_vi_last_search_char; 94 #endif 95 static int _rl_vi_last_replacement; 96 97 static int _rl_vi_last_key_before_insert; 98 99 static int vi_redoing; 100 101 /* Text modification commands. These are the `redoable' commands. */ 102 static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; 103 104 /* Arrays for the saved marks. */ 105 static int vi_mark_chars['z' - 'a' + 1]; 106 107 static void _rl_vi_stuff_insert PARAMS((int)); 108 static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); 109 static int rl_digit_loop1 PARAMS((void)); 110 111 void 112 _rl_vi_initialize_line () 113 { 114 register int i; 115 116 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 117 vi_mark_chars[i] = -1; 118 } 119 120 void 121 _rl_vi_reset_last () 122 { 123 _rl_vi_last_command = 'i'; 124 _rl_vi_last_repeat = 1; 125 _rl_vi_last_arg_sign = 1; 126 _rl_vi_last_motion = 0; 127 } 128 129 void 130 _rl_vi_set_last (key, repeat, sign) 131 int key, repeat, sign; 132 { 133 _rl_vi_last_command = key; 134 _rl_vi_last_repeat = repeat; 135 _rl_vi_last_arg_sign = sign; 136 } 137 138 /* Is the command C a VI mode text modification command? */ 139 int 140 _rl_vi_textmod_command (c) 141 int c; 142 { 143 return (member (c, vi_textmod)); 144 } 145 146 static void 147 _rl_vi_stuff_insert (count) 148 int count; 149 { 150 rl_begin_undo_group (); 151 while (count--) 152 rl_insert_text (vi_insert_buffer); 153 rl_end_undo_group (); 154 } 155 156 /* Bound to `.'. Called from command mode, so we know that we have to 157 redo a text modification command. The default for _rl_vi_last_command 158 puts you back into insert mode. */ 159 int 160 rl_vi_redo (count, c) 161 int count, c; 162 { 163 int r; 164 165 if (!rl_explicit_arg) 166 { 167 rl_numeric_arg = _rl_vi_last_repeat; 168 rl_arg_sign = _rl_vi_last_arg_sign; 169 } 170 171 r = 0; 172 vi_redoing = 1; 173 /* If we're redoing an insert with `i', stuff in the inserted text 174 and do not go into insertion mode. */ 175 if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 176 { 177 _rl_vi_stuff_insert (count); 178 /* And back up point over the last character inserted. */ 179 if (rl_point > 0) 180 rl_point--; 181 } 182 else 183 r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); 184 vi_redoing = 0; 185 186 return (r); 187 } 188 189 /* A placeholder for further expansion. */ 190 int 191 rl_vi_undo (count, key) 192 int count, key; 193 { 194 return (rl_undo_command (count, key)); 195 } 196 197 /* Yank the nth arg from the previous line into this line at point. */ 198 int 199 rl_vi_yank_arg (count, key) 200 int count, key; 201 { 202 /* Readline thinks that the first word on a line is the 0th, while vi 203 thinks the first word on a line is the 1st. Compensate. */ 204 if (rl_explicit_arg) 205 rl_yank_nth_arg (count - 1, 0); 206 else 207 rl_yank_nth_arg ('$', 0); 208 209 return (0); 210 } 211 212 /* With an argument, move back that many history lines, else move to the 213 beginning of history. */ 214 int 215 rl_vi_fetch_history (count, c) 216 int count, c; 217 { 218 int wanted; 219 220 /* Giving an argument of n means we want the nth command in the history 221 file. The command number is interpreted the same way that the bash 222 `history' command does it -- that is, giving an argument count of 450 223 to this command would get the command listed as number 450 in the 224 output of `history'. */ 225 if (rl_explicit_arg) 226 { 227 wanted = history_base + where_history () - count; 228 if (wanted <= 0) 229 rl_beginning_of_history (0, 0); 230 else 231 rl_get_previous_history (wanted, c); 232 } 233 else 234 rl_beginning_of_history (count, 0); 235 return (0); 236 } 237 238 /* Search again for the last thing searched for. */ 239 int 240 rl_vi_search_again (count, key) 241 int count, key; 242 { 243 switch (key) 244 { 245 case 'n': 246 rl_noninc_reverse_search_again (count, key); 247 break; 248 249 case 'N': 250 rl_noninc_forward_search_again (count, key); 251 break; 252 } 253 return (0); 254 } 255 256 /* Do a vi style search. */ 257 int 258 rl_vi_search (count, key) 259 int count, key; 260 { 261 switch (key) 262 { 263 case '?': 264 rl_noninc_forward_search (count, key); 265 break; 266 267 case '/': 268 rl_noninc_reverse_search (count, key); 269 break; 270 271 default: 272 rl_ding (); 273 break; 274 } 275 return (0); 276 } 277 278 /* Completion, from vi's point of view. */ 279 int 280 rl_vi_complete (ignore, key) 281 int ignore, key; 282 { 283 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 284 { 285 if (!whitespace (rl_line_buffer[rl_point + 1])) 286 rl_vi_end_word (1, 'E'); 287 rl_point++; 288 } 289 290 if (key == '*') 291 rl_complete_internal ('*'); /* Expansion and replacement. */ 292 else if (key == '=') 293 rl_complete_internal ('?'); /* List possible completions. */ 294 else if (key == '\\') 295 rl_complete_internal (TAB); /* Standard Readline completion. */ 296 else 297 rl_complete (0, key); 298 299 if (key == '*' || key == '\\') 300 { 301 _rl_vi_set_last (key, 1, rl_arg_sign); 302 rl_vi_insertion_mode (1, key); 303 } 304 return (0); 305 } 306 307 /* Tilde expansion for vi mode. */ 308 int 309 rl_vi_tilde_expand (ignore, key) 310 int ignore, key; 311 { 312 rl_tilde_expand (0, key); 313 _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ 314 rl_vi_insertion_mode (1, key); 315 return (0); 316 } 317 318 /* Previous word in vi mode. */ 319 int 320 rl_vi_prev_word (count, key) 321 int count, key; 322 { 323 if (count < 0) 324 return (rl_vi_next_word (-count, key)); 325 326 if (rl_point == 0) 327 { 328 rl_ding (); 329 return (0); 330 } 331 332 if (_rl_uppercase_p (key)) 333 rl_vi_bWord (count, key); 334 else 335 rl_vi_bword (count, key); 336 337 return (0); 338 } 339 340 /* Next word in vi mode. */ 341 int 342 rl_vi_next_word (count, key) 343 int count, key; 344 { 345 if (count < 0) 346 return (rl_vi_prev_word (-count, key)); 347 348 if (rl_point >= (rl_end - 1)) 349 { 350 rl_ding (); 351 return (0); 352 } 353 354 if (_rl_uppercase_p (key)) 355 rl_vi_fWord (count, key); 356 else 357 rl_vi_fword (count, key); 358 return (0); 359 } 360 361 /* Move to the end of the ?next? word. */ 362 int 363 rl_vi_end_word (count, key) 364 int count, key; 365 { 366 if (count < 0) 367 { 368 rl_ding (); 369 return -1; 370 } 371 372 if (_rl_uppercase_p (key)) 373 rl_vi_eWord (count, key); 374 else 375 rl_vi_eword (count, key); 376 return (0); 377 } 378 379 /* Move forward a word the way that 'W' does. */ 380 int 381 rl_vi_fWord (count, ignore) 382 int count, ignore; 383 { 384 while (count-- && rl_point < (rl_end - 1)) 385 { 386 /* Skip until whitespace. */ 387 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 388 rl_point++; 389 390 /* Now skip whitespace. */ 391 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 392 rl_point++; 393 } 394 return (0); 395 } 396 397 int 398 rl_vi_bWord (count, ignore) 399 int count, ignore; 400 { 401 while (count-- && rl_point > 0) 402 { 403 /* If we are at the start of a word, move back to whitespace so 404 we will go back to the start of the previous word. */ 405 if (!whitespace (rl_line_buffer[rl_point]) && 406 whitespace (rl_line_buffer[rl_point - 1])) 407 rl_point--; 408 409 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 410 rl_point--; 411 412 if (rl_point > 0) 413 { 414 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 415 rl_point++; 416 } 417 } 418 return (0); 419 } 420 421 int 422 rl_vi_eWord (count, ignore) 423 int count, ignore; 424 { 425 while (count-- && rl_point < (rl_end - 1)) 426 { 427 if (!whitespace (rl_line_buffer[rl_point])) 428 rl_point++; 429 430 /* Move to the next non-whitespace character (to the start of the 431 next word). */ 432 while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); 433 434 if (rl_point && rl_point < rl_end) 435 { 436 /* Skip whitespace. */ 437 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 438 rl_point++; 439 440 /* Skip until whitespace. */ 441 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 442 rl_point++; 443 444 /* Move back to the last character of the word. */ 445 rl_point--; 446 } 447 } 448 return (0); 449 } 450 451 int 452 rl_vi_fword (count, ignore) 453 int count, ignore; 454 { 455 while (count-- && rl_point < (rl_end - 1)) 456 { 457 /* Move to white space (really non-identifer). */ 458 if (_rl_isident (rl_line_buffer[rl_point])) 459 { 460 while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 461 rl_point++; 462 } 463 else /* if (!whitespace (rl_line_buffer[rl_point])) */ 464 { 465 while (!_rl_isident (rl_line_buffer[rl_point]) && 466 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 467 rl_point++; 468 } 469 470 /* Move past whitespace. */ 471 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 472 rl_point++; 473 } 474 return (0); 475 } 476 477 int 478 rl_vi_bword (count, ignore) 479 int count, ignore; 480 { 481 while (count-- && rl_point > 0) 482 { 483 int last_is_ident; 484 485 /* If we are at the start of a word, move back to whitespace 486 so we will go back to the start of the previous word. */ 487 if (!whitespace (rl_line_buffer[rl_point]) && 488 whitespace (rl_line_buffer[rl_point - 1])) 489 rl_point--; 490 491 /* If this character and the previous character are `opposite', move 492 back so we don't get messed up by the rl_point++ down there in 493 the while loop. Without this code, words like `l;' screw up the 494 function. */ 495 last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); 496 if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || 497 (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) 498 rl_point--; 499 500 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 501 rl_point--; 502 503 if (rl_point > 0) 504 { 505 if (_rl_isident (rl_line_buffer[rl_point])) 506 while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); 507 else 508 while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && 509 !whitespace (rl_line_buffer[rl_point])); 510 rl_point++; 511 } 512 } 513 return (0); 514 } 515 516 int 517 rl_vi_eword (count, ignore) 518 int count, ignore; 519 { 520 while (count-- && rl_point < rl_end - 1) 521 { 522 if (!whitespace (rl_line_buffer[rl_point])) 523 rl_point++; 524 525 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 526 rl_point++; 527 528 if (rl_point < rl_end) 529 { 530 if (_rl_isident (rl_line_buffer[rl_point])) 531 while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); 532 else 533 while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) 534 && !whitespace (rl_line_buffer[rl_point])); 535 } 536 rl_point--; 537 } 538 return (0); 539 } 540 541 int 542 rl_vi_insert_beg (count, key) 543 int count, key; 544 { 545 rl_beg_of_line (1, key); 546 rl_vi_insertion_mode (1, key); 547 return (0); 548 } 549 550 int 551 rl_vi_append_mode (count, key) 552 int count, key; 553 { 554 if (rl_point < rl_end) 555 { 556 if (MB_CUR_MAX == 1 || rl_byte_oriented) 557 rl_point++; 558 else 559 { 560 int point = rl_point; 561 rl_forward_char (1, key); 562 if (point == rl_point) 563 rl_point = rl_end; 564 } 565 } 566 rl_vi_insertion_mode (1, key); 567 return (0); 568 } 569 570 int 571 rl_vi_append_eol (count, key) 572 int count, key; 573 { 574 rl_end_of_line (1, key); 575 rl_vi_append_mode (1, key); 576 return (0); 577 } 578 579 /* What to do in the case of C-d. */ 580 int 581 rl_vi_eof_maybe (count, c) 582 int count, c; 583 { 584 return (rl_newline (1, '\n')); 585 } 586 587 /* Insertion mode stuff. */ 588 589 /* Switching from one mode to the other really just involves 590 switching keymaps. */ 591 int 592 rl_vi_insertion_mode (count, key) 593 int count, key; 594 { 595 _rl_keymap = vi_insertion_keymap; 596 _rl_vi_last_key_before_insert = key; 597 return (0); 598 } 599 600 static void 601 _rl_vi_save_insert (up) 602 UNDO_LIST *up; 603 { 604 int len, start, end; 605 606 if (up == 0) 607 { 608 if (vi_insert_buffer_size >= 1) 609 vi_insert_buffer[0] = '\0'; 610 return; 611 } 612 613 start = up->start; 614 end = up->end; 615 len = end - start + 1; 616 if (len >= vi_insert_buffer_size) 617 { 618 vi_insert_buffer_size += (len + 32) - (len % 32); 619 vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); 620 } 621 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 622 vi_insert_buffer[len-1] = '\0'; 623 } 624 625 void 626 _rl_vi_done_inserting () 627 { 628 if (_rl_vi_doing_insert) 629 { 630 /* The `C', `s', and `S' commands set this. */ 631 rl_end_undo_group (); 632 /* Now, the text between rl_undo_list->next->start and 633 rl_undo_list->next->end is what was inserted while in insert 634 mode. It gets copied to VI_INSERT_BUFFER because it depends 635 on absolute indices into the line which may change (though they 636 probably will not). */ 637 _rl_vi_doing_insert = 0; 638 _rl_vi_save_insert (rl_undo_list->next); 639 vi_continued_command = 1; 640 } 641 else 642 { 643 if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) 644 _rl_vi_save_insert (rl_undo_list); 645 /* XXX - Other keys probably need to be checked. */ 646 else if (_rl_vi_last_key_before_insert == 'C') 647 rl_end_undo_group (); 648 while (_rl_undo_group_level > 0) 649 rl_end_undo_group (); 650 vi_continued_command = 0; 651 } 652 } 653 654 int 655 rl_vi_movement_mode (count, key) 656 int count, key; 657 { 658 if (rl_point > 0) 659 rl_backward_char (1, key); 660 661 _rl_keymap = vi_movement_keymap; 662 _rl_vi_done_inserting (); 663 return (0); 664 } 665 666 int 667 rl_vi_arg_digit (count, c) 668 int count, c; 669 { 670 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 671 return (rl_beg_of_line (1, c)); 672 else 673 return (rl_digit_argument (count, c)); 674 } 675 676 /* Change the case of the next COUNT characters. */ 677 #if defined (HANDLE_MULTIBYTE) 678 static int 679 _rl_vi_change_mbchar_case (count) 680 int count; 681 { 682 wchar_t wc; 683 char mb[MB_LEN_MAX+1]; 684 int mblen; 685 mbstate_t ps; 686 687 memset (&ps, 0, sizeof (mbstate_t)); 688 if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 689 count--; 690 while (count-- && rl_point < rl_end) 691 { 692 mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 693 if (iswupper (wc)) 694 wc = towlower (wc); 695 else if (iswlower (wc)) 696 wc = towupper (wc); 697 else 698 { 699 /* Just skip over chars neither upper nor lower case */ 700 rl_forward_char (1, 0); 701 continue; 702 } 703 704 /* Vi is kind of strange here. */ 705 if (wc) 706 { 707 mblen = wctomb (mb, wc); 708 if (mblen >= 0) 709 mb[mblen] = '\0'; 710 rl_begin_undo_group (); 711 rl_delete (1, 0); 712 rl_insert_text (mb); 713 rl_end_undo_group (); 714 rl_vi_check (); 715 } 716 else 717 rl_forward_char (1, 0); 718 } 719 720 return 0; 721 } 722 #endif 723 724 int 725 rl_vi_change_case (count, ignore) 726 int count, ignore; 727 { 728 char c = 0; 729 730 /* Don't try this on an empty line. */ 731 if (rl_point >= rl_end) 732 return (0); 733 734 #if defined (HANDLE_MULTIBYTE) 735 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 736 return (_rl_vi_change_mbchar_case (count)); 737 #endif 738 739 while (count-- && rl_point < rl_end) 740 { 741 if (_rl_uppercase_p (rl_line_buffer[rl_point])) 742 c = _rl_to_lower (rl_line_buffer[rl_point]); 743 else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 744 c = _rl_to_upper (rl_line_buffer[rl_point]); 745 else 746 { 747 /* Just skip over characters neither upper nor lower case. */ 748 rl_forward_char (1, c); 749 continue; 750 } 751 752 /* Vi is kind of strange here. */ 753 if (c) 754 { 755 rl_begin_undo_group (); 756 rl_delete (1, c); 757 _rl_insert_char (1, c); 758 rl_end_undo_group (); 759 rl_vi_check (); 760 } 761 else 762 rl_forward_char (1, c); 763 } 764 return (0); 765 } 766 767 int 768 rl_vi_put (count, key) 769 int count, key; 770 { 771 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 772 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 773 774 rl_yank (1, key); 775 rl_backward_char (1, key); 776 return (0); 777 } 778 779 int 780 rl_vi_check () 781 { 782 if (rl_point && rl_point == rl_end) 783 { 784 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 785 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 786 else 787 rl_point--; 788 } 789 return (0); 790 } 791 792 int 793 rl_vi_column (count, key) 794 int count, key; 795 { 796 if (count > rl_end) 797 rl_end_of_line (1, key); 798 else 799 rl_point = count - 1; 800 return (0); 801 } 802 803 int 804 rl_vi_domove (key, nextkey) 805 int key, *nextkey; 806 { 807 int c, save; 808 int old_end; 809 810 rl_mark = rl_point; 811 RL_SETSTATE(RL_STATE_MOREINPUT); 812 c = rl_read_key (); 813 RL_UNSETSTATE(RL_STATE_MOREINPUT); 814 *nextkey = c; 815 816 if (!member (c, vi_motion)) 817 { 818 if (_rl_digit_p (c)) 819 { 820 save = rl_numeric_arg; 821 rl_numeric_arg = _rl_digit_value (c); 822 rl_digit_loop1 (); 823 rl_numeric_arg *= save; 824 RL_SETSTATE(RL_STATE_MOREINPUT); 825 c = rl_read_key (); /* real command */ 826 RL_UNSETSTATE(RL_STATE_MOREINPUT); 827 *nextkey = c; 828 } 829 else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 830 { 831 rl_mark = rl_end; 832 rl_beg_of_line (1, c); 833 _rl_vi_last_motion = c; 834 return (0); 835 } 836 else 837 return (-1); 838 } 839 840 _rl_vi_last_motion = c; 841 842 /* Append a blank character temporarily so that the motion routines 843 work right at the end of the line. */ 844 old_end = rl_end; 845 rl_line_buffer[rl_end++] = ' '; 846 rl_line_buffer[rl_end] = '\0'; 847 848 _rl_dispatch (c, _rl_keymap); 849 850 /* Remove the blank that we added. */ 851 rl_end = old_end; 852 rl_line_buffer[rl_end] = '\0'; 853 if (rl_point > rl_end) 854 rl_point = rl_end; 855 856 /* No change in position means the command failed. */ 857 if (rl_mark == rl_point) 858 return (-1); 859 860 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 861 word. If we are not at the end of the line, and we are on a 862 non-whitespace character, move back one (presumably to whitespace). */ 863 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 864 !whitespace (rl_line_buffer[rl_point])) 865 rl_point--; 866 867 /* If cw or cW, back up to the end of a word, so the behaviour of ce 868 or cE is the actual result. Brute-force, no subtlety. */ 869 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 870 { 871 /* Don't move farther back than where we started. */ 872 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 873 rl_point--; 874 875 /* Posix.2 says that if cw or cW moves the cursor towards the end of 876 the line, the character under the cursor should be deleted. */ 877 if (rl_point == rl_mark) 878 rl_point++; 879 else 880 { 881 /* Move past the end of the word so that the kill doesn't 882 remove the last letter of the previous word. Only do this 883 if we are not at the end of the line. */ 884 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 885 rl_point++; 886 } 887 } 888 889 if (rl_mark < rl_point) 890 SWAP (rl_point, rl_mark); 891 892 return (0); 893 } 894 895 /* A simplified loop for vi. Don't dispatch key at end. 896 Don't recognize minus sign? 897 Should this do rl_save_prompt/rl_restore_prompt? */ 898 static int 899 rl_digit_loop1 () 900 { 901 int key, c; 902 903 RL_SETSTATE(RL_STATE_NUMERICARG); 904 while (1) 905 { 906 if (rl_numeric_arg > 1000000) 907 { 908 rl_explicit_arg = rl_numeric_arg = 0; 909 rl_ding (); 910 rl_clear_message (); 911 RL_UNSETSTATE(RL_STATE_NUMERICARG); 912 return 1; 913 } 914 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); 915 RL_SETSTATE(RL_STATE_MOREINPUT); 916 key = c = rl_read_key (); 917 RL_UNSETSTATE(RL_STATE_MOREINPUT); 918 919 if (c >= 0 && _rl_keymap[c].type == ISFUNC && 920 _rl_keymap[c].function == rl_universal_argument) 921 { 922 rl_numeric_arg *= 4; 923 continue; 924 } 925 926 c = UNMETA (c); 927 if (_rl_digit_p (c)) 928 { 929 if (rl_explicit_arg) 930 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 931 else 932 rl_numeric_arg = _rl_digit_value (c); 933 rl_explicit_arg = 1; 934 } 935 else 936 { 937 rl_clear_message (); 938 rl_stuff_char (key); 939 break; 940 } 941 } 942 943 RL_UNSETSTATE(RL_STATE_NUMERICARG); 944 return (0); 945 } 946 947 int 948 rl_vi_delete_to (count, key) 949 int count, key; 950 { 951 int c; 952 953 if (_rl_uppercase_p (key)) 954 rl_stuff_char ('$'); 955 else if (vi_redoing) 956 rl_stuff_char (_rl_vi_last_motion); 957 958 if (rl_vi_domove (key, &c)) 959 { 960 rl_ding (); 961 return -1; 962 } 963 964 /* These are the motion commands that do not require adjusting the 965 mark. */ 966 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 967 rl_mark++; 968 969 rl_kill_text (rl_point, rl_mark); 970 return (0); 971 } 972 973 int 974 rl_vi_change_to (count, key) 975 int count, key; 976 { 977 int c, start_pos; 978 979 if (_rl_uppercase_p (key)) 980 rl_stuff_char ('$'); 981 else if (vi_redoing) 982 rl_stuff_char (_rl_vi_last_motion); 983 984 start_pos = rl_point; 985 986 if (rl_vi_domove (key, &c)) 987 { 988 rl_ding (); 989 return -1; 990 } 991 992 /* These are the motion commands that do not require adjusting the 993 mark. c[wW] are handled by special-case code in rl_vi_domove(), 994 and already leave the mark at the correct location. */ 995 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 996 rl_mark++; 997 998 /* The cursor never moves with c[wW]. */ 999 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 1000 rl_point = start_pos; 1001 1002 if (vi_redoing) 1003 { 1004 if (vi_insert_buffer && *vi_insert_buffer) 1005 rl_begin_undo_group (); 1006 rl_delete_text (rl_point, rl_mark); 1007 if (vi_insert_buffer && *vi_insert_buffer) 1008 { 1009 rl_insert_text (vi_insert_buffer); 1010 rl_end_undo_group (); 1011 } 1012 } 1013 else 1014 { 1015 rl_begin_undo_group (); /* to make the `u' command work */ 1016 rl_kill_text (rl_point, rl_mark); 1017 /* `C' does not save the text inserted for undoing or redoing. */ 1018 if (_rl_uppercase_p (key) == 0) 1019 _rl_vi_doing_insert = 1; 1020 _rl_vi_set_last (key, count, rl_arg_sign); 1021 rl_vi_insertion_mode (1, key); 1022 } 1023 1024 return (0); 1025 } 1026 1027 int 1028 rl_vi_yank_to (count, key) 1029 int count, key; 1030 { 1031 int c, save = rl_point; 1032 1033 if (_rl_uppercase_p (key)) 1034 rl_stuff_char ('$'); 1035 1036 if (rl_vi_domove (key, &c)) 1037 { 1038 rl_ding (); 1039 return -1; 1040 } 1041 1042 /* These are the motion commands that do not require adjusting the 1043 mark. */ 1044 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 1045 rl_mark++; 1046 1047 rl_begin_undo_group (); 1048 rl_kill_text (rl_point, rl_mark); 1049 rl_end_undo_group (); 1050 rl_do_undo (); 1051 rl_point = save; 1052 1053 return (0); 1054 } 1055 1056 int 1057 rl_vi_delete (count, key) 1058 int count, key; 1059 { 1060 int end; 1061 1062 if (rl_end == 0) 1063 { 1064 rl_ding (); 1065 return -1; 1066 } 1067 1068 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1069 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1070 else 1071 end = rl_point + count; 1072 1073 if (end >= rl_end) 1074 end = rl_end; 1075 1076 rl_kill_text (rl_point, end); 1077 1078 if (rl_point > 0 && rl_point == rl_end) 1079 rl_backward_char (1, key); 1080 return (0); 1081 } 1082 1083 int 1084 rl_vi_back_to_indent (count, key) 1085 int count, key; 1086 { 1087 rl_beg_of_line (1, key); 1088 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 1089 rl_point++; 1090 return (0); 1091 } 1092 1093 int 1094 rl_vi_first_print (count, key) 1095 int count, key; 1096 { 1097 return (rl_vi_back_to_indent (1, key)); 1098 } 1099 1100 int 1101 rl_vi_char_search (count, key) 1102 int count, key; 1103 { 1104 #if defined (HANDLE_MULTIBYTE) 1105 static char *target; 1106 static int mb_len; 1107 #else 1108 static char target; 1109 #endif 1110 static int orig_dir, dir; 1111 1112 if (key == ';' || key == ',') 1113 dir = key == ';' ? orig_dir : -orig_dir; 1114 else 1115 { 1116 if (vi_redoing) 1117 #if defined (HANDLE_MULTIBYTE) 1118 target = _rl_vi_last_search_mbchar; 1119 #else 1120 target = _rl_vi_last_search_char; 1121 #endif 1122 else 1123 { 1124 #if defined (HANDLE_MULTIBYTE) 1125 mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1126 target = _rl_vi_last_search_mbchar; 1127 #else 1128 RL_SETSTATE(RL_STATE_MOREINPUT); 1129 _rl_vi_last_search_char = target = rl_read_key (); 1130 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1131 #endif 1132 } 1133 1134 switch (key) 1135 { 1136 case 't': 1137 orig_dir = dir = FTO; 1138 break; 1139 1140 case 'T': 1141 orig_dir = dir = BTO; 1142 break; 1143 1144 case 'f': 1145 orig_dir = dir = FFIND; 1146 break; 1147 1148 case 'F': 1149 orig_dir = dir = BFIND; 1150 break; 1151 } 1152 } 1153 1154 #if defined (HANDLE_MULTIBYTE) 1155 return (_rl_char_search_internal (count, dir, target, mb_len)); 1156 #else 1157 return (_rl_char_search_internal (count, dir, target)); 1158 #endif 1159 } 1160 1161 /* Match brackets */ 1162 int 1163 rl_vi_match (ignore, key) 1164 int ignore, key; 1165 { 1166 int count = 1, brack, pos, tmp, pre; 1167 1168 pos = rl_point; 1169 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1170 { 1171 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1172 { 1173 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1174 { 1175 pre = rl_point; 1176 rl_forward_char (1, key); 1177 if (pre == rl_point) 1178 break; 1179 } 1180 } 1181 else 1182 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1183 rl_point < rl_end - 1) 1184 rl_forward_char (1, key); 1185 1186 if (brack <= 0) 1187 { 1188 rl_point = pos; 1189 rl_ding (); 1190 return -1; 1191 } 1192 } 1193 1194 pos = rl_point; 1195 1196 if (brack < 0) 1197 { 1198 while (count) 1199 { 1200 tmp = pos; 1201 if (MB_CUR_MAX == 1 || rl_byte_oriented) 1202 pos--; 1203 else 1204 { 1205 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1206 if (tmp == pos) 1207 pos--; 1208 } 1209 if (pos >= 0) 1210 { 1211 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1212 if (b == -brack) 1213 count--; 1214 else if (b == brack) 1215 count++; 1216 } 1217 else 1218 { 1219 rl_ding (); 1220 return -1; 1221 } 1222 } 1223 } 1224 else 1225 { /* brack > 0 */ 1226 while (count) 1227 { 1228 if (MB_CUR_MAX == 1 || rl_byte_oriented) 1229 pos++; 1230 else 1231 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1232 1233 if (pos < rl_end) 1234 { 1235 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1236 if (b == -brack) 1237 count--; 1238 else if (b == brack) 1239 count++; 1240 } 1241 else 1242 { 1243 rl_ding (); 1244 return -1; 1245 } 1246 } 1247 } 1248 rl_point = pos; 1249 return (0); 1250 } 1251 1252 int 1253 rl_vi_bracktype (c) 1254 int c; 1255 { 1256 switch (c) 1257 { 1258 case '(': return 1; 1259 case ')': return -1; 1260 case '[': return 2; 1261 case ']': return -2; 1262 case '{': return 3; 1263 case '}': return -3; 1264 default: return 0; 1265 } 1266 } 1267 1268 /* XXX - think about reading an entire mbchar with _rl_read_mbchar and 1269 inserting it in one bunch instead of the loop below (like in 1270 rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] 1271 for test against 033 or ^C. Make sure that _rl_read_mbchar does 1272 this right. */ 1273 int 1274 rl_vi_change_char (count, key) 1275 int count, key; 1276 { 1277 int c; 1278 1279 if (vi_redoing) 1280 c = _rl_vi_last_replacement; 1281 else 1282 { 1283 RL_SETSTATE(RL_STATE_MOREINPUT); 1284 _rl_vi_last_replacement = c = rl_read_key (); 1285 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1286 } 1287 1288 if (c == '\033' || c == CTRL ('C')) 1289 return -1; 1290 1291 while (count-- && rl_point < rl_end) 1292 { 1293 rl_begin_undo_group (); 1294 1295 rl_delete (1, c); 1296 #if defined (HANDLE_MULTIBYTE) 1297 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1298 while (_rl_insert_char (1, c)) 1299 { 1300 RL_SETSTATE (RL_STATE_MOREINPUT); 1301 c = rl_read_key (); 1302 RL_UNSETSTATE (RL_STATE_MOREINPUT); 1303 } 1304 else 1305 #endif 1306 _rl_insert_char (1, c); 1307 if (count == 0) 1308 rl_backward_char (1, c); 1309 1310 rl_end_undo_group (); 1311 } 1312 return (0); 1313 } 1314 1315 int 1316 rl_vi_subst (count, key) 1317 int count, key; 1318 { 1319 /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1320 if (vi_redoing == 0) 1321 rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ 1322 1323 return (rl_vi_change_to (count, 'c')); 1324 } 1325 1326 int 1327 rl_vi_overstrike (count, key) 1328 int count, key; 1329 { 1330 if (_rl_vi_doing_insert == 0) 1331 { 1332 _rl_vi_doing_insert = 1; 1333 rl_begin_undo_group (); 1334 } 1335 1336 if (count > 0) 1337 { 1338 _rl_overwrite_char (count, key); 1339 vi_replace_count += count; 1340 } 1341 1342 return (0); 1343 } 1344 1345 int 1346 rl_vi_overstrike_delete (count, key) 1347 int count, key; 1348 { 1349 int i, s; 1350 1351 for (i = 0; i < count; i++) 1352 { 1353 if (vi_replace_count == 0) 1354 { 1355 rl_ding (); 1356 break; 1357 } 1358 s = rl_point; 1359 1360 if (rl_do_undo ()) 1361 vi_replace_count--; 1362 1363 if (rl_point == s) 1364 rl_backward_char (1, key); 1365 } 1366 1367 if (vi_replace_count == 0 && _rl_vi_doing_insert) 1368 { 1369 rl_end_undo_group (); 1370 rl_do_undo (); 1371 _rl_vi_doing_insert = 0; 1372 } 1373 return (0); 1374 } 1375 1376 int 1377 rl_vi_replace (count, key) 1378 int count, key; 1379 { 1380 int i; 1381 1382 vi_replace_count = 0; 1383 1384 if (!vi_replace_map) 1385 { 1386 vi_replace_map = rl_make_bare_keymap (); 1387 1388 for (i = ' '; i < KEYMAP_SIZE; i++) 1389 vi_replace_map[i].function = rl_vi_overstrike; 1390 1391 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 1392 vi_replace_map[ESC].function = rl_vi_movement_mode; 1393 vi_replace_map[RETURN].function = rl_newline; 1394 vi_replace_map[NEWLINE].function = rl_newline; 1395 1396 /* If the normal vi insertion keymap has ^H bound to erase, do the 1397 same here. Probably should remove the assignment to RUBOUT up 1398 there, but I don't think it will make a difference in real life. */ 1399 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 1400 vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 1401 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 1402 1403 } 1404 _rl_keymap = vi_replace_map; 1405 return (0); 1406 } 1407 1408 #if 0 1409 /* Try to complete the word we are standing on or the word that ends with 1410 the previous character. A space matches everything. Word delimiters are 1411 space and ;. */ 1412 int 1413 rl_vi_possible_completions() 1414 { 1415 int save_pos = rl_point; 1416 1417 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 1418 { 1419 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 1420 rl_line_buffer[rl_point] != ';') 1421 rl_point++; 1422 } 1423 else if (rl_line_buffer[rl_point - 1] == ';') 1424 { 1425 rl_ding (); 1426 return (0); 1427 } 1428 1429 rl_possible_completions (); 1430 rl_point = save_pos; 1431 1432 return (0); 1433 } 1434 #endif 1435 1436 /* Functions to save and restore marks. */ 1437 int 1438 rl_vi_set_mark (count, key) 1439 int count, key; 1440 { 1441 int ch; 1442 1443 RL_SETSTATE(RL_STATE_MOREINPUT); 1444 ch = rl_read_key (); 1445 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1446 1447 if (ch < 'a' || ch > 'z') 1448 { 1449 rl_ding (); 1450 return -1; 1451 } 1452 ch -= 'a'; 1453 vi_mark_chars[ch] = rl_point; 1454 return 0; 1455 } 1456 1457 int 1458 rl_vi_goto_mark (count, key) 1459 int count, key; 1460 { 1461 int ch; 1462 1463 RL_SETSTATE(RL_STATE_MOREINPUT); 1464 ch = rl_read_key (); 1465 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1466 1467 if (ch == '`') 1468 { 1469 rl_point = rl_mark; 1470 return 0; 1471 } 1472 else if (ch < 'a' || ch > 'z') 1473 { 1474 rl_ding (); 1475 return -1; 1476 } 1477 1478 ch -= 'a'; 1479 if (vi_mark_chars[ch] == -1) 1480 { 1481 rl_ding (); 1482 return -1; 1483 } 1484 rl_point = vi_mark_chars[ch]; 1485 return 0; 1486 } 1487 1488 #endif /* VI_MODE */ 1489