1 /* $NetBSD: vi.c,v 1.12 2002/11/15 14:32:34 christos 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.12 2002/11/15 14:32:34 christos 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 extern char *get_alias_text(const char *); 921 char alias_name[3]; 922 char *alias_text; 923 __weak_extern(get_alias_text); 924 925 if (get_alias_text == 0) { 926 return CC_ERROR; 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 } 938 939 /* vi_to_history_line(): 940 * Vi go to specified history file line. 941 * [G] 942 */ 943 protected el_action_t 944 /*ARGSUSED*/ 945 vi_to_history_line(EditLine *el, int c) 946 { 947 int sv_event_no = el->el_history.eventno; 948 el_action_t rval; 949 950 951 if (el->el_history.eventno == 0) { 952 (void) strncpy(el->el_history.buf, el->el_line.buffer, 953 EL_BUFSIZ); 954 el->el_history.last = el->el_history.buf + 955 (el->el_line.lastchar - el->el_line.buffer); 956 } 957 958 /* Lack of a 'count' means oldest, not 1 */ 959 if (!el->el_state.doingarg) { 960 el->el_history.eventno = 0x7fffffff; 961 hist_get(el); 962 } else { 963 /* This is brain dead, all the rest of this code counts 964 * upwards going into the past. Here we need count in the 965 * other direction (to match the output of fc -l). 966 * I could change the world, but this seems to suffice. 967 */ 968 el->el_history.eventno = 1; 969 if (hist_get(el) == CC_ERROR) 970 return CC_ERROR; 971 el->el_history.eventno = 1 + el->el_history.ev.num 972 - el->el_state.argument; 973 if (el->el_history.eventno < 0) { 974 el->el_history.eventno = sv_event_no; 975 return CC_ERROR; 976 } 977 } 978 rval = hist_get(el); 979 if (rval == CC_ERROR) 980 el->el_history.eventno = sv_event_no; 981 return rval; 982 } 983 984 /* vi_histedit(): 985 * Vi edit history line with vi 986 * [v] 987 */ 988 protected el_action_t 989 /*ARGSUSED*/ 990 vi_histedit(EditLine *el, int c) 991 { 992 int fd; 993 pid_t pid; 994 int st; 995 char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; 996 char *cp; 997 998 if (el->el_state.doingarg) { 999 if (vi_to_history_line(el, 0) == CC_ERROR) 1000 return CC_ERROR; 1001 } 1002 1003 fd = mkstemp(tempfile); 1004 if (fd < 0) 1005 return CC_ERROR; 1006 cp = el->el_line.buffer; 1007 write(fd, cp, el->el_line.lastchar - cp +0u); 1008 write(fd, "\n", 1); 1009 pid = fork(); 1010 switch (pid) { 1011 case -1: 1012 close(fd); 1013 unlink(tempfile); 1014 return CC_ERROR; 1015 case 0: 1016 close(fd); 1017 execlp("vi", "vi", tempfile, 0); 1018 exit(0); 1019 /*NOTREACHED*/ 1020 default: 1021 while (waitpid(pid, &st, 0) != pid) 1022 continue; 1023 lseek(fd, 0ll, SEEK_SET); 1024 st = read(fd, cp, el->el_line.limit - cp +0u); 1025 if (st > 0 && cp[st - 1] == '\n') 1026 st--; 1027 el->el_line.cursor = cp; 1028 el->el_line.lastchar = cp + st; 1029 break; 1030 } 1031 1032 close(fd); 1033 unlink(tempfile); 1034 /* return CC_REFRESH; */ 1035 return ed_newline(el, 0); 1036 } 1037 1038 /* vi_history_word(): 1039 * Vi append word from previous input line 1040 * [_] 1041 * Who knows where this one came from! 1042 * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' 1043 */ 1044 protected el_action_t 1045 /*ARGSUSED*/ 1046 vi_history_word(EditLine *el, int c) 1047 { 1048 const char *wp = HIST_FIRST(el); 1049 const char *wep, *wsp; 1050 int len; 1051 char *cp; 1052 const char *lim; 1053 1054 if (wp == NULL) 1055 return CC_ERROR; 1056 1057 wsp = 0; 1058 do { 1059 while (isspace((unsigned char)*wp)) 1060 wp++; 1061 if (*wp == 0) 1062 break; 1063 wsp = wp; 1064 while (*wp && !isspace((unsigned char)*wp)) 1065 wp++; 1066 wep = wp; 1067 } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0); 1068 1069 if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) 1070 return CC_ERROR; 1071 1072 cv_undo(el); 1073 len = wep - wsp; 1074 if (el->el_line.cursor < el->el_line.lastchar) 1075 el->el_line.cursor++; 1076 c_insert(el, len + 1); 1077 cp = el->el_line.cursor; 1078 lim = el->el_line.limit; 1079 if (cp < lim) 1080 *cp++ = ' '; 1081 while (wsp < wep && cp < lim) 1082 *cp++ = *wsp++; 1083 el->el_line.cursor = cp; 1084 1085 el->el_map.current = el->el_map.key; 1086 return CC_REFRESH; 1087 } 1088 1089 /* vi_redo(): 1090 * Vi redo last non-motion command 1091 * [.] 1092 */ 1093 protected el_action_t 1094 /*ARGSUSED*/ 1095 vi_redo(EditLine *el, int c) 1096 { 1097 c_redo_t *r = &el->el_chared.c_redo; 1098 1099 if (!el->el_state.doingarg && r->count) { 1100 el->el_state.doingarg = 1; 1101 el->el_state.argument = r->count; 1102 } 1103 1104 el->el_chared.c_vcmd.pos = el->el_line.cursor; 1105 el->el_chared.c_vcmd.action = r->action; 1106 if (r->pos != r->buf) { 1107 if (r->pos + 1 > r->lim) 1108 /* sanity */ 1109 r->pos = r->lim - 1; 1110 r->pos[0] = 0; 1111 el_push(el, r->buf); 1112 } 1113 1114 el->el_state.thiscmd = r->cmd; 1115 el->el_state.thisch = r->ch; 1116 return (*el->el_map.func[r->cmd])(el, r->ch); 1117 } 1118