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