* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char *sccsid
= "@(#)ex_vadj.c 7.10 (Berkeley) %G%";
* 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.
register struct vlinfo
*vp
, *vpc
;
tfixnl(), fprintf(trace
, "vopen(%d, %d)\n", lineno(tp
), p
);
* Forget all that we once knew.
p
= WBOT
; LASTLINE
= WBOT
+ 1;
for (vp
= &vlinfo
[vcnt
]; vp
>= vpc
; vp
--)
* Dirtying all the lines is rather inefficient
* internally, but number mode is used rarely
* and so its not worth optimizing.
* If we are opening at the top of the window, can try a window
if (state
== VISUAL
&& vcline
== 0 && vcnt
> 1 && p
> ex_ZERO
) {
cnt
= p
+ vdepth() - LINE(1);
WLINES
= WBOT
- WTOP
+ 1;
vpc
->vliny
= p
, vpc
->vdepth
= 0, vpc
->vflags
= 0;
cnt
= vreopen(p
, lineno(tp
), vcline
);
LINE(vcnt
) = LINE(vcline
) + cnt
;
* Redisplay logical line l at physical line p with line number lineno.
register struct vlinfo
*vp
= &vlinfo
[l
];
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.
* 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.
* 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 (Put_char
== listchar
)
* 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
)
* 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.
} else if (state
== HARDOPEN
)
* 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);
* 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.
register struct vlinfo
*vp
= &vlinfo
[l
];
register int p
= vp
->vliny
;
short oldhold
, oldheldech
;
need
= p
+ vp
->vdepth
- (vp
+1)->vliny
;
if (state
== VISUAL
&& WTOP
- ex_ZERO
>= need
&& AL
&& DL
) {
WLINES
= WBOT
- WTOP
+ 1;
vinslin((vp
+1)->vliny
, need
, l
);
vp
[1].vliny
= vp
[0].vliny
+ vp
->vdepth
;
* Insert cnt blank lines before line p,
* logically and (if supported) physically.
tfixnl(), fprintf(trace
, "vinslin(%d, %d, %d)\n", p
, cnt
, l
);
if (p
+ cnt
> WBOT
&& CD
) {
* Really quick -- clear to end of screen.
vgoto(p
, 0), vputp(CD
, 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)
* 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
if (CE
&& (DA
|| 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
);
/* vt100 change scrolling region to fake AL */
vputp(tgoto(CS
, LINES
-1,p
), 1);
vputp(RC
, 1); /* CS homes stupid cursor */
vputp(SR
, 1); /* should do @'s */
vputp(tgoto(CS
, LINES
-1,0), 1);
vputp(RC
, 1); /* Once again put it back */
vputp(AL
, WECHO
+ 1 - p
);
for (i
= cnt
- 1; i
> 0; i
--) {
vputp(AL
, WECHO
+ 1 - outline
);
if ((hold
& HOLDAT
) == 0)
* 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.
register struct vlinfo
*vc
= &vlinfo
[l
+ 1];
register struct vlinfo
*ve
= &vlinfo
[vcnt
];
tfixnl(), fprintf(trace
, "vopenup(%d, %d, %d)\n", cnt
, could
, l
);
* 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.
* Will have to clean up brute force eventually,
* so push the line data around as little as possible.
vc
->vliny
+= cnt
, vc
->vflags
|= VDIRT
;
register int i
= vc
->vliny
+ vc
->vdepth
;
vc
->vliny
= i
, vc
->vflags
|= VDIRT
;
* Adjust data structure internally to account for insertion of
* blank lines on the screen.
tfixnl(), fprintf(trace
, "vadjal(%d, %d)\n", p
, cnt
);
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.
* Roll the screen up logically and physically
* so that line dl is the bottom line on the screen.
register int dc
= destcol
;
tfixnl(), fprintf(trace
, "vrollup(%d)\n", dl
);
cnt
= dl
- (splitw
? WECHO
: WBOT
);
if (splitw
&& (state
== VISUAL
|| state
== CRTOPEN
))
destline
= dl
- cnt
, destcol
= dc
;
* 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)
tfixnl(), fprintf(trace
, "vmoveitup(%d)\n", cnt
);
destcol
= (NONL
? 0 : outcol
% WCOLS
);
destcol
= (NONL
? 0 : outcol
% WCOLS
);
if (state
== ONEOPEN
|| state
== HARDOPEN
) {
vclrbyte(vtube
[0], WCOLS
);
* Scroll the screen up cnt lines logically.
fprintf(trace
, "vscroll(%d)\n", cnt
);
if (cnt
< 0 || cnt
> TUBELINES
)
error("Internal error: vscroll");
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
++)
* Discard logical lines due to physical wandering off the screen.
tfixnl(), fprintf(trace
, "vscrap\n"), tvliny();
if (vcnt
&& WBOT
!= WECHO
&& LINE(0) < WTOP
&& LINE(0) >= ex_ZERO
) {
WLINES
= WBOT
- WTOP
+ 1;
for (j
= 0; j
< vcnt
; j
++)
* Discard the first j physical lines off the top.
for (i
= 0; i
<= vcnt
; i
++)
vlcopy(vlinfo
[i
], vlinfo
[i
+ j
]);
* Discard lines off the bottom.
for (j
= 0; j
<= vcnt
; j
++)
if (LINE(j
) > WBOT
|| LINE(j
) + DEPTH(j
) - 1 > WBOT
) {
LASTLINE
= LINE(vcnt
-1) + DEPTH(vcnt
-1);
* Repaint the screen, with cursor at curs, aftern an arbitrary change.
* Handle notification on large changes.
* In open want to notify first.
* Deal with a totally useless display.
if (vcnt
== 0 || vcline
< 0 || vcline
> vcnt
|| holdupd
&& state
!= VISUAL
) {
register line
*odol
= dol
;
if (noteit(1) == 0 && odol
== zero
) {
error("No lines in buffer");
* Have some useful displayed text; refresh it.
* This is for boundary conditions in open mode.
* 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
if (vcline
>= vcnt
|| LINE(vcline
) > WBOT
) {
hold
|= HOLDAT
, vredraw(LASTLINE
), hold
= oldhold
;
register int i
= vcline
- vcnt
+ 1;
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.
* Finally. Move the cursor onto the current line.
* 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.
tfixnl(), fprintf(trace
, "vredraw(%d)\n", p
), tvliny();
if (state
== HARDOPEN
|| splitw
)
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.
while (l
< vcnt
&& LINE(l
) < p
)
* We hold off echo area clearing during the redraw in deference
* to a final clear of the echo area at the end if appropriate.
for (; l
< vcnt
&& Peek_key
!= ATTN
; l
++) {
* Delete junk between displayed lines.
if (LINE(l
) != LINE(l
+ 1) && LINE(l
) != p
) {
if (anydl
== 0 && DB
&& CD
) {
vdellin(p
, LINE(l
) - p
, l
);
* If line image is not know to be up to date, then
* redisplay it; else just skip onward.
if (l
!= vcline
&& p
+ DEPTH(l
) - 1 > WBOT
) {
ignore(vreopen(p
, lineno(tp
), l
));
* 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
) {
for (; tp
<= dol
&& Peek_key
!= ATTN
; tp
++) {
if (p
+ vdepth() - 1 > WBOT
)
* 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
++)
* Do the real work in deleting cnt lines starting at line p from
* the display. First affected line is line l.
if (DL
== NOSTR
|| cnt
< 0) {
* Can't do it; just remember that line l is munged.
tfixnl(), fprintf(trace
, "vdellin(%d, %d, %d)\n", p
, cnt
, l
);
* Send the deletes to the screen and then adjust logical
* and physical internal data structures.
if (DL_PARM
&& (cnt
>1 || *DL
==0)) {
vputp(tgoto(DL_PARM
, p
, cnt
), WECHO
-p
);
/* 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 */
for (i
= 0; i
< cnt
; i
++)
* Adjust internal physical screen image to account for deleted lines.
tfixnl(), fprintf(trace
, "vadjDL(%d, %d)\n", p
, cnt
);
* Would like to use structured assignment but early
* v7 compiler (released with phototypesetter for v6)
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.
* The guts of a sync. Similar to redraw but
register struct vlinfo
*vp
= &vlinfo
[0];
tfixnl(), fprintf(trace
, "vsync1(%d)\n", p
), tvliny();
if (state
== HARDOPEN
|| splitw
)
while (l
< vcnt
&& vp
->vliny
< p
)
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
)) {
getline(dot
[l
- vcline
]);
* Be careful that a long line doesn't cause the
if (l
!= vcline
&& (vp
->vflags
& VDIRT
)) {
if (p
+ vp
->vdepth
- 1 > WBOT
)
ignore(vreopen(p
, lineDOT() + (l
- vcline
), l
));
p
= vp
->vliny
+ vp
->vdepth
;
* A physical line between logical lines,
* so we settle for an @ at the beginning.
vclrlin(p
, dot
+ (l
- vcline
)), p
++;
* Subtract (logically) cnt physical lines from the
* displayed position of lines starting with line l.
tfixnl(), fprintf(trace
, "vcloseup(%d, %d)\n", l
, cnt
);
for (i
= l
+ 1; i
<= vcnt
; i
++)
* 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.
register int from
, to
, i
;
tfixnl(), fprintf(trace
, "vreplace(%d, %d, %d)\n", l
, cnt
, newcnt
);
* Nothing on the screen is relevant.
* Settle for redrawing from scratch (later).
* Normalize l to top of screen; the add is
* really a subtract from cnt since l is negative.
* Unseen lines were affect so notify (later).
* but would cause great havoc.
* Surely worthy of note if more than report
if (cnt
> value(REPORT
) || newcnt
> value(REPORT
))
* 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
)
* Lines are going away, squish them out.
* If non-displayed lines went away,
if (cnt
> 1 && l
+ cnt
> vcnt
)
for (from
= l
+ cnt
, to
= l
; from
<= vcnt
; to
++, from
++)
vlcopy(vlinfo
[to
], vlinfo
[from
]);
* 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.
* 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)
* 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
) {
from
= vcnt
, to
= vcnt
+ newcnt
;
for (; from
>= l
; from
--, to
--)
vlcopy(vlinfo
[to
], vlinfo
[from
]);
for (from
= to
+ 1, to
= l
; to
< l
+ newcnt
&& to
<= WBOT
+ 1; to
++) {
if (Pline
== numbline
&& cnt
!= newcnt
)
* When lines positions are shifted, the numbers
* 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
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.
for (l
= base
; l
< vcnt
; l
++) {