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