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