1 /*- 2 * Copyright (c) 1980 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ex_vops.c 7.9 (Berkeley) 04/17/91"; 10 #endif /* not lint */ 11 12 #include "ex.h" 13 #include "ex_tty.h" 14 #include "ex_vis.h" 15 16 /* 17 * This file defines the operation sequences which interface the 18 * logical changes to the file buffer with the internal and external 19 * display representations. 20 */ 21 22 /* 23 * Undo. 24 * 25 * Undo is accomplished in two ways. We often for small changes in the 26 * current line know how (in terms of a change operator) how the change 27 * occurred. Thus on an intelligent terminal we can undo the operation 28 * by another such operation, using insert and delete character 29 * stuff. The pointers vU[AD][12] index the buffer vutmp when this 30 * is possible and provide the necessary information. 31 * 32 * The other case is that the change involved multiple lines or that 33 * we have moved away from the line or forgotten how the change was 34 * accomplished. In this case we do a redisplay and hope that the 35 * low level optimization routines (which don't look for winning 36 * via insert/delete character) will not lose too badly. 37 */ 38 char *vUA1, *vUA2; 39 char *vUD1, *vUD2; 40 41 ex_vUndo() 42 { 43 44 /* 45 * Avoid UU which clobbers ability to do u. 46 */ 47 if (vundkind == VCAPU || vUNDdot != dot) { 48 beep(); 49 return; 50 } 51 CP(vutmp, linebuf); 52 vUD1 = linebuf; vUD2 = strend(linebuf); 53 putmk1(dot, vUNDsav); 54 getDOT(); 55 vUA1 = linebuf; vUA2 = strend(linebuf); 56 vundkind = VCAPU; 57 if (state == ONEOPEN || state == HARDOPEN) { 58 vjumpto(dot, vUNDcurs, 0); 59 return; 60 } 61 vdirty(vcline, 1); 62 vsyncCL(); 63 cursor = linebuf; 64 vfixcurs(); 65 } 66 67 vundo(show) 68 bool show; /* if true update the screen */ 69 { 70 register int cnt; 71 register line *addr; 72 register char *cp; 73 char temp[LBSIZE]; 74 bool savenote; 75 int (*OO)(); 76 short oldhold = hold; 77 78 switch (vundkind) { 79 80 case VMANYINS: 81 wcursor = 0; 82 addr1 = undap1; 83 addr2 = undap2 - 1; 84 vsave(); 85 YANKreg('1'); 86 notecnt = 0; 87 /* fall into ... */ 88 89 case VMANY: 90 case VMCHNG: 91 vsave(); 92 addr = dot - vcline; 93 notecnt = 1; 94 if (undkind == UNDPUT && undap1 == undap2) { 95 beep(); 96 break; 97 } 98 /* 99 * Undo() call below basically replaces undap1 to undap2-1 100 * with dol through unddol-1. Hack screen image to 101 * reflect this replacement. 102 */ 103 if (show) 104 if (undkind == UNDMOVE) 105 vdirty(0, LINES); 106 else 107 vreplace(undap1 - addr, undap2 - undap1, 108 undkind == UNDPUT ? 0 : unddol - dol); 109 savenote = notecnt; 110 undo(1); 111 if (show && (vundkind != VMCHNG || addr != dot)) 112 killU(); 113 vundkind = VMANY; 114 cnt = dot - addr; 115 if (cnt < 0 || cnt > vcnt || state != VISUAL) { 116 if (show) 117 vjumpto(dot, NOSTR, '.'); 118 break; 119 } 120 if (!savenote) 121 notecnt = 0; 122 if (show) { 123 vcline = cnt; 124 vrepaint(vmcurs); 125 } 126 vmcurs = 0; 127 break; 128 129 case VCHNG: 130 case VCAPU: 131 vundkind = VCHNG; 132 strcpy(temp, vutmp); 133 strcpy(vutmp, linebuf); 134 doomed = column(vUA2 - 1) - column(vUA1 - 1); 135 strcLIN(temp); 136 cp = vUA1; vUA1 = vUD1; vUD1 = cp; 137 cp = vUA2; vUA2 = vUD2; vUD2 = cp; 138 if (!show) 139 break; 140 cursor = vUD1; 141 if (state == HARDOPEN) { 142 doomed = 0; 143 vsave(); 144 vopen(dot, WBOT); 145 vnline(cursor); 146 break; 147 } 148 /* 149 * Pseudo insert command. 150 */ 151 vcursat(cursor); 152 OO = Outchar; Outchar = vinschar; hold |= HOLDQIK; 153 vprepins(); 154 temp[vUA2 - linebuf] = 0; 155 for (cp = &temp[vUA1 - linebuf]; *cp;) 156 ex_putchar(*cp++); 157 Outchar = OO; hold = oldhold; 158 endim(); 159 physdc(cindent(), cindent() + doomed); 160 doomed = 0; 161 vdirty(vcline, 1); 162 vsyncCL(); 163 if (cursor > linebuf && cursor >= strend(linebuf)) 164 cursor--; 165 vfixcurs(); 166 break; 167 168 case VNONE: 169 beep(); 170 break; 171 } 172 } 173 174 /* 175 * Routine to handle a change inside a macro. 176 * Fromvis is true if we were called from a visual command (as 177 * opposed to an ex command). This has nothing to do with being 178 * in open/visual mode as :s/foo/bar is not fromvis. 179 */ 180 vmacchng(fromvis) 181 bool fromvis; 182 { 183 line *savedot, *savedol; 184 char *savecursor; 185 char savelb[LBSIZE]; 186 int nlines, more; 187 int copyw(), copywR(); 188 189 if (!inopen) 190 return; 191 if (!vmacp) 192 vch_mac = VC_NOTINMAC; 193 #ifdef TRACE 194 if (trace) 195 fprintf(trace, "vmacchng, vch_mac=%d, linebuf='%s', *dot=%o\n", vch_mac, linebuf, *dot); 196 #endif 197 if (vmacp && fromvis) 198 vsave(); 199 #ifdef TRACE 200 if (trace) 201 fprintf(trace, "after vsave, linebuf='%s', *dot=%o\n", linebuf, *dot); 202 #endif 203 switch(vch_mac) { 204 case VC_NOCHANGE: 205 vch_mac = VC_ONECHANGE; 206 break; 207 case VC_ONECHANGE: 208 /* Save current state somewhere */ 209 #ifdef TRACE 210 vudump("before vmacchng hairy case"); 211 #endif 212 savedot = dot; savedol = dol; savecursor = cursor; 213 CP(savelb, linebuf); 214 nlines = dol - zero; 215 while ((line *) endcore - truedol < nlines) 216 if (morelines() < 0) { 217 dot = savedot; 218 dol = savedol; 219 cursor = savecursor; 220 CP(linebuf, savelb); 221 error("Out of memory@- too many lines to undo"); 222 } 223 copyw(truedol+1, zero+1, nlines); 224 truedol += nlines; 225 226 #ifdef TRACE 227 visdump("before vundo"); 228 #endif 229 /* Restore state as it was at beginning of macro */ 230 vundo(0); 231 #ifdef TRACE 232 visdump("after vundo"); 233 vudump("after vundo"); 234 #endif 235 236 /* Do the saveall we should have done then */ 237 saveall(); 238 #ifdef TRACE 239 vudump("after saveall"); 240 #endif 241 242 /* Restore current state from where saved */ 243 more = savedol - dol; /* amount we shift everything by */ 244 if (more) 245 (*(more>0 ? copywR : copyw))(savedol+1, dol+1, truedol-dol); 246 unddol += more; truedol += more; undap2 += more; 247 248 truedol -= nlines; 249 copyw(zero+1, truedol+1, nlines); 250 dot = savedot; dol = savedol ; cursor = savecursor; 251 CP(linebuf, savelb); 252 vch_mac = VC_MANYCHANGE; 253 254 /* Arrange that no further undo saving happens within macro */ 255 otchng = tchng; /* Copied this line blindly - bug? */ 256 inopen = -1; /* no need to save since it had to be 1 or -1 before */ 257 vundkind = VMANY; 258 #ifdef TRACE 259 vudump("after vmacchng"); 260 #endif 261 break; 262 case VC_NOTINMAC: 263 case VC_MANYCHANGE: 264 /* Nothing to do for various reasons. */ 265 break; 266 } 267 } 268 269 /* 270 * Initialize undo information before an append. 271 */ 272 vnoapp() 273 { 274 275 vUD1 = vUD2 = cursor; 276 } 277 278 /* 279 * All the rest of the motion sequences have one or more 280 * cases to deal with. In the case wdot == 0, operation 281 * is totally within current line, from cursor to wcursor. 282 * If wdot is given, but wcursor is 0, then operation affects 283 * the inclusive line range. The hardest case is when both wdot 284 * and wcursor are given, then operation affects from line dot at 285 * cursor to line wdot at wcursor. 286 */ 287 288 /* 289 * Move is simple, except for moving onto new lines in hardcopy open mode. 290 */ 291 vmove() 292 { 293 register int cnt; 294 295 if (wdot) { 296 if (wdot < one || wdot > dol) { 297 beep(); 298 return; 299 } 300 cnt = wdot - dot; 301 wdot = NOLINE; 302 if (cnt) 303 killU(); 304 vupdown(cnt, wcursor); 305 return; 306 } 307 308 /* 309 * When we move onto a new line, save information for U undo. 310 */ 311 if (vUNDdot != dot) { 312 vUNDsav = *dot; 313 vUNDcurs = wcursor; 314 vUNDdot = dot; 315 } 316 317 /* 318 * In hardcopy open, type characters to left of cursor 319 * on new line, or back cursor up if its to left of where we are. 320 * In any case if the current line is ``rubbled'' i.e. has trashy 321 * looking overstrikes on it or \'s from deletes, we reprint 322 * so it is more comprehensible (and also because we can't work 323 * if we let it get more out of sync since column() won't work right. 324 */ 325 if (state == HARDOPEN) { 326 register char *cp; 327 if (rubble) { 328 register int c; 329 int oldhold = hold; 330 331 sethard(); 332 cp = wcursor; 333 c = *cp; 334 *cp = 0; 335 hold |= HOLDDOL; 336 ignore(vreopen(WTOP, lineDOT(), vcline)); 337 hold = oldhold; 338 *cp = c; 339 } else if (wcursor > cursor) { 340 vfixcurs(); 341 for (cp = cursor; *cp && cp < wcursor;) { 342 register int c = *cp++ & TRIM; 343 344 ex_putchar(c ? c : ' '); 345 } 346 } 347 } 348 vsetcurs(wcursor); 349 } 350 351 /* 352 * Delete operator. 353 * 354 * Hard case of deleting a range where both wcursor and wdot 355 * are specified is treated as a special case of change and handled 356 * by vchange (although vchange may pass it back if it degenerates 357 * to a full line range delete.) 358 */ 359 vdelete(c) 360 char c; 361 { 362 register char *cp; 363 register int i; 364 365 if (wdot) { 366 if (wcursor) { 367 vchange('d'); 368 return; 369 } 370 if ((i = xdw()) < 0) 371 return; 372 if (state != VISUAL) { 373 vgoto(LINE(0), 0); 374 vputchar('@'); 375 } 376 wdot = dot; 377 vremote(i, ex_delete, 0); 378 notenam = "delete"; 379 DEL[0] = 0; 380 killU(); 381 vreplace(vcline, i, 0); 382 if (wdot > dol) 383 vcline--; 384 vrepaint(NOSTR); 385 return; 386 } 387 if (wcursor < linebuf) 388 wcursor = linebuf; 389 if (cursor == wcursor) { 390 beep(); 391 return; 392 } 393 i = vdcMID(); 394 cp = cursor; 395 setDEL(); 396 CP(cp, wcursor); 397 if (cp > linebuf && (cp[0] == 0 || c == '#')) 398 cp--; 399 if (state == HARDOPEN) { 400 bleep(i, cp); 401 cursor = cp; 402 return; 403 } 404 physdc(column(cursor - 1), i); 405 DEPTH(vcline) = 0; 406 ignore(vreopen(LINE(vcline), lineDOT(), vcline)); 407 vsyncCL(); 408 vsetcurs(cp); 409 } 410 411 /* 412 * Change operator. 413 * 414 * In a single line we mark the end of the changed area with '$'. 415 * On multiple whole lines, we clear the lines first. 416 * Across lines with both wcursor and wdot given, we delete 417 * and sync then append (but one operation for undo). 418 */ 419 vchange(c) 420 char c; 421 { 422 register char *cp; 423 register int i, ind, cnt; 424 line *addr; 425 426 if (wdot) { 427 /* 428 * Change/delete of lines or across line boundaries. 429 */ 430 if ((cnt = xdw()) < 0) 431 return; 432 getDOT(); 433 if (wcursor && cnt == 1) { 434 /* 435 * Not really. 436 */ 437 wdot = 0; 438 if (c == 'd') { 439 vdelete(c); 440 return; 441 } 442 goto smallchange; 443 } 444 if (cursor && wcursor) { 445 /* 446 * Across line boundaries, but not 447 * necessarily whole lines. 448 * Construct what will be left. 449 */ 450 *cursor = 0; 451 strcpy(genbuf, linebuf); 452 getline(*wdot); 453 if (strlen(genbuf) + strlen(wcursor) > LBSIZE - 2) { 454 getDOT(); 455 beep(); 456 return; 457 } 458 strcat(genbuf, wcursor); 459 if (c == 'd' && *vpastwh(genbuf) == 0) { 460 /* 461 * Although this is a delete 462 * spanning line boundaries, what 463 * would be left is all white space, 464 * so take it all away. 465 */ 466 wcursor = 0; 467 getDOT(); 468 op = 0; 469 notpart(lastreg); 470 notpart('1'); 471 vdelete(c); 472 return; 473 } 474 ind = -1; 475 } else if (c == 'd' && wcursor == 0) { 476 vdelete(c); 477 return; 478 } else 479 #ifdef LISPCODE 480 /* 481 * We are just substituting text for whole lines, 482 * so determine the first autoindent. 483 */ 484 if (value(LISP) && value(AUTOINDENT)) 485 ind = lindent(dot); 486 else 487 #endif 488 ind = whitecnt(linebuf); 489 i = vcline >= 0 ? LINE(vcline) : WTOP; 490 491 /* 492 * Delete the lines from the buffer, 493 * and remember how the partial stuff came about in 494 * case we are told to put. 495 */ 496 addr = dot; 497 vremote(cnt, ex_delete, 0); 498 setpk(); 499 notenam = "delete"; 500 if (c != 'd') 501 notenam = "change"; 502 /* 503 * If DEL[0] were nonzero, put would put it back 504 * rather than the deleted lines. 505 */ 506 DEL[0] = 0; 507 if (cnt > 1) 508 killU(); 509 510 /* 511 * Now hack the screen image coordination. 512 */ 513 vreplace(vcline, cnt, 0); 514 wdot = NOLINE; 515 ignore(noteit(0)); 516 vcline--; 517 if (addr <= dol) 518 dot--; 519 520 /* 521 * If this is a across line delete/change, 522 * cursor stays where it is; just splice together the pieces 523 * of the new line. Otherwise generate a autoindent 524 * after a S command. 525 */ 526 if (ind >= 0) { 527 *genindent(ind) = 0; 528 vdoappend(genbuf); 529 } else { 530 vmcurs = cursor; 531 strcLIN(genbuf); 532 vdoappend(linebuf); 533 } 534 535 /* 536 * Indicate a change on hardcopies by 537 * erasing the current line. 538 */ 539 if (c != 'd' && state != VISUAL && state != HARDOPEN) { 540 int oldhold = hold; 541 542 hold |= HOLDAT, vclrlin(i, dot), hold = oldhold; 543 } 544 545 /* 546 * Open the line (logically) on the screen, and 547 * update the screen tail. Unless we are really a delete 548 * go off and gather up inserted characters. 549 */ 550 vcline++; 551 if (vcline < 0) 552 vcline = 0; 553 vopen(dot, i); 554 vsyncCL(); 555 ignore(noteit(1)); 556 if (c != 'd') { 557 if (ind >= 0) { 558 cursor = linebuf; 559 linebuf[0] = 0; 560 vfixcurs(); 561 } else { 562 ind = 0; 563 vcursat(cursor); 564 } 565 vappend('x', 1, ind); 566 return; 567 } 568 if (*cursor == 0 && cursor > linebuf) 569 cursor--; 570 vrepaint(cursor); 571 return; 572 } 573 574 smallchange: 575 /* 576 * The rest of this is just low level hacking on changes 577 * of small numbers of characters. 578 */ 579 if (wcursor < linebuf) 580 wcursor = linebuf; 581 if (cursor == wcursor) { 582 beep(); 583 return; 584 } 585 i = vdcMID(); 586 cp = cursor; 587 if (state != HARDOPEN) 588 vfixcurs(); 589 590 /* 591 * Put out the \\'s indicating changed text in hardcopy, 592 * or mark the end of the change with $ if not hardcopy. 593 */ 594 if (state == HARDOPEN) 595 bleep(i, cp); 596 else { 597 vcursbef(wcursor); 598 ex_putchar('$'); 599 i = cindent(); 600 } 601 602 /* 603 * Remember the deleted text for possible put, 604 * and then prepare and execute the input portion of the change. 605 */ 606 cursor = cp; 607 setDEL(); 608 CP(cursor, wcursor); 609 if (state != HARDOPEN) { 610 vcursaft(cursor - 1); 611 doomed = i - cindent(); 612 } else { 613 /* 614 sethard(); 615 wcursor = cursor; 616 cursor = linebuf; 617 vgoto(outline, value(NUMBER) << 3); 618 vmove(); 619 */ 620 doomed = 0; 621 } 622 prepapp(); 623 vappend('c', 1, 0); 624 } 625 626 /* 627 * Open new lines. 628 * 629 * Tricky thing here is slowopen. This causes display updating 630 * to be held off so that 300 baud dumb terminals don't lose badly. 631 * This also suppressed counts, which otherwise say how many blank 632 * space to open up. Counts are also suppressed on intelligent terminals. 633 * Actually counts are obsoleted, since if your terminal is slow 634 * you are better off with slowopen. 635 */ 636 voOpen(c, cnt) 637 int c; /* mjm: char --> int */ 638 register int cnt; 639 { 640 register int ind = 0, i; 641 short oldhold = hold; 642 #ifdef SIGWINCH 643 int oldmask; 644 #endif 645 646 if (value(SLOWOPEN) || value(REDRAW) && AL && DL) 647 cnt = 1; 648 #ifdef SIGWINCH 649 oldmask = sigblock(sigmask(SIGWINCH)); 650 #endif 651 vsave(); 652 setLAST(); 653 if (value(AUTOINDENT)) 654 ind = whitecnt(linebuf); 655 if (c == 'O') { 656 vcline--; 657 dot--; 658 if (dot > zero) 659 getDOT(); 660 } 661 if (value(AUTOINDENT)) { 662 #ifdef LISPCODE 663 if (value(LISP)) 664 ind = lindent(dot + 1); 665 #endif 666 } 667 killU(); 668 prepapp(); 669 if (FIXUNDO) 670 vundkind = VMANY; 671 if (state != VISUAL) 672 c = WBOT + 1; 673 else { 674 c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline); 675 if (c < ex_ZERO) 676 c = ex_ZERO; 677 i = LINE(vcline + 1) - c; 678 if (i < cnt && c <= WBOT && (!AL || !DL)) 679 vinslin(c, cnt - i, vcline); 680 } 681 *genindent(ind) = 0; 682 vdoappend(genbuf); 683 vcline++; 684 oldhold = hold; 685 hold |= HOLDROL; 686 vopen(dot, c); 687 hold = oldhold; 688 if (value(SLOWOPEN)) 689 /* 690 * Oh, so lazy! 691 */ 692 vscrap(); 693 else 694 vsync1(LINE(vcline)); 695 cursor = linebuf; 696 linebuf[0] = 0; 697 vappend('o', 1, ind); 698 #ifdef SIGWINCH 699 (void)sigsetmask(oldmask); 700 #endif 701 } 702 703 /* 704 * > < and = shift operators. 705 * 706 * Note that =, which aligns lisp, is just a ragged sort of shift, 707 * since it never distributes text between lines. 708 */ 709 char vshnam[2] = { 'x', 0 }; 710 711 vshftop() 712 { 713 register line *addr; 714 register int cnt; 715 716 if ((cnt = xdw()) < 0) 717 return; 718 addr = dot; 719 vremote(cnt, vshift, 0); 720 vshnam[0] = op; 721 notenam = vshnam; 722 dot = addr; 723 vreplace(vcline, cnt, cnt); 724 if (state == HARDOPEN) 725 vcnt = 0; 726 vrepaint(NOSTR); 727 } 728 729 /* 730 * !. 731 * 732 * Filter portions of the buffer through unix commands. 733 */ 734 vfilter() 735 { 736 register line *addr; 737 register int cnt; 738 char *oglobp; 739 short d; 740 741 if ((cnt = xdw()) < 0) 742 return; 743 if (vglobp) 744 vglobp = uxb; 745 if (readecho('!')) 746 return; 747 oglobp = globp; globp = genbuf + 1; 748 d = peekc; ungetchar(0); 749 CATCH 750 fixech(); 751 unix0(0); 752 ONERR 753 splitw = 0; 754 ungetchar(d); 755 vrepaint(cursor); 756 globp = oglobp; 757 return; 758 ENDCATCH 759 ungetchar(d); globp = oglobp; 760 addr = dot; 761 CATCH 762 vgoto(WECHO, 0); flusho(); 763 vremote(cnt, filter, 2); 764 ONERR 765 vdirty(0, LINES); 766 ENDCATCH 767 if (dot == zero && dol > zero) 768 dot = one; 769 splitw = 0; 770 notenam = ""; 771 /* 772 * BUG: we shouldn't be depending on what undap2 and undap1 are, 773 * since we may be inside a macro. What's really wanted is the 774 * number of lines we read from the filter. However, the mistake 775 * will be an overestimate so it only results in extra work, 776 * it shouldn't cause any real screwups. 777 */ 778 vreplace(vcline, cnt, undap2 - undap1); 779 dot = addr; 780 if (dot > dol) { 781 dot--; 782 vcline--; 783 } 784 vrepaint(NOSTR); 785 } 786 787 /* 788 * Xdw exchanges dot and wdot if appropriate and also checks 789 * that wdot is reasonable. Its name comes from 790 * xchange dotand wdot 791 */ 792 xdw() 793 { 794 register char *cp; 795 register int cnt; 796 /* 797 register int notp = 0; 798 */ 799 800 if (wdot == NOLINE || wdot < one || wdot > dol) { 801 beep(); 802 return (-1); 803 } 804 vsave(); 805 setLAST(); 806 if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) { 807 register line *addr; 808 809 vcline -= dot - wdot; 810 addr = dot; dot = wdot; wdot = addr; 811 cp = cursor; cursor = wcursor; wcursor = cp; 812 } 813 /* 814 * If a region is specified but wcursor is at the begining 815 * of the last line, then we move it to be the end of the 816 * previous line (actually off the end). 817 */ 818 if (cursor && wcursor == linebuf && wdot > dot) { 819 wdot--; 820 getDOT(); 821 if (vpastwh(linebuf) >= cursor) 822 wcursor = 0; 823 else { 824 getline(*wdot); 825 wcursor = strend(linebuf); 826 getDOT(); 827 } 828 /* 829 * Should prepare in caller for possible dot == wdot. 830 */ 831 } 832 cnt = wdot - dot + 1; 833 if (vreg) { 834 vremote(cnt, YANKreg, vreg); 835 /* 836 if (notp) 837 notpart(vreg); 838 */ 839 } 840 841 /* 842 * Kill buffer code. If delete operator is c or d, then save 843 * the region in numbered buffers. 844 * 845 * BUG: This may be somewhat inefficient due 846 * to the way named buffer are implemented, 847 * necessitating some optimization. 848 */ 849 vreg = 0; 850 if (any(op, "cd")) { 851 vremote(cnt, YANKreg, '1'); 852 /* 853 if (notp) 854 notpart('1'); 855 */ 856 } 857 return (cnt); 858 } 859 860 /* 861 * Routine for vremote to call to implement shifts. 862 */ 863 vshift() 864 { 865 866 shift(op, 1); 867 } 868 869 /* 870 * Replace a single character with the next input character. 871 * A funny kind of insert. 872 */ 873 vrep(cnt) 874 register int cnt; 875 { 876 register int i, c; 877 878 if (cnt > strlen(cursor)) { 879 beep(); 880 return; 881 } 882 i = column(cursor + cnt - 1); 883 vcursat(cursor); 884 doomed = i - cindent(); 885 if (!vglobp) { 886 c = getesc(); 887 if (c == 0) { 888 vfixcurs(); 889 return; 890 } 891 ungetkey(c); 892 } 893 CP(vutmp, linebuf); 894 if (FIXUNDO) 895 vundkind = VCHNG; 896 wcursor = cursor + cnt; 897 vUD1 = cursor; vUD2 = wcursor; 898 CP(cursor, wcursor); 899 prepapp(); 900 vappend('r', cnt, 0); 901 *lastcp++ = INS[0]; 902 setLAST(); 903 } 904 905 /* 906 * Yank. 907 * 908 * Yanking to string registers occurs for free (essentially) 909 * in the routine xdw(). 910 */ 911 vyankit() 912 { 913 register int cnt; 914 915 if (wdot) { 916 if ((cnt = xdw()) < 0) 917 return; 918 vremote(cnt, yank, 0); 919 setpk(); 920 notenam = "yank"; 921 if (FIXUNDO) 922 vundkind = VNONE; 923 DEL[0] = 0; 924 wdot = NOLINE; 925 if (notecnt <= vcnt - vcline && notecnt < value(REPORT)) 926 notecnt = 0; 927 vrepaint(cursor); 928 return; 929 } 930 takeout(DEL); 931 } 932 933 /* 934 * Set pkill variables so a put can 935 * know how to put back partial text. 936 * This is necessary because undo needs the complete 937 * line images to be saved, while a put wants to trim 938 * the first and last lines. The compromise 939 * is for put to be more clever. 940 */ 941 setpk() 942 { 943 944 if (wcursor) { 945 pkill[0] = cursor; 946 pkill[1] = wcursor; 947 } 948 } 949