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