1 /* $NetBSD: vi.c,v 1.18 2003/06/19 15:55:06 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.18 2003/06/19 15:55:06 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 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 __attribute__((__unused__))) 613 { 614 615 if (el->el_line.cursor == el->el_line.lastchar) { 616 if (el->el_line.cursor == el->el_line.buffer) { 617 term_overwrite(el, STReof, 4); /* then do a EOF */ 618 term__flush(); 619 return (CC_EOF); 620 } else { 621 /* 622 * Here we could list completions, but it is an 623 * error right now 624 */ 625 term_beep(el); 626 return (CC_ERROR); 627 } 628 } else { 629 #ifdef notyet 630 re_goto_bottom(el); 631 *el->el_line.lastchar = '\0'; /* just in case */ 632 return (CC_LIST_CHOICES); 633 #else 634 /* 635 * Just complain for now. 636 */ 637 term_beep(el); 638 return (CC_ERROR); 639 #endif 640 } 641 } 642 643 644 /* vi_kill_line_prev(): 645 * Vi cut from beginning of line to cursor 646 * [^U] 647 */ 648 protected el_action_t 649 /*ARGSUSED*/ 650 vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__))) 651 { 652 char *kp, *cp; 653 654 cp = el->el_line.buffer; 655 kp = el->el_chared.c_kill.buf; 656 while (cp < el->el_line.cursor) 657 *kp++ = *cp++; /* copy it */ 658 el->el_chared.c_kill.last = kp; 659 c_delbefore(el, el->el_line.cursor - el->el_line.buffer); 660 el->el_line.cursor = el->el_line.buffer; /* zap! */ 661 return (CC_REFRESH); 662 } 663 664 665 /* vi_search_prev(): 666 * Vi search history previous 667 * [?] 668 */ 669 protected el_action_t 670 /*ARGSUSED*/ 671 vi_search_prev(EditLine *el, int c __attribute__((__unused__))) 672 { 673 674 return (cv_search(el, ED_SEARCH_PREV_HISTORY)); 675 } 676 677 678 /* vi_search_next(): 679 * Vi search history next 680 * [/] 681 */ 682 protected el_action_t 683 /*ARGSUSED*/ 684 vi_search_next(EditLine *el, int c __attribute__((__unused__))) 685 { 686 687 return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); 688 } 689 690 691 /* vi_repeat_search_next(): 692 * Vi repeat current search in the same search direction 693 * [n] 694 */ 695 protected el_action_t 696 /*ARGSUSED*/ 697 vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__))) 698 { 699 700 if (el->el_search.patlen == 0) 701 return (CC_ERROR); 702 else 703 return (cv_repeat_srch(el, el->el_search.patdir)); 704 } 705 706 707 /* vi_repeat_search_prev(): 708 * Vi repeat current search in the opposite search direction 709 * [N] 710 */ 711 /*ARGSUSED*/ 712 protected el_action_t 713 vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__))) 714 { 715 716 if (el->el_search.patlen == 0) 717 return (CC_ERROR); 718 else 719 return (cv_repeat_srch(el, 720 el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? 721 ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); 722 } 723 724 725 /* vi_next_char(): 726 * Vi move to the character specified next 727 * [f] 728 */ 729 protected el_action_t 730 /*ARGSUSED*/ 731 vi_next_char(EditLine *el, int c __attribute__((__unused__))) 732 { 733 return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); 734 } 735 736 737 /* vi_prev_char(): 738 * Vi move to the character specified previous 739 * [F] 740 */ 741 protected el_action_t 742 /*ARGSUSED*/ 743 vi_prev_char(EditLine *el, int c __attribute__((__unused__))) 744 { 745 return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); 746 } 747 748 749 /* vi_to_next_char(): 750 * Vi move up to the character specified next 751 * [t] 752 */ 753 protected el_action_t 754 /*ARGSUSED*/ 755 vi_to_next_char(EditLine *el, int c __attribute__((__unused__))) 756 { 757 return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); 758 } 759 760 761 /* vi_to_prev_char(): 762 * Vi move up to the character specified previous 763 * [T] 764 */ 765 protected el_action_t 766 /*ARGSUSED*/ 767 vi_to_prev_char(EditLine *el, int c __attribute__((__unused__))) 768 { 769 return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); 770 } 771 772 773 /* vi_repeat_next_char(): 774 * Vi repeat current character search in the same search direction 775 * [;] 776 */ 777 protected el_action_t 778 /*ARGSUSED*/ 779 vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__))) 780 { 781 782 return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, 783 el->el_state.argument, el->el_search.chatflg); 784 } 785 786 787 /* vi_repeat_prev_char(): 788 * Vi repeat current character search in the opposite search direction 789 * [,] 790 */ 791 protected el_action_t 792 /*ARGSUSED*/ 793 vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__))) 794 { 795 el_action_t r; 796 int dir = el->el_search.chadir; 797 798 r = cv_csearch(el, -dir, el->el_search.chacha, 799 el->el_state.argument, el->el_search.chatflg); 800 el->el_search.chadir = dir; 801 return r; 802 } 803 804 805 /* vi_match(): 806 * Vi go to matching () {} or [] 807 * [%] 808 */ 809 protected el_action_t 810 /*ARGSUSED*/ 811 vi_match(EditLine *el, int c) 812 { 813 const char match_chars[] = "()[]{}"; 814 char *cp; 815 int delta, i, count; 816 char o_ch, c_ch; 817 818 *el->el_line.lastchar = '\0'; /* just in case */ 819 820 i = strcspn(el->el_line.cursor, match_chars); 821 o_ch = el->el_line.cursor[i]; 822 if (o_ch == 0) 823 return CC_ERROR; 824 delta = strchr(match_chars, o_ch) - match_chars; 825 c_ch = match_chars[delta ^ 1]; 826 count = 1; 827 delta = 1 - (delta & 1) * 2; 828 829 for (cp = &el->el_line.cursor[i]; count; ) { 830 cp += delta; 831 if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) 832 return CC_ERROR; 833 if (*cp == o_ch) 834 count++; 835 else if (*cp == c_ch) 836 count--; 837 } 838 839 el->el_line.cursor = cp; 840 841 if (el->el_chared.c_vcmd.action != NOP) { 842 /* NB posix says char under cursor should NOT be deleted 843 for -ve delta - this is different to netbsd vi. */ 844 if (delta > 0) 845 el->el_line.cursor++; 846 cv_delfini(el); 847 return (CC_REFRESH); 848 } 849 return (CC_CURSOR); 850 } 851 852 /* vi_undo_line(): 853 * Vi undo all changes to line 854 * [U] 855 */ 856 protected el_action_t 857 /*ARGSUSED*/ 858 vi_undo_line(EditLine *el, int c) 859 { 860 861 cv_undo(el); 862 return hist_get(el); 863 } 864 865 /* vi_to_column(): 866 * Vi go to specified column 867 * [|] 868 * NB netbsd vi goes to screen column 'n', posix says nth character 869 */ 870 protected el_action_t 871 /*ARGSUSED*/ 872 vi_to_column(EditLine *el, int c) 873 { 874 875 el->el_line.cursor = el->el_line.buffer; 876 el->el_state.argument--; 877 return ed_next_char(el, 0); 878 } 879 880 /* vi_yank_end(): 881 * Vi yank to end of line 882 * [Y] 883 */ 884 protected el_action_t 885 /*ARGSUSED*/ 886 vi_yank_end(EditLine *el, int c) 887 { 888 889 cv_yank(el, el->el_line.cursor, 890 el->el_line.lastchar - el->el_line.cursor); 891 return CC_REFRESH; 892 } 893 894 /* vi_yank(): 895 * Vi yank 896 * [y] 897 */ 898 protected el_action_t 899 /*ARGSUSED*/ 900 vi_yank(EditLine *el, int c) 901 { 902 903 return cv_action(el, YANK); 904 } 905 906 /* vi_comment_out(): 907 * Vi comment out current command 908 * [c] 909 */ 910 protected el_action_t 911 /*ARGSUSED*/ 912 vi_comment_out(EditLine *el, int c) 913 { 914 915 el->el_line.cursor = el->el_line.buffer; 916 c_insert(el, 1); 917 *el->el_line.cursor = '#'; 918 re_refresh(el); 919 return ed_newline(el, 0); 920 } 921 922 /* vi_alias(): 923 * Vi include shell alias 924 * [@] 925 * NB: posix impiles that we should enter insert mode, however 926 * this is against historical precedent... 927 */ 928 protected el_action_t 929 /*ARGSUSED*/ 930 vi_alias(EditLine *el, int c) 931 { 932 #ifdef __weak_extern 933 char alias_name[3]; 934 char *alias_text; 935 extern char *get_alias_text(const char *); 936 __weak_extern(get_alias_text); 937 938 if (get_alias_text == 0) { 939 return CC_ERROR; 940 } 941 942 alias_name[0] = '_'; 943 alias_name[2] = 0; 944 if (el_getc(el, &alias_name[1]) != 1) 945 return CC_ERROR; 946 947 alias_text = get_alias_text(alias_name); 948 if (alias_text != NULL) 949 el_push(el, alias_text); 950 return CC_NORM; 951 #else 952 return CC_ERROR; 953 #endif 954 } 955 956 /* vi_to_history_line(): 957 * Vi go to specified history file line. 958 * [G] 959 */ 960 protected el_action_t 961 /*ARGSUSED*/ 962 vi_to_history_line(EditLine *el, int c) 963 { 964 int sv_event_no = el->el_history.eventno; 965 el_action_t rval; 966 967 968 if (el->el_history.eventno == 0) { 969 (void) strncpy(el->el_history.buf, el->el_line.buffer, 970 EL_BUFSIZ); 971 el->el_history.last = el->el_history.buf + 972 (el->el_line.lastchar - el->el_line.buffer); 973 } 974 975 /* Lack of a 'count' means oldest, not 1 */ 976 if (!el->el_state.doingarg) { 977 el->el_history.eventno = 0x7fffffff; 978 hist_get(el); 979 } else { 980 /* This is brain dead, all the rest of this code counts 981 * upwards going into the past. Here we need count in the 982 * other direction (to match the output of fc -l). 983 * I could change the world, but this seems to suffice. 984 */ 985 el->el_history.eventno = 1; 986 if (hist_get(el) == CC_ERROR) 987 return CC_ERROR; 988 el->el_history.eventno = 1 + el->el_history.ev.num 989 - el->el_state.argument; 990 if (el->el_history.eventno < 0) { 991 el->el_history.eventno = sv_event_no; 992 return CC_ERROR; 993 } 994 } 995 rval = hist_get(el); 996 if (rval == CC_ERROR) 997 el->el_history.eventno = sv_event_no; 998 return rval; 999 } 1000 1001 /* vi_histedit(): 1002 * Vi edit history line with vi 1003 * [v] 1004 */ 1005 protected el_action_t 1006 /*ARGSUSED*/ 1007 vi_histedit(EditLine *el, int c) 1008 { 1009 int fd; 1010 pid_t pid; 1011 int st; 1012 char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; 1013 char *cp; 1014 1015 if (el->el_state.doingarg) { 1016 if (vi_to_history_line(el, 0) == CC_ERROR) 1017 return CC_ERROR; 1018 } 1019 1020 fd = mkstemp(tempfile); 1021 if (fd < 0) 1022 return CC_ERROR; 1023 cp = el->el_line.buffer; 1024 write(fd, cp, el->el_line.lastchar - cp +0u); 1025 write(fd, "\n", 1); 1026 pid = fork(); 1027 switch (pid) { 1028 case -1: 1029 close(fd); 1030 unlink(tempfile); 1031 return CC_ERROR; 1032 case 0: 1033 close(fd); 1034 execlp("vi", "vi", tempfile, 0); 1035 exit(0); 1036 /*NOTREACHED*/ 1037 default: 1038 while (waitpid(pid, &st, 0) != pid) 1039 continue; 1040 lseek(fd, 0ll, SEEK_SET); 1041 st = read(fd, cp, el->el_line.limit - cp +0u); 1042 if (st > 0 && cp[st - 1] == '\n') 1043 st--; 1044 el->el_line.cursor = cp; 1045 el->el_line.lastchar = cp + st; 1046 break; 1047 } 1048 1049 close(fd); 1050 unlink(tempfile); 1051 /* return CC_REFRESH; */ 1052 return ed_newline(el, 0); 1053 } 1054 1055 /* vi_history_word(): 1056 * Vi append word from previous input line 1057 * [_] 1058 * Who knows where this one came from! 1059 * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' 1060 */ 1061 protected el_action_t 1062 /*ARGSUSED*/ 1063 vi_history_word(EditLine *el, int c) 1064 { 1065 const char *wp = HIST_FIRST(el); 1066 const char *wep, *wsp; 1067 int len; 1068 char *cp; 1069 const char *lim; 1070 1071 if (wp == NULL) 1072 return CC_ERROR; 1073 1074 wep = wsp = 0; 1075 do { 1076 while (isspace((unsigned char)*wp)) 1077 wp++; 1078 if (*wp == 0) 1079 break; 1080 wsp = wp; 1081 while (*wp && !isspace((unsigned char)*wp)) 1082 wp++; 1083 wep = wp; 1084 } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0); 1085 1086 if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) 1087 return CC_ERROR; 1088 1089 cv_undo(el); 1090 len = wep - wsp; 1091 if (el->el_line.cursor < el->el_line.lastchar) 1092 el->el_line.cursor++; 1093 c_insert(el, len + 1); 1094 cp = el->el_line.cursor; 1095 lim = el->el_line.limit; 1096 if (cp < lim) 1097 *cp++ = ' '; 1098 while (wsp < wep && cp < lim) 1099 *cp++ = *wsp++; 1100 el->el_line.cursor = cp; 1101 1102 el->el_map.current = el->el_map.key; 1103 return CC_REFRESH; 1104 } 1105 1106 /* vi_redo(): 1107 * Vi redo last non-motion command 1108 * [.] 1109 */ 1110 protected el_action_t 1111 /*ARGSUSED*/ 1112 vi_redo(EditLine *el, int c) 1113 { 1114 c_redo_t *r = &el->el_chared.c_redo; 1115 1116 if (!el->el_state.doingarg && r->count) { 1117 el->el_state.doingarg = 1; 1118 el->el_state.argument = r->count; 1119 } 1120 1121 el->el_chared.c_vcmd.pos = el->el_line.cursor; 1122 el->el_chared.c_vcmd.action = r->action; 1123 if (r->pos != r->buf) { 1124 if (r->pos + 1 > r->lim) 1125 /* sanity */ 1126 r->pos = r->lim - 1; 1127 r->pos[0] = 0; 1128 el_push(el, r->buf); 1129 } 1130 1131 el->el_state.thiscmd = r->cmd; 1132 el->el_state.thisch = r->ch; 1133 return (*el->el_map.func[r->cmd])(el, r->ch); 1134 } 1135