1 /* $OpenBSD: vi.c,v 1.25 2016/05/06 13:12:52 schwarze Exp $ */ 2 /* $NetBSD: vi.c,v 1.33 2011/02/17 16:44:48 joerg 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 38 /* 39 * vi.c: Vi mode commands. 40 */ 41 #include <sys/wait.h> 42 #include <ctype.h> 43 #include <limits.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "el.h" 49 #include "common.h" 50 #include "emacs.h" 51 #include "fcns.h" 52 #include "vi.h" 53 54 static el_action_t cv_action(EditLine *, wint_t); 55 static el_action_t cv_paste(EditLine *, wint_t); 56 57 /* cv_action(): 58 * Handle vi actions. 59 */ 60 static el_action_t 61 cv_action(EditLine *el, wint_t c) 62 { 63 64 if (el->el_chared.c_vcmd.action != NOP) { 65 /* 'cc', 'dd' and (possibly) friends */ 66 if (c != (wint_t)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 (int)(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 if (!(c & YANK)) { 76 el->el_line.lastchar = el->el_line.buffer; 77 el->el_line.cursor = el->el_line.buffer; 78 } 79 if (c & INSERT) 80 el->el_map.current = el->el_map.key; 81 82 return CC_REFRESH; 83 } 84 el->el_chared.c_vcmd.pos = el->el_line.cursor; 85 el->el_chared.c_vcmd.action = c; 86 return CC_ARGHACK; 87 } 88 89 /* cv_paste(): 90 * Paste previous deletion before or after the cursor 91 */ 92 static el_action_t 93 cv_paste(EditLine *el, wint_t c) 94 { 95 c_kill_t *k = &el->el_chared.c_kill; 96 size_t len = (size_t)(k->last - k->buf); 97 98 if (k->buf == NULL || len == 0) 99 return CC_ERROR; 100 #ifdef DEBUG_PASTE 101 (void) fprintf(el->el_errfile, "Paste: \"%.*ls\"\n", (int)len, 102 k->buf); 103 #endif 104 105 cv_undo(el); 106 107 if (!c && el->el_line.cursor < el->el_line.lastchar) 108 el->el_line.cursor++; 109 110 c_insert(el, (int)len); 111 if (el->el_line.cursor + len > el->el_line.lastchar) 112 return CC_ERROR; 113 (void) memcpy(el->el_line.cursor, k->buf, len * 114 sizeof(*el->el_line.cursor)); 115 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, wint_t 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, wint_t 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, wint_t c __attribute__((__unused__))) 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, wint_t 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, wint_t c __attribute__((__unused__))) 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, wint_t 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, wint_t 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 = *el->el_line.cursor; 259 if (iswupper(c)) 260 *el->el_line.cursor = towlower(c); 261 else if (iswlower(c)) 262 *el->el_line.cursor = towupper(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, wint_t 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, wint_t 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, wint_t 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, wint_t 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, wint_t 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, wint_t c __attribute__((__unused__))) 365 { 366 367 cv_undo(el); 368 cv_yank(el, el->el_line.buffer, 369 (int)(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, wint_t c __attribute__((__unused__))) 383 { 384 385 cv_undo(el); 386 cv_yank(el, el->el_line.cursor, 387 (int)(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, wint_t 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, wint_t 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, wint_t 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, wint_t 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, wint_t c __attribute__((__unused__))) 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, wint_t 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, wint_t 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 = 528 (int)(el->el_line.cursor - el->el_line.buffer); 529 el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); 530 el->el_line.buffer = un.buf; 531 el->el_line.cursor = un.buf + un.cursor; 532 el->el_line.lastchar = un.buf + un.len; 533 534 return CC_REFRESH; 535 } 536 537 538 /* vi_command_mode(): 539 * Vi enter command mode (use alternative key bindings) 540 * [<ESC>] 541 */ 542 protected el_action_t 543 /*ARGSUSED*/ 544 vi_command_mode(EditLine *el, wint_t c __attribute__((__unused__))) 545 { 546 547 /* [Esc] cancels pending action */ 548 el->el_chared.c_vcmd.action = NOP; 549 el->el_chared.c_vcmd.pos = 0; 550 551 el->el_state.doingarg = 0; 552 553 el->el_state.inputmode = MODE_INSERT; 554 el->el_map.current = el->el_map.alt; 555 #ifdef VI_MOVE 556 if (el->el_line.cursor > el->el_line.buffer) 557 el->el_line.cursor--; 558 #endif 559 return CC_CURSOR; 560 } 561 562 563 /* vi_zero(): 564 * Vi move to the beginning of line 565 * [0] 566 */ 567 protected el_action_t 568 vi_zero(EditLine *el, wint_t c) 569 { 570 571 if (el->el_state.doingarg) 572 return ed_argument_digit(el, c); 573 574 el->el_line.cursor = el->el_line.buffer; 575 if (el->el_chared.c_vcmd.action != NOP) { 576 cv_delfini(el); 577 return CC_REFRESH; 578 } 579 return CC_CURSOR; 580 } 581 582 583 /* vi_delete_prev_char(): 584 * Vi move to previous character (backspace) 585 * [^H] in insert mode only 586 */ 587 protected el_action_t 588 /*ARGSUSED*/ 589 vi_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) 590 { 591 592 if (el->el_line.cursor <= el->el_line.buffer) 593 return CC_ERROR; 594 595 c_delbefore1(el); 596 el->el_line.cursor--; 597 return CC_REFRESH; 598 } 599 600 601 /* vi_list_or_eof(): 602 * Vi list choices for completion or indicate end of file if empty line 603 * [^D] 604 */ 605 protected el_action_t 606 /*ARGSUSED*/ 607 vi_list_or_eof(EditLine *el, wint_t c) 608 { 609 610 if (el->el_line.cursor == el->el_line.lastchar) { 611 if (el->el_line.cursor == el->el_line.buffer) { 612 terminal_writec(el, c); /* then do a EOF */ 613 return CC_EOF; 614 } else { 615 /* 616 * Here we could list completions, but it is an 617 * error right now 618 */ 619 terminal_beep(el); 620 return CC_ERROR; 621 } 622 } else { 623 #ifdef notyet 624 re_goto_bottom(el); 625 *el->el_line.lastchar = '\0'; /* just in case */ 626 return CC_LIST_CHOICES; 627 #else 628 /* 629 * Just complain for now. 630 */ 631 terminal_beep(el); 632 return CC_ERROR; 633 #endif 634 } 635 } 636 637 638 /* vi_kill_line_prev(): 639 * Vi cut from beginning of line to cursor 640 * [^U] 641 */ 642 protected el_action_t 643 /*ARGSUSED*/ 644 vi_kill_line_prev(EditLine *el, wint_t c __attribute__((__unused__))) 645 { 646 wchar_t *kp, *cp; 647 648 cp = el->el_line.buffer; 649 kp = el->el_chared.c_kill.buf; 650 while (cp < el->el_line.cursor) 651 *kp++ = *cp++; /* copy it */ 652 el->el_chared.c_kill.last = kp; 653 c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); 654 el->el_line.cursor = el->el_line.buffer; /* zap! */ 655 return CC_REFRESH; 656 } 657 658 659 /* vi_search_prev(): 660 * Vi search history previous 661 * [?] 662 */ 663 protected el_action_t 664 /*ARGSUSED*/ 665 vi_search_prev(EditLine *el, wint_t c __attribute__((__unused__))) 666 { 667 668 return cv_search(el, ED_SEARCH_PREV_HISTORY); 669 } 670 671 672 /* vi_search_next(): 673 * Vi search history next 674 * [/] 675 */ 676 protected el_action_t 677 /*ARGSUSED*/ 678 vi_search_next(EditLine *el, wint_t c __attribute__((__unused__))) 679 { 680 681 return cv_search(el, ED_SEARCH_NEXT_HISTORY); 682 } 683 684 685 /* vi_repeat_search_next(): 686 * Vi repeat current search in the same search direction 687 * [n] 688 */ 689 protected el_action_t 690 /*ARGSUSED*/ 691 vi_repeat_search_next(EditLine *el, wint_t c __attribute__((__unused__))) 692 { 693 694 if (el->el_search.patlen == 0) 695 return CC_ERROR; 696 else 697 return cv_repeat_srch(el, el->el_search.patdir); 698 } 699 700 701 /* vi_repeat_search_prev(): 702 * Vi repeat current search in the opposite search direction 703 * [N] 704 */ 705 /*ARGSUSED*/ 706 protected el_action_t 707 vi_repeat_search_prev(EditLine *el, wint_t c __attribute__((__unused__))) 708 { 709 710 if (el->el_search.patlen == 0) 711 return CC_ERROR; 712 else 713 return (cv_repeat_srch(el, 714 el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? 715 ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); 716 } 717 718 719 /* vi_next_char(): 720 * Vi move to the character specified next 721 * [f] 722 */ 723 protected el_action_t 724 /*ARGSUSED*/ 725 vi_next_char(EditLine *el, wint_t c __attribute__((__unused__))) 726 { 727 return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); 728 } 729 730 731 /* vi_prev_char(): 732 * Vi move to the character specified previous 733 * [F] 734 */ 735 protected el_action_t 736 /*ARGSUSED*/ 737 vi_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) 738 { 739 return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); 740 } 741 742 743 /* vi_to_next_char(): 744 * Vi move up to the character specified next 745 * [t] 746 */ 747 protected el_action_t 748 /*ARGSUSED*/ 749 vi_to_next_char(EditLine *el, wint_t c __attribute__((__unused__))) 750 { 751 return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); 752 } 753 754 755 /* vi_to_prev_char(): 756 * Vi move up to the character specified previous 757 * [T] 758 */ 759 protected el_action_t 760 /*ARGSUSED*/ 761 vi_to_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) 762 { 763 return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); 764 } 765 766 767 /* vi_repeat_next_char(): 768 * Vi repeat current character search in the same search direction 769 * [;] 770 */ 771 protected el_action_t 772 /*ARGSUSED*/ 773 vi_repeat_next_char(EditLine *el, wint_t c __attribute__((__unused__))) 774 { 775 776 return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, 777 el->el_state.argument, el->el_search.chatflg); 778 } 779 780 781 /* vi_repeat_prev_char(): 782 * Vi repeat current character search in the opposite search direction 783 * [,] 784 */ 785 protected el_action_t 786 /*ARGSUSED*/ 787 vi_repeat_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) 788 { 789 el_action_t r; 790 int dir = el->el_search.chadir; 791 792 r = cv_csearch(el, -dir, el->el_search.chacha, 793 el->el_state.argument, el->el_search.chatflg); 794 el->el_search.chadir = dir; 795 return r; 796 } 797 798 799 /* vi_match(): 800 * Vi go to matching () {} or [] 801 * [%] 802 */ 803 protected el_action_t 804 /*ARGSUSED*/ 805 vi_match(EditLine *el, wint_t c __attribute__((__unused__))) 806 { 807 const wchar_t match_chars[] = L"()[]{}"; 808 wchar_t *cp; 809 size_t delta, i, count; 810 wchar_t o_ch, c_ch; 811 812 *el->el_line.lastchar = '\0'; /* just in case */ 813 814 i = wcscspn(el->el_line.cursor, match_chars); 815 o_ch = el->el_line.cursor[i]; 816 if (o_ch == 0) 817 return CC_ERROR; 818 delta = wcschr(match_chars, o_ch) - match_chars; 819 c_ch = match_chars[delta ^ 1]; 820 count = 1; 821 delta = 1 - (delta & 1) * 2; 822 823 for (cp = &el->el_line.cursor[i]; count; ) { 824 cp += delta; 825 if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) 826 return CC_ERROR; 827 if (*cp == o_ch) 828 count++; 829 else if (*cp == c_ch) 830 count--; 831 } 832 833 el->el_line.cursor = cp; 834 835 if (el->el_chared.c_vcmd.action != NOP) { 836 /* NB posix says char under cursor should NOT be deleted 837 for -ve delta - this is different to netbsd vi. */ 838 if (delta > 0) 839 el->el_line.cursor++; 840 cv_delfini(el); 841 return CC_REFRESH; 842 } 843 return CC_CURSOR; 844 } 845 846 /* vi_undo_line(): 847 * Vi undo all changes to line 848 * [U] 849 */ 850 protected el_action_t 851 /*ARGSUSED*/ 852 vi_undo_line(EditLine *el, wint_t c __attribute__((__unused__))) 853 { 854 855 cv_undo(el); 856 return hist_get(el); 857 } 858 859 /* vi_to_column(): 860 * Vi go to specified column 861 * [|] 862 * NB netbsd vi goes to screen column 'n', posix says nth character 863 */ 864 protected el_action_t 865 /*ARGSUSED*/ 866 vi_to_column(EditLine *el, wint_t c __attribute__((__unused__))) 867 { 868 869 el->el_line.cursor = el->el_line.buffer; 870 el->el_state.argument--; 871 return ed_next_char(el, 0); 872 } 873 874 /* vi_yank_end(): 875 * Vi yank to end of line 876 * [Y] 877 */ 878 protected el_action_t 879 /*ARGSUSED*/ 880 vi_yank_end(EditLine *el, wint_t c __attribute__((__unused__))) 881 { 882 883 cv_yank(el, el->el_line.cursor, 884 (int)(el->el_line.lastchar - el->el_line.cursor)); 885 return CC_REFRESH; 886 } 887 888 /* vi_yank(): 889 * Vi yank 890 * [y] 891 */ 892 protected el_action_t 893 /*ARGSUSED*/ 894 vi_yank(EditLine *el, wint_t c __attribute__((__unused__))) 895 { 896 897 return cv_action(el, YANK); 898 } 899 900 /* vi_comment_out(): 901 * Vi comment out current command 902 * [#] 903 */ 904 protected el_action_t 905 /*ARGSUSED*/ 906 vi_comment_out(EditLine *el, wint_t c __attribute__((__unused__))) 907 { 908 909 el->el_line.cursor = el->el_line.buffer; 910 c_insert(el, 1); 911 *el->el_line.cursor = '#'; 912 re_refresh(el); 913 return ed_newline(el, 0); 914 } 915 916 /* vi_alias(): 917 * Vi include shell alias 918 * [@] 919 * NB: posix implies that we should enter insert mode, however 920 * this is against historical precedent... 921 */ 922 #ifdef __weak_reference 923 __weakref_visible char *my_get_alias_text(const char *) 924 __weak_reference(get_alias_text); 925 #endif 926 protected el_action_t 927 /*ARGSUSED*/ 928 vi_alias(EditLine *el, wint_t c __attribute__((__unused__))) 929 { 930 #ifdef __weak_reference 931 char alias_name[3]; 932 char *alias_text; 933 934 if (my_get_alias_text == 0) { 935 return CC_ERROR; 936 } 937 938 alias_name[0] = '_'; 939 alias_name[2] = 0; 940 if (el_getc(el, &alias_name[1]) != 1) 941 return CC_ERROR; 942 943 alias_text = my_get_alias_text(alias_name); 944 if (alias_text != NULL) 945 el_wpush(el, ct_decode_string(alias_text, &el->el_scratch)); 946 return CC_NORM; 947 #else 948 return CC_ERROR; 949 #endif 950 } 951 952 /* vi_to_history_line(): 953 * Vi go to specified history file line. 954 * [G] 955 */ 956 protected el_action_t 957 /*ARGSUSED*/ 958 vi_to_history_line(EditLine *el, wint_t c __attribute__((__unused__))) 959 { 960 int sv_event_no = el->el_history.eventno; 961 el_action_t rval; 962 963 964 if (el->el_history.eventno == 0) { 965 (void) wcsncpy(el->el_history.buf, el->el_line.buffer, 966 EL_BUFSIZ); 967 el->el_history.last = el->el_history.buf + 968 (el->el_line.lastchar - el->el_line.buffer); 969 } 970 971 /* Lack of a 'count' means oldest, not 1 */ 972 if (!el->el_state.doingarg) { 973 el->el_history.eventno = 0x7fffffff; 974 hist_get(el); 975 } else { 976 /* This is brain dead, all the rest of this code counts 977 * upwards going into the past. Here we need count in the 978 * other direction (to match the output of fc -l). 979 * I could change the world, but this seems to suffice. 980 */ 981 el->el_history.eventno = 1; 982 if (hist_get(el) == CC_ERROR) 983 return CC_ERROR; 984 el->el_history.eventno = 1 + el->el_history.ev.num 985 - el->el_state.argument; 986 if (el->el_history.eventno < 0) { 987 el->el_history.eventno = sv_event_no; 988 return CC_ERROR; 989 } 990 } 991 rval = hist_get(el); 992 if (rval == CC_ERROR) 993 el->el_history.eventno = sv_event_no; 994 return rval; 995 } 996 997 /* vi_histedit(): 998 * Vi edit history line with vi 999 * [v] 1000 */ 1001 protected el_action_t 1002 /*ARGSUSED*/ 1003 vi_histedit(EditLine *el, wint_t c __attribute__((__unused__))) 1004 { 1005 int fd; 1006 pid_t pid; 1007 ssize_t st; 1008 int status; 1009 char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; 1010 char *cp; 1011 size_t len; 1012 wchar_t *line; 1013 1014 if (el->el_state.doingarg) { 1015 if (vi_to_history_line(el, 0) == CC_ERROR) 1016 return CC_ERROR; 1017 } 1018 1019 fd = mkstemp(tempfile); 1020 if (fd < 0) 1021 return CC_ERROR; 1022 len = (size_t)(el->el_line.lastchar - el->el_line.buffer); 1023 #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) 1024 cp = malloc(TMP_BUFSIZ); 1025 if (cp == NULL) { 1026 close(fd); 1027 unlink(tempfile); 1028 return CC_ERROR; 1029 } 1030 line = reallocarray(NULL, len, sizeof(*line)); 1031 if (line == NULL) { 1032 close(fd); 1033 unlink(tempfile); 1034 free(cp); 1035 return CC_ERROR; 1036 } 1037 wcsncpy(line, el->el_line.buffer, len); 1038 line[len] = '\0'; 1039 wcstombs(cp, line, TMP_BUFSIZ - 1); 1040 cp[TMP_BUFSIZ - 1] = '\0'; 1041 len = strlen(cp); 1042 write(fd, cp, len); 1043 write(fd, "\n", 1); 1044 pid = fork(); 1045 switch (pid) { 1046 case -1: 1047 close(fd); 1048 unlink(tempfile); 1049 free(cp); 1050 free(line); 1051 return CC_ERROR; 1052 case 0: 1053 close(fd); 1054 execlp("vi", "vi", tempfile, (char *)NULL); 1055 exit(0); 1056 /*NOTREACHED*/ 1057 default: 1058 while (waitpid(pid, &status, 0) != pid) 1059 continue; 1060 lseek(fd, (off_t)0, SEEK_SET); 1061 st = read(fd, cp, TMP_BUFSIZ); 1062 if (st > 0) { 1063 len = (size_t)(el->el_line.lastchar - 1064 el->el_line.buffer); 1065 len = mbstowcs(el->el_line.buffer, cp, len); 1066 if (len > 0 && el->el_line.buffer[len -1] == '\n') 1067 --len; 1068 } 1069 else 1070 len = 0; 1071 el->el_line.cursor = el->el_line.buffer; 1072 el->el_line.lastchar = el->el_line.buffer + len; 1073 free(cp); 1074 free(line); 1075 break; 1076 } 1077 1078 close(fd); 1079 unlink(tempfile); 1080 /* return CC_REFRESH; */ 1081 return ed_newline(el, 0); 1082 } 1083 1084 /* vi_history_word(): 1085 * Vi append word from previous input line 1086 * [_] 1087 * Who knows where this one came from! 1088 * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' 1089 */ 1090 protected el_action_t 1091 /*ARGSUSED*/ 1092 vi_history_word(EditLine *el, wint_t c __attribute__((__unused__))) 1093 { 1094 const wchar_t *wp = HIST_FIRST(el); 1095 const wchar_t *wep, *wsp; 1096 int len; 1097 wchar_t *cp; 1098 const wchar_t *lim; 1099 1100 if (wp == NULL) 1101 return CC_ERROR; 1102 1103 wep = wsp = NULL; 1104 do { 1105 while (iswspace(*wp)) 1106 wp++; 1107 if (*wp == 0) 1108 break; 1109 wsp = wp; 1110 while (*wp && !iswspace(*wp)) 1111 wp++; 1112 wep = wp; 1113 } while ((!el->el_state.doingarg || --el->el_state.argument > 0) 1114 && *wp != 0); 1115 1116 if (wsp == NULL || (el->el_state.doingarg && el->el_state.argument != 0)) 1117 return CC_ERROR; 1118 1119 cv_undo(el); 1120 len = (int)(wep - wsp); 1121 if (el->el_line.cursor < el->el_line.lastchar) 1122 el->el_line.cursor++; 1123 c_insert(el, len + 1); 1124 cp = el->el_line.cursor; 1125 lim = el->el_line.limit; 1126 if (cp < lim) 1127 *cp++ = ' '; 1128 while (wsp < wep && cp < lim) 1129 *cp++ = *wsp++; 1130 el->el_line.cursor = cp; 1131 1132 el->el_map.current = el->el_map.key; 1133 return CC_REFRESH; 1134 } 1135 1136 /* vi_redo(): 1137 * Vi redo last non-motion command 1138 * [.] 1139 */ 1140 protected el_action_t 1141 /*ARGSUSED*/ 1142 vi_redo(EditLine *el, wint_t c __attribute__((__unused__))) 1143 { 1144 c_redo_t *r = &el->el_chared.c_redo; 1145 1146 if (!el->el_state.doingarg && r->count) { 1147 el->el_state.doingarg = 1; 1148 el->el_state.argument = r->count; 1149 } 1150 1151 el->el_chared.c_vcmd.pos = el->el_line.cursor; 1152 el->el_chared.c_vcmd.action = r->action; 1153 if (r->pos != r->buf) { 1154 if (r->pos + 1 > r->lim) 1155 /* sanity */ 1156 r->pos = r->lim - 1; 1157 r->pos[0] = 0; 1158 el_wpush(el, r->buf); 1159 } 1160 1161 el->el_state.thiscmd = r->cmd; 1162 el->el_state.thisch = r->ch; 1163 return (*el->el_map.func[r->cmd])(el, r->ch); 1164 } 1165