4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 /* Copyright (c) 1981 Regents of the University of California */
38 * Routines to deal with management of logical versus physical
39 * display, opening and redisplaying lines on the screen, and
40 * use of intelligent terminal operations. Routines to deal with
41 * screen cleanup after a change.
45 * Display a new line at physical line p, returning
46 * the depth of the newly displayed line. We may decide
47 * to expand the window on an intelligent terminal if it is
48 * less than a full screen by deleting a line above the top of the
49 * window before doing an insert line to keep all the good text
50 * on the screen in which case the line may actually end up
51 * somewhere other than line p.
54 vopen(line
*tp
, int p
)
57 struct vlinfo
*vp
, *vpc
;
61 tfixnl(), fprintf(trace
, "vopen(%d, %d)\n", lineno(tp
), p
);
63 if (state
!= VISUAL
) {
71 * Forget all that we once knew.
74 p
= WBOT
; LASTLINE
= WBOT
+ 1;
79 vpc
= &vlinfo
[vcline
];
80 for (vp
= &vlinfo
[vcnt
]; vp
>= vpc
; vp
--)
83 if (Pline
== numbline
)
85 * Dirtying all the lines is rather inefficient
86 * internally, but number mode is used rarely
87 * and so it's not worth optimizing.
89 vdirty(vcline
+1, WECHO
);
93 * If we are opening at the top of the window, can try a window
94 * expansion at the top.
96 if (state
== VISUAL
&& vcline
== 0 && vcnt
> 1 && p
> ZERO
) {
97 cnt
= p
+ vdepth() - LINE(1);
103 WLINES
= WBOT
- WTOP
+ 1;
106 vpc
->vliny
= p
, vpc
->vdepth
= 0, vpc
->vflags
= 0;
107 cnt
= vreopen(p
, lineno(tp
), vcline
);
108 if (vcline
+ 1 == vcnt
)
109 LINE(vcnt
) = LINE(vcline
) + cnt
;
113 * Redisplay logical line l at physical line p with line number lineno.
116 vreopen(int p
, int lineno
, int l
)
119 struct vlinfo
*vp
= &vlinfo
[l
];
122 if (d
== 0 || (vp
->vflags
& VDIRT
))
123 vp
->vdepth
= d
= vdepth();
124 vp
->vliny
= p
, vp
->vflags
&= ~VDIRT
;
127 * Try to win by making the screen larger rather than inserting
128 * a line and driving text off the bottom.
133 * BUG: Should consider using clr_eol here to clear to end of line.
134 * As it stands we always strike over the current text.
135 * Since often the current text is the same as what
136 * we are overstriking with, it tends not to show.
137 * On the other hand if it is different and we end up
138 * spacing out a lot of text, we could have won with
139 * a clr_eol. This is probably worthwhile at low speed
140 * only however, since clearly computation will be
141 * necessary to determine which way to go.
146 if (state
== VISUAL
&& l
== vcline
&& vp
->vliny
< 0) {
153 * When we are typing part of a line for hardcopy open, don't
154 * want to type the '$' marking an end of line if in list mode.
158 if (Putchar
== listchar
)
162 * Optimization of cursor motion may prevent screen rollup if the
163 * line has blanks/tabs at the end unless we force the cursor to appear
164 * on the last line segment.
166 if (vp
->vliny
+ d
- 1 > WBOT
)
170 * Switch into hardcopy open mode if we are in one line (adm3)
171 * open mode and this line is now too long. If in hardcopy
172 * open mode, then call sethard to move onto the next line
173 * with appropriate positioning.
175 if (state
== ONEOPEN
) {
182 } else if (state
== HARDOPEN
)
186 * Unless we filled (completely) the last line we typed on,
187 * we have to clear to the end of the line
188 * in case stuff is left from before.
190 if (vp
->vliny
+ d
> destline
) {
191 if (insert_null_glitch
&& destcol
== WCOLS
)
192 vigoto(vp
->vliny
+ d
- 1, 0);
199 * Real work for winning growing of window at top
200 * when inserting in the middle of a partially full
201 * screen on an intelligent terminal. We have as argument
202 * the logical line number to be inserted after, and the offset
203 * from that line where the insert will go.
204 * We look at the picture of depths and positions, and if we can
205 * delete some (blank) lines from the top of the screen so that
206 * later inserts will not push stuff off the bottom.
209 vglitchup(int l
, int o
)
211 struct vlinfo
*vp
= &vlinfo
[l
];
214 short oldhold
, oldheldech
;
218 need
= p
+ vp
->vdepth
- (vp
+1)->vliny
;
220 if (state
== VISUAL
&& WTOP
- ZERO
>= need
&& insert_line
&& delete_line
) {
223 WLINES
= WBOT
- WTOP
+ 1;
229 vdellin(WTOP
, need
, -1);
230 oldheldech
= heldech
;
234 vinslin((vp
+1)->vliny
, need
, l
);
237 heldech
= oldheldech
;
241 vp
[1].vliny
= vp
[0].vliny
+ vp
->vdepth
;
246 * Insert cnt blank lines before line p,
247 * logically and (if supported) physically.
250 vinslin(int p
, int cnt
, int l
)
257 tfixnl(), fprintf(trace
, "vinslin(%d, %d, %d)\n", p
, cnt
, l
);
259 if (p
+ cnt
> WBOT
&& clr_eos
) {
261 * Really quick -- clear to end of screen.
264 vgoto(p
, 0), vputp(clr_eos
, cnt
);
267 } else if (scroll_reverse
&& p
== WTOP
&& costSR
< costAL
) {
269 * Use reverse scroll mode of the terminal, at
270 * the top of the window. Reverse linefeed works
271 * too, since we only use it from line WTOP.
273 for (i
= cnt
; i
> 0; i
--) {
274 vgoto(p
, 0), vputp(scroll_reverse
, 0);
275 if (i
> 1 && (hold
& HOLDAT
) == 0)
278 * If we are at the top of the screen, and the
279 * terminal retains display above, then we
280 * should try to clear to end of line.
281 * Have to use clr_eol since we don't remember what is
282 * actually on the line.
284 if (clr_eol
&& (memory_above
|| p
!= 0))
288 } else if (insert_line
) {
293 if (parm_insert_line
&& (cnt
>1 || *insert_line
==0)) {
294 /* insert cnt lines. Should do @'s too. */
295 vputp(tparm(parm_insert_line
, cnt
, p
), WECHO
+1-p
);
297 else if (change_scroll_region
&& *insert_line
==0) {
298 /* vt100 change scrolling region to fake insert_line */
299 vputp(save_cursor
, 1);
300 vputp(tparm(change_scroll_region
, p
, lines
-1), 1);
301 vputp(restore_cursor
, 1); /* change_scroll_region homes stupid cursor */
302 for (i
=cnt
; i
>0; i
--)
303 vputp(scroll_reverse
, 1); /* should do @'s */
304 vputp(tparm(change_scroll_region
, 0, lines
-1), 1);
305 vputp(restore_cursor
, 1); /* Once again put it back */
308 vputp(insert_line
, WECHO
+ 1 - p
);
309 for (i
= cnt
- 1; i
> 0; i
--) {
311 vputp(insert_line
, WECHO
+ 1 - outline
);
312 if ((hold
& HOLDAT
) == 0)
319 vopenup(cnt
, could
, l
);
323 * Logically open up after line l, cnt of them.
324 * We need to know if it was done ``physically'' since in this
325 * case we accept what the hardware gives us. If we have to do
326 * it ourselves (brute force) we will squish out @ lines in the process
327 * if this will save us work.
330 vopenup(int cnt
, bool could
, int l
)
332 struct vlinfo
*vc
= &vlinfo
[l
+ 1];
333 struct vlinfo
*ve
= &vlinfo
[vcnt
];
337 tfixnl(), fprintf(trace
, "vopenup(%d, %d, %d)\n", cnt
, could
, l
);
341 * This will push @ lines down the screen,
342 * just as the hardware did. Since the default
343 * for intelligent terminals is to never have @
344 * lines on the screen, this should never happen,
345 * and the code makes no special effort to be nice in this
346 * case, e.g. squishing out the @ lines by delete lines
347 * before doing append lines.
349 for (; vc
<= ve
; vc
++)
353 * Will have to clean up brute force eventually,
354 * so push the line data around as little as possible.
356 vc
->vliny
+= cnt
, vc
->vflags
|= VDIRT
;
358 int i
= vc
->vliny
+ vc
->vdepth
;
363 vc
->vliny
= i
, vc
->vflags
|= VDIRT
;
370 * Adjust data structure internally to account for insertion of
371 * blank lines on the screen.
374 vadjAL(int p
, int cnt
)
376 wchar_t *tlines
[TUBELINES
];
381 tfixnl(), fprintf(trace
, "vadjal(%d, %d)\n", p
, cnt
);
383 copy(tlines
, vtube
, sizeof vtube
); /*SASSIGN*/
384 for (from
= p
, to
= p
+ cnt
; to
<= WECHO
; from
++, to
++)
385 vtube
[to
] = tlines
[from
];
386 for (to
= p
; from
<= WECHO
; from
++, to
++) {
387 vtube
[to
] = tlines
[from
];
388 vclrbyte(vtube
[to
], WCOLS
);
391 * Have to clear the echo area since its contents aren't
392 * necessarily consistent with the rest of the display.
398 * Roll the screen up logically and physically
399 * so that line dl is the bottom line on the screen.
409 tfixnl(), fprintf(trace
, "vrollup(%d)\n", dl
);
411 cnt
= dl
- (splitw
? WECHO
: WBOT
);
412 if (splitw
&& (state
== VISUAL
|| state
== CRTOPEN
))
416 destline
= dl
- cnt
, destcol
= dc
;
427 * Scroll the screen up cnt lines physically.
428 * If doclr is true, do a clear eol if the terminal
429 * has standout (to prevent it from scrolling up)
432 vmoveitup(int cnt
, bool doclr
)
439 tfixnl(), fprintf(trace
, "vmoveitup(%d)\n", cnt
);
443 if (scroll_forward
) {
445 destcol
= (NONL
? 0 : outcol
% WCOLS
);
448 vputp(scroll_forward
, 0), cnt
--;
451 destline
= WECHO
+ cnt
;
452 destcol
= (NONL
? 0 : outcol
% WCOLS
);
454 if (state
== ONEOPEN
|| state
== HARDOPEN
) {
455 outline
= destline
= 0;
456 vclrbyte(vtube
[0], WCOLS
);
459 /* Get rid of line we just rolled up */
460 if (doclr
&& memory_below
&& clr_eol
)
465 * Scroll the screen up cnt lines logically.
471 wchar_t *tlines
[TUBELINES
];
475 fprintf(trace
, "vscroll(%d)\n", cnt
);
477 if (cnt
< 0 || cnt
> TUBELINES
)
478 error(gettext("Internal error: vscroll"));
481 copy(tlines
, vtube
, sizeof vtube
);
482 for (to
= ZERO
, from
= ZERO
+ cnt
; to
<= WECHO
- cnt
; to
++, from
++)
483 vtube
[to
] = tlines
[from
];
484 for (from
= ZERO
; to
<= WECHO
; to
++, from
++) {
485 vtube
[to
] = tlines
[from
];
486 vclrbyte(vtube
[to
], WCOLS
);
488 for (from
= 0; from
<= vcnt
; from
++)
493 * Discard logical lines due to physical wandering off the screen.
502 tfixnl(), fprintf(trace
, "vscrap\n"), tvliny();
506 if (vcnt
&& WBOT
!= WECHO
&& LINE(0) < WTOP
&& LINE(0) >= ZERO
) {
508 WLINES
= WBOT
- WTOP
+ 1;
510 for (j
= 0; j
< vcnt
; j
++)
511 if (LINE(j
) >= WTOP
) {
515 * Discard the first j physical lines off the top.
517 vcnt
-= j
, vcline
-= j
;
518 for (i
= 0; i
<= vcnt
; i
++)
519 vlcopy(vlinfo
[i
], vlinfo
[i
+ j
]);
523 * Discard lines off the bottom.
526 for (j
= 0; j
<= vcnt
; j
++)
527 if (LINE(j
) > WBOT
|| LINE(j
) + DEPTH(j
) - 1 > WBOT
) {
534 LASTLINE
= LINE(vcnt
-1) + DEPTH(vcnt
-1);
546 * Repaint the screen, with cursor at curs, aftern an arbitrary change.
547 * Handle notification on large changes.
550 vrepaint(unsigned char *curs
)
555 * In open want to notify first.
561 * Deal with a totally useless display.
563 if (vcnt
== 0 || vcline
< 0 || vcline
> vcnt
|| holdupd
&& state
!= VISUAL
) {
577 if (noteit(1) == 0 && odol
== zero
) {
579 error(gettext("No lines in buffer"));
589 * Have some useful displayed text; refresh it.
594 * This is for boundary conditions in open mode.
596 if (FLAGS(0) & VDIRT
)
600 * If the current line is after the last displayed line
601 * or the bottom of the screen, then special effort is needed
602 * to get it on the screen. We first try a redraw at the
603 * last line on the screen, hoping it will fill in where @
604 * lines are now. If this doesn't work, then roll it onto
607 if (vcline
>= vcnt
|| LINE(vcline
) > WBOT
) {
608 short oldhold
= hold
;
609 hold
|= HOLDAT
, vredraw(LASTLINE
), hold
= oldhold
;
610 if (vcline
>= vcnt
) {
611 int i
= vcline
- vcnt
+ 1;
619 vsync(vcline
> 0 ? LINE(vcline
- 1) : WTOP
);
622 * Notification on large change for visual
623 * has to be done last or we may lose
624 * the echo area with redisplay.
629 * Finally. Move the cursor onto the current line.
635 * Fully cleanup the screen, leaving no @ lines except at end when
636 * line after last won't completely fit. The routine vsync is
637 * more conservative and much less work on dumb terminals.
644 unsigned char temp
[LBSIZE
];
646 short oldhold
= hold
;
650 tfixnl(), fprintf(trace
, "vredraw(%d)\n", p
), tvliny();
656 if (state
== HARDOPEN
|| splitw
)
658 if (p
< 0 /* || p > WECHO */)
659 error(gettext("Internal error: vredraw"));
662 * Trim the ragged edges (lines which are off the screen but
663 * not yet logically discarded), save the current line, and
664 * search for first logical line affected by the redraw.
672 while (l
< vcnt
&& LINE(l
) < p
)
676 * We hold off echo area clearing during the redraw in deference
677 * to a final clear of the echo area at the end if appropriate.
681 for (; l
< vcnt
&& Peekkey
!= ATTN
; l
++) {
688 * Delete junk between displayed lines.
690 if (LINE(l
) != LINE(l
+ 1) && LINE(l
) != p
) {
691 if (anydl
== 0 && memory_below
&& clr_eos
) {
698 vdellin(p
, LINE(l
) - p
, l
);
702 * If line image is not know to be up to date, then
703 * redisplay it; else just skip onward.
706 if (FLAGS(l
) & VDIRT
) {
708 if (l
!= vcline
&& p
+ DEPTH(l
) - 1 > WBOT
) {
713 (void) vreopen(p
, lineno(tp
), l
);
714 p
= LINE(l
) + DEPTH(l
);
721 * That takes care of lines which were already partially displayed.
722 * Now try to fill the rest of the screen with text.
724 if (state
== VISUAL
&& p
<= WBOT
) {
725 int ovcline
= vcline
;
728 for (; tp
<= dol
&& Peekkey
!= ATTN
; tp
++) {
730 if (p
+ vdepth() - 1 > WBOT
)
740 * That's all the text we can get on.
741 * Now rest of lines (if any) get either a ~ if they
742 * are past end of file, or an @ if the next line won't fit.
744 for (; p
<= WBOT
&& Peekkey
!= ATTN
; p
++)
757 * Do the real work in deleting cnt lines starting at line p from
758 * the display. First affected line is line l.
761 vdellin(int p
, int cnt
, int l
)
767 if (delete_line
== NOSTR
|| cnt
< 0) {
769 * Can't do it; just remember that line l is munged.
776 tfixnl(), fprintf(trace
, "vdellin(%d, %d, %d)\n", p
, cnt
, l
);
779 * Send the deletes to the screen and then adjust logical
780 * and physical internal data structures.
783 if (parm_delete_line
&& (cnt
>1 || *delete_line
==0)) {
784 vputp(tparm(parm_delete_line
, cnt
, p
), WECHO
-p
);
786 else if (change_scroll_region
&& *delete_line
==0) {
787 /* vt100: fake delete_line by changing scrolling region */
788 vputp(save_cursor
, 1); /* Save since change_scroll_region homes stupid cursor */
789 vputp(tparm(change_scroll_region
, p
, lines
-1), 1);
790 vputp(tparm(cursor_address
, lines
-1, 0), 1);/* Go to lower left corner */
791 for (i
=0; i
<cnt
; i
++) /* .. and scroll cnt times */
792 (void) putch('\n'); /* should check NL too */
793 vputp(tparm(change_scroll_region
, 0, lines
-1), 1);/* restore scrolling region */
794 vputp(restore_cursor
, 1); /* put cursor back */
797 for (i
= 0; i
< cnt
; i
++)
798 vputp(delete_line
, WECHO
- p
);
804 * Adjust internal physical screen image to account for deleted lines.
807 vadjDL(int p
, int cnt
)
809 wchar_t *tlines
[TUBELINES
];
814 tfixnl(), fprintf(trace
, "vadjDL(%d, %d)\n", p
, cnt
);
817 * Would like to use structured assignment but early
818 * v7 compiler (released with phototypesetter for v6)
821 copy(tlines
, vtube
, sizeof vtube
); /*SASSIGN*/
822 for (from
= p
+ cnt
, to
= p
; from
<= WECHO
; from
++, to
++)
823 vtube
[to
] = tlines
[from
];
824 for (from
= p
; to
<= WECHO
; from
++, to
++) {
825 vtube
[to
] = tlines
[from
];
826 vclrbyte(vtube
[to
], WCOLS
);
830 * Sync the screen, like redraw but more lazy and willing to leave
831 * @ lines on the screen. VsyncCL syncs starting at the current line.
832 * In any case, if the redraw option is set then all syncs map to redraws
833 * as if vsync didn't exist.
846 if (value(vi_REDRAW
))
853 * The guts of a sync. Similar to redraw but
854 * just less ambitious.
860 unsigned char temp
[LBSIZE
];
861 struct vlinfo
*vp
= &vlinfo
[0];
862 short oldhold
= hold
;
866 tfixnl(), fprintf(trace
, "vsync1(%d)\n", p
), tvliny();
873 if (state
== HARDOPEN
|| splitw
)
880 while (l
< vcnt
&& vp
->vliny
< p
)
884 while (p
<= WBOT
&& Peekkey
!= ATTN
) {
886 * Want to put a line here if not in visual and first line
887 * or if there are lies left and this line starts before
888 * the current line, or if this line is piled under the
889 * next line (vreplace does this and we undo it).
891 if (l
== 0 && state
!= VISUAL
||
892 (l
< vcnt
&& (vp
->vliny
<= p
|| vp
[0].vliny
== vp
[1].vliny
))) {
893 if (l
== 0 || vp
->vliny
< p
|| (vp
->vflags
& VDIRT
)) {
897 getaline(dot
[l
- vcline
]);
899 * Be careful that a long line doesn't cause the
900 * screen to shoot up.
902 if (l
!= vcline
&& (vp
->vflags
& VDIRT
)) {
903 vp
->vdepth
= vdepth();
904 vp
->vflags
&= ~VDIRT
;
905 if (p
+ vp
->vdepth
- 1 > WBOT
)
908 (void) vreopen(p
, lineDOT() + (l
- vcline
), l
);
910 p
= vp
->vliny
+ vp
->vdepth
;
915 * A physical line between logical lines,
916 * so we settle for an @ at the beginning.
918 vclrlin(p
, dot
+ (l
- vcline
)), p
++;
927 * Subtract (logically) cnt physical lines from the
928 * displayed position of lines starting with line l.
931 vcloseup(int l
, int cnt
)
937 tfixnl(), fprintf(trace
, "vcloseup(%d, %d)\n", l
, cnt
);
939 for (i
= l
+ 1; i
<= vcnt
; i
++)
944 * Workhorse for rearranging line descriptors on changes.
945 * The idea here is that, starting with line l, cnt lines
946 * have been replaced with newcnt lines. All of these may
947 * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0,
948 * since we may be called from an undo after the screen has
949 * moved a lot. Thus we have to be careful.
951 * Many boundary conditions here.
954 vreplace(int l
, int cnt
, int newcnt
)
961 tfixnl(), fprintf(trace
, "vreplace(%d, %d, %d)\n", l
, cnt
, newcnt
);
970 * Nothing on the screen is relevant.
971 * Settle for redrawing from scratch (later).
977 * Normalize l to top of screen; the add is
978 * really a subtract from cnt since l is negative.
984 * Unseen lines were affected so notify (later).
990 * These shouldn't happen
991 * but would cause great havoc.
999 * Surely worthy of note if more than report
1000 * lines were changed.
1002 if (cnt
> value(vi_REPORT
) || newcnt
> value(vi_REPORT
))
1006 * Same number of lines affected as on screen, and we
1007 * can insert and delete lines. Thus we just type
1008 * over them, since otherwise we will push them
1009 * slowly off the screen, a clear lose.
1011 if (cnt
== newcnt
|| vcnt
- l
== newcnt
&& insert_line
&& delete_line
) {
1012 if (cnt
> 1 && l
+ cnt
> vcnt
)
1017 * Lines are going away, squish them out.
1021 * If non-displayed lines went away,
1024 if (cnt
> 1 && l
+ cnt
> vcnt
)
1026 if (l
+ cnt
>= vcnt
)
1029 for (from
= l
+ cnt
, to
= l
; from
<= vcnt
; to
++, from
++)
1030 vlcopy(vlinfo
[to
], vlinfo
[from
]);
1034 * Open up space for new lines appearing.
1035 * All new lines are piled in the same place,
1036 * and will be unpiled by vredraw/vsync, which
1037 * inserts lines in front as it unpiles.
1041 * Newlines are appearing which may not show,
1042 * so notify (this is only approximately correct
1043 * when long lines are present).
1045 if (newcnt
> 1 && l
+ newcnt
> vcnt
+ 1)
1049 * If there will be more lines than fit, then
1050 * just throw way the rest of the stuff on the screen.
1052 if (l
+ newcnt
> WBOT
&& insert_line
&& delete_line
) {
1056 from
= vcnt
, to
= vcnt
+ newcnt
;
1061 for (; from
>= l
; from
--, to
--)
1062 vlcopy(vlinfo
[to
], vlinfo
[from
]);
1063 for (from
= to
+ 1, to
= l
; to
< l
+ newcnt
&& to
<= WBOT
+ 1; to
++) {
1064 LINE(to
) = LINE(from
);
1071 if (Pline
== numbline
&& cnt
!= newcnt
)
1073 * When lines positions are shifted, the numbers
1086 * Start harcopy open.
1087 * Print an image of the line to the left of the cursor
1088 * under the full print of the line and position the cursor.
1089 * If we are in a scroll ^D within hardcopy open then all this
1096 if (state
== VISUAL
)
1104 if (Pline
== numbline
)
1105 vgoto(WBOT
, 0), viprintf("%6d ", lineDOT());
1109 * Mark the lines starting at base for i lines
1110 * as dirty so that they will be checked for correct
1111 * display at next sync/redraw.
1114 vdirty(int base
, int i
)
1118 for (l
= base
; l
< vcnt
; l
++) {