vi_mode.c revision 119611
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. */ 67static int _rl_vi_doing_insert; 68 69/* Command keys which do movement for xxx_to commands. */ 70static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; 71 72/* Keymap used for vi replace characters. Created dynamically since 73 rarely used. */ 74static Keymap vi_replace_map; 75 76/* The number of characters inserted in the last replace operation. */ 77static 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 `.'. */ 82static int vi_continued_command; 83static char *vi_insert_buffer; 84static int vi_insert_buffer_size; 85 86static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 87static int _rl_vi_last_repeat = 1; 88static int _rl_vi_last_arg_sign = 1; 89static int _rl_vi_last_motion; 90#if defined (HANDLE_MULTIBYTE) 91static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; 92#else 93static int _rl_vi_last_search_char; 94#endif 95static int _rl_vi_last_replacement; 96 97static int _rl_vi_last_key_before_insert; 98 99static int vi_redoing; 100 101/* Text modification commands. These are the `redoable' commands. */ 102static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; 103 104/* Arrays for the saved marks. */ 105static int vi_mark_chars['z' - 'a' + 1]; 106 107static void _rl_vi_stuff_insert PARAMS((int)); 108static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); 109static int rl_digit_loop1 PARAMS((void)); 110 111void 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 120void 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 129void 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? */ 139int 140_rl_vi_textmod_command (c) 141 int c; 142{ 143 return (member (c, vi_textmod)); 144} 145 146static 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. */ 159int 160rl_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. */ 190int 191rl_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. */ 198int 199rl_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. */ 214int 215rl_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. */ 239int 240rl_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. */ 257int 258rl_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. */ 279int 280rl_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. */ 308int 309rl_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. */ 319int 320rl_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. */ 341int 342rl_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. */ 362int 363rl_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. */ 380int 381rl_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 397int 398rl_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 421int 422rl_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 451int 452rl_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 477int 478rl_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 516int 517rl_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 541int 542rl_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 550int 551rl_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 570int 571rl_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. */ 580int 581rl_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. */ 591int 592rl_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 600static 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 625void 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 654int 655rl_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 666int 667rl_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) 678static int 679_rl_vi_change_mbchar_case (count) 680 int count; 681{ 682 wchar_t wc; 683 char mb[MB_LEN_MAX]; 684 mbstate_t ps; 685 686 memset (&ps, 0, sizeof (mbstate_t)); 687 if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) 688 count--; 689 while (count-- && rl_point < rl_end) 690 { 691 mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); 692 if (iswupper (wc)) 693 wc = towlower (wc); 694 else if (iswlower (wc)) 695 wc = towupper (wc); 696 else 697 { 698 /* Just skip over chars neither upper nor lower case */ 699 rl_forward_char (1, 0); 700 continue; 701 } 702 703 /* Vi is kind of strange here. */ 704 if (wc) 705 { 706 wctomb (mb, wc); 707 rl_begin_undo_group (); 708 rl_delete (1, 0); 709 rl_insert_text (mb); 710 rl_end_undo_group (); 711 rl_vi_check (); 712 } 713 else 714 rl_forward_char (1, 0); 715 } 716 717 return 0; 718} 719#endif 720 721int 722rl_vi_change_case (count, ignore) 723 int count, ignore; 724{ 725 char c = 0; 726 727 /* Don't try this on an empty line. */ 728 if (rl_point >= rl_end) 729 return (0); 730 731#if defined (HANDLE_MULTIBYTE) 732 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 733 return (_rl_vi_change_mbchar_case (count)); 734#endif 735 736 while (count-- && rl_point < rl_end) 737 { 738 if (_rl_uppercase_p (rl_line_buffer[rl_point])) 739 c = _rl_to_lower (rl_line_buffer[rl_point]); 740 else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 741 c = _rl_to_upper (rl_line_buffer[rl_point]); 742 else 743 { 744 /* Just skip over characters neither upper nor lower case. */ 745 rl_forward_char (1, c); 746 continue; 747 } 748 749 /* Vi is kind of strange here. */ 750 if (c) 751 { 752 rl_begin_undo_group (); 753 rl_delete (1, c); 754 _rl_insert_char (1, c); 755 rl_end_undo_group (); 756 rl_vi_check (); 757 } 758 else 759 rl_forward_char (1, c); 760 } 761 return (0); 762} 763 764int 765rl_vi_put (count, key) 766 int count, key; 767{ 768 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 769 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); 770 771 rl_yank (1, key); 772 rl_backward_char (1, key); 773 return (0); 774} 775 776int 777rl_vi_check () 778{ 779 if (rl_point && rl_point == rl_end) 780 { 781 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 782 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 783 else 784 rl_point--; 785 } 786 return (0); 787} 788 789int 790rl_vi_column (count, key) 791 int count, key; 792{ 793 if (count > rl_end) 794 rl_end_of_line (1, key); 795 else 796 rl_point = count - 1; 797 return (0); 798} 799 800int 801rl_vi_domove (key, nextkey) 802 int key, *nextkey; 803{ 804 int c, save; 805 int old_end; 806 807 rl_mark = rl_point; 808 RL_SETSTATE(RL_STATE_MOREINPUT); 809 c = rl_read_key (); 810 RL_UNSETSTATE(RL_STATE_MOREINPUT); 811 *nextkey = c; 812 813 if (!member (c, vi_motion)) 814 { 815 if (_rl_digit_p (c)) 816 { 817 save = rl_numeric_arg; 818 rl_numeric_arg = _rl_digit_value (c); 819 rl_digit_loop1 (); 820 rl_numeric_arg *= save; 821 RL_SETSTATE(RL_STATE_MOREINPUT); 822 c = rl_read_key (); /* real command */ 823 RL_UNSETSTATE(RL_STATE_MOREINPUT); 824 *nextkey = c; 825 } 826 else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 827 { 828 rl_mark = rl_end; 829 rl_beg_of_line (1, c); 830 _rl_vi_last_motion = c; 831 return (0); 832 } 833 else 834 return (-1); 835 } 836 837 _rl_vi_last_motion = c; 838 839 /* Append a blank character temporarily so that the motion routines 840 work right at the end of the line. */ 841 old_end = rl_end; 842 rl_line_buffer[rl_end++] = ' '; 843 rl_line_buffer[rl_end] = '\0'; 844 845 _rl_dispatch (c, _rl_keymap); 846 847 /* Remove the blank that we added. */ 848 rl_end = old_end; 849 rl_line_buffer[rl_end] = '\0'; 850 if (rl_point > rl_end) 851 rl_point = rl_end; 852 853 /* No change in position means the command failed. */ 854 if (rl_mark == rl_point) 855 return (-1); 856 857 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 858 word. If we are not at the end of the line, and we are on a 859 non-whitespace character, move back one (presumably to whitespace). */ 860 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 861 !whitespace (rl_line_buffer[rl_point])) 862 rl_point--; 863 864 /* If cw or cW, back up to the end of a word, so the behaviour of ce 865 or cE is the actual result. Brute-force, no subtlety. */ 866 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 867 { 868 /* Don't move farther back than where we started. */ 869 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 870 rl_point--; 871 872 /* Posix.2 says that if cw or cW moves the cursor towards the end of 873 the line, the character under the cursor should be deleted. */ 874 if (rl_point == rl_mark) 875 rl_point++; 876 else 877 { 878 /* Move past the end of the word so that the kill doesn't 879 remove the last letter of the previous word. Only do this 880 if we are not at the end of the line. */ 881 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 882 rl_point++; 883 } 884 } 885 886 if (rl_mark < rl_point) 887 SWAP (rl_point, rl_mark); 888 889 return (0); 890} 891 892/* A simplified loop for vi. Don't dispatch key at end. 893 Don't recognize minus sign? 894 Should this do rl_save_prompt/rl_restore_prompt? */ 895static int 896rl_digit_loop1 () 897{ 898 int key, c; 899 900 RL_SETSTATE(RL_STATE_NUMERICARG); 901 while (1) 902 { 903 if (rl_numeric_arg > 1000000) 904 { 905 rl_explicit_arg = rl_numeric_arg = 0; 906 rl_ding (); 907 rl_clear_message (); 908 RL_UNSETSTATE(RL_STATE_NUMERICARG); 909 return 1; 910 } 911 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); 912 RL_SETSTATE(RL_STATE_MOREINPUT); 913 key = c = rl_read_key (); 914 RL_UNSETSTATE(RL_STATE_MOREINPUT); 915 916 if (c >= 0 && _rl_keymap[c].type == ISFUNC && 917 _rl_keymap[c].function == rl_universal_argument) 918 { 919 rl_numeric_arg *= 4; 920 continue; 921 } 922 923 c = UNMETA (c); 924 if (_rl_digit_p (c)) 925 { 926 if (rl_explicit_arg) 927 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 928 else 929 rl_numeric_arg = _rl_digit_value (c); 930 rl_explicit_arg = 1; 931 } 932 else 933 { 934 rl_clear_message (); 935 rl_stuff_char (key); 936 break; 937 } 938 } 939 940 RL_UNSETSTATE(RL_STATE_NUMERICARG); 941 return (0); 942} 943 944int 945rl_vi_delete_to (count, key) 946 int count, key; 947{ 948 int c; 949 950 if (_rl_uppercase_p (key)) 951 rl_stuff_char ('$'); 952 else if (vi_redoing) 953 rl_stuff_char (_rl_vi_last_motion); 954 955 if (rl_vi_domove (key, &c)) 956 { 957 rl_ding (); 958 return -1; 959 } 960 961 /* These are the motion commands that do not require adjusting the 962 mark. */ 963 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 964 rl_mark++; 965 966 rl_kill_text (rl_point, rl_mark); 967 return (0); 968} 969 970int 971rl_vi_change_to (count, key) 972 int count, key; 973{ 974 int c, start_pos; 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 start_pos = rl_point; 982 983 if (rl_vi_domove (key, &c)) 984 { 985 rl_ding (); 986 return -1; 987 } 988 989 /* These are the motion commands that do not require adjusting the 990 mark. c[wW] are handled by special-case code in rl_vi_domove(), 991 and already leave the mark at the correct location. */ 992 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 993 rl_mark++; 994 995 /* The cursor never moves with c[wW]. */ 996 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 997 rl_point = start_pos; 998 999 if (vi_redoing) 1000 { 1001 if (vi_insert_buffer && *vi_insert_buffer) 1002 rl_begin_undo_group (); 1003 rl_delete_text (rl_point, rl_mark); 1004 if (vi_insert_buffer && *vi_insert_buffer) 1005 { 1006 rl_insert_text (vi_insert_buffer); 1007 rl_end_undo_group (); 1008 } 1009 } 1010 else 1011 { 1012 rl_begin_undo_group (); /* to make the `u' command work */ 1013 rl_kill_text (rl_point, rl_mark); 1014 /* `C' does not save the text inserted for undoing or redoing. */ 1015 if (_rl_uppercase_p (key) == 0) 1016 _rl_vi_doing_insert = 1; 1017 _rl_vi_set_last (key, count, rl_arg_sign); 1018 rl_vi_insertion_mode (1, key); 1019 } 1020 1021 return (0); 1022} 1023 1024int 1025rl_vi_yank_to (count, key) 1026 int count, key; 1027{ 1028 int c, save = rl_point; 1029 1030 if (_rl_uppercase_p (key)) 1031 rl_stuff_char ('$'); 1032 1033 if (rl_vi_domove (key, &c)) 1034 { 1035 rl_ding (); 1036 return -1; 1037 } 1038 1039 /* These are the motion commands that do not require adjusting the 1040 mark. */ 1041 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 1042 rl_mark++; 1043 1044 rl_begin_undo_group (); 1045 rl_kill_text (rl_point, rl_mark); 1046 rl_end_undo_group (); 1047 rl_do_undo (); 1048 rl_point = save; 1049 1050 return (0); 1051} 1052 1053int 1054rl_vi_delete (count, key) 1055 int count, key; 1056{ 1057 int end; 1058 1059 if (rl_end == 0) 1060 { 1061 rl_ding (); 1062 return -1; 1063 } 1064 1065 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1066 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1067 else 1068 end = rl_point + count; 1069 1070 if (end >= rl_end) 1071 end = rl_end; 1072 1073 rl_kill_text (rl_point, end); 1074 1075 if (rl_point > 0 && rl_point == rl_end) 1076 rl_backward_char (1, key); 1077 return (0); 1078} 1079 1080int 1081rl_vi_back_to_indent (count, key) 1082 int count, key; 1083{ 1084 rl_beg_of_line (1, key); 1085 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 1086 rl_point++; 1087 return (0); 1088} 1089 1090int 1091rl_vi_first_print (count, key) 1092 int count, key; 1093{ 1094 return (rl_vi_back_to_indent (1, key)); 1095} 1096 1097int 1098rl_vi_char_search (count, key) 1099 int count, key; 1100{ 1101#if defined (HANDLE_MULTIBYTE) 1102 static char *target; 1103 static int mb_len; 1104#else 1105 static char target; 1106#endif 1107 static int orig_dir, dir; 1108 1109 if (key == ';' || key == ',') 1110 dir = key == ';' ? orig_dir : -orig_dir; 1111 else 1112 { 1113 if (vi_redoing) 1114#if defined (HANDLE_MULTIBYTE) 1115 target = _rl_vi_last_search_mbchar; 1116#else 1117 target = _rl_vi_last_search_char; 1118#endif 1119 else 1120 { 1121#if defined (HANDLE_MULTIBYTE) 1122 mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1123 target = _rl_vi_last_search_mbchar; 1124#else 1125 RL_SETSTATE(RL_STATE_MOREINPUT); 1126 _rl_vi_last_search_char = target = rl_read_key (); 1127 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1128#endif 1129 } 1130 1131 switch (key) 1132 { 1133 case 't': 1134 orig_dir = dir = FTO; 1135 break; 1136 1137 case 'T': 1138 orig_dir = dir = BTO; 1139 break; 1140 1141 case 'f': 1142 orig_dir = dir = FFIND; 1143 break; 1144 1145 case 'F': 1146 orig_dir = dir = BFIND; 1147 break; 1148 } 1149 } 1150 1151#if defined (HANDLE_MULTIBYTE) 1152 return (_rl_char_search_internal (count, dir, target, mb_len)); 1153#else 1154 return (_rl_char_search_internal (count, dir, target)); 1155#endif 1156} 1157 1158/* Match brackets */ 1159int 1160rl_vi_match (ignore, key) 1161 int ignore, key; 1162{ 1163 int count = 1, brack, pos, tmp, pre; 1164 1165 pos = rl_point; 1166 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1167 { 1168 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1169 { 1170 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1171 { 1172 pre = rl_point; 1173 rl_forward_char (1, key); 1174 if (pre == rl_point) 1175 break; 1176 } 1177 } 1178 else 1179 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1180 rl_point < rl_end - 1) 1181 rl_forward_char (1, key); 1182 1183 if (brack <= 0) 1184 { 1185 rl_point = pos; 1186 rl_ding (); 1187 return -1; 1188 } 1189 } 1190 1191 pos = rl_point; 1192 1193 if (brack < 0) 1194 { 1195 while (count) 1196 { 1197 tmp = pos; 1198 if (MB_CUR_MAX == 1 || rl_byte_oriented) 1199 pos--; 1200 else 1201 { 1202 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1203 if (tmp == pos) 1204 pos--; 1205 } 1206 if (pos >= 0) 1207 { 1208 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1209 if (b == -brack) 1210 count--; 1211 else if (b == brack) 1212 count++; 1213 } 1214 else 1215 { 1216 rl_ding (); 1217 return -1; 1218 } 1219 } 1220 } 1221 else 1222 { /* brack > 0 */ 1223 while (count) 1224 { 1225 if (MB_CUR_MAX == 1 || rl_byte_oriented) 1226 pos++; 1227 else 1228 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1229 1230 if (pos < rl_end) 1231 { 1232 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1233 if (b == -brack) 1234 count--; 1235 else if (b == brack) 1236 count++; 1237 } 1238 else 1239 { 1240 rl_ding (); 1241 return -1; 1242 } 1243 } 1244 } 1245 rl_point = pos; 1246 return (0); 1247} 1248 1249int 1250rl_vi_bracktype (c) 1251 int c; 1252{ 1253 switch (c) 1254 { 1255 case '(': return 1; 1256 case ')': return -1; 1257 case '[': return 2; 1258 case ']': return -2; 1259 case '{': return 3; 1260 case '}': return -3; 1261 default: return 0; 1262 } 1263} 1264 1265/* XXX - think about reading an entire mbchar with _rl_read_mbchar and 1266 inserting it in one bunch instead of the loop below (like in 1267 rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] 1268 for test against 033 or ^C. Make sure that _rl_read_mbchar does 1269 this right. */ 1270int 1271rl_vi_change_char (count, key) 1272 int count, key; 1273{ 1274 int c; 1275 1276 if (vi_redoing) 1277 c = _rl_vi_last_replacement; 1278 else 1279 { 1280 RL_SETSTATE(RL_STATE_MOREINPUT); 1281 _rl_vi_last_replacement = c = rl_read_key (); 1282 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1283 } 1284 1285 if (c == '\033' || c == CTRL ('C')) 1286 return -1; 1287 1288 while (count-- && rl_point < rl_end) 1289 { 1290 rl_begin_undo_group (); 1291 1292 rl_delete (1, c); 1293#if defined (HANDLE_MULTIBYTE) 1294 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1295 while (_rl_insert_char (1, c)) 1296 { 1297 RL_SETSTATE (RL_STATE_MOREINPUT); 1298 c = rl_read_key (); 1299 RL_UNSETSTATE (RL_STATE_MOREINPUT); 1300 } 1301 else 1302#endif 1303 _rl_insert_char (1, c); 1304 if (count == 0) 1305 rl_backward_char (1, c); 1306 1307 rl_end_undo_group (); 1308 } 1309 return (0); 1310} 1311 1312int 1313rl_vi_subst (count, key) 1314 int count, key; 1315{ 1316 /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1317 if (vi_redoing == 0) 1318 rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ 1319 1320 return (rl_vi_change_to (count, 'c')); 1321} 1322 1323int 1324rl_vi_overstrike (count, key) 1325 int count, key; 1326{ 1327 if (_rl_vi_doing_insert == 0) 1328 { 1329 _rl_vi_doing_insert = 1; 1330 rl_begin_undo_group (); 1331 } 1332 1333 if (count > 0) 1334 { 1335 _rl_overwrite_char (count, key); 1336 vi_replace_count += count; 1337 } 1338 1339 return (0); 1340} 1341 1342int 1343rl_vi_overstrike_delete (count, key) 1344 int count, key; 1345{ 1346 int i, s; 1347 1348 for (i = 0; i < count; i++) 1349 { 1350 if (vi_replace_count == 0) 1351 { 1352 rl_ding (); 1353 break; 1354 } 1355 s = rl_point; 1356 1357 if (rl_do_undo ()) 1358 vi_replace_count--; 1359 1360 if (rl_point == s) 1361 rl_backward_char (1, key); 1362 } 1363 1364 if (vi_replace_count == 0 && _rl_vi_doing_insert) 1365 { 1366 rl_end_undo_group (); 1367 rl_do_undo (); 1368 _rl_vi_doing_insert = 0; 1369 } 1370 return (0); 1371} 1372 1373int 1374rl_vi_replace (count, key) 1375 int count, key; 1376{ 1377 int i; 1378 1379 vi_replace_count = 0; 1380 1381 if (!vi_replace_map) 1382 { 1383 vi_replace_map = rl_make_bare_keymap (); 1384 1385 for (i = ' '; i < KEYMAP_SIZE; i++) 1386 vi_replace_map[i].function = rl_vi_overstrike; 1387 1388 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 1389 vi_replace_map[ESC].function = rl_vi_movement_mode; 1390 vi_replace_map[RETURN].function = rl_newline; 1391 vi_replace_map[NEWLINE].function = rl_newline; 1392 1393 /* If the normal vi insertion keymap has ^H bound to erase, do the 1394 same here. Probably should remove the assignment to RUBOUT up 1395 there, but I don't think it will make a difference in real life. */ 1396 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 1397 vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 1398 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 1399 1400 } 1401 _rl_keymap = vi_replace_map; 1402 return (0); 1403} 1404 1405#if 0 1406/* Try to complete the word we are standing on or the word that ends with 1407 the previous character. A space matches everything. Word delimiters are 1408 space and ;. */ 1409int 1410rl_vi_possible_completions() 1411{ 1412 int save_pos = rl_point; 1413 1414 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 1415 { 1416 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 1417 rl_line_buffer[rl_point] != ';') 1418 rl_point++; 1419 } 1420 else if (rl_line_buffer[rl_point - 1] == ';') 1421 { 1422 rl_ding (); 1423 return (0); 1424 } 1425 1426 rl_possible_completions (); 1427 rl_point = save_pos; 1428 1429 return (0); 1430} 1431#endif 1432 1433/* Functions to save and restore marks. */ 1434int 1435rl_vi_set_mark (count, key) 1436 int count, key; 1437{ 1438 int ch; 1439 1440 RL_SETSTATE(RL_STATE_MOREINPUT); 1441 ch = rl_read_key (); 1442 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1443 1444 if (ch < 'a' || ch > 'z') 1445 { 1446 rl_ding (); 1447 return -1; 1448 } 1449 ch -= 'a'; 1450 vi_mark_chars[ch] = rl_point; 1451 return 0; 1452} 1453 1454int 1455rl_vi_goto_mark (count, key) 1456 int count, key; 1457{ 1458 int ch; 1459 1460 RL_SETSTATE(RL_STATE_MOREINPUT); 1461 ch = rl_read_key (); 1462 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1463 1464 if (ch == '`') 1465 { 1466 rl_point = rl_mark; 1467 return 0; 1468 } 1469 else if (ch < 'a' || ch > 'z') 1470 { 1471 rl_ding (); 1472 return -1; 1473 } 1474 1475 ch -= 'a'; 1476 if (vi_mark_chars[ch] == -1) 1477 { 1478 rl_ding (); 1479 return -1; 1480 } 1481 rl_point = vi_mark_chars[ch]; 1482 return 0; 1483} 1484 1485#endif /* VI_MODE */ 1486