1 /* Copyright (c) 1981 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_vadj.c 7.1 07/08/81"; 3 #include "ex.h" 4 #include "ex_tty.h" 5 #include "ex_vis.h" 6 7 /* 8 * Routines to deal with management of logical versus physical 9 * display, opening and redisplaying lines on the screen, and 10 * use of intelligent terminal operations. Routines to deal with 11 * screen cleanup after a change. 12 */ 13 14 /* 15 * Display a new line at physical line p, returning 16 * the depth of the newly displayed line. We may decide 17 * to expand the window on an intelligent terminal if it is 18 * less than a full screen by deleting a line above the top of the 19 * window before doing an insert line to keep all the good text 20 * on the screen in which case the line may actually end up 21 * somewhere other than line p. 22 */ 23 vopen(tp, p) 24 line *tp; 25 int p; 26 { 27 register int cnt; 28 register struct vlinfo *vp, *vpc; 29 30 #ifdef ADEBUG 31 if (trace != NULL) 32 tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p); 33 #endif 34 if (state != VISUAL) { 35 if (vcnt) 36 if (hold & HOLDROL) 37 vup1(); 38 else 39 vclean(); 40 41 /* 42 * Forget all that we once knew. 43 */ 44 vcnt = vcline = 0; 45 p = WBOT; LASTLINE = WBOT + 1; 46 state = bastate; 47 WTOP = basWTOP; 48 WLINES = basWLINES; 49 } 50 vpc = &vlinfo[vcline]; 51 for (vp = &vlinfo[vcnt]; vp >= vpc; vp--) 52 vlcopy(vp[1], vp[0]); 53 vcnt++; 54 if (Pline == numbline) 55 /* 56 * Dirtying all the lines is rather inefficient 57 * internally, but number mode is used rarely 58 * and so its not worth optimizing. 59 */ 60 vdirty(vcline+1, WECHO); 61 getline(*tp); 62 63 /* 64 * If we are opening at the top of the window, can try a window 65 * expansion at the top. 66 */ 67 if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) { 68 cnt = p + vdepth() - LINE(1); 69 if (cnt > 0) { 70 p -= cnt; 71 if (p < ZERO) 72 p = ZERO; 73 WTOP = p; 74 WLINES = WBOT - WTOP + 1; 75 } 76 } 77 vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0; 78 cnt = vreopen(p, lineno(tp), vcline); 79 if (vcline + 1 == vcnt) 80 LINE(vcnt) = LINE(vcline) + cnt; 81 } 82 83 /* 84 * Redisplay logical line l at physical line p with line number lineno. 85 */ 86 vreopen(p, lineno, l) 87 int p, lineno, l; 88 { 89 register int d; 90 register struct vlinfo *vp = &vlinfo[l]; 91 92 d = vp->vdepth; 93 if (d == 0 || (vp->vflags & VDIRT)) 94 vp->vdepth = d = vdepth(); 95 vp->vliny = p, vp->vflags &= ~VDIRT; 96 97 /* 98 * Try to win by making the screen larger rather than inserting 99 * a line and driving text off the bottom. 100 */ 101 p = vglitchup(l, 0); 102 103 /* 104 * BUG: Should consider using CE here to clear to end of line. 105 * As it stands we always strike over the current text. 106 * Since often the current text is the same as what 107 * we are overstriking with, it tends not to show. 108 * On the other hand if it is different and we end up 109 * spacing out a lot of text, we could have won with 110 * a CE. This is probably worthwhile at low speed 111 * only however, since clearly computation will be 112 * necessary to determine which way to go. 113 */ 114 vigoto(p, 0); 115 pline(lineno); 116 117 /* 118 * When we are typing part of a line for hardcopy open, don't 119 * want to type the '$' marking an end of line if in list mode. 120 */ 121 if (hold & HOLDDOL) 122 return (d); 123 if (Putchar == listchar) 124 putchar('$'); 125 126 /* 127 * Optimization of cursor motion may prevent screen rollup if the 128 * line has blanks/tabs at the end unless we force the cursor to appear 129 * on the last line segment. 130 */ 131 if (vp->vliny + d - 1 > WBOT) 132 vcsync(); 133 134 /* 135 * Switch into hardcopy open mode if we are in one line (adm3) 136 * open mode and this line is now too long. If in hardcopy 137 * open mode, then call sethard to move onto the next line 138 * with appropriate positioning. 139 */ 140 if (state == ONEOPEN) { 141 WCOLS = OCOLUMNS; 142 if (vdepth() > 1) { 143 WCOLS = TUBECOLS; 144 sethard(); 145 } else 146 WCOLS = TUBECOLS; 147 } else if (state == HARDOPEN) 148 sethard(); 149 150 /* 151 * Unless we filled (completely) the last line we typed on, 152 * we have to clear to the end of the line 153 * in case stuff is left from before. 154 */ 155 if (vp->vliny + d > destline) { 156 if (IN && destcol == WCOLS) 157 vigoto(vp->vliny + d - 1, 0); 158 vclreol(); 159 } 160 return (d); 161 } 162 163 /* 164 * Real work for winning growing of window at top 165 * when inserting in the middle of a partially full 166 * screen on an intelligent terminal. We have as argument 167 * the logical line number to be inserted after, and the offset 168 * from that line where the insert will go. 169 * We look at the picture of depths and positions, and if we can 170 * delete some (blank) lines from the top of the screen so that 171 * later inserts will not push stuff off the bottom. 172 */ 173 vglitchup(l, o) 174 int l, o; 175 { 176 register struct vlinfo *vp = &vlinfo[l]; 177 register int need; 178 register int p = vp->vliny; 179 short oldhold, oldheldech; 180 bool glitched = 0; 181 182 if (l < vcnt - 1) { 183 need = p + vp->vdepth - (vp+1)->vliny; 184 if (need > 0) { 185 if (state == VISUAL && WTOP - ZERO >= need && AL && DL) { 186 glitched++; 187 WTOP -= need; 188 WLINES = WBOT - WTOP + 1; 189 p -= need; 190 if (p + o == WTOP) { 191 vp->vliny = WTOP; 192 return (WTOP + o); 193 } 194 vdellin(WTOP, need, -1); 195 oldheldech = heldech; 196 oldhold = hold; 197 hold |= HOLDECH; 198 } 199 vinslin((vp+1)->vliny, need, l); 200 if (glitched) { 201 hold = oldhold; 202 heldech = oldheldech; 203 } 204 } 205 } else 206 vp[1].vliny = vp[0].vliny + vp->vdepth; 207 return (p + o); 208 } 209 210 /* 211 * Insert cnt blank lines before line p, 212 * logically and (if supported) physically. 213 */ 214 vinslin(p, cnt, l) 215 register int p, cnt; 216 int l; 217 { 218 register int i; 219 bool could = 1; 220 221 #ifdef ADEBUG 222 if (trace) 223 tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l); 224 #endif 225 if (p + cnt > WBOT && CD) { 226 /* 227 * Really quick -- clear to end of screen. 228 */ 229 cnt = WECHO + 1 - p; 230 vgoto(p, 0), vputp(CD, cnt); 231 vclrech(1); 232 vadjAL(p, cnt); 233 } else if (SR && p == WTOP && costSR < costAL) { 234 /* 235 * Use reverse scroll mode of the terminal, at 236 * the top of the window. Reverse linefeed works 237 * too, since we only use it from line WTOP. 238 */ 239 for (i = cnt; i > 0; i--) { 240 vgoto(p, 0), vputp(SR, 0); 241 if (i > 1 && (hold & HOLDAT) == 0) 242 putchar('@'); 243 /* 244 * If we are at the top of the screen, and the 245 * terminal retains display above, then we 246 * should try to clear to end of line. 247 * Have to use CE since we don't remember what is 248 * actually on the line. 249 */ 250 if (CE && (DA || p != 0)) 251 vputp(CE, 1); 252 } 253 vadjAL(p, cnt); 254 } else if (AL) { 255 /* 256 * Use insert line. 257 */ 258 vgoto(p, 0); 259 if (XV) 260 vputp(tgoto(AL, 0, p), WECHO + 1 - p); 261 else 262 vputp(AL, WECHO + 1 - p); 263 for (i = cnt - 1; i > 0; i--) { 264 vgoto(outline+1, 0); 265 if (XV) 266 vputp(tgoto(AL, 0, outline+1), WECHO + 1 - outline); 267 else 268 vputp(AL, WECHO + 1 - outline); 269 if ((hold & HOLDAT) == 0) 270 putchar('@'); 271 } 272 vadjAL(p, cnt); 273 } else 274 could = 0; 275 vopenup(cnt, could, l); 276 } 277 278 /* 279 * Logically open up after line l, cnt of them. 280 * We need to know if it was done ``physically'' since in this 281 * case we accept what the hardware gives us. If we have to do 282 * it ourselves (brute force) we will squish out @ lines in the process 283 * if this will save us work. 284 */ 285 vopenup(cnt, could, l) 286 int cnt; 287 bool could; 288 { 289 register struct vlinfo *vc = &vlinfo[l + 1]; 290 register struct vlinfo *ve = &vlinfo[vcnt]; 291 292 #ifdef ADEBUG 293 if (trace) 294 tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l); 295 #endif 296 if (could) 297 /* 298 * This will push @ lines down the screen, 299 * just as the hardware did. Since the default 300 * for intelligent terminals is to never have @ 301 * lines on the screen, this should never happen, 302 * and the code makes no special effort to be nice in this 303 * case, e.g. squishing out the @ lines by delete lines 304 * before doing append lines. 305 */ 306 for (; vc <= ve; vc++) 307 vc->vliny += cnt; 308 else { 309 /* 310 * Will have to clean up brute force eventually, 311 * so push the line data around as little as possible. 312 */ 313 vc->vliny += cnt, vc->vflags |= VDIRT; 314 while (vc < ve) { 315 register int i = vc->vliny + vc->vdepth; 316 317 vc++; 318 if (i <= vc->vliny) 319 break; 320 vc->vliny = i, vc->vflags |= VDIRT; 321 } 322 } 323 vscrap(); 324 } 325 326 /* 327 * Adjust data structure internally to account for insertion of 328 * blank lines on the screen. 329 */ 330 vadjAL(p, cnt) 331 int p, cnt; 332 { 333 char *tlines[TUBELINES]; 334 register int from, to; 335 336 #ifdef ADEBUG 337 if (trace) 338 tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt); 339 #endif 340 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 341 for (from = p, to = p + cnt; to <= WECHO; from++, to++) 342 vtube[to] = tlines[from]; 343 for (to = p; from <= WECHO; from++, to++) { 344 vtube[to] = tlines[from]; 345 vclrbyte(vtube[to], WCOLS); 346 } 347 /* 348 * Have to clear the echo area since its contents aren't 349 * necessarily consistent with the rest of the display. 350 */ 351 vclrech(0); 352 } 353 354 /* 355 * Roll the screen up logically and physically 356 * so that line dl is the bottom line on the screen. 357 */ 358 vrollup(dl) 359 int dl; 360 { 361 register int cnt; 362 register int dc = destcol; 363 364 #ifdef ADEBUG 365 if (trace) 366 tfixnl(), fprintf(trace, "vrollup(%d)\n", dl); 367 #endif 368 cnt = dl - (splitw ? WECHO : WBOT); 369 if (splitw && (state == VISUAL || state == CRTOPEN)) 370 holdupd = 1; 371 vmoveitup(cnt, 1); 372 vscroll(cnt); 373 destline = dl - cnt, destcol = dc; 374 } 375 376 vup1() 377 { 378 379 vrollup(WBOT + 1); 380 } 381 382 /* 383 * Scroll the screen up cnt lines physically. 384 * If doclr is true, do a clear eol if the terminal 385 * has standout (to prevent it from scrolling up) 386 */ 387 vmoveitup(cnt, doclr) 388 register int cnt; 389 bool doclr; 390 { 391 392 if (cnt == 0) 393 return; 394 #ifdef ADEBUG 395 if (trace) 396 tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt); 397 #endif 398 if (doclr && (SO || SE)) 399 vclrech(0); 400 if (SF) { 401 while (cnt > 0) 402 vputp(SF, 0), cnt--; 403 return; 404 } 405 destline = WECHO + cnt; 406 destcol = (NONL ? 0 : outcol % WCOLS); 407 fgoto(); 408 if (state == ONEOPEN || state == HARDOPEN) { 409 outline = destline = 0; 410 vclrbyte(vtube[0], WCOLS); 411 } 412 } 413 414 /* 415 * Scroll the screen up cnt lines logically. 416 */ 417 vscroll(cnt) 418 register int cnt; 419 { 420 register int from, to; 421 char *tlines[TUBELINES]; 422 423 #ifdef ADEBUG 424 if (trace) 425 fprintf(trace, "vscroll(%d)\n", cnt); 426 #endif 427 if (cnt < 0 || cnt > TUBELINES) 428 error("Internal error: vscroll"); 429 if (cnt == 0) 430 return; 431 copy(tlines, vtube, sizeof vtube); 432 for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++) 433 vtube[to] = tlines[from]; 434 for (from = ZERO; to <= WECHO; to++, from++) { 435 vtube[to] = tlines[from]; 436 vclrbyte(vtube[to], WCOLS); 437 } 438 for (from = 0; from <= vcnt; from++) 439 LINE(from) -= cnt; 440 } 441 442 /* 443 * Discard logical lines due to physical wandering off the screen. 444 */ 445 vscrap() 446 { 447 register int i, j; 448 449 #ifdef ADEBUG 450 if (trace) 451 tfixnl(), fprintf(trace, "vscrap\n"), tvliny(); 452 #endif 453 if (splitw) 454 return; 455 if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) { 456 WTOP = LINE(0); 457 WLINES = WBOT - WTOP + 1; 458 } 459 for (j = 0; j < vcnt; j++) 460 if (LINE(j) >= WTOP) { 461 if (j == 0) 462 break; 463 /* 464 * Discard the first j physical lines off the top. 465 */ 466 vcnt -= j, vcline -= j; 467 for (i = 0; i <= vcnt; i++) 468 vlcopy(vlinfo[i], vlinfo[i + j]); 469 break; 470 } 471 /* 472 * Discard lines off the bottom. 473 */ 474 if (vcnt) { 475 for (j = 0; j <= vcnt; j++) 476 if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) { 477 vcnt = j; 478 break; 479 } 480 LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1); 481 } 482 #ifdef ADEBUG 483 if (trace) 484 tvliny(); 485 #endif 486 /* 487 * May have no lines! 488 */ 489 } 490 491 /* 492 * Repaint the screen, with cursor at curs, aftern an arbitrary change. 493 * Handle notification on large changes. 494 */ 495 vrepaint(curs) 496 char *curs; 497 { 498 499 wdot = NOLINE; 500 /* 501 * In open want to notify first. 502 */ 503 noteit(0); 504 vscrap(); 505 506 /* 507 * Deal with a totally useless display. 508 */ 509 if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) { 510 register line *odol = dol; 511 512 vcnt = 0; 513 if (holdupd) 514 if (state == VISUAL) 515 ignore(peekkey()); 516 else 517 vup1(); 518 holdupd = 0; 519 if (odol == zero) 520 fixzero(); 521 vcontext(dot, '.'); 522 noteit(1); 523 if (noteit(1) == 0 && odol == zero) { 524 CATCH 525 error("No lines in buffer"); 526 ENDCATCH 527 linebuf[0] = 0; 528 splitw = 0; 529 } 530 vnline(curs); 531 return; 532 } 533 534 /* 535 * Have some useful displayed text; refresh it. 536 */ 537 getDOT(); 538 539 /* 540 * This is for boundary conditions in open mode. 541 */ 542 if (FLAGS(0) & VDIRT) 543 vsync(WTOP); 544 545 /* 546 * If the current line is after the last displayed line 547 * or the bottom of the screen, then special effort is needed 548 * to get it on the screen. We first try a redraw at the 549 * last line on the screen, hoping it will fill in where @ 550 * lines are now. If this doesn't work, then roll it onto 551 * the screen. 552 */ 553 if (vcline >= vcnt || LINE(vcline) > WBOT) { 554 short oldhold = hold; 555 hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold; 556 if (vcline >= vcnt) { 557 register int i = vcline - vcnt + 1; 558 559 dot -= i; 560 vcline -= i; 561 vroll(i); 562 } else 563 vsyncCL(); 564 } else 565 vsync(vcline > 0 ? LINE(vcline - 1) : WTOP); 566 567 /* 568 * Notification on large change for visual 569 * has to be done last or we may lose 570 * the echo area with redisplay. 571 */ 572 noteit(1); 573 574 /* 575 * Finally. Move the cursor onto the current line. 576 */ 577 vnline(curs); 578 } 579 580 /* 581 * Fully cleanup the screen, leaving no @ lines except at end when 582 * line after last won't completely fit. The routine vsync is 583 * more conservative and much less work on dumb terminals. 584 */ 585 vredraw(p) 586 register int p; 587 { 588 register int l; 589 register line *tp; 590 char temp[LBSIZE]; 591 bool anydl = 0; 592 short oldhold = hold; 593 594 #ifdef ADEBUG 595 if (trace) 596 tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny(); 597 #endif 598 if (holdupd) { 599 holdupd = 3; 600 return; 601 } 602 if (state == HARDOPEN || splitw) 603 return; 604 if (p < 0 /* || p > WECHO */) 605 error("Internal error: vredraw"); 606 607 /* 608 * Trim the ragged edges (lines which are off the screen but 609 * not yet logically discarded), save the current line, and 610 * search for first logical line affected by the redraw. 611 */ 612 vscrap(); 613 CP(temp, linebuf); 614 l = 0; 615 tp = dot - vcline; 616 if (vcnt == 0) 617 LINE(0) = WTOP; 618 while (l < vcnt && LINE(l) < p) 619 l++, tp++; 620 621 /* 622 * We hold off echo area clearing during the redraw in deference 623 * to a final clear of the echo area at the end if appropriate. 624 */ 625 heldech = 0; 626 hold |= HOLDECH; 627 for (; l < vcnt && Peekkey != ATTN; l++) { 628 if (l == vcline) 629 strcLIN(temp); 630 else 631 getline(*tp); 632 633 /* 634 * Delete junk between displayed lines. 635 */ 636 if (LINE(l) != LINE(l + 1) && LINE(l) != p) { 637 if (anydl == 0 && DB && CD) { 638 hold = oldhold; 639 vclrech(0); 640 anydl = 1; 641 hold |= HOLDECH; 642 heldech = 0; 643 } 644 vdellin(p, LINE(l) - p, l); 645 } 646 647 /* 648 * If line image is not know to be up to date, then 649 * redisplay it; else just skip onward. 650 */ 651 LINE(l) = p; 652 if (FLAGS(l) & VDIRT) { 653 DEPTH(l) = vdepth(); 654 if (l != vcline && p + DEPTH(l) - 1 > WBOT) { 655 vscrap(); 656 break; 657 } 658 FLAGS(l) &= ~VDIRT; 659 vreopen(p, lineno(tp), l); 660 p = LINE(l) + DEPTH(l); 661 } else 662 p += DEPTH(l); 663 tp++; 664 } 665 666 /* 667 * That takes care of lines which were already partially displayed. 668 * Now try to fill the rest of the screen with text. 669 */ 670 if (state == VISUAL && p <= WBOT) { 671 int ovcline = vcline; 672 673 vcline = l; 674 for (; tp <= dol && Peekkey != ATTN; tp++) { 675 getline(*tp); 676 if (p + vdepth() - 1 > WBOT) 677 break; 678 vopen(tp, p); 679 p += DEPTH(vcline); 680 vcline++; 681 } 682 vcline = ovcline; 683 } 684 685 /* 686 * Thats all the text we can get on. 687 * Now rest of lines (if any) get either a ~ if they 688 * are past end of file, or an @ if the next line won't fit. 689 */ 690 for (; p <= WBOT && Peekkey != ATTN; p++) 691 vclrlin(p, tp); 692 strcLIN(temp); 693 hold = oldhold; 694 if (heldech) 695 vclrech(0); 696 #ifdef ADEBUG 697 if (trace) 698 tvliny(); 699 #endif 700 } 701 702 /* 703 * Do the real work in deleting cnt lines starting at line p from 704 * the display. First affected line is line l. 705 */ 706 vdellin(p, cnt, l) 707 int p, cnt, l; 708 { 709 register int i; 710 711 if (cnt == 0) 712 return; 713 if (DL == NOSTR || cnt < 0) { 714 /* 715 * Can't do it; just remember that line l is munged. 716 */ 717 FLAGS(l) |= VDIRT; 718 return; 719 } 720 #ifdef ADEBUG 721 if (trace) 722 tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l); 723 #endif 724 /* 725 * Send the deletes to the screen and then adjust logical 726 * and physical internal data structures. 727 */ 728 vgoto(p, 0); 729 for (i = 0; i < cnt; i++) 730 if (XV) 731 vputp(tgoto(DL, 0, p), WECHO - p); 732 else 733 vputp(DL, WECHO - p); 734 vadjDL(p, cnt); 735 vcloseup(l, cnt); 736 } 737 /* 738 * Adjust internal physical screen image to account for deleted lines. 739 */ 740 vadjDL(p, cnt) 741 int p, cnt; 742 { 743 char *tlines[TUBELINES]; 744 register int from, to; 745 746 #ifdef ADEBUG 747 if (trace) 748 tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt); 749 #endif 750 /* 751 * Would like to use structured assignment but early 752 * v7 compiler (released with phototypesetter for v6) 753 * can't hack it. 754 */ 755 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 756 for (from = p + cnt, to = p; from <= WECHO; from++, to++) 757 vtube[to] = tlines[from]; 758 for (from = p; to <= WECHO; from++, to++) { 759 vtube[to] = tlines[from]; 760 vclrbyte(vtube[to], WCOLS); 761 } 762 } 763 /* 764 * Sync the screen, like redraw but more lazy and willing to leave 765 * @ lines on the screen. VsyncCL syncs starting at the current line. 766 * In any case, if the redraw option is set then all syncs map to redraws 767 * as if vsync didn't exist. 768 */ 769 vsyncCL() 770 { 771 772 vsync(LINE(vcline)); 773 } 774 775 vsync(p) 776 register int p; 777 { 778 779 if (value(REDRAW)) 780 vredraw(p); 781 else 782 vsync1(p); 783 } 784 785 /* 786 * The guts of a sync. Similar to redraw but 787 * just less ambitous. 788 */ 789 vsync1(p) 790 register int p; 791 { 792 register int l; 793 char temp[LBSIZE]; 794 register struct vlinfo *vp = &vlinfo[0]; 795 short oldhold = hold; 796 797 #ifdef ADEBUG 798 if (trace) 799 tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny(); 800 #endif 801 if (holdupd) { 802 if (holdupd < 3) 803 holdupd = 2; 804 return; 805 } 806 if (state == HARDOPEN || splitw) 807 return; 808 vscrap(); 809 CP(temp, linebuf); 810 if (vcnt == 0) 811 LINE(0) = WTOP; 812 l = 0; 813 while (l < vcnt && vp->vliny < p) 814 l++, vp++; 815 heldech = 0; 816 hold |= HOLDECH; 817 while (p <= WBOT && Peekkey != ATTN) { 818 /* 819 * Want to put a line here if not in visual and first line 820 * or if there are lies left and this line starts before 821 * the current line, or if this line is piled under the 822 * next line (vreplace does this and we undo it). 823 */ 824 if (l == 0 && state != VISUAL || 825 (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) { 826 if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) { 827 if (l == vcline) 828 strcLIN(temp); 829 else 830 getline(dot[l - vcline]); 831 /* 832 * Be careful that a long line doesn't cause the 833 * screen to shoot up. 834 */ 835 if (l != vcline && (vp->vflags & VDIRT)) { 836 vp->vdepth = vdepth(); 837 vp->vflags &= ~VDIRT; 838 if (p + vp->vdepth - 1 > WBOT) 839 break; 840 } 841 vreopen(p, lineDOT() + (l - vcline), l); 842 } 843 p = vp->vliny + vp->vdepth; 844 vp++; 845 l++; 846 } else 847 /* 848 * A physical line between logical lines, 849 * so we settle for an @ at the beginning. 850 */ 851 vclrlin(p, dot + (l - vcline)), p++; 852 } 853 strcLIN(temp); 854 hold = oldhold; 855 if (heldech) 856 vclrech(0); 857 } 858 859 /* 860 * Subtract (logically) cnt physical lines from the 861 * displayed position of lines starting with line l. 862 */ 863 vcloseup(l, cnt) 864 int l; 865 register int cnt; 866 { 867 register int i; 868 869 #ifdef ADEBUG 870 if (trace) 871 tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt); 872 #endif 873 for (i = l + 1; i <= vcnt; i++) 874 LINE(i) -= cnt; 875 } 876 877 /* 878 * Workhorse for rearranging line descriptors on changes. 879 * The idea here is that, starting with line l, cnt lines 880 * have been replaced with newcnt lines. All of these may 881 * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0, 882 * since we may be called from an undo after the screen has 883 * moved a lot. Thus we have to be careful. 884 * 885 * Many boundary conditions here. 886 */ 887 vreplace(l, cnt, newcnt) 888 int l, cnt, newcnt; 889 { 890 register int from, to, i; 891 bool savenote = 0; 892 893 #ifdef ADEBUG 894 if (trace) { 895 tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt); 896 tvliny(); 897 } 898 #endif 899 if (l >= vcnt) 900 return; 901 if (l < 0) { 902 if (l + cnt < 0) { 903 /* 904 * Nothing on the screen is relevant. 905 * Settle for redrawing from scratch (later). 906 */ 907 vcnt = 0; 908 return; 909 } 910 /* 911 * Normalize l to top of screen; the add is 912 * really a subtract from cnt since l is negative. 913 */ 914 cnt += l; 915 l = 0; 916 917 /* 918 * Unseen lines were affect so notify (later). 919 */ 920 savenote++; 921 } 922 923 /* 924 * These shouldn't happen 925 * but would cause great havoc. 926 */ 927 if (cnt < 0) 928 cnt = 0; 929 if (newcnt < 0) 930 newcnt = 0; 931 932 /* 933 * Surely worthy of note if more than report 934 * lines were changed. 935 */ 936 if (cnt > value(REPORT) || newcnt > value(REPORT)) 937 savenote++; 938 939 /* 940 * Same number of lines affeted as on screen, and we 941 * can insert and delete lines. Thus we just type 942 * over them, since otherwise we will push them 943 * slowly off the screen, a clear lose. 944 */ 945 if (cnt == newcnt || vcnt - l == newcnt && AL && DL) { 946 if (cnt > 1 && l + cnt > vcnt) 947 savenote++; 948 vdirty(l, newcnt); 949 } else { 950 /* 951 * Lines are going away, squish them out. 952 */ 953 if (cnt > 0) { 954 /* 955 * If non-displayed lines went away, 956 * always notify. 957 */ 958 if (cnt > 1 && l + cnt > vcnt) 959 savenote++; 960 if (l + cnt >= vcnt) 961 cnt = vcnt - l; 962 else 963 for (from = l + cnt, to = l; from <= vcnt; to++, from++) 964 vlcopy(vlinfo[to], vlinfo[from]); 965 vcnt -= cnt; 966 } 967 /* 968 * Open up space for new lines appearing. 969 * All new lines are piled in the same place, 970 * and will be unpiled by vredraw/vsync, which 971 * inserts lines in front as it unpiles. 972 */ 973 if (newcnt > 0) { 974 /* 975 * Newlines are appearing which may not show, 976 * so notify (this is only approximately correct 977 * when long lines are present). 978 */ 979 if (newcnt > 1 && l + newcnt > vcnt + 1) 980 savenote++; 981 982 /* 983 * If there will be more lines than fit, then 984 * just throw way the rest of the stuff on the screen. 985 */ 986 if (l + newcnt > WBOT && AL && DL) { 987 vcnt = l; 988 goto skip; 989 } 990 from = vcnt, to = vcnt + newcnt; 991 i = TUBELINES - to; 992 if (i < 0) 993 from += i, to += i; 994 vcnt = to; 995 for (; from >= l; from--, to--) 996 vlcopy(vlinfo[to], vlinfo[from]); 997 for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) { 998 LINE(to) = LINE(from); 999 DEPTH(to) = 0; 1000 FLAGS(to) = VDIRT; 1001 } 1002 } 1003 } 1004 skip: 1005 if (Pline == numbline && cnt != newcnt) 1006 /* 1007 * When lines positions are shifted, the numbers 1008 * will be wrong. 1009 */ 1010 vdirty(l, WECHO); 1011 if (!savenote) 1012 notecnt = 0; 1013 #ifdef ADEBUG 1014 if (trace) 1015 tvliny(); 1016 #endif 1017 } 1018 1019 /* 1020 * Start harcopy open. 1021 * Print an image of the line to the left of the cursor 1022 * under the full print of the line and position the cursor. 1023 * If we are in a scroll ^D within hardcopy open then all this 1024 * is suppressed. 1025 */ 1026 sethard() 1027 { 1028 1029 if (state == VISUAL) 1030 return; 1031 rubble = 0; 1032 state = HARDOPEN; 1033 if (hold & HOLDROL) 1034 return; 1035 vup1(); 1036 LINE(0) = WBOT; 1037 if (Pline == numbline) 1038 vgoto(WBOT, 0), printf("%6d ", lineDOT()); 1039 } 1040 1041 /* 1042 * Mark the lines starting at base for i lines 1043 * as dirty so that they will be checked for correct 1044 * display at next sync/redraw. 1045 */ 1046 vdirty(base, i) 1047 register int base, i; 1048 { 1049 register int l; 1050 1051 for (l = base; l < vcnt; l++) { 1052 if (--i < 0) 1053 return; 1054 FLAGS(l) |= VDIRT; 1055 } 1056 } 1057