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