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.24 2005/08/10 12:46:24 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: src/lib/libedit/vi.c,v 1.13 2005/08/10 13:38:01 stefanf Exp $"); 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 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 int len = 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", 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, 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 +0u); 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 */ 116el_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 */ 129el_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 */ 142el_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 */ 167el_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 */ 192el_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 */ 216el_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 */ 240el_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 */ 271el_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 */ 288el_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 */ 304el_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 */ 323el_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 */ 339el_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 */ 354el_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 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 */ 372el_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 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 */ 390el_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 */ 405el_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 */ 430el_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 */ 446el_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 */ 459el_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 */ 483el_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 */ 507el_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 = el->el_line.cursor - el->el_line.buffer; 520 el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); 521 el->el_line.buffer = un.buf; 522 el->el_line.cursor = un.buf + un.cursor; 523 el->el_line.lastchar = un.buf + un.len; 524 525 return (CC_REFRESH); 526} 527 528 529/* vi_command_mode(): 530 * Vi enter command mode (use alternative key bindings) 531 * [<ESC>] 532 */ 533el_action_t 534/*ARGSUSED*/ 535vi_command_mode(EditLine *el, int c __unused) 536{ 537 538 /* [Esc] cancels pending action */ 539 el->el_chared.c_vcmd.action = NOP; 540 el->el_chared.c_vcmd.pos = 0; 541 542 el->el_state.doingarg = 0; 543 544 el->el_state.inputmode = MODE_INSERT; 545 el->el_map.current = el->el_map.alt; 546#ifdef VI_MOVE 547 if (el->el_line.cursor > el->el_line.buffer) 548 el->el_line.cursor--; 549#endif 550 return (CC_CURSOR); 551} 552 553 554/* vi_zero(): 555 * Vi move to the beginning of line 556 * [0] 557 */ 558el_action_t 559vi_zero(EditLine *el, int c) 560{ 561 562 if (el->el_state.doingarg) 563 return ed_argument_digit(el, c); 564 565 el->el_line.cursor = el->el_line.buffer; 566 if (el->el_chared.c_vcmd.action != NOP) { 567 cv_delfini(el); 568 return (CC_REFRESH); 569 } 570 return (CC_CURSOR); 571} 572 573 574/* vi_delete_prev_char(): 575 * Vi move to previous character (backspace) 576 * [^H] in insert mode only 577 */ 578el_action_t 579/*ARGSUSED*/ 580vi_delete_prev_char(EditLine *el, int c __unused) 581{ 582 583 if (el->el_line.cursor <= el->el_line.buffer) 584 return (CC_ERROR); 585 586 c_delbefore1(el); 587 el->el_line.cursor--; 588 return (CC_REFRESH); 589} 590 591 592/* vi_list_or_eof(): 593 * Vi list choices for completion or indicate end of file if empty line 594 * [^D] 595 */ 596el_action_t 597/*ARGSUSED*/ 598vi_list_or_eof(EditLine *el, int c __unused) 599{ 600 601 if (el->el_line.cursor == el->el_line.lastchar) { 602 if (el->el_line.cursor == el->el_line.buffer) { 603 term_overwrite(el, STReof, 4); /* then do a EOF */ 604 term__flush(); 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 */ 634el_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, 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 */ 655el_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 */ 668el_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 */ 681el_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*/ 698el_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 */ 715el_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 */ 727el_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 */ 739el_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 */ 751el_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 */ 763el_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 */ 777el_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 */ 795el_action_t 796/*ARGSUSED*/ 797vi_match(EditLine *el, int c) 798{ 799 const char match_chars[] = "()[]{}"; 800 char *cp; 801 int 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 */ 842el_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 */ 856el_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 */ 870el_action_t 871/*ARGSUSED*/ 872vi_yank_end(EditLine *el, int c) 873{ 874 875 cv_yank(el, el->el_line.cursor, 876 el->el_line.lastchar - el->el_line.cursor); 877 return CC_REFRESH; 878} 879 880/* vi_yank(): 881 * Vi yank 882 * [y] 883 */ 884el_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 */ 896el_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 */ 914el_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 */ 946el_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 */ 991el_action_t 992/*ARGSUSED*/ 993vi_histedit(EditLine *el, int c) 994{ 995 int fd; 996 pid_t pid; 997 int st; 998 char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; 999 char *cp; 1000 1001 if (el->el_state.doingarg) { 1002 if (vi_to_history_line(el, 0) == CC_ERROR) 1003 return CC_ERROR; 1004 } 1005 1006 fd = mkstemp(tempfile); 1007 if (fd < 0) 1008 return CC_ERROR; 1009 cp = el->el_line.buffer; 1010 write(fd, cp, el->el_line.lastchar - cp +0u); 1011 write(fd, "\n", 1); 1012 pid = fork(); 1013 switch (pid) { 1014 case -1: 1015 close(fd); 1016 unlink(tempfile); 1017 return CC_ERROR; 1018 case 0: 1019 close(fd); 1020 execlp("vi", "vi", tempfile, NULL); 1021 exit(0); 1022 /*NOTREACHED*/ 1023 default: 1024 while (waitpid(pid, &st, 0) != pid) 1025 continue; 1026 lseek(fd, 0ll, SEEK_SET); 1027 st = read(fd, cp, el->el_line.limit - cp +0u); 1028 if (st > 0 && cp[st - 1] == '\n') 1029 st--; 1030 el->el_line.cursor = cp; 1031 el->el_line.lastchar = cp + st; 1032 break; 1033 } 1034 1035 close(fd); 1036 unlink(tempfile); 1037 /* return CC_REFRESH; */ 1038 return ed_newline(el, 0); 1039} 1040 1041/* vi_history_word(): 1042 * Vi append word from previous input line 1043 * [_] 1044 * Who knows where this one came from! 1045 * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' 1046 */ 1047el_action_t 1048/*ARGSUSED*/ 1049vi_history_word(EditLine *el, int c) 1050{ 1051 const char *wp = HIST_FIRST(el); 1052 const char *wep, *wsp; 1053 int len; 1054 char *cp; 1055 const char *lim; 1056 1057 if (wp == NULL) 1058 return CC_ERROR; 1059 1060 wep = wsp = 0; 1061 do { 1062 while (isspace((unsigned char)*wp)) 1063 wp++; 1064 if (*wp == 0) 1065 break; 1066 wsp = wp; 1067 while (*wp && !isspace((unsigned char)*wp)) 1068 wp++; 1069 wep = wp; 1070 } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0); 1071 1072 if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) 1073 return CC_ERROR; 1074 1075 cv_undo(el); 1076 len = wep - wsp; 1077 if (el->el_line.cursor < el->el_line.lastchar) 1078 el->el_line.cursor++; 1079 c_insert(el, len + 1); 1080 cp = el->el_line.cursor; 1081 lim = el->el_line.limit; 1082 if (cp < lim) 1083 *cp++ = ' '; 1084 while (wsp < wep && cp < lim) 1085 *cp++ = *wsp++; 1086 el->el_line.cursor = cp; 1087 1088 el->el_map.current = el->el_map.key; 1089 return CC_REFRESH; 1090} 1091 1092/* vi_redo(): 1093 * Vi redo last non-motion command 1094 * [.] 1095 */ 1096el_action_t 1097/*ARGSUSED*/ 1098vi_redo(EditLine *el, int c) 1099{ 1100 c_redo_t *r = &el->el_chared.c_redo; 1101 1102 if (!el->el_state.doingarg && r->count) { 1103 el->el_state.doingarg = 1; 1104 el->el_state.argument = r->count; 1105 } 1106 1107 el->el_chared.c_vcmd.pos = el->el_line.cursor; 1108 el->el_chared.c_vcmd.action = r->action; 1109 if (r->pos != r->buf) { 1110 if (r->pos + 1 > r->lim) 1111 /* sanity */ 1112 r->pos = r->lim - 1; 1113 r->pos[0] = 0; 1114 el_push(el, r->buf); 1115 } 1116 1117 el->el_state.thiscmd = r->cmd; 1118 el->el_state.thisch = r->ch; 1119 return (*el->el_map.func[r->cmd])(el, r->ch); 1120} 1121