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