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