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