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