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