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