BSD 4_3_Tahoe release
[unix-history] / usr / src / ucb / ex / ex_vadj.c
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char *sccsid = "@(#)ex_vadj.c 7.10 (Berkeley) 3/9/87";
#endif not lint
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
/*
* Routines to deal with management of logical versus physical
* display, opening and redisplaying lines on the screen, and
* use of intelligent terminal operations. Routines to deal with
* screen cleanup after a change.
*/
/*
* Display a new line at physical line p, returning
* the depth of the newly displayed line. We may decide
* to expand the window on an intelligent terminal if it is
* less than a full screen by deleting a line above the top of the
* window before doing an insert line to keep all the good text
* on the screen in which case the line may actually end up
* somewhere other than line p.
*/
vopen(tp, p)
line *tp;
int p;
{
register int cnt;
register struct vlinfo *vp, *vpc;
#ifdef ADEBUG
if (trace != NULL)
tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
#endif
if (state != VISUAL) {
if (vcnt)
if (hold & HOLDROL)
vup1();
else
vclean();
/*
* Forget all that we once knew.
*/
vcnt = vcline = 0;
p = WBOT; LASTLINE = WBOT + 1;
state = bastate;
WTOP = basWTOP;
WLINES = basWLINES;
}
vpc = &vlinfo[vcline];
for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
vlcopy(vp[1], vp[0]);
vcnt++;
if (Pline == numbline)
/*
* Dirtying all the lines is rather inefficient
* internally, but number mode is used rarely
* and so its not worth optimizing.
*/
vdirty(vcline+1, WECHO);
getline(*tp);
/*
* If we are opening at the top of the window, can try a window
* expansion at the top.
*/
if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ex_ZERO) {
cnt = p + vdepth() - LINE(1);
if (cnt > 0) {
p -= cnt;
if (p < ex_ZERO)
p = ex_ZERO;
WTOP = p;
WLINES = WBOT - WTOP + 1;
}
}
vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
cnt = vreopen(p, lineno(tp), vcline);
if (vcline + 1 == vcnt)
LINE(vcnt) = LINE(vcline) + cnt;
}
/*
* Redisplay logical line l at physical line p with line number lineno.
*/
vreopen(p, lineno, l)
int p, lineno, l;
{
register int d;
register struct vlinfo *vp = &vlinfo[l];
d = vp->vdepth;
if (d == 0 || (vp->vflags & VDIRT))
vp->vdepth = d = vdepth();
vp->vliny = p, vp->vflags &= ~VDIRT;
/*
* Try to win by making the screen larger rather than inserting
* a line and driving text off the bottom.
*/
p = vglitchup(l, 0);
/*
* BUG: Should consider using CE here to clear to end of line.
* As it stands we always strike over the current text.
* Since often the current text is the same as what
* we are overstriking with, it tends not to show.
* On the other hand if it is different and we end up
* spacing out a lot of text, we could have won with
* a CE. This is probably worthwhile at low speed
* only however, since clearly computation will be
* necessary to determine which way to go.
*/
vigoto(p, 0);
pline(lineno);
/*
* When we are typing part of a line for hardcopy open, don't
* want to type the '$' marking an end of line if in list mode.
*/
if (hold & HOLDDOL)
return (d);
if (Put_char == listchar)
ex_putchar('$');
/*
* Optimization of cursor motion may prevent screen rollup if the
* line has blanks/tabs at the end unless we force the cursor to appear
* on the last line segment.
*/
if (vp->vliny + d - 1 > WBOT)
vcsync();
/*
* Switch into hardcopy open mode if we are in one line (adm3)
* open mode and this line is now too long. If in hardcopy
* open mode, then call sethard to move onto the next line
* with appropriate positioning.
*/
if (state == ONEOPEN) {
WCOLS = OCOLUMNS;
if (vdepth() > 1) {
WCOLS = TUBECOLS;
sethard();
} else
WCOLS = TUBECOLS;
} else if (state == HARDOPEN)
sethard();
/*
* Unless we filled (completely) the last line we typed on,
* we have to clear to the end of the line
* in case stuff is left from before.
*/
if (vp->vliny + d > destline) {
if (IN && destcol == WCOLS)
vigoto(vp->vliny + d - 1, 0);
vclreol();
}
return (d);
}
/*
* Real work for winning growing of window at top
* when inserting in the middle of a partially full
* screen on an intelligent terminal. We have as argument
* the logical line number to be inserted after, and the offset
* from that line where the insert will go.
* We look at the picture of depths and positions, and if we can
* delete some (blank) lines from the top of the screen so that
* later inserts will not push stuff off the bottom.
*/
vglitchup(l, o)
int l, o;
{
register struct vlinfo *vp = &vlinfo[l];
register int need;
register int p = vp->vliny;
short oldhold, oldheldech;
bool glitched = 0;
if (l < vcnt - 1) {
need = p + vp->vdepth - (vp+1)->vliny;
if (need > 0) {
if (state == VISUAL && WTOP - ex_ZERO >= need && AL && DL) {
glitched++;
WTOP -= need;
WLINES = WBOT - WTOP + 1;
p -= need;
if (p + o == WTOP) {
vp->vliny = WTOP;
return (WTOP + o);
}
vdellin(WTOP, need, -1);
oldheldech = heldech;
oldhold = hold;
hold |= HOLDECH;
}
vinslin((vp+1)->vliny, need, l);
if (glitched) {
hold = oldhold;
heldech = oldheldech;
}
}
} else
vp[1].vliny = vp[0].vliny + vp->vdepth;
return (p + o);
}
/*
* Insert cnt blank lines before line p,
* logically and (if supported) physically.
*/
vinslin(p, cnt, l)
register int p, cnt;
int l;
{
register int i;
bool could = 1;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
#endif
if (p + cnt > WBOT && CD) {
/*
* Really quick -- clear to end of screen.
*/
cnt = WECHO + 1 - p;
vgoto(p, 0), vputp(CD, cnt);
vclrech(1);
vadjAL(p, cnt);
} else if (SR && p == WTOP && costSR < costAL) {
/*
* Use reverse scroll mode of the terminal, at
* the top of the window. Reverse linefeed works
* too, since we only use it from line WTOP.
*/
for (i = cnt; i > 0; i--) {
vgoto(p, 0), vputp(SR, 0);
if (i > 1 && (hold & HOLDAT) == 0)
ex_putchar('@');
/*
* If we are at the top of the screen, and the
* terminal retains display above, then we
* should try to clear to end of line.
* Have to use CE since we don't remember what is
* actually on the line.
*/
if (CE && (DA || p != 0))
vputp(CE, 1);
}
vadjAL(p, cnt);
} else if (AL) {
/*
* Use insert line.
*/
vgoto(p, 0);
if (AL_PARM && (cnt>1 || *AL==0)) {
/* insert cnt lines. Should do @'s too. */
vputp(tgoto(AL_PARM, p, cnt), WECHO+1-p);
}
else if (CS && *AL==0) {
/* vt100 change scrolling region to fake AL */
vputp(SC, 1);
vputp(tgoto(CS, LINES-1,p), 1);
vputp(RC, 1); /* CS homes stupid cursor */
for (i=cnt; i>0; i--)
vputp(SR, 1); /* should do @'s */
vputp(tgoto(CS, LINES-1,0), 1);
vputp(RC, 1); /* Once again put it back */
}
else {
vputp(AL, WECHO + 1 - p);
for (i = cnt - 1; i > 0; i--) {
vgoto(outline+1, 0);
vputp(AL, WECHO + 1 - outline);
if ((hold & HOLDAT) == 0)
ex_putchar('@');
}
}
vadjAL(p, cnt);
} else
could = 0;
vopenup(cnt, could, l);
}
/*
* Logically open up after line l, cnt of them.
* We need to know if it was done ``physically'' since in this
* case we accept what the hardware gives us. If we have to do
* it ourselves (brute force) we will squish out @ lines in the process
* if this will save us work.
*/
vopenup(cnt, could, l)
int cnt;
bool could;
{
register struct vlinfo *vc = &vlinfo[l + 1];
register struct vlinfo *ve = &vlinfo[vcnt];
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
#endif
if (could)
/*
* This will push @ lines down the screen,
* just as the hardware did. Since the default
* for intelligent terminals is to never have @
* lines on the screen, this should never happen,
* and the code makes no special effort to be nice in this
* case, e.g. squishing out the @ lines by delete lines
* before doing append lines.
*/
for (; vc <= ve; vc++)
vc->vliny += cnt;
else {
/*
* Will have to clean up brute force eventually,
* so push the line data around as little as possible.
*/
vc->vliny += cnt, vc->vflags |= VDIRT;
while (vc < ve) {
register int i = vc->vliny + vc->vdepth;
vc++;
if (i <= vc->vliny)
break;
vc->vliny = i, vc->vflags |= VDIRT;
}
}
vscrap();
}
/*
* Adjust data structure internally to account for insertion of
* blank lines on the screen.
*/
vadjAL(p, cnt)
int p, cnt;
{
char *tlines[TUBELINES];
register int from, to;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt);
#endif
copy(tlines, vtube, sizeof vtube); /*SASSIGN*/
for (from = p, to = p + cnt; to <= WECHO; from++, to++)
vtube[to] = tlines[from];
for (to = p; from <= WECHO; from++, to++) {
vtube[to] = tlines[from];
vclrbyte(vtube[to], WCOLS);
}
/*
* Have to clear the echo area since its contents aren't
* necessarily consistent with the rest of the display.
*/
vclrech(0);
}
/*
* Roll the screen up logically and physically
* so that line dl is the bottom line on the screen.
*/
vrollup(dl)
int dl;
{
register int cnt;
register int dc = destcol;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vrollup(%d)\n", dl);
#endif
cnt = dl - (splitw ? WECHO : WBOT);
if (splitw && (state == VISUAL || state == CRTOPEN))
holdupd = 1;
vmoveitup(cnt, 1);
vscroll(cnt);
destline = dl - cnt, destcol = dc;
}
vup1()
{
vrollup(WBOT + 1);
}
/*
* Scroll the screen up cnt lines physically.
* If doclr is true, do a clear eol if the terminal
* has standout (to prevent it from scrolling up)
*/
vmoveitup(cnt, doclr)
register int cnt;
bool doclr;
{
if (cnt == 0)
return;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt);
#endif
if (doclr && (SO || SE))
vclrech(0);
if (SF) {
destline = WECHO;
destcol = (NONL ? 0 : outcol % WCOLS);
fgoto();
while (cnt > 0)
vputp(SF, 0), cnt--;
return;
}
destline = WECHO + cnt;
destcol = (NONL ? 0 : outcol % WCOLS);
fgoto();
if (state == ONEOPEN || state == HARDOPEN) {
outline = destline = 0;
vclrbyte(vtube[0], WCOLS);
}
}
/*
* Scroll the screen up cnt lines logically.
*/
vscroll(cnt)
register int cnt;
{
register int from, to;
char *tlines[TUBELINES];
#ifdef ADEBUG
if (trace)
fprintf(trace, "vscroll(%d)\n", cnt);
#endif
if (cnt < 0 || cnt > TUBELINES)
error("Internal error: vscroll");
if (cnt == 0)
return;
copy(tlines, vtube, sizeof vtube);
for (to = ex_ZERO, from = ex_ZERO + cnt; to <= WECHO - cnt; to++, from++)
vtube[to] = tlines[from];
for (from = ex_ZERO; to <= WECHO; to++, from++) {
vtube[to] = tlines[from];
vclrbyte(vtube[to], WCOLS);
}
for (from = 0; from <= vcnt; from++)
LINE(from) -= cnt;
}
/*
* Discard logical lines due to physical wandering off the screen.
*/
vscrap()
{
register int i, j;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vscrap\n"), tvliny();
#endif
if (splitw)
return;
if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ex_ZERO) {
WTOP = LINE(0);
WLINES = WBOT - WTOP + 1;
}
for (j = 0; j < vcnt; j++)
if (LINE(j) >= WTOP) {
if (j == 0)
break;
/*
* Discard the first j physical lines off the top.
*/
vcnt -= j, vcline -= j;
for (i = 0; i <= vcnt; i++)
vlcopy(vlinfo[i], vlinfo[i + j]);
break;
}
/*
* Discard lines off the bottom.
*/
if (vcnt) {
for (j = 0; j <= vcnt; j++)
if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) {
vcnt = j;
break;
}
LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1);
}
#ifdef ADEBUG
if (trace)
tvliny();
#endif
/*
* May have no lines!
*/
}
/*
* Repaint the screen, with cursor at curs, aftern an arbitrary change.
* Handle notification on large changes.
*/
vrepaint(curs)
char *curs;
{
wdot = NOLINE;
/*
* In open want to notify first.
*/
ignore(noteit(0));
vscrap();
/*
* Deal with a totally useless display.
*/
if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
register line *odol = dol;
vcnt = 0;
if (holdupd)
if (state == VISUAL)
ignore(peekkey());
else
vup1();
holdupd = 0;
if (odol == zero)
fixzero();
vcontext(dot, '.');
ignore(noteit(1));
if (noteit(1) == 0 && odol == zero) {
CATCH
error("No lines in buffer");
ENDCATCH
linebuf[0] = 0;
splitw = 0;
}
vnline(curs);
return;
}
/*
* Have some useful displayed text; refresh it.
*/
getDOT();
/*
* This is for boundary conditions in open mode.
*/
if (FLAGS(0) & VDIRT)
vsync(WTOP);
/*
* If the current line is after the last displayed line
* or the bottom of the screen, then special effort is needed
* to get it on the screen. We first try a redraw at the
* last line on the screen, hoping it will fill in where @
* lines are now. If this doesn't work, then roll it onto
* the screen.
*/
if (vcline >= vcnt || LINE(vcline) > WBOT) {
short oldhold = hold;
hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
if (vcline >= vcnt) {
register int i = vcline - vcnt + 1;
dot -= i;
vcline -= i;
vroll(i);
} else
vsyncCL();
} else
vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);
/*
* Notification on large change for visual
* has to be done last or we may lose
* the echo area with redisplay.
*/
ignore(noteit(1));
/*
* Finally. Move the cursor onto the current line.
*/
vnline(curs);
}
/*
* Fully cleanup the screen, leaving no @ lines except at end when
* line after last won't completely fit. The routine vsync is
* more conservative and much less work on dumb terminals.
*/
vredraw(p)
register int p;
{
register int l;
register line *tp;
char temp[LBSIZE];
bool anydl = 0;
short oldhold = hold;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
#endif
if (holdupd) {
holdupd = 3;
return;
}
if (state == HARDOPEN || splitw)
return;
if (p < 0 /* || p > WECHO */)
error("Internal error: vredraw");
/*
* Trim the ragged edges (lines which are off the screen but
* not yet logically discarded), save the current line, and
* search for first logical line affected by the redraw.
*/
vscrap();
CP(temp, linebuf);
l = 0;
tp = dot - vcline;
if (vcnt == 0)
LINE(0) = WTOP;
while (l < vcnt && LINE(l) < p)
l++, tp++;
/*
* We hold off echo area clearing during the redraw in deference
* to a final clear of the echo area at the end if appropriate.
*/
heldech = 0;
hold |= HOLDECH;
for (; l < vcnt && Peek_key != ATTN; l++) {
if (l == vcline)
strcLIN(temp);
else
getline(*tp);
/*
* Delete junk between displayed lines.
*/
if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
if (anydl == 0 && DB && CD) {
hold = oldhold;
vclrech(0);
anydl = 1;
hold |= HOLDECH;
heldech = 0;
}
vdellin(p, LINE(l) - p, l);
}
/*
* If line image is not know to be up to date, then
* redisplay it; else just skip onward.
*/
LINE(l) = p;
if (FLAGS(l) & VDIRT) {
DEPTH(l) = vdepth();
if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
vscrap();
break;
}
FLAGS(l) &= ~VDIRT;
ignore(vreopen(p, lineno(tp), l));
p = LINE(l) + DEPTH(l);
} else
p += DEPTH(l);
tp++;
}
/*
* That takes care of lines which were already partially displayed.
* Now try to fill the rest of the screen with text.
*/
if (state == VISUAL && p <= WBOT) {
int ovcline = vcline;
vcline = l;
for (; tp <= dol && Peek_key != ATTN; tp++) {
getline(*tp);
if (p + vdepth() - 1 > WBOT)
break;
vopen(tp, p);
p += DEPTH(vcline);
vcline++;
}
vcline = ovcline;
}
/*
* Thats all the text we can get on.
* Now rest of lines (if any) get either a ~ if they
* are past end of file, or an @ if the next line won't fit.
*/
for (; p <= WBOT && Peek_key != ATTN; p++)
vclrlin(p, tp);
strcLIN(temp);
hold = oldhold;
if (heldech)
vclrech(0);
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
/*
* Do the real work in deleting cnt lines starting at line p from
* the display. First affected line is line l.
*/
vdellin(p, cnt, l)
int p, cnt, l;
{
register int i;
if (cnt == 0)
return;
if (DL == NOSTR || cnt < 0) {
/*
* Can't do it; just remember that line l is munged.
*/
FLAGS(l) |= VDIRT;
return;
}
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
#endif
/*
* Send the deletes to the screen and then adjust logical
* and physical internal data structures.
*/
vgoto(p, 0);
if (DL_PARM && (cnt>1 || *DL==0)) {
vputp(tgoto(DL_PARM, p, cnt), WECHO-p);
}
else if (CS && *DL==0) {
/* vt100: fake DL by changing scrolling region */
vputp(SC, 1); /* Save since CS homes stupid cursor */
vputp(tgoto(CS, LINES-1, p), 1);
vputp(tgoto(CM, 0, LINES-1), 1);/* Go to lower left corner */
for (i=0; i<cnt; i++) /* .. and scroll cnt times */
putch('\n'); /* should check NL too */
vputp(tgoto(CS, LINES-1, 0), 1);/* restore scrolling region */
vputp(RC, 1); /* put cursor back */
}
else {
for (i = 0; i < cnt; i++)
vputp(DL, WECHO - p);
}
vadjDL(p, cnt);
vcloseup(l, cnt);
}
/*
* Adjust internal physical screen image to account for deleted lines.
*/
vadjDL(p, cnt)
int p, cnt;
{
char *tlines[TUBELINES];
register int from, to;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt);
#endif
/*
* Would like to use structured assignment but early
* v7 compiler (released with phototypesetter for v6)
* can't hack it.
*/
copy(tlines, vtube, sizeof vtube); /*SASSIGN*/
for (from = p + cnt, to = p; from <= WECHO; from++, to++)
vtube[to] = tlines[from];
for (from = p; to <= WECHO; from++, to++) {
vtube[to] = tlines[from];
vclrbyte(vtube[to], WCOLS);
}
}
/*
* Sync the screen, like redraw but more lazy and willing to leave
* @ lines on the screen. VsyncCL syncs starting at the current line.
* In any case, if the redraw option is set then all syncs map to redraws
* as if vsync didn't exist.
*/
vsyncCL()
{
vsync(LINE(vcline));
}
vsync(p)
register int p;
{
if (value(REDRAW))
vredraw(p);
else
vsync1(p);
}
/*
* The guts of a sync. Similar to redraw but
* just less ambitous.
*/
vsync1(p)
register int p;
{
register int l;
char temp[LBSIZE];
register struct vlinfo *vp = &vlinfo[0];
short oldhold = hold;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
#endif
if (holdupd) {
if (holdupd < 3)
holdupd = 2;
return;
}
if (state == HARDOPEN || splitw)
return;
vscrap();
CP(temp, linebuf);
if (vcnt == 0)
LINE(0) = WTOP;
l = 0;
while (l < vcnt && vp->vliny < p)
l++, vp++;
heldech = 0;
hold |= HOLDECH;
while (p <= WBOT && Peek_key != ATTN) {
/*
* Want to put a line here if not in visual and first line
* or if there are lies left and this line starts before
* the current line, or if this line is piled under the
* next line (vreplace does this and we undo it).
*/
if (l == 0 && state != VISUAL ||
(l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
if (l == vcline)
strcLIN(temp);
else
getline(dot[l - vcline]);
/*
* Be careful that a long line doesn't cause the
* screen to shoot up.
*/
if (l != vcline && (vp->vflags & VDIRT)) {
vp->vdepth = vdepth();
vp->vflags &= ~VDIRT;
if (p + vp->vdepth - 1 > WBOT)
break;
}
ignore(vreopen(p, lineDOT() + (l - vcline), l));
}
p = vp->vliny + vp->vdepth;
vp++;
l++;
} else
/*
* A physical line between logical lines,
* so we settle for an @ at the beginning.
*/
vclrlin(p, dot + (l - vcline)), p++;
}
strcLIN(temp);
hold = oldhold;
if (heldech)
vclrech(0);
}
/*
* Subtract (logically) cnt physical lines from the
* displayed position of lines starting with line l.
*/
vcloseup(l, cnt)
int l;
register int cnt;
{
register int i;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt);
#endif
for (i = l + 1; i <= vcnt; i++)
LINE(i) -= cnt;
}
/*
* Workhorse for rearranging line descriptors on changes.
* The idea here is that, starting with line l, cnt lines
* have been replaced with newcnt lines. All of these may
* be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0,
* since we may be called from an undo after the screen has
* moved a lot. Thus we have to be careful.
*
* Many boundary conditions here.
*/
vreplace(l, cnt, newcnt)
int l, cnt, newcnt;
{
register int from, to, i;
bool savenote = 0;
#ifdef ADEBUG
if (trace) {
tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt);
tvliny();
}
#endif
if (l >= vcnt)
return;
if (l < 0) {
if (l + cnt < 0) {
/*
* Nothing on the screen is relevant.
* Settle for redrawing from scratch (later).
*/
vcnt = 0;
return;
}
/*
* Normalize l to top of screen; the add is
* really a subtract from cnt since l is negative.
*/
cnt += l;
l = 0;
/*
* Unseen lines were affect so notify (later).
*/
savenote++;
}
/*
* These shouldn't happen
* but would cause great havoc.
*/
if (cnt < 0)
cnt = 0;
if (newcnt < 0)
newcnt = 0;
/*
* Surely worthy of note if more than report
* lines were changed.
*/
if (cnt > value(REPORT) || newcnt > value(REPORT))
savenote++;
/*
* Same number of lines affeted as on screen, and we
* can insert and delete lines. Thus we just type
* over them, since otherwise we will push them
* slowly off the screen, a clear lose.
*/
if (cnt == newcnt || vcnt - l == newcnt && AL && DL) {
if (cnt > 1 && l + cnt > vcnt)
savenote++;
vdirty(l, newcnt);
} else {
/*
* Lines are going away, squish them out.
*/
if (cnt > 0) {
/*
* If non-displayed lines went away,
* always notify.
*/
if (cnt > 1 && l + cnt > vcnt)
savenote++;
if (l + cnt >= vcnt)
cnt = vcnt - l;
else
for (from = l + cnt, to = l; from <= vcnt; to++, from++)
vlcopy(vlinfo[to], vlinfo[from]);
vcnt -= cnt;
}
/*
* Open up space for new lines appearing.
* All new lines are piled in the same place,
* and will be unpiled by vredraw/vsync, which
* inserts lines in front as it unpiles.
*/
if (newcnt > 0) {
/*
* Newlines are appearing which may not show,
* so notify (this is only approximately correct
* when long lines are present).
*/
if (newcnt > 1 && l + newcnt > vcnt + 1)
savenote++;
/*
* If there will be more lines than fit, then
* just throw way the rest of the stuff on the screen.
*/
if (l + newcnt > WBOT && AL && DL) {
vcnt = l;
goto skip;
}
from = vcnt, to = vcnt + newcnt;
i = TUBELINES - to;
if (i < 0)
from += i, to += i;
vcnt = to;
for (; from >= l; from--, to--)
vlcopy(vlinfo[to], vlinfo[from]);
for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) {
LINE(to) = LINE(from);
DEPTH(to) = 0;
FLAGS(to) = VDIRT;
}
}
}
skip:
if (Pline == numbline && cnt != newcnt)
/*
* When lines positions are shifted, the numbers
* will be wrong.
*/
vdirty(l, WECHO);
if (!savenote)
notecnt = 0;
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
/*
* Start harcopy open.
* Print an image of the line to the left of the cursor
* under the full print of the line and position the cursor.
* If we are in a scroll ^D within hardcopy open then all this
* is suppressed.
*/
sethard()
{
if (state == VISUAL)
return;
rubble = 0;
state = HARDOPEN;
if (hold & HOLDROL)
return;
vup1();
LINE(0) = WBOT;
if (Pline == numbline)
vgoto(WBOT, 0), ex_printf("%6d ", lineDOT());
}
/*
* Mark the lines starting at base for i lines
* as dirty so that they will be checked for correct
* display at next sync/redraw.
*/
vdirty(base, i)
register int base, i;
{
register int l;
for (l = base; l < vcnt; l++) {
if (--i < 0)
return;
FLAGS(l) |= VDIRT;
}
}