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