vi_mode.c revision 75406
1193645Ssimon/* vi_mode.c -- A vi emulation mode for Bash. 2280297Sjkim Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ 3280297Sjkim 4280297Sjkim/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. 5193645Ssimon 6193645Ssimon This file is part of the GNU Readline Library, a library for 7340704Sjkim reading lines of text with interactive input and history editing. 8193645Ssimon 9193645Ssimon The GNU Readline Library is free software; you can redistribute it 10193645Ssimon and/or modify it under the terms of the GNU General Public License 11193645Ssimon as published by the Free Software Foundation; either version 2, or 12193645Ssimon (at your option) any later version. 13193645Ssimon 14280297Sjkim The GNU Readline Library is distributed in the hope that it will be 15193645Ssimon useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16193645Ssimon of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17193645Ssimon GNU General Public License for more details. 18193645Ssimon 19193645Ssimon The GNU General Public License is often shipped with GNU software, and 20193645Ssimon is generally kept in a file called COPYING or LICENSE. If you do not 21193645Ssimon have a copy of the license, write to the Free Software Foundation, 22193645Ssimon 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 23193645Ssimon#define READLINE_LIBRARY 24193645Ssimon 25193645Ssimon/* **************************************************************** */ 26193645Ssimon/* */ 27193645Ssimon/* VI Emulation Mode */ 28193645Ssimon/* */ 29193645Ssimon/* **************************************************************** */ 30193645Ssimon#include "rlconf.h" 31193645Ssimon 32193645Ssimon#if defined (VI_MODE) 33193645Ssimon 34193645Ssimon#if defined (HAVE_CONFIG_H) 35193645Ssimon# include <config.h> 36193645Ssimon#endif 37193645Ssimon 38193645Ssimon#include <sys/types.h> 39193645Ssimon 40193645Ssimon#if defined (HAVE_STDLIB_H) 41193645Ssimon# include <stdlib.h> 42193645Ssimon#else 43193645Ssimon# include "ansi_stdlib.h" 44193645Ssimon#endif /* HAVE_STDLIB_H */ 45193645Ssimon 46193645Ssimon#if defined (HAVE_UNISTD_H) 47193645Ssimon# include <unistd.h> 48193645Ssimon#endif 49193645Ssimon 50193645Ssimon#include <stdio.h> 51193645Ssimon 52193645Ssimon/* Some standard library routines. */ 53193645Ssimon#include "rldefs.h" 54193645Ssimon#include "readline.h" 55193645Ssimon#include "history.h" 56193645Ssimon 57193645Ssimon#include "rlprivate.h" 58193645Ssimon#include "xmalloc.h" 59193645Ssimon 60193645Ssimon#ifndef _rl_digit_p 61193645Ssimon#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') 62193645Ssimon#endif 63193645Ssimon 64193645Ssimon#ifndef _rl_digit_value 65280297Sjkim#define _rl_digit_value(c) ((c) - '0') 66280297Sjkim#endif 67280297Sjkim 68193645Ssimon#ifndef member 69193645Ssimon#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) 70193645Ssimon#endif 71280297Sjkim 72280297Sjkim#ifndef isident 73280297Sjkim#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_')) 74280297Sjkim#endif 75280297Sjkim 76280297Sjkim#ifndef exchange 77280297Sjkim#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0) 78280297Sjkim#endif 79280297Sjkim 80280297Sjkim/* Non-zero means enter insertion mode. */ 81280297Sjkimstatic int _rl_vi_doing_insert; 82280297Sjkim 83280297Sjkim/* Command keys which do movement for xxx_to commands. */ 84280297Sjkimstatic const char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; 85280297Sjkim 86280297Sjkim/* Keymap used for vi replace characters. Created dynamically since 87280297Sjkim rarely used. */ 88280297Sjkimstatic Keymap vi_replace_map; 89280297Sjkim 90193645Ssimon/* The number of characters inserted in the last replace operation. */ 91280297Sjkimstatic int vi_replace_count; 92280297Sjkim 93280297Sjkim/* If non-zero, we have text inserted after a c[motion] command that put 94280297Sjkim us implicitly into insert mode. Some people want this text to be 95193645Ssimon attached to the command so that it is `redoable' with `.'. */ 96193645Ssimonstatic int vi_continued_command; 97193645Ssimonstatic char *vi_insert_buffer; 98280297Sjkimstatic int vi_insert_buffer_size; 99280297Sjkim 100280297Sjkimstatic int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ 101280297Sjkimstatic int _rl_vi_last_repeat = 1; 102280297Sjkimstatic int _rl_vi_last_arg_sign = 1; 103193645Ssimonstatic int _rl_vi_last_motion; 104280297Sjkimstatic int _rl_vi_last_search_char; 105193645Ssimonstatic int _rl_vi_last_replacement; 106280297Sjkim 107280297Sjkimstatic int _rl_vi_last_key_before_insert; 108280297Sjkim 109193645Ssimonstatic int vi_redoing; 110280297Sjkim 111280297Sjkim/* Text modification commands. These are the `redoable' commands. */ 112280297Sjkimstatic const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; 113193645Ssimon 114280297Sjkim/* Arrays for the saved marks. */ 115280297Sjkimstatic int vi_mark_chars[27]; 116193645Ssimon 117280297Sjkimstatic int rl_digit_loop1 __P((void)); 118193645Ssimon 119280297Sjkimvoid 120193645Ssimon_rl_vi_initialize_line () 121280297Sjkim{ 122193645Ssimon register int i; 123280297Sjkim 124280297Sjkim for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) 125193645Ssimon vi_mark_chars[i] = -1; 126280297Sjkim} 127280297Sjkim 128193645Ssimonvoid 129280297Sjkim_rl_vi_reset_last () 130280297Sjkim{ 131193645Ssimon _rl_vi_last_command = 'i'; 132280297Sjkim _rl_vi_last_repeat = 1; 133193645Ssimon _rl_vi_last_arg_sign = 1; 134280297Sjkim _rl_vi_last_motion = 0; 135280297Sjkim} 136193645Ssimon 137280297Sjkimvoid 138280297Sjkim_rl_vi_set_last (key, repeat, sign) 139193645Ssimon int key, repeat, sign; 140280297Sjkim{ 141280297Sjkim _rl_vi_last_command = key; 142193645Ssimon _rl_vi_last_repeat = repeat; 143280297Sjkim _rl_vi_last_arg_sign = sign; 144280297Sjkim} 145193645Ssimon 146280297Sjkim/* Is the command C a VI mode text modification command? */ 147280297Sjkimint 148193645Ssimon_rl_vi_textmod_command (c) 149280297Sjkim int c; 150280297Sjkim{ 151193645Ssimon return (member (c, vi_textmod)); 152280297Sjkim} 153193645Ssimon 154280297Sjkimstatic void 155280297Sjkim_rl_vi_stuff_insert (count) 156193645Ssimon int count; 157280297Sjkim{ 158280297Sjkim rl_begin_undo_group (); 159193645Ssimon while (count--) 160280297Sjkim rl_insert_text (vi_insert_buffer); 161193645Ssimon rl_end_undo_group (); 162280297Sjkim} 163280297Sjkim 164280297Sjkim/* Bound to `.'. Called from command mode, so we know that we have to 165280297Sjkim redo a text modification command. The default for _rl_vi_last_command 166280297Sjkim puts you back into insert mode. */ 167280297Sjkimint 168280297Sjkimrl_vi_redo (count, c) 169280297Sjkim int count, c; 170280297Sjkim{ 171280297Sjkim if (!rl_explicit_arg) 172280297Sjkim { 173280297Sjkim rl_numeric_arg = _rl_vi_last_repeat; 174280297Sjkim rl_arg_sign = _rl_vi_last_arg_sign; 175280297Sjkim } 176280297Sjkim 177280297Sjkim vi_redoing = 1; 178280297Sjkim /* If we're redoing an insert with `i', stuff in the inserted text 179280297Sjkim and do not go into insertion mode. */ 180280297Sjkim if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) 181280297Sjkim { 182193645Ssimon _rl_vi_stuff_insert (count); 183280297Sjkim /* And back up point over the last character inserted. */ 184193645Ssimon if (rl_point > 0) 185280297Sjkim rl_point--; 186193645Ssimon } 187280297Sjkim else 188193645Ssimon _rl_dispatch (_rl_vi_last_command, _rl_keymap); 189280297Sjkim vi_redoing = 0; 190193645Ssimon 191280297Sjkim return (0); 192280297Sjkim} 193193645Ssimon 194280297Sjkim/* A placeholder for further expansion. */ 195280297Sjkimint 196280297Sjkimrl_vi_undo (count, key) 197193645Ssimon int count, key; 198193645Ssimon{ 199193645Ssimon return (rl_undo_command (count, key)); 200280297Sjkim} 201280297Sjkim 202280297Sjkim/* Yank the nth arg from the previous line into this line at point. */ 203280297Sjkimint 204280297Sjkimrl_vi_yank_arg (count, key) 205280297Sjkim int count, key; 206280297Sjkim{ 207280297Sjkim /* Readline thinks that the first word on a line is the 0th, while vi 208280297Sjkim thinks the first word on a line is the 1st. Compensate. */ 209280297Sjkim if (rl_explicit_arg) 210280297Sjkim rl_yank_nth_arg (count - 1, 0); 211280297Sjkim else 212280297Sjkim rl_yank_nth_arg ('$', 0); 213280297Sjkim 214280297Sjkim return (0); 215280297Sjkim} 216291719Sjkim 217193645Ssimon/* With an argument, move back that many history lines, else move to the 218280297Sjkim beginning of history. */ 219280297Sjkimint 220325337Sjkimrl_vi_fetch_history (count, c) 221325337Sjkim int count, c; 222193645Ssimon{ 223280297Sjkim int wanted; 224280297Sjkim 225291719Sjkim /* Giving an argument of n means we want the nth command in the history 226340704Sjkim file. The command number is interpreted the same way that the bash 227280297Sjkim `history' command does it -- that is, giving an argument count of 450 228340704Sjkim to this command would get the command listed as number 450 in the 229340704Sjkim output of `history'. */ 230280297Sjkim if (rl_explicit_arg) 231280297Sjkim { 232280297Sjkim wanted = history_base + where_history () - count; 233193645Ssimon if (wanted <= 0) 234280297Sjkim rl_beginning_of_history (0, 0); 235193645Ssimon else 236280297Sjkim rl_get_previous_history (wanted, c); 237280297Sjkim } 238193645Ssimon else 239280297Sjkim rl_beginning_of_history (count, 0); 240193645Ssimon return (0); 241291719Sjkim} 242291719Sjkim 243291719Sjkim/* Search again for the last thing searched for. */ 244280297Sjkimint 245193645Ssimonrl_vi_search_again (count, key) 246280297Sjkim int count, key; 247280297Sjkim{ 248280297Sjkim switch (key) 249280297Sjkim { 250280297Sjkim case 'n': 251280297Sjkim rl_noninc_reverse_search_again (count, key); 252193645Ssimon break; 253193645Ssimon 254193645Ssimon case 'N': 255280297Sjkim rl_noninc_forward_search_again (count, key); 256280297Sjkim break; 257280297Sjkim } 258280297Sjkim return (0); 259280297Sjkim} 260193645Ssimon 261280297Sjkim/* Do a vi style search. */ 262325337Sjkimint 263280297Sjkimrl_vi_search (count, key) 264325337Sjkim int count, key; 265280297Sjkim{ 266325337Sjkim switch (key) 267325337Sjkim { 268193645Ssimon case '?': 269280297Sjkim rl_noninc_forward_search (count, key); 270280297Sjkim break; 271280297Sjkim 272280297Sjkim case '/': 273280297Sjkim rl_noninc_reverse_search (count, key); 274280297Sjkim break; 275193645Ssimon 276280297Sjkim default: 277193645Ssimon rl_ding (); 278280297Sjkim break; 279280297Sjkim } 280193645Ssimon return (0); 281280297Sjkim} 282193645Ssimon 283280297Sjkim/* Completion, from vi's point of view. */ 284int 285rl_vi_complete (ignore, key) 286 int ignore, key; 287{ 288 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) 289 { 290 if (!whitespace (rl_line_buffer[rl_point + 1])) 291 rl_vi_end_word (1, 'E'); 292 rl_point++; 293 } 294 295 if (key == '*') 296 rl_complete_internal ('*'); /* Expansion and replacement. */ 297 else if (key == '=') 298 rl_complete_internal ('?'); /* List possible completions. */ 299 else if (key == '\\') 300 rl_complete_internal (TAB); /* Standard Readline completion. */ 301 else 302 rl_complete (0, key); 303 304 if (key == '*' || key == '\\') 305 { 306 _rl_vi_set_last (key, 1, rl_arg_sign); 307 rl_vi_insertion_mode (1, key); 308 } 309 return (0); 310} 311 312/* Tilde expansion for vi mode. */ 313int 314rl_vi_tilde_expand (ignore, key) 315 int ignore, key; 316{ 317 rl_tilde_expand (0, key); 318 _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ 319 rl_vi_insertion_mode (1, key); 320 return (0); 321} 322 323/* Previous word in vi mode. */ 324int 325rl_vi_prev_word (count, key) 326 int count, key; 327{ 328 if (count < 0) 329 return (rl_vi_next_word (-count, key)); 330 331 if (rl_point == 0) 332 { 333 rl_ding (); 334 return (0); 335 } 336 337 if (_rl_uppercase_p (key)) 338 rl_vi_bWord (count, key); 339 else 340 rl_vi_bword (count, key); 341 342 return (0); 343} 344 345/* Next word in vi mode. */ 346int 347rl_vi_next_word (count, key) 348 int count, key; 349{ 350 if (count < 0) 351 return (rl_vi_prev_word (-count, key)); 352 353 if (rl_point >= (rl_end - 1)) 354 { 355 rl_ding (); 356 return (0); 357 } 358 359 if (_rl_uppercase_p (key)) 360 rl_vi_fWord (count, key); 361 else 362 rl_vi_fword (count, key); 363 return (0); 364} 365 366/* Move to the end of the ?next? word. */ 367int 368rl_vi_end_word (count, key) 369 int count, key; 370{ 371 if (count < 0) 372 { 373 rl_ding (); 374 return -1; 375 } 376 377 if (_rl_uppercase_p (key)) 378 rl_vi_eWord (count, key); 379 else 380 rl_vi_eword (count, key); 381 return (0); 382} 383 384/* Move forward a word the way that 'W' does. */ 385int 386rl_vi_fWord (count, ignore) 387 int count, ignore; 388{ 389 while (count-- && rl_point < (rl_end - 1)) 390 { 391 /* Skip until whitespace. */ 392 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 393 rl_point++; 394 395 /* Now skip whitespace. */ 396 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 397 rl_point++; 398 } 399 return (0); 400} 401 402int 403rl_vi_bWord (count, ignore) 404 int count, ignore; 405{ 406 while (count-- && rl_point > 0) 407 { 408 /* If we are at the start of a word, move back to whitespace so 409 we will go back to the start of the previous word. */ 410 if (!whitespace (rl_line_buffer[rl_point]) && 411 whitespace (rl_line_buffer[rl_point - 1])) 412 rl_point--; 413 414 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 415 rl_point--; 416 417 if (rl_point > 0) 418 { 419 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); 420 rl_point++; 421 } 422 } 423 return (0); 424} 425 426int 427rl_vi_eWord (count, ignore) 428 int count, ignore; 429{ 430 while (count-- && rl_point < (rl_end - 1)) 431 { 432 if (!whitespace (rl_line_buffer[rl_point])) 433 rl_point++; 434 435 /* Move to the next non-whitespace character (to the start of the 436 next word). */ 437 while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); 438 439 if (rl_point && rl_point < rl_end) 440 { 441 /* Skip whitespace. */ 442 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 443 rl_point++; 444 445 /* Skip until whitespace. */ 446 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) 447 rl_point++; 448 449 /* Move back to the last character of the word. */ 450 rl_point--; 451 } 452 } 453 return (0); 454} 455 456int 457rl_vi_fword (count, ignore) 458 int count, ignore; 459{ 460 while (count-- && rl_point < (rl_end - 1)) 461 { 462 /* Move to white space (really non-identifer). */ 463 if (isident (rl_line_buffer[rl_point])) 464 { 465 while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end) 466 rl_point++; 467 } 468 else /* if (!whitespace (rl_line_buffer[rl_point])) */ 469 { 470 while (!isident (rl_line_buffer[rl_point]) && 471 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 472 rl_point++; 473 } 474 475 /* Move past whitespace. */ 476 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) 477 rl_point++; 478 } 479 return (0); 480} 481 482int 483rl_vi_bword (count, ignore) 484 int count, ignore; 485{ 486 while (count-- && rl_point > 0) 487 { 488 int last_is_ident; 489 490 /* If we are at the start of a word, move back to whitespace 491 so we will go back to the start of the previous word. */ 492 if (!whitespace (rl_line_buffer[rl_point]) && 493 whitespace (rl_line_buffer[rl_point - 1])) 494 rl_point--; 495 496 /* If this character and the previous character are `opposite', move 497 back so we don't get messed up by the rl_point++ down there in 498 the while loop. Without this code, words like `l;' screw up the 499 function. */ 500 last_is_ident = isident (rl_line_buffer[rl_point - 1]); 501 if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) || 502 (!isident (rl_line_buffer[rl_point]) && last_is_ident)) 503 rl_point--; 504 505 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) 506 rl_point--; 507 508 if (rl_point > 0) 509 { 510 if (isident (rl_line_buffer[rl_point])) 511 while (--rl_point >= 0 && isident (rl_line_buffer[rl_point])); 512 else 513 while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) && 514 !whitespace (rl_line_buffer[rl_point])); 515 rl_point++; 516 } 517 } 518 return (0); 519} 520 521int 522rl_vi_eword (count, ignore) 523 int count, ignore; 524{ 525 while (count-- && rl_point < rl_end - 1) 526 { 527 if (!whitespace (rl_line_buffer[rl_point])) 528 rl_point++; 529 530 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 531 rl_point++; 532 533 if (rl_point < rl_end) 534 { 535 if (isident (rl_line_buffer[rl_point])) 536 while (++rl_point < rl_end && isident (rl_line_buffer[rl_point])); 537 else 538 while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point]) 539 && !whitespace (rl_line_buffer[rl_point])); 540 } 541 rl_point--; 542 } 543 return (0); 544} 545 546int 547rl_vi_insert_beg (count, key) 548 int count, key; 549{ 550 rl_beg_of_line (1, key); 551 rl_vi_insertion_mode (1, key); 552 return (0); 553} 554 555int 556rl_vi_append_mode (count, key) 557 int count, key; 558{ 559 if (rl_point < rl_end) 560 rl_point++; 561 rl_vi_insertion_mode (1, key); 562 return (0); 563} 564 565int 566rl_vi_append_eol (count, key) 567 int count, key; 568{ 569 rl_end_of_line (1, key); 570 rl_vi_append_mode (1, key); 571 return (0); 572} 573 574/* What to do in the case of C-d. */ 575int 576rl_vi_eof_maybe (count, c) 577 int count, c; 578{ 579 return (rl_newline (1, '\n')); 580} 581 582/* Insertion mode stuff. */ 583 584/* Switching from one mode to the other really just involves 585 switching keymaps. */ 586int 587rl_vi_insertion_mode (count, key) 588 int count, key; 589{ 590 _rl_keymap = vi_insertion_keymap; 591 _rl_vi_last_key_before_insert = key; 592 return (0); 593} 594 595static void 596_rl_vi_save_insert (up) 597 UNDO_LIST *up; 598{ 599 int len, start, end; 600 601 if (up == 0) 602 { 603 if (vi_insert_buffer_size >= 1) 604 vi_insert_buffer[0] = '\0'; 605 return; 606 } 607 608 start = up->start; 609 end = up->end; 610 len = end - start + 1; 611 if (len >= vi_insert_buffer_size) 612 { 613 vi_insert_buffer_size += (len + 32) - (len % 32); 614 vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size); 615 } 616 strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); 617 vi_insert_buffer[len-1] = '\0'; 618} 619 620void 621_rl_vi_done_inserting () 622{ 623 if (_rl_vi_doing_insert) 624 { 625 rl_end_undo_group (); 626 /* Now, the text between rl_undo_list->next->start and 627 rl_undo_list->next->end is what was inserted while in insert 628 mode. It gets copied to VI_INSERT_BUFFER because it depends 629 on absolute indices into the line which may change (though they 630 probably will not). */ 631 _rl_vi_doing_insert = 0; 632 _rl_vi_save_insert (rl_undo_list->next); 633 vi_continued_command = 1; 634 } 635 else 636 { 637 if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) 638 _rl_vi_save_insert (rl_undo_list); 639 /* XXX - Other keys probably need to be checked. */ 640 else if (_rl_vi_last_key_before_insert == 'C') 641 rl_end_undo_group (); 642 while (_rl_undo_group_level > 0) 643 rl_end_undo_group (); 644 vi_continued_command = 0; 645 } 646} 647 648int 649rl_vi_movement_mode (count, key) 650 int count, key; 651{ 652 if (rl_point > 0) 653 rl_backward (1, key); 654 655 _rl_keymap = vi_movement_keymap; 656 _rl_vi_done_inserting (); 657 return (0); 658} 659 660int 661rl_vi_arg_digit (count, c) 662 int count, c; 663{ 664 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) 665 return (rl_beg_of_line (1, c)); 666 else 667 return (rl_digit_argument (count, c)); 668} 669 670int 671rl_vi_change_case (count, ignore) 672 int count, ignore; 673{ 674 char c = 0; 675 676 /* Don't try this on an empty line. */ 677 if (rl_point >= rl_end) 678 return (0); 679 680 while (count-- && rl_point < rl_end) 681 { 682 if (_rl_uppercase_p (rl_line_buffer[rl_point])) 683 c = _rl_to_lower (rl_line_buffer[rl_point]); 684 else if (_rl_lowercase_p (rl_line_buffer[rl_point])) 685 c = _rl_to_upper (rl_line_buffer[rl_point]); 686 else 687 { 688 /* Just skip over characters neither upper nor lower case. */ 689 rl_forward (1, c); 690 continue; 691 } 692 693 /* Vi is kind of strange here. */ 694 if (c) 695 { 696 rl_begin_undo_group (); 697 rl_delete (1, c); 698 rl_insert (1, c); 699 rl_end_undo_group (); 700 rl_vi_check (); 701 } 702 else 703 rl_forward (1, c); 704 } 705 return (0); 706} 707 708int 709rl_vi_put (count, key) 710 int count, key; 711{ 712 if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) 713 rl_point++; 714 715 rl_yank (1, key); 716 rl_backward (1, key); 717 return (0); 718} 719 720int 721rl_vi_check () 722{ 723 if (rl_point && rl_point == rl_end) 724 rl_point--; 725 return (0); 726} 727 728int 729rl_vi_column (count, key) 730 int count, key; 731{ 732 if (count > rl_end) 733 rl_end_of_line (1, key); 734 else 735 rl_point = count - 1; 736 return (0); 737} 738 739int 740rl_vi_domove (key, nextkey) 741 int key, *nextkey; 742{ 743 int c, save; 744 int old_end; 745 746 rl_mark = rl_point; 747 RL_SETSTATE(RL_STATE_MOREINPUT); 748 c = rl_read_key (); 749 RL_UNSETSTATE(RL_STATE_MOREINPUT); 750 *nextkey = c; 751 752 if (!member (c, vi_motion)) 753 { 754 if (_rl_digit_p (c)) 755 { 756 save = rl_numeric_arg; 757 rl_numeric_arg = _rl_digit_value (c); 758 rl_digit_loop1 (); 759 rl_numeric_arg *= save; 760 RL_SETSTATE(RL_STATE_MOREINPUT); 761 c = rl_read_key (); /* real command */ 762 RL_UNSETSTATE(RL_STATE_MOREINPUT); 763 *nextkey = c; 764 } 765 else if (key == c && (key == 'd' || key == 'y' || key == 'c')) 766 { 767 rl_mark = rl_end; 768 rl_beg_of_line (1, c); 769 _rl_vi_last_motion = c; 770 return (0); 771 } 772 else 773 return (-1); 774 } 775 776 _rl_vi_last_motion = c; 777 778 /* Append a blank character temporarily so that the motion routines 779 work right at the end of the line. */ 780 old_end = rl_end; 781 rl_line_buffer[rl_end++] = ' '; 782 rl_line_buffer[rl_end] = '\0'; 783 784 _rl_dispatch (c, _rl_keymap); 785 786 /* Remove the blank that we added. */ 787 rl_end = old_end; 788 rl_line_buffer[rl_end] = '\0'; 789 if (rl_point > rl_end) 790 rl_point = rl_end; 791 792 /* No change in position means the command failed. */ 793 if (rl_mark == rl_point) 794 return (-1); 795 796 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next 797 word. If we are not at the end of the line, and we are on a 798 non-whitespace character, move back one (presumably to whitespace). */ 799 if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && 800 !whitespace (rl_line_buffer[rl_point])) 801 rl_point--; 802 803 /* If cw or cW, back up to the end of a word, so the behaviour of ce 804 or cE is the actual result. Brute-force, no subtlety. */ 805 if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) 806 { 807 /* Don't move farther back than where we started. */ 808 while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) 809 rl_point--; 810 811 /* Posix.2 says that if cw or cW moves the cursor towards the end of 812 the line, the character under the cursor should be deleted. */ 813 if (rl_point == rl_mark) 814 rl_point++; 815 else 816 { 817 /* Move past the end of the word so that the kill doesn't 818 remove the last letter of the previous word. Only do this 819 if we are not at the end of the line. */ 820 if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) 821 rl_point++; 822 } 823 } 824 825 if (rl_mark < rl_point) 826 exchange (rl_point, rl_mark); 827 828 return (0); 829} 830 831/* A simplified loop for vi. Don't dispatch key at end. 832 Don't recognize minus sign? 833 Should this do rl_save_prompt/rl_restore_prompt? */ 834static int 835rl_digit_loop1 () 836{ 837 int key, c; 838 839 RL_SETSTATE(RL_STATE_NUMERICARG); 840 while (1) 841 { 842 if (rl_numeric_arg > 1000000) 843 { 844 rl_explicit_arg = rl_numeric_arg = 0; 845 rl_ding (); 846 rl_clear_message (); 847 RL_UNSETSTATE(RL_STATE_NUMERICARG); 848 return 1; 849 } 850 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0); 851 RL_SETSTATE(RL_STATE_MOREINPUT); 852 key = c = rl_read_key (); 853 RL_UNSETSTATE(RL_STATE_MOREINPUT); 854 855 if (_rl_keymap[c].type == ISFUNC && 856 _rl_keymap[c].function == rl_universal_argument) 857 { 858 rl_numeric_arg *= 4; 859 continue; 860 } 861 862 c = UNMETA (c); 863 if (_rl_digit_p (c)) 864 { 865 if (rl_explicit_arg) 866 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); 867 else 868 rl_numeric_arg = _rl_digit_value (c); 869 rl_explicit_arg = 1; 870 } 871 else 872 { 873 rl_clear_message (); 874 rl_stuff_char (key); 875 break; 876 } 877 } 878 879 RL_UNSETSTATE(RL_STATE_NUMERICARG); 880 return (0); 881} 882 883int 884rl_vi_delete_to (count, key) 885 int count, key; 886{ 887 int c; 888 889 if (_rl_uppercase_p (key)) 890 rl_stuff_char ('$'); 891 else if (vi_redoing) 892 rl_stuff_char (_rl_vi_last_motion); 893 894 if (rl_vi_domove (key, &c)) 895 { 896 rl_ding (); 897 return -1; 898 } 899 900 /* These are the motion commands that do not require adjusting the 901 mark. */ 902 if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) 903 rl_mark++; 904 905 rl_kill_text (rl_point, rl_mark); 906 return (0); 907} 908 909int 910rl_vi_change_to (count, key) 911 int count, key; 912{ 913 int c, start_pos; 914 915 if (_rl_uppercase_p (key)) 916 rl_stuff_char ('$'); 917 else if (vi_redoing) 918 rl_stuff_char (_rl_vi_last_motion); 919 920 start_pos = rl_point; 921 922 if (rl_vi_domove (key, &c)) 923 { 924 rl_ding (); 925 return -1; 926 } 927 928 /* These are the motion commands that do not require adjusting the 929 mark. c[wW] are handled by special-case code in rl_vi_domove(), 930 and already leave the mark at the correct location. */ 931 if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) 932 rl_mark++; 933 934 /* The cursor never moves with c[wW]. */ 935 if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) 936 rl_point = start_pos; 937 938 if (vi_redoing) 939 { 940 if (vi_insert_buffer && *vi_insert_buffer) 941 rl_begin_undo_group (); 942 rl_delete_text (rl_point, rl_mark); 943 if (vi_insert_buffer && *vi_insert_buffer) 944 { 945 rl_insert_text (vi_insert_buffer); 946 rl_end_undo_group (); 947 } 948 } 949 else 950 { 951 rl_begin_undo_group (); /* to make the `u' command work */ 952 rl_kill_text (rl_point, rl_mark); 953 /* `C' does not save the text inserted for undoing or redoing. */ 954 if (_rl_uppercase_p (key) == 0) 955 _rl_vi_doing_insert = 1; 956 _rl_vi_set_last (key, count, rl_arg_sign); 957 rl_vi_insertion_mode (1, key); 958 } 959 960 return (0); 961} 962 963int 964rl_vi_yank_to (count, key) 965 int count, key; 966{ 967 int c, save = rl_point; 968 969 if (_rl_uppercase_p (key)) 970 rl_stuff_char ('$'); 971 972 if (rl_vi_domove (key, &c)) 973 { 974 rl_ding (); 975 return -1; 976 } 977 978 /* These are the motion commands that do not require adjusting the 979 mark. */ 980 if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) 981 rl_mark++; 982 983 rl_begin_undo_group (); 984 rl_kill_text (rl_point, rl_mark); 985 rl_end_undo_group (); 986 rl_do_undo (); 987 rl_point = save; 988 989 return (0); 990} 991 992int 993rl_vi_delete (count, key) 994 int count, key; 995{ 996 int end; 997 998 if (rl_end == 0) 999 { 1000 rl_ding (); 1001 return -1; 1002 } 1003 1004 end = rl_point + count; 1005 1006 if (end >= rl_end) 1007 end = rl_end; 1008 1009 rl_kill_text (rl_point, end); 1010 1011 if (rl_point > 0 && rl_point == rl_end) 1012 rl_backward (1, key); 1013 return (0); 1014} 1015 1016int 1017rl_vi_back_to_indent (count, key) 1018 int count, key; 1019{ 1020 rl_beg_of_line (1, key); 1021 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) 1022 rl_point++; 1023 return (0); 1024} 1025 1026int 1027rl_vi_first_print (count, key) 1028 int count, key; 1029{ 1030 return (rl_vi_back_to_indent (1, key)); 1031} 1032 1033int 1034rl_vi_char_search (count, key) 1035 int count, key; 1036{ 1037 static char target; 1038 static int orig_dir, dir; 1039 1040 if (key == ';' || key == ',') 1041 dir = key == ';' ? orig_dir : -orig_dir; 1042 else 1043 { 1044 if (vi_redoing) 1045 target = _rl_vi_last_search_char; 1046 else 1047 { 1048 RL_SETSTATE(RL_STATE_MOREINPUT); 1049 _rl_vi_last_search_char = target = rl_read_key (); 1050 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1051 } 1052 1053 switch (key) 1054 { 1055 case 't': 1056 orig_dir = dir = FTO; 1057 break; 1058 1059 case 'T': 1060 orig_dir = dir = BTO; 1061 break; 1062 1063 case 'f': 1064 orig_dir = dir = FFIND; 1065 break; 1066 1067 case 'F': 1068 orig_dir = dir = BFIND; 1069 break; 1070 } 1071 } 1072 1073 return (_rl_char_search_internal (count, dir, target)); 1074} 1075 1076/* Match brackets */ 1077int 1078rl_vi_match (ignore, key) 1079 int ignore, key; 1080{ 1081 int count = 1, brack, pos; 1082 1083 pos = rl_point; 1084 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) 1085 { 1086 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && 1087 rl_point < rl_end - 1) 1088 rl_forward (1, key); 1089 1090 if (brack <= 0) 1091 { 1092 rl_point = pos; 1093 rl_ding (); 1094 return -1; 1095 } 1096 } 1097 1098 pos = rl_point; 1099 1100 if (brack < 0) 1101 { 1102 while (count) 1103 { 1104 if (--pos >= 0) 1105 { 1106 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1107 if (b == -brack) 1108 count--; 1109 else if (b == brack) 1110 count++; 1111 } 1112 else 1113 { 1114 rl_ding (); 1115 return -1; 1116 } 1117 } 1118 } 1119 else 1120 { /* brack > 0 */ 1121 while (count) 1122 { 1123 if (++pos < rl_end) 1124 { 1125 int b = rl_vi_bracktype (rl_line_buffer[pos]); 1126 if (b == -brack) 1127 count--; 1128 else if (b == brack) 1129 count++; 1130 } 1131 else 1132 { 1133 rl_ding (); 1134 return -1; 1135 } 1136 } 1137 } 1138 rl_point = pos; 1139 return (0); 1140} 1141 1142int 1143rl_vi_bracktype (c) 1144 int c; 1145{ 1146 switch (c) 1147 { 1148 case '(': return 1; 1149 case ')': return -1; 1150 case '[': return 2; 1151 case ']': return -2; 1152 case '{': return 3; 1153 case '}': return -3; 1154 default: return 0; 1155 } 1156} 1157 1158int 1159rl_vi_change_char (count, key) 1160 int count, key; 1161{ 1162 int c; 1163 1164 if (vi_redoing) 1165 c = _rl_vi_last_replacement; 1166 else 1167 { 1168 RL_SETSTATE(RL_STATE_MOREINPUT); 1169 _rl_vi_last_replacement = c = rl_read_key (); 1170 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1171 } 1172 1173 if (c == '\033' || c == CTRL ('C')) 1174 return -1; 1175 1176 while (count-- && rl_point < rl_end) 1177 { 1178 rl_begin_undo_group (); 1179 1180 rl_delete (1, c); 1181 rl_insert (1, c); 1182 if (count == 0) 1183 rl_backward (1, c); 1184 1185 rl_end_undo_group (); 1186 } 1187 return (0); 1188} 1189 1190int 1191rl_vi_subst (count, key) 1192 int count, key; 1193{ 1194 rl_begin_undo_group (); 1195 1196 if (_rl_uppercase_p (key)) 1197 { 1198 rl_beg_of_line (1, key); 1199 rl_kill_line (1, key); 1200 } 1201 else 1202 rl_delete_text (rl_point, rl_point+count); 1203 1204 rl_end_undo_group (); 1205 1206 _rl_vi_set_last (key, count, rl_arg_sign); 1207 1208 if (vi_redoing) 1209 { 1210 int o = _rl_doing_an_undo; 1211 1212 _rl_doing_an_undo = 1; 1213 if (vi_insert_buffer && *vi_insert_buffer) 1214 rl_insert_text (vi_insert_buffer); 1215 _rl_doing_an_undo = o; 1216 } 1217 else 1218 { 1219 rl_begin_undo_group (); 1220 _rl_vi_doing_insert = 1; 1221 rl_vi_insertion_mode (1, key); 1222 } 1223 1224 return (0); 1225} 1226 1227int 1228rl_vi_overstrike (count, key) 1229 int count, key; 1230{ 1231 int i; 1232 1233 if (_rl_vi_doing_insert == 0) 1234 { 1235 _rl_vi_doing_insert = 1; 1236 rl_begin_undo_group (); 1237 } 1238 1239 for (i = 0; i < count; i++) 1240 { 1241 vi_replace_count++; 1242 rl_begin_undo_group (); 1243 1244 if (rl_point < rl_end) 1245 { 1246 rl_delete (1, key); 1247 rl_insert (1, key); 1248 } 1249 else 1250 rl_insert (1, key); 1251 1252 rl_end_undo_group (); 1253 } 1254 return (0); 1255} 1256 1257int 1258rl_vi_overstrike_delete (count, key) 1259 int count, key; 1260{ 1261 int i, s; 1262 1263 for (i = 0; i < count; i++) 1264 { 1265 if (vi_replace_count == 0) 1266 { 1267 rl_ding (); 1268 break; 1269 } 1270 s = rl_point; 1271 1272 if (rl_do_undo ()) 1273 vi_replace_count--; 1274 1275 if (rl_point == s) 1276 rl_backward (1, key); 1277 } 1278 1279 if (vi_replace_count == 0 && _rl_vi_doing_insert) 1280 { 1281 rl_end_undo_group (); 1282 rl_do_undo (); 1283 _rl_vi_doing_insert = 0; 1284 } 1285 return (0); 1286} 1287 1288int 1289rl_vi_replace (count, key) 1290 int count, key; 1291{ 1292 int i; 1293 1294 vi_replace_count = 0; 1295 1296 if (!vi_replace_map) 1297 { 1298 vi_replace_map = rl_make_bare_keymap (); 1299 1300 for (i = ' '; i < KEYMAP_SIZE; i++) 1301 vi_replace_map[i].function = rl_vi_overstrike; 1302 1303 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; 1304 vi_replace_map[ESC].function = rl_vi_movement_mode; 1305 vi_replace_map[RETURN].function = rl_newline; 1306 vi_replace_map[NEWLINE].function = rl_newline; 1307 1308 /* If the normal vi insertion keymap has ^H bound to erase, do the 1309 same here. Probably should remove the assignment to RUBOUT up 1310 there, but I don't think it will make a difference in real life. */ 1311 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && 1312 vi_insertion_keymap[CTRL ('H')].function == rl_rubout) 1313 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; 1314 1315 } 1316 _rl_keymap = vi_replace_map; 1317 return (0); 1318} 1319 1320#if 0 1321/* Try to complete the word we are standing on or the word that ends with 1322 the previous character. A space matches everything. Word delimiters are 1323 space and ;. */ 1324int 1325rl_vi_possible_completions() 1326{ 1327 int save_pos = rl_point; 1328 1329 if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') 1330 { 1331 while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && 1332 rl_line_buffer[rl_point] != ';') 1333 rl_point++; 1334 } 1335 else if (rl_line_buffer[rl_point - 1] == ';') 1336 { 1337 rl_ding (); 1338 return (0); 1339 } 1340 1341 rl_possible_completions (); 1342 rl_point = save_pos; 1343 1344 return (0); 1345} 1346#endif 1347 1348/* Functions to save and restore marks. */ 1349int 1350rl_vi_set_mark (count, key) 1351 int count, key; 1352{ 1353 int ch; 1354 1355 RL_SETSTATE(RL_STATE_MOREINPUT); 1356 ch = rl_read_key (); 1357 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1358 1359 if (_rl_lowercase_p (ch) == 0) 1360 { 1361 rl_ding (); 1362 return -1; 1363 } 1364 ch -= 'a'; 1365 vi_mark_chars[ch] = rl_point; 1366 return 0; 1367} 1368 1369int 1370rl_vi_goto_mark (count, key) 1371 int count, key; 1372{ 1373 int ch; 1374 1375 RL_SETSTATE(RL_STATE_MOREINPUT); 1376 ch = rl_read_key (); 1377 RL_UNSETSTATE(RL_STATE_MOREINPUT); 1378 1379 if (ch == '`') 1380 { 1381 rl_point = rl_mark; 1382 return 0; 1383 } 1384 else if (_rl_lowercase_p (ch) == 0) 1385 { 1386 rl_ding (); 1387 return -1; 1388 } 1389 1390 ch -= 'a'; 1391 if (vi_mark_chars[ch] == -1) 1392 { 1393 rl_ding (); 1394 return -1; 1395 } 1396 rl_point = vi_mark_chars[ch]; 1397 return 0; 1398} 1399 1400#endif /* VI_MODE */ 1401