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