1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_vadj.c 5.1 08/20/80"; 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 #ifdef ADEBUG 93 if (trace) 94 tfixnl(), fprintf(trace, "vreopen(%d, %d, %d)\n", p, lineno, l); 95 #endif 96 d = vp->vdepth; 97 if (d == 0 || (vp->vflags & VDIRT)) 98 vp->vdepth = d = vdepth(); 99 vp->vliny = p, vp->vflags &= ~VDIRT; 100 101 /* 102 * Try to win by making the screen larger rather than inserting 103 * a line and driving text off the bottom. 104 */ 105 p = vglitchup(l, 0); 106 107 /* 108 * BUG: Should consider using CE here to clear to end of line. 109 * As it stands we always strike over the current text. 110 * Since often the current text is the same as what 111 * we are overstriking with, it tends not to show. 112 * On the other hand if it is different and we end up 113 * spacing out a lot of text, we could have won with 114 * a CE. This is probably worthwhile at low speed 115 * only however, since clearly computation will be 116 * necessary to determine which way to go. 117 */ 118 vigoto(p, 0); 119 #ifdef TRACE 120 if (trace) 121 fprintf(trace, "before pline in vreopen\n"); 122 #endif 123 pline(lineno); 124 #ifdef TRACE 125 if (trace) 126 fprintf(trace, "after pline in vreopen\n"); 127 #endif 128 129 /* 130 * When we are typing part of a line for hardcopy open, don't 131 * want to type the '$' marking an end of line if in list mode. 132 */ 133 if (hold & HOLDDOL) 134 return (d); 135 if (Putchar == listchar) 136 putchar('$'); 137 138 /* 139 * Optimization of cursor motion may prevent screen rollup if the 140 * line has blanks/tabs at the end unless we force the cursor to appear 141 * on the last line segment. 142 */ 143 if (vp->vliny + d - 1 > WBOT) 144 vcsync(); 145 146 /* 147 * Switch into hardcopy open mode if we are in one line (adm3) 148 * open mode and this line is now too long. If in hardcopy 149 * open mode, then call sethard to move onto the next line 150 * with appropriate positioning. 151 */ 152 if (state == ONEOPEN) { 153 WCOLS = OCOLUMNS; 154 if (vdepth() > 1) { 155 WCOLS = TUBECOLS; 156 sethard(); 157 } else 158 WCOLS = TUBECOLS; 159 } else if (state == HARDOPEN) 160 sethard(); 161 162 /* 163 * Unless we filled (completely) the last line we typed on, 164 * we have to clear to the end of the line 165 * in case stuff is left from before. 166 */ 167 if (vp->vliny + d > destline) { 168 if (IN && destcol == WCOLS) 169 vigoto(vp->vliny + d - 1, 0); 170 vclreol(); 171 } 172 return (d); 173 } 174 175 /* 176 * Real work for winning growing of window at top 177 * when inserting in the middle of a partially full 178 * screen on an intelligent terminal. We have as argument 179 * the logical line number to be inserted after, and the offset 180 * from that line where the insert will go. 181 * We look at the picture of depths and positions, and if we can 182 * delete some (blank) lines from the top of the screen so that 183 * later inserts will not push stuff off the bottom. 184 */ 185 vglitchup(l, o) 186 int l, o; 187 { 188 register struct vlinfo *vp = &vlinfo[l]; 189 register int need; 190 register int p = vp->vliny; 191 short oldhold, oldheldech; 192 bool glitched = 0; 193 194 if (l < vcnt - 1) { 195 need = p + vp->vdepth - (vp+1)->vliny; 196 if (need > 0) { 197 if (state == VISUAL && WTOP - ZERO >= need && AL && DL) { 198 glitched++; 199 WTOP -= need; 200 WLINES = WBOT - WTOP + 1; 201 p -= need; 202 if (p + o == WTOP) { 203 vp->vliny = WTOP; 204 return (WTOP + o); 205 } 206 vdellin(WTOP, need, -1); 207 oldheldech = heldech; 208 oldhold = hold; 209 hold |= HOLDECH; 210 } 211 vinslin((vp+1)->vliny, need, l); 212 if (glitched) { 213 hold = oldhold; 214 heldech = oldheldech; 215 } 216 } 217 } else 218 vp[1].vliny = vp[0].vliny + vp->vdepth; 219 return (p + o); 220 } 221 222 /* 223 * Insert cnt blank lines before line p, 224 * logically and (if supported) physically. 225 */ 226 vinslin(p, cnt, l) 227 register int p, cnt; 228 int l; 229 { 230 register int i; 231 bool could = 1; 232 233 #ifdef ADEBUG 234 if (trace) 235 tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l); 236 #endif 237 if (p + cnt > WBOT && CD) { 238 /* 239 * Really quick -- clear to end of screen. 240 */ 241 cnt = WECHO + 1 - p; 242 vgoto(p, 0), vputp(CD, cnt); 243 vclrech(1); 244 vadjAL(p, cnt); 245 } else if (AL) { 246 /* 247 * Use insert line. 248 */ 249 vgoto(p, 0), vputp(AL, WECHO + 1 - p); 250 for (i = cnt - 1; i > 0; i--) { 251 vgoto(outline+1, 0), vputp(AL, WECHO + 1 - outline); 252 if ((hold & HOLDAT) == 0) 253 putchar('@'); 254 } 255 vadjAL(p, cnt); 256 } else if (SR && p == WTOP) { 257 /* 258 * Use reverse scroll mode of the terminal, at 259 * the top of the window. 260 */ 261 for (i = cnt; i > 0; i--) { 262 vgoto(p, 0), vputp(SR, 0); 263 if (i > 1 && (hold & HOLDAT) == 0) 264 putchar('@'); 265 /* 266 * If we are at the top of the screen, and the 267 * terminal retains display above, then we 268 * should try to clear to end of line. 269 * Have to use CE since we don't remember what is 270 * actually on the line. 271 */ 272 if (CE && (DA || p != 0)) 273 vputp(CE, 1); 274 } 275 vadjAL(p, cnt); 276 } else 277 could = 0; 278 vopenup(cnt, could, l); 279 } 280 281 /* 282 * Logically open up after line l, cnt of them. 283 * We need to know if it was done ``physically'' since in this 284 * case we accept what the hardware gives us. If we have to do 285 * it ourselves (brute force) we will squish out @ lines in the process 286 * if this will save us work. 287 */ 288 vopenup(cnt, could, l) 289 int cnt; 290 bool could; 291 { 292 register struct vlinfo *vc = &vlinfo[l + 1]; 293 register struct vlinfo *ve = &vlinfo[vcnt]; 294 295 #ifdef ADEBUG 296 if (trace) 297 tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l); 298 #endif 299 if (could) 300 /* 301 * This will push @ lines down the screen, 302 * just as the hardware did. Since the default 303 * for intelligent terminals is to never have @ 304 * lines on the screen, this should never happen, 305 * and the code makes no special effort to be nice in this 306 * case, e.g. squishing out the @ lines by delete lines 307 * before doing append lines. 308 */ 309 for (; vc <= ve; vc++) 310 vc->vliny += cnt; 311 else { 312 /* 313 * Will have to clean up brute force eventually, 314 * so push the line data around as little as possible. 315 */ 316 vc->vliny += cnt, vc->vflags |= VDIRT; 317 while (vc < ve) { 318 register int i = vc->vliny + vc->vdepth; 319 320 vc++; 321 if (i <= vc->vliny) 322 break; 323 vc->vliny = i, vc->vflags |= VDIRT; 324 } 325 } 326 vscrap(); 327 } 328 329 /* 330 * Adjust data structure internally to account for insertion of 331 * blank lines on the screen. 332 */ 333 vadjAL(p, cnt) 334 int p, cnt; 335 { 336 char *tlines[TUBELINES]; 337 register int from, to; 338 339 #ifdef ADEBUG 340 if (trace) 341 tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt); 342 #endif 343 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 344 for (from = p, to = p + cnt; to <= WECHO; from++, to++) 345 vtube[to] = tlines[from]; 346 for (to = p; from <= WECHO; from++, to++) { 347 vtube[to] = tlines[from]; 348 vclrbyte(vtube[to], WCOLS); 349 } 350 /* 351 * Have to clear the echo area since its contents aren't 352 * necessarily consistent with the rest of the display. 353 */ 354 vclrech(0); 355 } 356 357 /* 358 * Roll the screen up logically and physically 359 * so that line dl is the bottom line on the screen. 360 */ 361 vrollup(dl) 362 int dl; 363 { 364 register int cnt; 365 register int dc = destcol; 366 367 #ifdef ADEBUG 368 if (trace) 369 tfixnl(), fprintf(trace, "vrollup(%d)\n", dl); 370 #endif 371 cnt = dl - (splitw ? WECHO : WBOT); 372 if (splitw && (state == VISUAL || state == CRTOPEN)) 373 holdupd = 1; 374 vmoveitup(cnt, 1); 375 vscroll(cnt); 376 destline = dl - cnt, destcol = dc; 377 } 378 379 vup1() 380 { 381 382 vrollup(WBOT + 1); 383 } 384 385 /* 386 * Scroll the screen up cnt lines physically. 387 * If doclr is true, do a clear eol if the terminal 388 * has standout (to prevent it from scrolling up) 389 */ 390 vmoveitup(cnt, doclr) 391 register int cnt; 392 bool doclr; 393 { 394 395 if (cnt == 0) 396 return; 397 #ifdef ADEBUG 398 if (trace) 399 tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt); 400 #endif 401 if (doclr && (SO || SE)) 402 vclrech(0); 403 if (SF) { 404 while (cnt > 0) 405 vputp(SF, 0), cnt--; 406 return; 407 } 408 destline = WECHO + cnt; 409 destcol = (NONL ? 0 : outcol % WCOLS); 410 fgoto(); 411 if (state == ONEOPEN || state == HARDOPEN) { 412 outline = destline = 0; 413 vclrbyte(vtube[0], WCOLS); 414 } 415 } 416 417 /* 418 * Scroll the screen up cnt lines logically. 419 */ 420 vscroll(cnt) 421 register int cnt; 422 { 423 register int from, to; 424 char *tlines[TUBELINES]; 425 426 #ifdef ADEBUG 427 if (trace) 428 fprintf(trace, "vscroll(%d)\n", cnt); 429 #endif 430 if (cnt < 0 || cnt > TUBELINES) 431 error("Internal error: vscroll"); 432 if (cnt == 0) 433 return; 434 copy(tlines, vtube, sizeof vtube); 435 for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++) 436 vtube[to] = tlines[from]; 437 for (from = ZERO; to <= WECHO; to++, from++) { 438 vtube[to] = tlines[from]; 439 vclrbyte(vtube[to], WCOLS); 440 } 441 for (from = 0; from <= vcnt; from++) 442 LINE(from) -= cnt; 443 } 444 445 /* 446 * Discard logical lines due to physical wandering off the screen. 447 */ 448 vscrap() 449 { 450 register int i, j; 451 452 #ifdef ADEBUG 453 if (trace) 454 tfixnl(), fprintf(trace, "vscrap\n"), tvliny(); 455 #endif 456 if (splitw) 457 return; 458 if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) { 459 WTOP = LINE(0); 460 WLINES = WBOT - WTOP + 1; 461 } 462 for (j = 0; j < vcnt; j++) 463 if (LINE(j) >= WTOP) { 464 if (j == 0) 465 break; 466 /* 467 * Discard the first j physical lines off the top. 468 */ 469 vcnt -= j, vcline -= j; 470 for (i = 0; i <= vcnt; i++) 471 vlcopy(vlinfo[i], vlinfo[i + j]); 472 break; 473 } 474 /* 475 * Discard lines off the bottom. 476 */ 477 if (vcnt) { 478 for (j = 0; j <= vcnt; j++) 479 if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) { 480 vcnt = j; 481 break; 482 } 483 LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1); 484 } 485 #ifdef ADEBUG 486 if (trace) 487 tvliny(); 488 #endif 489 /* 490 * May have no lines! 491 */ 492 } 493 494 /* 495 * Repaint the screen, with cursor at curs, aftern an arbitrary change. 496 * Handle notification on large changes. 497 */ 498 vrepaint(curs) 499 char *curs; 500 { 501 502 wdot = NOLINE; 503 /* 504 * In open want to notify first. 505 */ 506 noteit(0); 507 vscrap(); 508 509 /* 510 * Deal with a totally useless display. 511 */ 512 if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) { 513 register line *odol = dol; 514 515 vcnt = 0; 516 if (holdupd) 517 if (state == VISUAL) 518 ignore(peekkey()); 519 else 520 vup1(); 521 holdupd = 0; 522 if (odol == zero) 523 fixzero(); 524 vcontext(dot, '.'); 525 noteit(1); 526 if (noteit(1) == 0 && odol == zero) { 527 CATCH 528 error("No lines in buffer"); 529 ENDCATCH 530 linebuf[0] = 0; 531 splitw = 0; 532 } 533 vnline(curs); 534 return; 535 } 536 537 /* 538 * Have some useful displayed text; refresh it. 539 */ 540 getDOT(); 541 542 /* 543 * This is for boundary conditions in open mode. 544 */ 545 if (FLAGS(0) & VDIRT) 546 vsync(WTOP); 547 548 /* 549 * If the current line is after the last displayed line 550 * or the bottom of the screen, then special effort is needed 551 * to get it on the screen. We first try a redraw at the 552 * last line on the screen, hoping it will fill in where @ 553 * lines are now. If this doesn't work, then roll it onto 554 * the screen. 555 */ 556 if (vcline >= vcnt || LINE(vcline) > WBOT) { 557 short oldhold = hold; 558 hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold; 559 if (vcline >= vcnt) { 560 register int i = vcline - vcnt + 1; 561 562 dot -= i; 563 vcline -= i; 564 vroll(i); 565 } else 566 vsyncCL(); 567 } else 568 vsync(vcline > 0 ? LINE(vcline - 1) : WTOP); 569 570 /* 571 * Notification on large change for visual 572 * has to be done last or we may lose 573 * the echo area with redisplay. 574 */ 575 noteit(1); 576 577 /* 578 * Finally. Move the cursor onto the current line. 579 */ 580 vnline(curs); 581 } 582 583 /* 584 * Fully cleanup the screen, leaving no @ lines except at end when 585 * line after last won't completely fit. The routine vsync is 586 * more conservative and much less work on dumb terminals. 587 */ 588 vredraw(p) 589 register int p; 590 { 591 register int l; 592 register line *tp; 593 char temp[LBSIZE]; 594 bool anydl = 0; 595 short oldhold = hold; 596 597 #ifdef ADEBUG 598 if (trace) 599 tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny(); 600 #endif 601 if (holdupd) { 602 holdupd = 3; 603 return; 604 } 605 if (state == HARDOPEN || splitw) 606 return; 607 if (p < 0 /* || p > WECHO */) 608 error("Internal error: vredraw"); 609 610 /* 611 * Trim the ragged edges (lines which are off the screen but 612 * not yet logically discarded), save the current line, and 613 * search for first logical line affected by the redraw. 614 */ 615 vscrap(); 616 CP(temp, linebuf); 617 l = 0; 618 tp = dot - vcline; 619 if (vcnt == 0) 620 LINE(0) = WTOP; 621 while (l < vcnt && LINE(l) < p) 622 l++, tp++; 623 624 /* 625 * We hold off echo area clearing during the redraw in deference 626 * to a final clear of the echo area at the end if appropriate. 627 */ 628 heldech = 0; 629 hold |= HOLDECH; 630 for (; l < vcnt && Peekkey != ATTN; l++) { 631 if (l == vcline) 632 strcLIN(temp); 633 else 634 getline(*tp); 635 636 /* 637 * Delete junk between displayed lines. 638 */ 639 if (LINE(l) != LINE(l + 1) && LINE(l) != p) { 640 if (anydl == 0 && DB && CD) { 641 hold = oldhold; 642 vclrech(0); 643 anydl = 1; 644 hold |= HOLDECH; 645 heldech = 0; 646 } 647 vdellin(p, LINE(l) - p, l); 648 } 649 650 /* 651 * If line image is not know to be up to date, then 652 * redisplay it; else just skip onward. 653 */ 654 LINE(l) = p; 655 if (FLAGS(l) & VDIRT) { 656 DEPTH(l) = vdepth(); 657 if (l != vcline && p + DEPTH(l) - 1 > WBOT) { 658 vscrap(); 659 break; 660 } 661 FLAGS(l) &= ~VDIRT; 662 vreopen(p, lineno(tp), l); 663 p = LINE(l) + DEPTH(l); 664 } else 665 p += DEPTH(l); 666 tp++; 667 } 668 669 /* 670 * That takes care of lines which were already partially displayed. 671 * Now try to fill the rest of the screen with text. 672 */ 673 if (state == VISUAL && p <= WBOT) { 674 int ovcline = vcline; 675 676 vcline = l; 677 for (; tp <= dol && Peekkey != ATTN; tp++) { 678 getline(*tp); 679 if (p + vdepth() - 1 > WBOT) 680 break; 681 vopen(tp, p); 682 p += DEPTH(vcline); 683 vcline++; 684 } 685 vcline = ovcline; 686 } 687 688 /* 689 * Thats all the text we can get on. 690 * Now rest of lines (if any) get either a ~ if they 691 * are past end of file, or an @ if the next line won't fit. 692 */ 693 for (; p <= WBOT && Peekkey != ATTN; p++) 694 vclrlin(p, tp); 695 strcLIN(temp); 696 hold = oldhold; 697 if (heldech) 698 vclrech(0); 699 #ifdef ADEBUG 700 if (trace) 701 tvliny(); 702 #endif 703 } 704 705 /* 706 * Do the real work in deleting cnt lines starting at line p from 707 * the display. First affected line is line l. 708 */ 709 vdellin(p, cnt, l) 710 int p, cnt, l; 711 { 712 register int i; 713 714 if (cnt == 0) 715 return; 716 if (DL == NOSTR || cnt < 0) { 717 /* 718 * Can't do it; just remember that line l is munged. 719 */ 720 FLAGS(l) |= VDIRT; 721 return; 722 } 723 #ifdef ADEBUG 724 if (trace) 725 tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l); 726 #endif 727 /* 728 * Send the deletes to the screen and then adjust logical 729 * and physical internal data structures. 730 */ 731 vgoto(p, 0); 732 for (i = 0; i < cnt; i++) 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