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