vi_mode.c revision 173406
1/* $FreeBSD: head/contrib/libreadline/vi_mode.c 173406 2007-11-07 04:42:20Z 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 891 if (c < 0) 892 { 893 *nextkey = 0; 894 return -1; 895 } 896 897 *nextkey = c; 898 899 if (!member (c, vi_motion)) 900 { 901 if (_rl_digit_p (c)) 902 { 903 save = rl_numeric_arg; 904 rl_numeric_arg = _rl_digit_value (c); 905 rl_explicit_arg = 1; 906 RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION); 907 rl_digit_loop1 (); 908 RL_UNSETSTATE (RL_STATE_VIMOTION); 909 rl_numeric_arg *= save; 910 RL_SETSTATE(RL_STATE_MOREINPUT); 911 c = rl_read_key (); /* real command */ 912 RL_UNSETSTATE(RL_STATE_MOREINPUT); 913 if (c < 0) 914 { 915 *nextkey = 0; 916 return -1; 917 } 918 *nextkey = c; 919 } 920 else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 921 { 922 rl_mark = rl_end; 923 rl_beg_of_line (1, c); 924 _rl_vi_last_motion = c; 925 return (0); 926 } 927 else 928 return (-1); 929 } 930 931 _rl_vi_last_motion = c; 932 933 /* Append a blank character temporarily so that the motion routines 934 work right at the end of the line. */ 935 old_end = rl_end; 936 rl_line_buffer[rl_end++] = ' '; 937 rl_line_buffer[rl_end] = '\0'; 938 939 _rl_dispatch (c, _rl_keymap); 940 941 /* Remove the blank that we added. */ 942 rl_end = old_end; 943 rl_line_buffer[rl_end] = '\0'; 944 if (rl_point > rl_end) 945 rl_point = rl_end; 946 947 /* No change in position means the command failed. */ 948 if (rl_mark == rl_point) 949 return (-1); 950 951 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 952 word. If we are not at the end of the line, and we are on a 953 non-whitespace character, move back one (presumably to whitespace). */ 954 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 955 !whitespace (rl_line_buffer[rl_point])) 956 rl_point--; 957 958 /* If cw or cW, back up to the end of a word, so the behaviour of ce 959 or cE is the actual result. Brute-force, no subtlety. */ 960 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 961 { 962 /* Don't move farther back than where we started. */ 963 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 964 rl_point--; 965 966 /* Posix.2 says that if cw or cW moves the cursor towards the end of 967 the line, the character under the cursor should be deleted. */ 968 if (rl_point == rl_mark) 969 rl_point++; 970 else 971 { 972 /* Move past the end of the word so that the kill doesn't 973 remove the last letter of the previous word. Only do this 974 if we are not at the end of the line. */ 975 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 976 rl_point++; 977 } 978 } 979 980 if (rl_mark < rl_point) 981 SWAP (rl_point, rl_mark); 982 983 return (0); 984} 985 986/* Process C as part of the current numeric argument. Return -1 if the 987 argument should be aborted, 0 if we should not read any more chars, and 988 1 if we should continue to read chars. */ 989static int 990_rl_vi_arg_dispatch (c) 991 int c; 992{ 993 int key; 994 995 key = c; 996 if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument) 997 { 998 rl_numeric_arg *= 4; 999 return 1; 1000 } 1001 1002 c = UNMETA (c); 1003 1004 if (_rl_digit_p (c)) 1005 { 1006 if (rl_explicit_arg) 1007 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 1008 else 1009 rl_numeric_arg = _rl_digit_value (c); 1010 rl_explicit_arg = 1; 1011 return 1; 1012 } 1013 else 1014 { 1015 rl_clear_message (); 1016 rl_stuff_char (key); 1017 return 0; 1018 } 1019} 1020 1021/* A simplified loop for vi. Don't dispatch key at end. 1022 Don't recognize minus sign? 1023 Should this do rl_save_prompt/rl_restore_prompt? */ 1024static int 1025rl_digit_loop1 () 1026{ 1027 int c, r; 1028 1029 while (1) 1030 { 1031 if (_rl_arg_overflow ()) 1032 return 1; 1033 1034 c = _rl_arg_getchar (); 1035 1036 r = _rl_vi_arg_dispatch (c); 1037 if (r <= 0) 1038 break; 1039 } 1040 1041 RL_UNSETSTATE(RL_STATE_NUMERICARG); 1042 return (0); 1043} 1044 1045int 1046rl_vi_delete_to (count, key) 1047 int count, key; 1048{ 1049 int c; 1050 1051 if (_rl_uppercase_p (key)) 1052 rl_stuff_char ('$'); 1053 else if (vi_redoing) 1054 rl_stuff_char (_rl_vi_last_motion); 1055 1056 if (rl_vi_domove (key, &c)) 1057 { 1058 rl_ding (); 1059 return -1; 1060 } 1061 1062 /* These are the motion commands that do not require adjusting the 1063 mark. */ 1064 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 1065 rl_mark++; 1066 1067 rl_kill_text (rl_point, rl_mark); 1068 return (0); 1069} 1070 1071int 1072rl_vi_change_to (count, key) 1073 int count, key; 1074{ 1075 int c, start_pos; 1076 1077 if (_rl_uppercase_p (key)) 1078 rl_stuff_char ('$'); 1079 else if (vi_redoing) 1080 rl_stuff_char (_rl_vi_last_motion); 1081 1082 start_pos = rl_point; 1083 1084 if (rl_vi_domove (key, &c)) 1085 { 1086 rl_ding (); 1087 return -1; 1088 } 1089 1090 /* These are the motion commands that do not require adjusting the 1091 mark. c[wW] are handled by special-case code in rl_vi_domove(), 1092 and already leave the mark at the correct location. */ 1093 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 1094 rl_mark++; 1095 1096 /* The cursor never moves with c[wW]. */ 1097 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 1098 rl_point = start_pos; 1099 1100 if (vi_redoing) 1101 { 1102 if (vi_insert_buffer && *vi_insert_buffer) 1103 rl_begin_undo_group (); 1104 rl_delete_text (rl_point, rl_mark); 1105 if (vi_insert_buffer && *vi_insert_buffer) 1106 { 1107 rl_insert_text (vi_insert_buffer); 1108 rl_end_undo_group (); 1109 } 1110 } 1111 else 1112 { 1113 rl_begin_undo_group (); /* to make the `u' command work */ 1114 rl_kill_text (rl_point, rl_mark); 1115 /* `C' does not save the text inserted for undoing or redoing. */ 1116 if (_rl_uppercase_p (key) == 0) 1117 _rl_vi_doing_insert = 1; 1118 rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); 1119 } 1120 1121 return (0); 1122} 1123 1124int 1125rl_vi_yank_to (count, key) 1126 int count, key; 1127{ 1128 int c, save; 1129 1130 save = rl_point; 1131 if (_rl_uppercase_p (key)) 1132 rl_stuff_char ('$'); 1133 1134 if (rl_vi_domove (key, &c)) 1135 { 1136 rl_ding (); 1137 return -1; 1138 } 1139 1140 /* These are the motion commands that do not require adjusting the 1141 mark. */ 1142 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 1143 rl_mark++; 1144 1145 rl_begin_undo_group (); 1146 rl_kill_text (rl_point, rl_mark); 1147 rl_end_undo_group (); 1148 rl_do_undo (); 1149 rl_point = save; 1150 1151 return (0); 1152} 1153 1154int 1155rl_vi_rubout (count, key) 1156 int count, key; 1157{ 1158 int opoint; 1159 1160 if (count < 0) 1161 return (rl_vi_delete (-count, key)); 1162 1163 if (rl_point == 0) 1164 { 1165 rl_ding (); 1166 return -1; 1167 } 1168 1169 opoint = rl_point; 1170 if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1171 rl_backward_char (count, key); 1172 else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1173 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); 1174 else 1175 rl_point -= count; 1176 1177 if (rl_point < 0) 1178 rl_point = 0; 1179 1180 rl_kill_text (rl_point, opoint); 1181 1182 return (0); 1183} 1184 1185int 1186rl_vi_delete (count, key) 1187 int count, key; 1188{ 1189 int end; 1190 1191 if (count < 0) 1192 return (rl_vi_rubout (-count, key)); 1193 1194 if (rl_end == 0) 1195 { 1196 rl_ding (); 1197 return -1; 1198 } 1199 1200 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1201 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); 1202 else 1203 end = rl_point + count; 1204 1205 if (end >= rl_end) 1206 end = rl_end; 1207 1208 rl_kill_text (rl_point, end); 1209 1210 if (rl_point > 0 && rl_point == rl_end) 1211 rl_backward_char (1, key); 1212 1213 return (0); 1214} 1215 1216int 1217rl_vi_back_to_indent (count, key) 1218 int count, key; 1219{ 1220 rl_beg_of_line (1, key); 1221 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 1222 rl_point++; 1223 return (0); 1224} 1225 1226int 1227rl_vi_first_print (count, key) 1228 int count, key; 1229{ 1230 return (rl_vi_back_to_indent (1, key)); 1231} 1232 1233static int _rl_cs_dir, _rl_cs_orig_dir; 1234 1235#if defined (READLINE_CALLBACKS) 1236static int 1237_rl_vi_callback_char_search (data) 1238 _rl_callback_generic_arg *data; 1239{ 1240 int c; 1241#if defined (HANDLE_MULTIBYTE) 1242 c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1243#else 1244 RL_SETSTATE(RL_STATE_MOREINPUT); 1245 c = rl_read_key (); 1246 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1247#endif 1248 1249 if (c <= 0) 1250 return -1; 1251 1252#if !defined (HANDLE_MULTIBYTE) 1253 _rl_vi_last_search_char = c; 1254#endif 1255 1256 _rl_callback_func = 0; 1257 _rl_want_redisplay = 1; 1258 1259#if defined (HANDLE_MULTIBYTE) 1260 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen)); 1261#else 1262 return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char)); 1263#endif 1264} 1265#endif 1266 1267int 1268rl_vi_char_search (count, key) 1269 int count, key; 1270{ 1271 int c; 1272#if defined (HANDLE_MULTIBYTE) 1273 static char *target; 1274 static int tlen; 1275#else 1276 static char target; 1277#endif 1278 1279 if (key == ';' || key == ',') 1280 _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir; 1281 else 1282 { 1283 switch (key) 1284 { 1285 case 't': 1286 _rl_cs_orig_dir = _rl_cs_dir = FTO; 1287 break; 1288 1289 case 'T': 1290 _rl_cs_orig_dir = _rl_cs_dir = BTO; 1291 break; 1292 1293 case 'f': 1294 _rl_cs_orig_dir = _rl_cs_dir = FFIND; 1295 break; 1296 1297 case 'F': 1298 _rl_cs_orig_dir = _rl_cs_dir = BFIND; 1299 break; 1300 } 1301 1302 if (vi_redoing) 1303 { 1304 /* set target and tlen below */ 1305 } 1306#if defined (READLINE_CALLBACKS) 1307 else if (RL_ISSTATE (RL_STATE_CALLBACK)) 1308 { 1309 _rl_callback_data = _rl_callback_data_alloc (count); 1310 _rl_callback_data->i1 = _rl_cs_dir; 1311 _rl_callback_func = _rl_vi_callback_char_search; 1312 return (0); 1313 } 1314#endif 1315 else 1316 { 1317#if defined (HANDLE_MULTIBYTE) 1318 c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); 1319 if (c <= 0) 1320 return -1; 1321 _rl_vi_last_search_mblen = c; 1322#else 1323 RL_SETSTATE(RL_STATE_MOREINPUT); 1324 c = rl_read_key (); 1325 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1326 if (c < 0) 1327 return -1; 1328 _rl_vi_last_search_char = c; 1329#endif 1330 } 1331 } 1332 1333#if defined (HANDLE_MULTIBYTE) 1334 target = _rl_vi_last_search_mbchar; 1335 tlen = _rl_vi_last_search_mblen; 1336#else 1337 target = _rl_vi_last_search_char; 1338#endif 1339 1340#if defined (HANDLE_MULTIBYTE) 1341 return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen)); 1342#else 1343 return (_rl_char_search_internal (count, _rl_cs_dir, target)); 1344#endif 1345} 1346 1347/* Match brackets */ 1348int 1349rl_vi_match (ignore, key) 1350 int ignore, key; 1351{ 1352 int count = 1, brack, pos, tmp, pre; 1353 1354 pos = rl_point; 1355 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1356 { 1357 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1358 { 1359 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1360 { 1361 pre = rl_point; 1362 rl_forward_char (1, key); 1363 if (pre == rl_point) 1364 break; 1365 } 1366 } 1367 else 1368 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1369 rl_point < rl_end - 1) 1370 rl_forward_char (1, key); 1371 1372 if (brack <= 0) 1373 { 1374 rl_point = pos; 1375 rl_ding (); 1376 return -1; 1377 } 1378 } 1379 1380 pos = rl_point; 1381 1382 if (brack < 0) 1383 { 1384 while (count) 1385 { 1386 tmp = pos; 1387 if (MB_CUR_MAX == 1 || rl_byte_oriented) 1388 pos--; 1389 else 1390 { 1391 pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); 1392 if (tmp == pos) 1393 pos--; 1394 } 1395 if (pos >= 0) 1396 { 1397 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1398 if (b == -brack) 1399 count--; 1400 else if (b == brack) 1401 count++; 1402 } 1403 else 1404 { 1405 rl_ding (); 1406 return -1; 1407 } 1408 } 1409 } 1410 else 1411 { /* brack > 0 */ 1412 while (count) 1413 { 1414 if (MB_CUR_MAX == 1 || rl_byte_oriented) 1415 pos++; 1416 else 1417 pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); 1418 1419 if (pos < rl_end) 1420 { 1421 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1422 if (b == -brack) 1423 count--; 1424 else if (b == brack) 1425 count++; 1426 } 1427 else 1428 { 1429 rl_ding (); 1430 return -1; 1431 } 1432 } 1433 } 1434 rl_point = pos; 1435 return (0); 1436} 1437 1438int 1439rl_vi_bracktype (c) 1440 int c; 1441{ 1442 switch (c) 1443 { 1444 case '(': return 1; 1445 case ')': return -1; 1446 case '[': return 2; 1447 case ']': return -2; 1448 case '{': return 3; 1449 case '}': return -3; 1450 default: return 0; 1451 } 1452} 1453 1454static int 1455_rl_vi_change_char (count, c, mb) 1456 int count, c; 1457 char *mb; 1458{ 1459 int p; 1460 1461 if (c == '\033' || c == CTRL ('C')) 1462 return -1; 1463 1464 rl_begin_undo_group (); 1465 while (count-- && rl_point < rl_end) 1466 { 1467 p = rl_point; 1468 rl_vi_delete (1, c); 1469 if (rl_point < p) /* Did we retreat at EOL? */ 1470 rl_point++; 1471#if defined (HANDLE_MULTIBYTE) 1472 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1473 rl_insert_text (mb); 1474 else 1475#endif 1476 _rl_insert_char (1, c); 1477 } 1478 1479 /* The cursor shall be left on the last character changed. */ 1480 rl_backward_char (1, c); 1481 1482 rl_end_undo_group (); 1483 1484 return (0); 1485} 1486 1487static int 1488_rl_vi_callback_getchar (mb, mlen) 1489 char *mb; 1490 int mlen; 1491{ 1492 int c; 1493 1494 RL_SETSTATE(RL_STATE_MOREINPUT); 1495 c = rl_read_key (); 1496 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1497 1498 if (c < 0) 1499 return -1; 1500 1501#if defined (HANDLE_MULTIBYTE) 1502 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) 1503 c = _rl_read_mbstring (c, mb, mlen); 1504#endif 1505 1506 return c; 1507} 1508 1509#if defined (READLINE_CALLBACKS) 1510static int 1511_rl_vi_callback_change_char (data) 1512 _rl_callback_generic_arg *data; 1513{ 1514 int c; 1515 char mb[MB_LEN_MAX]; 1516 1517 _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); 1518 1519 if (c < 0) 1520 return -1; 1521 1522 _rl_callback_func = 0; 1523 _rl_want_redisplay = 1; 1524 1525 return (_rl_vi_change_char (data->count, c, mb)); 1526} 1527#endif 1528 1529int 1530rl_vi_change_char (count, key) 1531 int count, key; 1532{ 1533 int c; 1534 char mb[MB_LEN_MAX]; 1535 1536 if (vi_redoing) 1537 { 1538 c = _rl_vi_last_replacement; 1539 mb[0] = c; 1540 mb[1] = '\0'; 1541 } 1542#if defined (READLINE_CALLBACKS) 1543 else if (RL_ISSTATE (RL_STATE_CALLBACK)) 1544 { 1545 _rl_callback_data = _rl_callback_data_alloc (count); 1546 _rl_callback_func = _rl_vi_callback_change_char; 1547 return (0); 1548 } 1549#endif 1550 else 1551 _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); 1552 1553 if (c < 0) 1554 return -1; 1555 1556 return (_rl_vi_change_char (count, c, mb)); 1557} 1558 1559int 1560rl_vi_subst (count, key) 1561 int count, key; 1562{ 1563 /* If we are redoing, rl_vi_change_to will stuff the last motion char */ 1564 if (vi_redoing == 0) 1565 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ 1566 1567 return (rl_vi_change_to (count, 'c')); 1568} 1569 1570int 1571rl_vi_overstrike (count, key) 1572 int count, key; 1573{ 1574 if (_rl_vi_doing_insert == 0) 1575 { 1576 _rl_vi_doing_insert = 1; 1577 rl_begin_undo_group (); 1578 } 1579 1580 if (count > 0) 1581 { 1582 _rl_overwrite_char (count, key); 1583 vi_replace_count += count; 1584 } 1585 1586 return (0); 1587} 1588 1589int 1590rl_vi_overstrike_delete (count, key) 1591 int count, key; 1592{ 1593 int i, s; 1594 1595 for (i = 0; i < count; i++) 1596 { 1597 if (vi_replace_count == 0) 1598 { 1599 rl_ding (); 1600 break; 1601 } 1602 s = rl_point; 1603 1604 if (rl_do_undo ()) 1605 vi_replace_count--; 1606 1607 if (rl_point == s) 1608 rl_backward_char (1, key); 1609 } 1610 1611 if (vi_replace_count == 0 && _rl_vi_doing_insert) 1612 { 1613 rl_end_undo_group (); 1614 rl_do_undo (); 1615 _rl_vi_doing_insert = 0; 1616 } 1617 return (0); 1618} 1619 1620int 1621rl_vi_replace (count, key) 1622 int count, key; 1623{ 1624 int i; 1625 1626 vi_replace_count = 0; 1627 1628 if (!vi_replace_map) 1629 { 1630 vi_replace_map = rl_make_bare_keymap (); 1631 1632 for (i = ' '; i < KEYMAP_SIZE; i++) 1633 vi_replace_map[i].function = rl_vi_overstrike; 1634 1635 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 1636 vi_replace_map[ESC].function = rl_vi_movement_mode; 1637 vi_replace_map[RETURN].function = rl_newline; 1638 vi_replace_map[NEWLINE].function = rl_newline; 1639 1640 /* If the normal vi insertion keymap has ^H bound to erase, do the 1641 same here. Probably should remove the assignment to RUBOUT up 1642 there, but I don't think it will make a difference in real life. */ 1643 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 1644 vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 1645 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 1646 1647 } 1648 _rl_keymap = vi_replace_map; 1649 return (0); 1650} 1651 1652#if 0 1653/* Try to complete the word we are standing on or the word that ends with 1654 the previous character. A space matches everything. Word delimiters are 1655 space and ;. */ 1656int 1657rl_vi_possible_completions() 1658{ 1659 int save_pos = rl_point; 1660 1661 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 1662 { 1663 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 1664 rl_line_buffer[rl_point] != ';') 1665 rl_point++; 1666 } 1667 else if (rl_line_buffer[rl_point - 1] == ';') 1668 { 1669 rl_ding (); 1670 return (0); 1671 } 1672 1673 rl_possible_completions (); 1674 rl_point = save_pos; 1675 1676 return (0); 1677} 1678#endif 1679 1680/* Functions to save and restore marks. */ 1681static int 1682_rl_vi_set_mark () 1683{ 1684 int ch; 1685 1686 RL_SETSTATE(RL_STATE_MOREINPUT); 1687 ch = rl_read_key (); 1688 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1689 1690 if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ 1691 { 1692 rl_ding (); 1693 return -1; 1694 } 1695 ch -= 'a'; 1696 vi_mark_chars[ch] = rl_point; 1697 return 0; 1698} 1699 1700#if defined (READLINE_CALLBACKS) 1701static int 1702_rl_vi_callback_set_mark (data) 1703 _rl_callback_generic_arg *data; 1704{ 1705 _rl_callback_func = 0; 1706 _rl_want_redisplay = 1; 1707 1708 return (_rl_vi_set_mark ()); 1709} 1710#endif 1711 1712int 1713rl_vi_set_mark (count, key) 1714 int count, key; 1715{ 1716#if defined (READLINE_CALLBACKS) 1717 if (RL_ISSTATE (RL_STATE_CALLBACK)) 1718 { 1719 _rl_callback_data = 0; 1720 _rl_callback_func = _rl_vi_callback_set_mark; 1721 return (0); 1722 } 1723#endif 1724 1725 return (_rl_vi_set_mark ()); 1726} 1727 1728static int 1729_rl_vi_goto_mark () 1730{ 1731 int ch; 1732 1733 RL_SETSTATE(RL_STATE_MOREINPUT); 1734 ch = rl_read_key (); 1735 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1736 1737 if (ch == '`') 1738 { 1739 rl_point = rl_mark; 1740 return 0; 1741 } 1742 else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ 1743 { 1744 rl_ding (); 1745 return -1; 1746 } 1747 1748 ch -= 'a'; 1749 if (vi_mark_chars[ch] == -1) 1750 { 1751 rl_ding (); 1752 return -1; 1753 } 1754 rl_point = vi_mark_chars[ch]; 1755 return 0; 1756} 1757 1758#if defined (READLINE_CALLBACKS) 1759static int 1760_rl_vi_callback_goto_mark (data) 1761 _rl_callback_generic_arg *data; 1762{ 1763 _rl_callback_func = 0; 1764 _rl_want_redisplay = 1; 1765 1766 return (_rl_vi_goto_mark ()); 1767} 1768#endif 1769 1770int 1771rl_vi_goto_mark (count, key) 1772 int count, key; 1773{ 1774#if defined (READLINE_CALLBACKS) 1775 if (RL_ISSTATE (RL_STATE_CALLBACK)) 1776 { 1777 _rl_callback_data = 0; 1778 _rl_callback_func = _rl_vi_callback_goto_mark; 1779 return (0); 1780 } 1781#endif 1782 1783 return (_rl_vi_goto_mark ()); 1784} 1785#endif /* VI_MODE */ 1786