1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_vadj.c 6.2 10/23/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 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), vputp(AL, WECHO + 1 - p); 259 for (i = cnt - 1; i > 0; i--) { 260 vgoto(outline+1, 0), vputp(AL, WECHO + 1 - outline); 261 if ((hold & HOLDAT) == 0) 262 putchar('@'); 263 } 264 vadjAL(p, cnt); 265 } else 266 could = 0; 267 vopenup(cnt, could, l); 268 } 269 270 /* 271 * Logically open up after line l, cnt of them. 272 * We need to know if it was done ``physically'' since in this 273 * case we accept what the hardware gives us. If we have to do 274 * it ourselves (brute force) we will squish out @ lines in the process 275 * if this will save us work. 276 */ 277 vopenup(cnt, could, l) 278 int cnt; 279 bool could; 280 { 281 register struct vlinfo *vc = &vlinfo[l + 1]; 282 register struct vlinfo *ve = &vlinfo[vcnt]; 283 284 #ifdef ADEBUG 285 if (trace) 286 tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l); 287 #endif 288 if (could) 289 /* 290 * This will push @ lines down the screen, 291 * just as the hardware did. Since the default 292 * for intelligent terminals is to never have @ 293 * lines on the screen, this should never happen, 294 * and the code makes no special effort to be nice in this 295 * case, e.g. squishing out the @ lines by delete lines 296 * before doing append lines. 297 */ 298 for (; vc <= ve; vc++) 299 vc->vliny += cnt; 300 else { 301 /* 302 * Will have to clean up brute force eventually, 303 * so push the line data around as little as possible. 304 */ 305 vc->vliny += cnt, vc->vflags |= VDIRT; 306 while (vc < ve) { 307 register int i = vc->vliny + vc->vdepth; 308 309 vc++; 310 if (i <= vc->vliny) 311 break; 312 vc->vliny = i, vc->vflags |= VDIRT; 313 } 314 } 315 vscrap(); 316 } 317 318 /* 319 * Adjust data structure internally to account for insertion of 320 * blank lines on the screen. 321 */ 322 vadjAL(p, cnt) 323 int p, cnt; 324 { 325 char *tlines[TUBELINES]; 326 register int from, to; 327 328 #ifdef ADEBUG 329 if (trace) 330 tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt); 331 #endif 332 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 333 for (from = p, to = p + cnt; to <= WECHO; from++, to++) 334 vtube[to] = tlines[from]; 335 for (to = p; from <= WECHO; from++, to++) { 336 vtube[to] = tlines[from]; 337 vclrbyte(vtube[to], WCOLS); 338 } 339 /* 340 * Have to clear the echo area since its contents aren't 341 * necessarily consistent with the rest of the display. 342 */ 343 vclrech(0); 344 } 345 346 /* 347 * Roll the screen up logically and physically 348 * so that line dl is the bottom line on the screen. 349 */ 350 vrollup(dl) 351 int dl; 352 { 353 register int cnt; 354 register int dc = destcol; 355 356 #ifdef ADEBUG 357 if (trace) 358 tfixnl(), fprintf(trace, "vrollup(%d)\n", dl); 359 #endif 360 cnt = dl - (splitw ? WECHO : WBOT); 361 if (splitw && (state == VISUAL || state == CRTOPEN)) 362 holdupd = 1; 363 vmoveitup(cnt, 1); 364 vscroll(cnt); 365 destline = dl - cnt, destcol = dc; 366 } 367 368 vup1() 369 { 370 371 vrollup(WBOT + 1); 372 } 373 374 /* 375 * Scroll the screen up cnt lines physically. 376 * If doclr is true, do a clear eol if the terminal 377 * has standout (to prevent it from scrolling up) 378 */ 379 vmoveitup(cnt, doclr) 380 register int cnt; 381 bool doclr; 382 { 383 384 if (cnt == 0) 385 return; 386 #ifdef ADEBUG 387 if (trace) 388 tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt); 389 #endif 390 if (doclr && (SO || SE)) 391 vclrech(0); 392 if (SF) { 393 while (cnt > 0) 394 vputp(SF, 0), cnt--; 395 return; 396 } 397 destline = WECHO + cnt; 398 destcol = (NONL ? 0 : outcol % WCOLS); 399 fgoto(); 400 if (state == ONEOPEN || state == HARDOPEN) { 401 outline = destline = 0; 402 vclrbyte(vtube[0], WCOLS); 403 } 404 } 405 406 /* 407 * Scroll the screen up cnt lines logically. 408 */ 409 vscroll(cnt) 410 register int cnt; 411 { 412 register int from, to; 413 char *tlines[TUBELINES]; 414 415 #ifdef ADEBUG 416 if (trace) 417 fprintf(trace, "vscroll(%d)\n", cnt); 418 #endif 419 if (cnt < 0 || cnt > TUBELINES) 420 error("Internal error: vscroll"); 421 if (cnt == 0) 422 return; 423 copy(tlines, vtube, sizeof vtube); 424 for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++) 425 vtube[to] = tlines[from]; 426 for (from = ZERO; to <= WECHO; to++, from++) { 427 vtube[to] = tlines[from]; 428 vclrbyte(vtube[to], WCOLS); 429 } 430 for (from = 0; from <= vcnt; from++) 431 LINE(from) -= cnt; 432 } 433 434 /* 435 * Discard logical lines due to physical wandering off the screen. 436 */ 437 vscrap() 438 { 439 register int i, j; 440 441 #ifdef ADEBUG 442 if (trace) 443 tfixnl(), fprintf(trace, "vscrap\n"), tvliny(); 444 #endif 445 if (splitw) 446 return; 447 if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) { 448 WTOP = LINE(0); 449 WLINES = WBOT - WTOP + 1; 450 } 451 for (j = 0; j < vcnt; j++) 452 if (LINE(j) >= WTOP) { 453 if (j == 0) 454 break; 455 /* 456 * Discard the first j physical lines off the top. 457 */ 458 vcnt -= j, vcline -= j; 459 for (i = 0; i <= vcnt; i++) 460 vlcopy(vlinfo[i], vlinfo[i + j]); 461 break; 462 } 463 /* 464 * Discard lines off the bottom. 465 */ 466 if (vcnt) { 467 for (j = 0; j <= vcnt; j++) 468 if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) { 469 vcnt = j; 470 break; 471 } 472 LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1); 473 } 474 #ifdef ADEBUG 475 if (trace) 476 tvliny(); 477 #endif 478 /* 479 * May have no lines! 480 */ 481 } 482 483 /* 484 * Repaint the screen, with cursor at curs, aftern an arbitrary change. 485 * Handle notification on large changes. 486 */ 487 vrepaint(curs) 488 char *curs; 489 { 490 491 wdot = NOLINE; 492 /* 493 * In open want to notify first. 494 */ 495 noteit(0); 496 vscrap(); 497 498 /* 499 * Deal with a totally useless display. 500 */ 501 if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) { 502 register line *odol = dol; 503 504 vcnt = 0; 505 if (holdupd) 506 if (state == VISUAL) 507 ignore(peekkey()); 508 else 509 vup1(); 510 holdupd = 0; 511 if (odol == zero) 512 fixzero(); 513 vcontext(dot, '.'); 514 noteit(1); 515 if (noteit(1) == 0 && odol == zero) { 516 CATCH 517 error("No lines in buffer"); 518 ENDCATCH 519 linebuf[0] = 0; 520 splitw = 0; 521 } 522 vnline(curs); 523 return; 524 } 525 526 /* 527 * Have some useful displayed text; refresh it. 528 */ 529 getDOT(); 530 531 /* 532 * This is for boundary conditions in open mode. 533 */ 534 if (FLAGS(0) & VDIRT) 535 vsync(WTOP); 536 537 /* 538 * If the current line is after the last displayed line 539 * or the bottom of the screen, then special effort is needed 540 * to get it on the screen. We first try a redraw at the 541 * last line on the screen, hoping it will fill in where @ 542 * lines are now. If this doesn't work, then roll it onto 543 * the screen. 544 */ 545 if (vcline >= vcnt || LINE(vcline) > WBOT) { 546 short oldhold = hold; 547 hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold; 548 if (vcline >= vcnt) { 549 register int i = vcline - vcnt + 1; 550 551 dot -= i; 552 vcline -= i; 553 vroll(i); 554 } else 555 vsyncCL(); 556 } else 557 vsync(vcline > 0 ? LINE(vcline - 1) : WTOP); 558 559 /* 560 * Notification on large change for visual 561 * has to be done last or we may lose 562 * the echo area with redisplay. 563 */ 564 noteit(1); 565 566 /* 567 * Finally. Move the cursor onto the current line. 568 */ 569 vnline(curs); 570 } 571 572 /* 573 * Fully cleanup the screen, leaving no @ lines except at end when 574 * line after last won't completely fit. The routine vsync is 575 * more conservative and much less work on dumb terminals. 576 */ 577 vredraw(p) 578 register int p; 579 { 580 register int l; 581 register line *tp; 582 char temp[LBSIZE]; 583 bool anydl = 0; 584 short oldhold = hold; 585 586 #ifdef ADEBUG 587 if (trace) 588 tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny(); 589 #endif 590 if (holdupd) { 591 holdupd = 3; 592 return; 593 } 594 if (state == HARDOPEN || splitw) 595 return; 596 if (p < 0 /* || p > WECHO */) 597 error("Internal error: vredraw"); 598 599 /* 600 * Trim the ragged edges (lines which are off the screen but 601 * not yet logically discarded), save the current line, and 602 * search for first logical line affected by the redraw. 603 */ 604 vscrap(); 605 CP(temp, linebuf); 606 l = 0; 607 tp = dot - vcline; 608 if (vcnt == 0) 609 LINE(0) = WTOP; 610 while (l < vcnt && LINE(l) < p) 611 l++, tp++; 612 613 /* 614 * We hold off echo area clearing during the redraw in deference 615 * to a final clear of the echo area at the end if appropriate. 616 */ 617 heldech = 0; 618 hold |= HOLDECH; 619 for (; l < vcnt && Peekkey != ATTN; l++) { 620 if (l == vcline) 621 strcLIN(temp); 622 else 623 getline(*tp); 624 625 /* 626 * Delete junk between displayed lines. 627 */ 628 if (LINE(l) != LINE(l + 1) && LINE(l) != p) { 629 if (anydl == 0 && DB && CD) { 630 hold = oldhold; 631 vclrech(0); 632 anydl = 1; 633 hold |= HOLDECH; 634 heldech = 0; 635 } 636 vdellin(p, LINE(l) - p, l); 637 } 638 639 /* 640 * If line image is not know to be up to date, then 641 * redisplay it; else just skip onward. 642 */ 643 LINE(l) = p; 644 if (FLAGS(l) & VDIRT) { 645 DEPTH(l) = vdepth(); 646 if (l != vcline && p + DEPTH(l) - 1 > WBOT) { 647 vscrap(); 648 break; 649 } 650 FLAGS(l) &= ~VDIRT; 651 vreopen(p, lineno(tp), l); 652 p = LINE(l) + DEPTH(l); 653 } else 654 p += DEPTH(l); 655 tp++; 656 } 657 658 /* 659 * That takes care of lines which were already partially displayed. 660 * Now try to fill the rest of the screen with text. 661 */ 662 if (state == VISUAL && p <= WBOT) { 663 int ovcline = vcline; 664 665 vcline = l; 666 for (; tp <= dol && Peekkey != ATTN; tp++) { 667 getline(*tp); 668 if (p + vdepth() - 1 > WBOT) 669 break; 670 vopen(tp, p); 671 p += DEPTH(vcline); 672 vcline++; 673 } 674 vcline = ovcline; 675 } 676 677 /* 678 * Thats all the text we can get on. 679 * Now rest of lines (if any) get either a ~ if they 680 * are past end of file, or an @ if the next line won't fit. 681 */ 682 for (; p <= WBOT && Peekkey != ATTN; p++) 683 vclrlin(p, tp); 684 strcLIN(temp); 685 hold = oldhold; 686 if (heldech) 687 vclrech(0); 688 #ifdef ADEBUG 689 if (trace) 690 tvliny(); 691 #endif 692 } 693 694 /* 695 * Do the real work in deleting cnt lines starting at line p from 696 * the display. First affected line is line l. 697 */ 698 vdellin(p, cnt, l) 699 int p, cnt, l; 700 { 701 register int i; 702 703 if (cnt == 0) 704 return; 705 if (DL == NOSTR || cnt < 0) { 706 /* 707 * Can't do it; just remember that line l is munged. 708 */ 709 FLAGS(l) |= VDIRT; 710 return; 711 } 712 #ifdef ADEBUG 713 if (trace) 714 tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l); 715 #endif 716 /* 717 * Send the deletes to the screen and then adjust logical 718 * and physical internal data structures. 719 */ 720 vgoto(p, 0); 721 for (i = 0; i < cnt; i++) 722 vputp(DL, WECHO - p); 723 vadjDL(p, cnt); 724 vcloseup(l, cnt); 725 } 726 /* 727 * Adjust internal physical screen image to account for deleted lines. 728 */ 729 vadjDL(p, cnt) 730 int p, cnt; 731 { 732 char *tlines[TUBELINES]; 733 register int from, to; 734 735 #ifdef ADEBUG 736 if (trace) 737 tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt); 738 #endif 739 /* 740 * Would like to use structured assignment but early 741 * v7 compiler (released with phototypesetter for v6) 742 * can't hack it. 743 */ 744 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 745 for (from = p + cnt, to = p; from <= WECHO; from++, to++) 746 vtube[to] = tlines[from]; 747 for (from = p; to <= WECHO; from++, to++) { 748 vtube[to] = tlines[from]; 749 vclrbyte(vtube[to], WCOLS); 750 } 751 } 752 /* 753 * Sync the screen, like redraw but more lazy and willing to leave 754 * @ lines on the screen. VsyncCL syncs starting at the current line. 755 * In any case, if the redraw option is set then all syncs map to redraws 756 * as if vsync didn't exist. 757 */ 758 vsyncCL() 759 { 760 761 vsync(LINE(vcline)); 762 } 763 764 vsync(p) 765 register int p; 766 { 767 768 if (value(REDRAW)) 769 vredraw(p); 770 else 771 vsync1(p); 772 } 773 774 /* 775 * The guts of a sync. Similar to redraw but 776 * just less ambitous. 777 */ 778 vsync1(p) 779 register int p; 780 { 781 register int l; 782 char temp[LBSIZE]; 783 register struct vlinfo *vp = &vlinfo[0]; 784 short oldhold = hold; 785 786 #ifdef ADEBUG 787 if (trace) 788 tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny(); 789 #endif 790 if (holdupd) { 791 if (holdupd < 3) 792 holdupd = 2; 793 return; 794 } 795 if (state == HARDOPEN || splitw) 796 return; 797 vscrap(); 798 CP(temp, linebuf); 799 if (vcnt == 0) 800 LINE(0) = WTOP; 801 l = 0; 802 while (l < vcnt && vp->vliny < p) 803 l++, vp++; 804 heldech = 0; 805 hold |= HOLDECH; 806 while (p <= WBOT && Peekkey != ATTN) { 807 /* 808 * Want to put a line here if not in visual and first line 809 * or if there are lies left and this line starts before 810 * the current line, or if this line is piled under the 811 * next line (vreplace does this and we undo it). 812 */ 813 if (l == 0 && state != VISUAL || 814 (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) { 815 if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) { 816 if (l == vcline) 817 strcLIN(temp); 818 else 819 getline(dot[l - vcline]); 820 /* 821 * Be careful that a long line doesn't cause the 822 * screen to shoot up. 823 */ 824 if (l != vcline && (vp->vflags & VDIRT)) { 825 vp->vdepth = vdepth(); 826 vp->vflags &= ~VDIRT; 827 if (p + vp->vdepth - 1 > WBOT) 828 break; 829 } 830 vreopen(p, lineDOT() + (l - vcline), l); 831 } 832 p = vp->vliny + vp->vdepth; 833 vp++; 834 l++; 835 } else 836 /* 837 * A physical line between logical lines, 838 * so we settle for an @ at the beginning. 839 */ 840 vclrlin(p, dot + (l - vcline)), p++; 841 } 842 strcLIN(temp); 843 hold = oldhold; 844 if (heldech) 845 vclrech(0); 846 } 847 848 /* 849 * Subtract (logically) cnt physical lines from the 850 * displayed position of lines starting with line l. 851 */ 852 vcloseup(l, cnt) 853 int l; 854 register int cnt; 855 { 856 register int i; 857 858 #ifdef ADEBUG 859 if (trace) 860 tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt); 861 #endif 862 for (i = l + 1; i <= vcnt; i++) 863 LINE(i) -= cnt; 864 } 865 866 /* 867 * Workhorse for rearranging line descriptors on changes. 868 * The idea here is that, starting with line l, cnt lines 869 * have been replaced with newcnt lines. All of these may 870 * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0, 871 * since we may be called from an undo after the screen has 872 * moved a lot. Thus we have to be careful. 873 * 874 * Many boundary conditions here. 875 */ 876 vreplace(l, cnt, newcnt) 877 int l, cnt, newcnt; 878 { 879 register int from, to, i; 880 bool savenote = 0; 881 882 #ifdef ADEBUG 883 if (trace) { 884 tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt); 885 tvliny(); 886 } 887 #endif 888 if (l >= vcnt) 889 return; 890 if (l < 0) { 891 if (l + cnt < 0) { 892 /* 893 * Nothing on the screen is relevant. 894 * Settle for redrawing from scratch (later). 895 */ 896 vcnt = 0; 897 return; 898 } 899 /* 900 * Normalize l to top of screen; the add is 901 * really a subtract from cnt since l is negative. 902 */ 903 cnt += l; 904 l = 0; 905 906 /* 907 * Unseen lines were affect so notify (later). 908 */ 909 savenote++; 910 } 911 912 /* 913 * These shouldn't happen 914 * but would cause great havoc. 915 */ 916 if (cnt < 0) 917 cnt = 0; 918 if (newcnt < 0) 919 newcnt = 0; 920 921 /* 922 * Surely worthy of note if more than report 923 * lines were changed. 924 */ 925 if (cnt > value(REPORT) || newcnt > value(REPORT)) 926 savenote++; 927 928 /* 929 * Same number of lines affeted as on screen, and we 930 * can insert and delete lines. Thus we just type 931 * over them, since otherwise we will push them 932 * slowly off the screen, a clear lose. 933 */ 934 if (cnt == newcnt || vcnt - l == newcnt && AL && DL) { 935 if (cnt > 1 && l + cnt > vcnt) 936 savenote++; 937 vdirty(l, newcnt); 938 } else { 939 /* 940 * Lines are going away, squish them out. 941 */ 942 if (cnt > 0) { 943 /* 944 * If non-displayed lines went away, 945 * always notify. 946 */ 947 if (cnt > 1 && l + cnt > vcnt) 948 savenote++; 949 if (l + cnt >= vcnt) 950 cnt = vcnt - l; 951 else 952 for (from = l + cnt, to = l; from <= vcnt; to++, from++) 953 vlcopy(vlinfo[to], vlinfo[from]); 954 vcnt -= cnt; 955 } 956 /* 957 * Open up space for new lines appearing. 958 * All new lines are piled in the same place, 959 * and will be unpiled by vredraw/vsync, which 960 * inserts lines in front as it unpiles. 961 */ 962 if (newcnt > 0) { 963 /* 964 * Newlines are appearing which may not show, 965 * so notify (this is only approximately correct 966 * when long lines are present). 967 */ 968 if (newcnt > 1 && l + newcnt > vcnt + 1) 969 savenote++; 970 971 /* 972 * If there will be more lines than fit, then 973 * just throw way the rest of the stuff on the screen. 974 */ 975 if (l + newcnt > WBOT && AL && DL) { 976 vcnt = l; 977 goto skip; 978 } 979 from = vcnt, to = vcnt + newcnt; 980 i = TUBELINES - to; 981 if (i < 0) 982 from += i, to += i; 983 vcnt = to; 984 for (; from >= l; from--, to--) 985 vlcopy(vlinfo[to], vlinfo[from]); 986 for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) { 987 LINE(to) = LINE(from); 988 DEPTH(to) = 0; 989 FLAGS(to) = VDIRT; 990 } 991 } 992 } 993 skip: 994 if (Pline == numbline && cnt != newcnt) 995 /* 996 * When lines positions are shifted, the numbers 997 * will be wrong. 998 */ 999 vdirty(l, WECHO); 1000 if (!savenote) 1001 notecnt = 0; 1002 #ifdef ADEBUG 1003 if (trace) 1004 tvliny(); 1005 #endif 1006 } 1007 1008 /* 1009 * Start harcopy open. 1010 * Print an image of the line to the left of the cursor 1011 * under the full print of the line and position the cursor. 1012 * If we are in a scroll ^D within hardcopy open then all this 1013 * is suppressed. 1014 */ 1015 sethard() 1016 { 1017 1018 if (state == VISUAL) 1019 return; 1020 rubble = 0; 1021 state = HARDOPEN; 1022 if (hold & HOLDROL) 1023 return; 1024 vup1(); 1025 LINE(0) = WBOT; 1026 if (Pline == numbline) 1027 vgoto(WBOT, 0), printf("%6d ", lineDOT()); 1028 } 1029 1030 /* 1031 * Mark the lines starting at base for i lines 1032 * as dirty so that they will be checked for correct 1033 * display at next sync/redraw. 1034 */ 1035 vdirty(base, i) 1036 register int base, i; 1037 { 1038 register int l; 1039 1040 for (l = base; l < vcnt; l++) { 1041 if (--i < 0) 1042 return; 1043 FLAGS(l) |= VDIRT; 1044 } 1045 } 1046