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