vi.c revision 148834
1/*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Christos Zoulas of Cornell University. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $NetBSD: vi.c,v 1.21 2005/04/25 01:06:03 matt Exp $ 33 */ 34 35#if !defined(lint) && !defined(SCCSID) 36static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; 37#endif /* not lint && not SCCSID */ 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: head/lib/libedit/vi.c 148834 2005-08-07 20:55:59Z stefanf $"); 40 41/* 42 * vi.c: Vi mode commands. 43 */ 44#include <sys/wait.h> 45#include "sys.h" 46#include "el.h" 47 48private el_action_t cv_action(EditLine *, int); 49private el_action_t cv_paste(EditLine *, int); 50 51/* cv_action(): 52 * Handle vi actions. 53 */ 54private el_action_t 55cv_action(EditLine *el, int c) 56{ 57 58 if (el->el_chared.c_vcmd.action != NOP) { 59 /* 'cc', 'dd' and (possibly) friends */ 60 if (c != el->el_chared.c_vcmd.action) 61 return CC_ERROR; 62 63 if (!(c & YANK)) 64 cv_undo(el); 65 cv_yank(el, el->el_line.buffer, 66 el->el_line.lastchar - el->el_line.buffer); 67 el->el_chared.c_vcmd.action = NOP; 68 el->el_chared.c_vcmd.pos = 0; 69 el->el_line.lastchar = el->el_line.buffer; 70 el->el_line.cursor = el->el_line.buffer; 71 if (c & INSERT) 72 el->el_map.current = el->el_map.key; 73 74 return (CC_REFRESH); 75 } 76 el->el_chared.c_vcmd.pos = el->el_line.cursor; 77 el->el_chared.c_vcmd.action = c; 78 return (CC_ARGHACK); 79} 80 81/* cv_paste(): 82 * Paste previous deletion before or after the cursor 83 */ 84private el_action_t 85cv_paste(EditLine *el, int c) 86{ 87 char *ptr; 88 c_kill_t *k = &el->el_chared.c_kill; 89 int len = k->last - k->buf; 90 91 if (k->buf == NULL || len == 0) 92 return (CC_ERROR); 93#ifdef DEBUG_PASTE 94 (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", len, k->buf); 95#endif 96 97 cv_undo(el); 98 99 if (!c && el->el_line.cursor < el->el_line.lastchar) 100 el->el_line.cursor++; 101 ptr = el->el_line.cursor; 102 103 c_insert(el, len); 104 if (el->el_line.cursor + len > el->el_line.lastchar) 105 return (CC_ERROR); 106 (void) memcpy(ptr, k->buf, len +0u); 107 return (CC_REFRESH); 108} 109 110 111/* vi_paste_next(): 112 * Vi paste previous deletion to the right of the cursor 113 * [p] 114 */ 115protected el_action_t 116/*ARGSUSED*/ 117vi_paste_next(EditLine *el, int c __unused) 118{ 119 120 return (cv_paste(el, 0)); 121} 122 123 124/* vi_paste_prev(): 125 * Vi paste previous deletion to the left of the cursor 126 * [P] 127 */ 128protected el_action_t 129/*ARGSUSED*/ 130vi_paste_prev(EditLine *el, int c __unused) 131{ 132 133 return (cv_paste(el, 1)); 134} 135 136 137/* vi_prev_big_word(): 138 * Vi move to the previous space delimited word 139 * [B] 140 */ 141protected el_action_t 142/*ARGSUSED*/ 143vi_prev_big_word(EditLine *el, int c) 144{ 145 146 if (el->el_line.cursor == el->el_line.buffer) 147 return (CC_ERROR); 148 149 el->el_line.cursor = cv_prev_word(el->el_line.cursor, 150 el->el_line.buffer, 151 el->el_state.argument, 152 cv__isWord); 153 154 if (el->el_chared.c_vcmd.action != NOP) { 155 cv_delfini(el); 156 return (CC_REFRESH); 157 } 158 return (CC_CURSOR); 159} 160 161 162/* vi_prev_word(): 163 * Vi move to the previous word 164 * [b] 165 */ 166protected el_action_t 167/*ARGSUSED*/ 168vi_prev_word(EditLine *el, int c __unused) 169{ 170 171 if (el->el_line.cursor == el->el_line.buffer) 172 return (CC_ERROR); 173 174 el->el_line.cursor = cv_prev_word(el->el_line.cursor, 175 el->el_line.buffer, 176 el->el_state.argument, 177 cv__isword); 178 179 if (el->el_chared.c_vcmd.action != NOP) { 180 cv_delfini(el); 181 return (CC_REFRESH); 182 } 183 return (CC_CURSOR); 184} 185 186 187/* vi_next_big_word(): 188 * Vi move to the next space delimited word 189 * [W] 190 */ 191protected el_action_t 192/*ARGSUSED*/ 193vi_next_big_word(EditLine *el, int c) 194{ 195 196 if (el->el_line.cursor >= el->el_line.lastchar - 1) 197 return (CC_ERROR); 198 199 el->el_line.cursor = cv_next_word(el, el->el_line.cursor, 200 el->el_line.lastchar, el->el_state.argument, cv__isWord); 201 202 if (el->el_map.type == MAP_VI) 203 if (el->el_chared.c_vcmd.action != NOP) { 204 cv_delfini(el); 205 return (CC_REFRESH); 206 } 207 return (CC_CURSOR); 208} 209 210 211/* vi_next_word(): 212 * Vi move to the next word 213 * [w] 214 */ 215protected el_action_t 216/*ARGSUSED*/ 217vi_next_word(EditLine *el, int c __unused) 218{ 219 220 if (el->el_line.cursor >= el->el_line.lastchar - 1) 221 return (CC_ERROR); 222 223 el->el_line.cursor = cv_next_word(el, el->el_line.cursor, 224 el->el_line.lastchar, el->el_state.argument, cv__isword); 225 226 if (el->el_map.type == MAP_VI) 227 if (el->el_chared.c_vcmd.action != NOP) { 228 cv_delfini(el); 229 return (CC_REFRESH); 230 } 231 return (CC_CURSOR); 232} 233 234 235/* vi_change_case(): 236 * Vi change case of character under the cursor and advance one character 237 * [~] 238 */ 239protected el_action_t 240vi_change_case(EditLine *el, int c) 241{ 242 int i; 243 244 if (el->el_line.cursor >= el->el_line.lastchar) 245 return (CC_ERROR); 246 cv_undo(el); 247 for (i = 0; i < el->el_state.argument; i++) { 248 249 c = *(unsigned char *)el->el_line.cursor; 250 if (isupper(c)) 251 *el->el_line.cursor = tolower(c); 252 else if (islower(c)) 253 *el->el_line.cursor = toupper(c); 254 255 if (++el->el_line.cursor >= el->el_line.lastchar) { 256 el->el_line.cursor--; 257 re_fastaddc(el); 258 break; 259 } 260 re_fastaddc(el); 261 } 262 return CC_NORM; 263} 264 265 266/* vi_change_meta(): 267 * Vi change prefix command 268 * [c] 269 */ 270protected el_action_t 271/*ARGSUSED*/ 272vi_change_meta(EditLine *el, int c __unused) 273{ 274 275 /* 276 * Delete with insert == change: first we delete and then we leave in 277 * insert mode. 278 */ 279 return (cv_action(el, DELETE | INSERT)); 280} 281 282 283/* vi_insert_at_bol(): 284 * Vi enter insert mode at the beginning of line 285 * [I] 286 */ 287protected el_action_t 288/*ARGSUSED*/ 289vi_insert_at_bol(EditLine *el, int c __unused) 290{ 291 292 el->el_line.cursor = el->el_line.buffer; 293 cv_undo(el); 294 el->el_map.current = el->el_map.key; 295 return (CC_CURSOR); 296} 297 298 299/* vi_replace_char(): 300 * Vi replace character under the cursor with the next character typed 301 * [r] 302 */ 303protected el_action_t 304/*ARGSUSED*/ 305vi_replace_char(EditLine *el, int c __unused) 306{ 307 308 if (el->el_line.cursor >= el->el_line.lastchar) 309 return CC_ERROR; 310 311 el->el_map.current = el->el_map.key; 312 el->el_state.inputmode = MODE_REPLACE_1; 313 cv_undo(el); 314 return (CC_ARGHACK); 315} 316 317 318/* vi_replace_mode(): 319 * Vi enter replace mode 320 * [R] 321 */ 322protected el_action_t 323/*ARGSUSED*/ 324vi_replace_mode(EditLine *el, int c __unused) 325{ 326 327 el->el_map.current = el->el_map.key; 328 el->el_state.inputmode = MODE_REPLACE; 329 cv_undo(el); 330 return (CC_NORM); 331} 332 333 334/* vi_substitute_char(): 335 * Vi replace character under the cursor and enter insert mode 336 * [s] 337 */ 338protected el_action_t 339/*ARGSUSED*/ 340vi_substitute_char(EditLine *el, int c __unused) 341{ 342 343 c_delafter(el, el->el_state.argument); 344 el->el_map.current = el->el_map.key; 345 return (CC_REFRESH); 346} 347 348 349/* vi_substitute_line(): 350 * Vi substitute entire line 351 * [S] 352 */ 353protected el_action_t 354/*ARGSUSED*/ 355vi_substitute_line(EditLine *el, int c __unused) 356{ 357 358 cv_undo(el); 359 cv_yank(el, el->el_line.buffer, 360 el->el_line.lastchar - el->el_line.buffer); 361 (void) em_kill_line(el, 0); 362 el->el_map.current = el->el_map.key; 363 return (CC_REFRESH); 364} 365 366 367/* vi_change_to_eol(): 368 * Vi change to end of line 369 * [C] 370 */ 371protected el_action_t 372/*ARGSUSED*/ 373vi_change_to_eol(EditLine *el, int c __unused) 374{ 375 376 cv_undo(el); 377 cv_yank(el, el->el_line.cursor, 378 el->el_line.lastchar - el->el_line.cursor); 379 (void) ed_kill_line(el, 0); 380 el->el_map.current = el->el_map.key; 381 return (CC_REFRESH); 382} 383 384 385/* vi_insert(): 386 * Vi enter insert mode 387 * [i] 388 */ 389protected el_action_t 390/*ARGSUSED*/ 391vi_insert(EditLine *el, int c __unused) 392{ 393 394 el->el_map.current = el->el_map.key; 395 cv_undo(el); 396 return (CC_NORM); 397} 398 399 400/* vi_add(): 401 * Vi enter insert mode after the cursor 402 * [a] 403 */ 404protected el_action_t 405/*ARGSUSED*/ 406vi_add(EditLine *el, int c __unused) 407{ 408 int ret; 409 410 el->el_map.current = el->el_map.key; 411 if (el->el_line.cursor < el->el_line.lastchar) { 412 el->el_line.cursor++; 413 if (el->el_line.cursor > el->el_line.lastchar) 414 el->el_line.cursor = el->el_line.lastchar; 415 ret = CC_CURSOR; 416 } else 417 ret = CC_NORM; 418 419 cv_undo(el); 420 421 return (ret); 422} 423 424 425/* vi_add_at_eol(): 426 * Vi enter insert mode at end of line 427 * [A] 428 */ 429protected el_action_t 430/*ARGSUSED*/ 431vi_add_at_eol(EditLine *el, int c __unused) 432{ 433 434 el->el_map.current = el->el_map.key; 435 el->el_line.cursor = el->el_line.lastchar; 436 cv_undo(el); 437 return (CC_CURSOR); 438} 439 440 441/* vi_delete_meta(): 442 * Vi delete prefix command 443 * [d] 444 */ 445protected el_action_t 446/*ARGSUSED*/ 447vi_delete_meta(EditLine *el, int c __unused) 448{ 449 450 return (cv_action(el, DELETE)); 451} 452 453 454/* vi_end_big_word(): 455 * Vi move to the end of the current space delimited word 456 * [E] 457 */ 458protected el_action_t 459/*ARGSUSED*/ 460vi_end_big_word(EditLine *el, int c) 461{ 462 463 if (el->el_line.cursor == el->el_line.lastchar) 464 return (CC_ERROR); 465 466 el->el_line.cursor = cv__endword(el->el_line.cursor, 467 el->el_line.lastchar, el->el_state.argument, cv__isWord); 468 469 if (el->el_chared.c_vcmd.action != NOP) { 470 el->el_line.cursor++; 471 cv_delfini(el); 472 return (CC_REFRESH); 473 } 474 return (CC_CURSOR); 475} 476 477 478/* vi_end_word(): 479 * Vi move to the end of the current word 480 * [e] 481 */ 482protected el_action_t 483/*ARGSUSED*/ 484vi_end_word(EditLine *el, int c __unused) 485{ 486 487 if (el->el_line.cursor == el->el_line.lastchar) 488 return (CC_ERROR); 489 490 el->el_line.cursor = cv__endword(el->el_line.cursor, 491 el->el_line.lastchar, el->el_state.argument, cv__isword); 492 493 if (el->el_chared.c_vcmd.action != NOP) { 494 el->el_line.cursor++; 495 cv_delfini(el); 496 return (CC_REFRESH); 497 } 498 return (CC_CURSOR); 499} 500 501 502/* vi_undo(): 503 * Vi undo last change 504 * [u] 505 */ 506protected el_action_t 507/*ARGSUSED*/ 508vi_undo(EditLine *el, int c __unused) 509{ 510 c_undo_t un = el->el_chared.c_undo; 511 512 if (un.len == -1) 513 return CC_ERROR; 514 515 /* switch line buffer and undo buffer */ 516 el->el_chared.c_undo.buf = el->el_line.buffer; 517 el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; 518 el->el_chared.c_undo.cursor = el->el_line.cursor - el->el_line.buffer; 519 el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); 520 el->el_line.buffer = un.buf; 521 el->el_line.cursor = un.buf + un.cursor; 522 el->el_line.lastchar = un.buf + un.len; 523 524 return (CC_REFRESH); 525} 526 527 528/* vi_command_mode(): 529 * Vi enter command mode (use alternative key bindings) 530 * [<ESC>] 531 */ 532protected el_action_t 533/*ARGSUSED*/ 534vi_command_mode(EditLine *el, int c __unused) 535{ 536 537 /* [Esc] cancels pending action */ 538 el->el_chared.c_vcmd.action = NOP; 539 el->el_chared.c_vcmd.pos = 0; 540 541 el->el_state.doingarg = 0; 542 543 el->el_state.inputmode = MODE_INSERT; 544 el->el_map.current = el->el_map.alt; 545#ifdef VI_MOVE 546 if (el->el_line.cursor > el->el_line.buffer) 547 el->el_line.cursor--; 548#endif 549 return (CC_CURSOR); 550} 551 552 553/* vi_zero(): 554 * Vi move to the beginning of line 555 * [0] 556 */ 557protected el_action_t 558vi_zero(EditLine *el, int c) 559{ 560 561 if (el->el_state.doingarg) 562 return ed_argument_digit(el, c); 563 564 el->el_line.cursor = el->el_line.buffer; 565 if (el->el_chared.c_vcmd.action != NOP) { 566 cv_delfini(el); 567 return (CC_REFRESH); 568 } 569 return (CC_CURSOR); 570} 571 572 573/* vi_delete_prev_char(): 574 * Vi move to previous character (backspace) 575 * [^H] in insert mode only 576 */ 577protected el_action_t 578/*ARGSUSED*/ 579vi_delete_prev_char(EditLine *el, int c __unused) 580{ 581 582 if (el->el_line.cursor <= el->el_line.buffer) 583 return (CC_ERROR); 584 585 c_delbefore1(el); 586 el->el_line.cursor--; 587 return (CC_REFRESH); 588} 589 590 591/* vi_list_or_eof(): 592 * Vi list choices for completion or indicate end of file if empty line 593 * [^D] 594 */ 595protected el_action_t 596/*ARGSUSED*/ 597vi_list_or_eof(EditLine *el, int c __unused) 598{ 599 600 if (el->el_line.cursor == el->el_line.lastchar) { 601 if (el->el_line.cursor == el->el_line.buffer) { 602 term_overwrite(el, STReof, 4); /* then do a EOF */ 603 term__flush(); 604 return (CC_EOF); 605 } else { 606 /* 607 * Here we could list completions, but it is an 608 * error right now 609 */ 610 term_beep(el); 611 return (CC_ERROR); 612 } 613 } else { 614#ifdef notyet 615 re_goto_bottom(el); 616 *el->el_line.lastchar = '\0'; /* just in case */ 617 return (CC_LIST_CHOICES); 618#else 619 /* 620 * Just complain for now. 621 */ 622 term_beep(el); 623 return (CC_ERROR); 624#endif 625 } 626} 627 628 629/* vi_kill_line_prev(): 630 * Vi cut from beginning of line to cursor 631 * [^U] 632 */ 633protected el_action_t 634/*ARGSUSED*/ 635vi_kill_line_prev(EditLine *el, int c __unused) 636{ 637 char *kp, *cp; 638 639 cp = el->el_line.buffer; 640 kp = el->el_chared.c_kill.buf; 641 while (cp < el->el_line.cursor) 642 *kp++ = *cp++; /* copy it */ 643 el->el_chared.c_kill.last = kp; 644 c_delbefore(el, el->el_line.cursor - el->el_line.buffer); 645 el->el_line.cursor = el->el_line.buffer; /* zap! */ 646 return (CC_REFRESH); 647} 648 649 650/* vi_search_prev(): 651 * Vi search history previous 652 * [?] 653 */ 654protected el_action_t 655/*ARGSUSED*/ 656vi_search_prev(EditLine *el, int c __unused) 657{ 658 659 return (cv_search(el, ED_SEARCH_PREV_HISTORY)); 660} 661 662 663/* vi_search_next(): 664 * Vi search history next 665 * [/] 666 */ 667protected el_action_t 668/*ARGSUSED*/ 669vi_search_next(EditLine *el, int c __unused) 670{ 671 672 return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); 673} 674 675 676/* vi_repeat_search_next(): 677 * Vi repeat current search in the same search direction 678 * [n] 679 */ 680protected el_action_t 681/*ARGSUSED*/ 682vi_repeat_search_next(EditLine *el, int c __unused) 683{ 684 685 if (el->el_search.patlen == 0) 686 return (CC_ERROR); 687 else 688 return (cv_repeat_srch(el, el->el_search.patdir)); 689} 690 691 692/* vi_repeat_search_prev(): 693 * Vi repeat current search in the opposite search direction 694 * [N] 695 */ 696/*ARGSUSED*/ 697protected el_action_t 698vi_repeat_search_prev(EditLine *el, int c __unused) 699{ 700 701 if (el->el_search.patlen == 0) 702 return (CC_ERROR); 703 else 704 return (cv_repeat_srch(el, 705 el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? 706 ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); 707} 708 709 710/* vi_next_char(): 711 * Vi move to the character specified next 712 * [f] 713 */ 714protected el_action_t 715/*ARGSUSED*/ 716vi_next_char(EditLine *el, int c __unused) 717{ 718 return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); 719} 720 721 722/* vi_prev_char(): 723 * Vi move to the character specified previous 724 * [F] 725 */ 726protected el_action_t 727/*ARGSUSED*/ 728vi_prev_char(EditLine *el, int c __unused) 729{ 730 return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); 731} 732 733 734/* vi_to_next_char(): 735 * Vi move up to the character specified next 736 * [t] 737 */ 738protected el_action_t 739/*ARGSUSED*/ 740vi_to_next_char(EditLine *el, int c __unused) 741{ 742 return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); 743} 744 745 746/* vi_to_prev_char(): 747 * Vi move up to the character specified previous 748 * [T] 749 */ 750protected el_action_t 751/*ARGSUSED*/ 752vi_to_prev_char(EditLine *el, int c __unused) 753{ 754 return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); 755} 756 757 758/* vi_repeat_next_char(): 759 * Vi repeat current character search in the same search direction 760 * [;] 761 */ 762protected el_action_t 763/*ARGSUSED*/ 764vi_repeat_next_char(EditLine *el, int c __unused) 765{ 766 767 return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, 768 el->el_state.argument, el->el_search.chatflg); 769} 770 771 772/* vi_repeat_prev_char(): 773 * Vi repeat current character search in the opposite search direction 774 * [,] 775 */ 776protected el_action_t 777/*ARGSUSED*/ 778vi_repeat_prev_char(EditLine *el, int c __unused) 779{ 780 el_action_t r; 781 int dir = el->el_search.chadir; 782 783 r = cv_csearch(el, -dir, el->el_search.chacha, 784 el->el_state.argument, el->el_search.chatflg); 785 el->el_search.chadir = dir; 786 return r; 787} 788 789 790/* vi_match(): 791 * Vi go to matching () {} or [] 792 * [%] 793 */ 794protected el_action_t 795/*ARGSUSED*/ 796vi_match(EditLine *el, int c) 797{ 798 const char match_chars[] = "()[]{}"; 799 char *cp; 800 int delta, i, count; 801 char o_ch, c_ch; 802 803 *el->el_line.lastchar = '\0'; /* just in case */ 804 805 i = strcspn(el->el_line.cursor, match_chars); 806 o_ch = el->el_line.cursor[i]; 807 if (o_ch == 0) 808 return CC_ERROR; 809 delta = strchr(match_chars, o_ch) - match_chars; 810 c_ch = match_chars[delta ^ 1]; 811 count = 1; 812 delta = 1 - (delta & 1) * 2; 813 814 for (cp = &el->el_line.cursor[i]; count; ) { 815 cp += delta; 816 if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) 817 return CC_ERROR; 818 if (*cp == o_ch) 819 count++; 820 else if (*cp == c_ch) 821 count--; 822 } 823 824 el->el_line.cursor = cp; 825 826 if (el->el_chared.c_vcmd.action != NOP) { 827 /* NB posix says char under cursor should NOT be deleted 828 for -ve delta - this is different to netbsd vi. */ 829 if (delta > 0) 830 el->el_line.cursor++; 831 cv_delfini(el); 832 return (CC_REFRESH); 833 } 834 return (CC_CURSOR); 835} 836 837/* vi_undo_line(): 838 * Vi undo all changes to line 839 * [U] 840 */ 841protected el_action_t 842/*ARGSUSED*/ 843vi_undo_line(EditLine *el, int c) 844{ 845 846 cv_undo(el); 847 return hist_get(el); 848} 849 850/* vi_to_column(): 851 * Vi go to specified column 852 * [|] 853 * NB netbsd vi goes to screen column 'n', posix says nth character 854 */ 855protected el_action_t 856/*ARGSUSED*/ 857vi_to_column(EditLine *el, int c) 858{ 859 860 el->el_line.cursor = el->el_line.buffer; 861 el->el_state.argument--; 862 return ed_next_char(el, 0); 863} 864 865/* vi_yank_end(): 866 * Vi yank to end of line 867 * [Y] 868 */ 869protected el_action_t 870/*ARGSUSED*/ 871vi_yank_end(EditLine *el, int c) 872{ 873 874 cv_yank(el, el->el_line.cursor, 875 el->el_line.lastchar - el->el_line.cursor); 876 return CC_REFRESH; 877} 878 879/* vi_yank(): 880 * Vi yank 881 * [y] 882 */ 883protected el_action_t 884/*ARGSUSED*/ 885vi_yank(EditLine *el, int c) 886{ 887 888 return cv_action(el, YANK); 889} 890 891/* vi_comment_out(): 892 * Vi comment out current command 893 * [c] 894 */ 895protected el_action_t 896/*ARGSUSED*/ 897vi_comment_out(EditLine *el, int c) 898{ 899 900 el->el_line.cursor = el->el_line.buffer; 901 c_insert(el, 1); 902 *el->el_line.cursor = '#'; 903 re_refresh(el); 904 return ed_newline(el, 0); 905} 906 907/* vi_alias(): 908 * Vi include shell alias 909 * [@] 910 * NB: posix impiles that we should enter insert mode, however 911 * this is against historical precedent... 912 */ 913protected el_action_t 914/*ARGSUSED*/ 915vi_alias(EditLine *el, int c) 916{ 917#ifdef __weak_extern 918 char alias_name[3]; 919 char *alias_text; 920 extern char *get_alias_text(const char *); 921 __weak_extern(get_alias_text); 922 923 if (get_alias_text == 0) { 924 return CC_ERROR; 925 } 926 927 alias_name[0] = '_'; 928 alias_name[2] = 0; 929 if (el_getc(el, &alias_name[1]) != 1) 930 return CC_ERROR; 931 932 alias_text = get_alias_text(alias_name); 933 if (alias_text != NULL) 934 el_push(el, alias_text); 935 return CC_NORM; 936#else 937 return CC_ERROR; 938#endif 939} 940 941/* vi_to_history_line(): 942 * Vi go to specified history file line. 943 * [G] 944 */ 945protected el_action_t 946/*ARGSUSED*/ 947vi_to_history_line(EditLine *el, int c) 948{ 949 int sv_event_no = el->el_history.eventno; 950 el_action_t rval; 951 952 953 if (el->el_history.eventno == 0) { 954 (void) strncpy(el->el_history.buf, el->el_line.buffer, 955 EL_BUFSIZ); 956 el->el_history.last = el->el_history.buf + 957 (el->el_line.lastchar - el->el_line.buffer); 958 } 959 960 /* Lack of a 'count' means oldest, not 1 */ 961 if (!el->el_state.doingarg) { 962 el->el_history.eventno = 0x7fffffff; 963 hist_get(el); 964 } else { 965 /* This is brain dead, all the rest of this code counts 966 * upwards going into the past. Here we need count in the 967 * other direction (to match the output of fc -l). 968 * I could change the world, but this seems to suffice. 969 */ 970 el->el_history.eventno = 1; 971 if (hist_get(el) == CC_ERROR) 972 return CC_ERROR; 973 el->el_history.eventno = 1 + el->el_history.ev.num 974 - el->el_state.argument; 975 if (el->el_history.eventno < 0) { 976 el->el_history.eventno = sv_event_no; 977 return CC_ERROR; 978 } 979 } 980 rval = hist_get(el); 981 if (rval == CC_ERROR) 982 el->el_history.eventno = sv_event_no; 983 return rval; 984} 985 986/* vi_histedit(): 987 * Vi edit history line with vi 988 * [v] 989 */ 990protected el_action_t 991/*ARGSUSED*/ 992vi_histedit(EditLine *el, int c) 993{ 994 int fd; 995 pid_t pid; 996 int st; 997 char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; 998 char *cp; 999 1000 if (el->el_state.doingarg) { 1001 if (vi_to_history_line(el, 0) == CC_ERROR) 1002 return CC_ERROR; 1003 } 1004 1005 fd = mkstemp(tempfile); 1006 if (fd < 0) 1007 return CC_ERROR; 1008 cp = el->el_line.buffer; 1009 write(fd, cp, el->el_line.lastchar - cp +0u); 1010 write(fd, "\n", 1); 1011 pid = fork(); 1012 switch (pid) { 1013 case -1: 1014 close(fd); 1015 unlink(tempfile); 1016 return CC_ERROR; 1017 case 0: 1018 close(fd); 1019 execlp("vi", "vi", tempfile, NULL); 1020 exit(0); 1021 /*NOTREACHED*/ 1022 default: 1023 while (waitpid(pid, &st, 0) != pid) 1024 continue; 1025 lseek(fd, 0ll, SEEK_SET); 1026 st = read(fd, cp, el->el_line.limit - cp +0u); 1027 if (st > 0 && cp[st - 1] == '\n') 1028 st--; 1029 el->el_line.cursor = cp; 1030 el->el_line.lastchar = cp + st; 1031 break; 1032 } 1033 1034 close(fd); 1035 unlink(tempfile); 1036 /* return CC_REFRESH; */ 1037 return ed_newline(el, 0); 1038} 1039 1040/* vi_history_word(): 1041 * Vi append word from previous input line 1042 * [_] 1043 * Who knows where this one came from! 1044 * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' 1045 */ 1046protected el_action_t 1047/*ARGSUSED*/ 1048vi_history_word(EditLine *el, int c) 1049{ 1050 const char *wp = HIST_FIRST(el); 1051 const char *wep, *wsp; 1052 int len; 1053 char *cp; 1054 const char *lim; 1055 1056 if (wp == NULL) 1057 return CC_ERROR; 1058 1059 wep = wsp = 0; 1060 do { 1061 while (isspace((unsigned char)*wp)) 1062 wp++; 1063 if (*wp == 0) 1064 break; 1065 wsp = wp; 1066 while (*wp && !isspace((unsigned char)*wp)) 1067 wp++; 1068 wep = wp; 1069 } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0); 1070 1071 if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) 1072 return CC_ERROR; 1073 1074 cv_undo(el); 1075 len = wep - wsp; 1076 if (el->el_line.cursor < el->el_line.lastchar) 1077 el->el_line.cursor++; 1078 c_insert(el, len + 1); 1079 cp = el->el_line.cursor; 1080 lim = el->el_line.limit; 1081 if (cp < lim) 1082 *cp++ = ' '; 1083 while (wsp < wep && cp < lim) 1084 *cp++ = *wsp++; 1085 el->el_line.cursor = cp; 1086 1087 el->el_map.current = el->el_map.key; 1088 return CC_REFRESH; 1089} 1090 1091/* vi_redo(): 1092 * Vi redo last non-motion command 1093 * [.] 1094 */ 1095protected el_action_t 1096/*ARGSUSED*/ 1097vi_redo(EditLine *el, int c) 1098{ 1099 c_redo_t *r = &el->el_chared.c_redo; 1100 1101 if (!el->el_state.doingarg && r->count) { 1102 el->el_state.doingarg = 1; 1103 el->el_state.argument = r->count; 1104 } 1105 1106 el->el_chared.c_vcmd.pos = el->el_line.cursor; 1107 el->el_chared.c_vcmd.action = r->action; 1108 if (r->pos != r->buf) { 1109 if (r->pos + 1 > r->lim) 1110 /* sanity */ 1111 r->pos = r->lim - 1; 1112 r->pos[0] = 0; 1113 el_push(el, r->buf); 1114 } 1115 1116 el->el_state.thiscmd = r->cmd; 1117 el->el_state.thisch = r->ch; 1118 return (*el->el_map.func[r->cmd])(el, r->ch); 1119} 1120