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