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