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