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