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