5 * 14407 SW Teal Blvd. #C
11 /* This file contains functions that draw text on the screen. The major entry
13 * redrawrange() - called from modify.c to give hints about what parts
14 * of the screen need to be redrawn.
15 * redraw() - redraws the screen (or part of it) and positions
16 * the cursor where it belongs.
17 * idx2col() - converts a markidx() value to a logical column number.
23 /* This variable contains the line number that smartdrawtext() knows best */
26 /* This function remembers where changes were made, so that the screen can be
27 * redraw in a more efficient manner.
29 static long redrawafter
; /* line# of first line that must be redrawn */
30 static long preredraw
; /* line# of last line changed, before change */
31 static long postredraw
; /* line# of last line changed, after change */
32 static int mustredraw
; /* boolean: anything forcing a screen update? */
33 void redrawrange(after
, pre
, post
)
34 long after
; /* lower bound of redrawafter */
35 long pre
; /* upper bound of preredraw */
36 long post
; /* upper bound of postredraw */
38 if (after
== redrawafter
)
40 /* multiple insertions/deletions at the same place -- combine
43 preredraw
-= (post
- pre
);
44 if (postredraw
< post
)
46 preredraw
+= (post
- postredraw
);
49 if (redrawafter
> preredraw
)
51 redrawafter
= preredraw
;
56 preredraw
= postredraw
= INFINITY
;
59 else if (postredraw
> 0L)
61 /* multiple changes in different places -- redraw everything
64 postredraw
= preredraw
= INFINITY
;
65 if (after
< redrawafter
)
80 /* see if a given line uses character attribute strings */
81 static int hasattr(lno
, text
)
82 long lno
; /* the line# of the cursor */
83 REG
char *text
; /* the text of the line, from fetchline */
85 static long plno
; /* previous line number */
86 static long chgs
; /* previous value of changes counter */
87 static int panswer
;/* previous answer */
90 /* if charattr is off, then the answer is "no, it doesn't" */
93 chgs
= 0; /* <- forces us to check if charattr is later set */
97 /* if we already know the answer, return it... */
98 if (lno
== plno
&& chgs
== changes
)
103 /* get the line & look for "\fX" */
104 if (!text
[0] || !text
[1] || !text
[2])
110 for (scan
= text
; scan
[2] && !(scan
[0] == '\\' && scan
[1] == 'f'); scan
++)
113 panswer
= (scan
[2] != '\0');
116 /* save the results */
120 /* return the results */
127 /* This function checks to make sure that the correct lines are shown in
128 * reverse-video. This is used to handle the "v" and "V" commands.
130 static long vizlow
, vizhigh
; /* the starting and ending lines */
131 static int vizleft
, vizright
; /* starting & ending indicies */
132 static int vizchange
; /* boolean: must use stupid drawtext? */
133 static void setviz(curs
)
136 long newlow
, newhigh
;
139 /* for now, assume the worst... */
142 /* set newlow & newhigh according to V_from and cursor */
145 /* no lines should have reverse-video */
148 redrawrange(vizlow
, vizhigh
+ 1L, vizhigh
+ 1L);
149 vizlow
= vizhigh
= 0L;
158 /* figure out which lines *SHOULD* have hilites */
161 newlow
= markline(V_from
);
162 newhigh
= markline(curs
);
163 vizleft
= markidx(V_from
);
164 vizright
= markidx(curs
) + 1;
168 newlow
= markline(curs
);
169 newhigh
= markline(V_from
);
170 vizleft
= markidx(curs
);
171 vizright
= markidx(V_from
) + 1;
174 /* adjust for line-mode hiliting */
178 vizright
= BLKSIZE
- 1;
185 /* arrange for the necessary lines to be redrawn */
188 /* just starting to redraw */
189 redrawrange(newlow
, newhigh
, newhigh
);
193 /* Were new lines added/removed at the front? */
194 if (newlow
!= vizlow
)
197 redrawrange(newlow
, vizlow
+ extra
, vizlow
+ extra
);
199 redrawrange(vizlow
, newlow
+ extra
, newlow
+ extra
);
202 /* Were new lines added/removed at the back? */
203 if (newhigh
!= vizhigh
)
205 if (newhigh
< vizhigh
)
206 redrawrange(newhigh
+ 1L - extra
, vizhigh
+ 1L, vizhigh
+ 1L);
208 redrawrange(vizhigh
+ 1L - extra
, newhigh
, newhigh
);
212 /* remember which lines will contain hilighted text now */
216 #endif /* !NO_VISIBLE */
219 /* This function converts a MARK to a column number. It doesn't automatically
220 * adjust for leftcol; that must be done by the calling function
222 int idx2col(curs
, text
, inputting
)
223 MARK curs
; /* the line# & index# of the cursor */
224 REG
char *text
; /* the text of the line, from fetchline */
225 int inputting
; /* boolean: called from input() ? */
227 static MARK pcursor
;/* previous cursor, for possible shortcut */
228 static MARK pcol
; /* column number for pcol */
229 static long chgs
; /* previous value of changes counter */
230 REG
int col
; /* used to count column numbers */
231 REG
int idx
; /* used to count down the index */
234 /* for now, assume we have to start counting at the left edge */
238 /* if the file hasn't changed & line number is the same & it has no
239 * embedded character attribute strings, can we do shortcuts?
242 && !((curs
^ pcursor
) & ~(BLKSIZE
- 1))
244 && !hasattr(markline(curs
), text
)
251 /* return the column of the char; for tabs, return its last column */
252 if (text
[idx
] == '\t' && !inputting
&& !*o_list
)
254 return pcol
+ *o_tabstop
- (pcol
% *o_tabstop
) - 1;
262 /* movement to right? */
265 /* start counting from previous place */
267 idx
= markidx(curs
) - markidx(pcursor
);
268 text
+= markidx(pcursor
);
272 /* count over to the char after the idx position */
273 while (idx
> 0 && (i
= *text
)) /* yes, ASSIGNMENT! */
275 if (i
== '\t' && !*o_list
)
278 col
-= col
% *o_tabstop
;
280 else if (i
>= '\0' && i
< ' ' || i
== '\177')
285 else if (i
== '\\' && text
[1] == 'f' && text
[2] && *o_charattr
)
287 text
+= 2; /* plus one more at bottom of loop */
299 /* save stuff to speed next call */
304 /* return the column of the char; for tabs, return its last column */
305 if (*text
== '\t' && !inputting
&& !*o_list
)
307 return col
+ *o_tabstop
- (col
% *o_tabstop
) - 1;
316 /* This function is similar to idx2col except that it takes care of sideways
317 * scrolling - for the given line, at least.
319 int mark2phys(m
, text
, inputting
)
320 MARK m
; /* a mark to convert */
321 char *text
; /* the line that m refers to */
322 int inputting
; /* boolean: caled from input() ? */
326 i
= idx2col(m
, text
, inputting
);
329 leftcol
-= *o_sidescroll
;
331 redrawrange(1L, INFINITY
, INFINITY
);
335 leftcol
+= *o_sidescroll
;
337 redrawrange(1L, INFINITY
, INFINITY
);
339 physrow
= markline(m
) - topline
;
340 physcol
= i
- leftcol
;
347 /* This function draws a single line of text on the screen. The screen's
348 * cursor is assumed to be located at the leftmost column of the appropriate
351 static void drawtext(text
, lno
, clr
)
352 REG
char *text
; /* the text to draw */
353 long lno
; /* the number of the line to draw */
354 int clr
; /* boolean: do a clrtoeol? */
356 REG
int col
; /* column number */
358 REG
int tabstop
; /* *o_tabstop */
359 REG
int limitcol
; /* leftcol or leftcol + COLS */
360 int abnormal
; /* boolean: charattr != A_NORMAL? */
362 int rev
; /* boolean: standout mode, too? */
367 /* show the line number, if necessary */
370 sprintf(numstr
, "%6ld |", lno
);
375 /* if we're hiding format lines, and this is one of them, then hide it */
376 if (*o_hideformat
&& *text
== '.')
388 /* move some things into registers... */
390 tabstop
= *o_tabstop
;
398 /* skip stuff that was scrolled off left edge */
400 (i
= *text
) && col
< limitcol
; /* yes, ASSIGNMENT! */
406 if (i
== '\t' && !*o_list
)
408 col
= col
+ tabstop
- (col
% tabstop
);
410 else if (i
>= 0 && i
< ' ' || i
== '\177')
415 else if (i
== '\\' && text
[1] == 'f' && text
[2] && *o_charattr
)
417 text
+= 2; /* plus one more as part of "for" loop */
419 /* since this attribute might carry over, we need it */
434 attrset(A_UNDERLINE
);
439 attrset(A_ALTCHARSET
);
452 /* Should we start hiliting at the first char of this line? */
453 if ((lno
> vizlow
&& lno
<= vizhigh
454 || lno
== vizlow
&& vizleft
< idx
)
455 && !(lno
== vizhigh
&& vizright
< idx
))
462 /* adjust for control char that was partially visible */
463 while (col
> limitcol
)
469 /* now for the visible characters */
470 limitcol
= leftcol
+ COLS
;
473 for (; (i
= *text
) && col
< limitcol
; text
++)
476 /* maybe turn hilite on/off in the middle of the line */
477 if (lno
== vizlow
&& vizleft
== idx
)
482 if (lno
== vizhigh
&& vizright
== idx
)
489 /* if hiliting, never emit physical tabs */
490 if (rev
&& i
== '\t' && !*o_list
)
492 i
= col
+ tabstop
- (col
% tabstop
);
500 #endif /* !NO_VISIBLE */
501 if (i
== '\t' && !*o_list
)
503 i
= col
+ tabstop
- (col
% tabstop
);
507 if (!clr
&& has_PT
&& !((i
- leftcol
) & 7))
509 if (has_PT
&& !((i
- leftcol
) & 7))
515 col
+= 8; /* not exact! */
517 col
= i
; /* NOW it is exact */
528 else /* tab ending after screen? next line! */
533 addch('\n'); /* GB */
537 else if (i
>= 0 && i
< ' ' || i
== '\177')
547 else if (i
== '\\' && text
[1] == 'f' && text
[2] && *o_charattr
)
549 text
+= 2; /* plus one more as part of "for" loop */
564 attrset(A_UNDERLINE
);
569 attrset(A_ALTCHARSET
);
582 /* get ready for the next line */
589 if (*o_list
&& col
< limitcol
)
596 /* did we hilite this whole line? If so, STOP! */
604 if (clr
&& col
< limitcol
)
609 if (!has_AM
|| col
< limitcol
)
619 static void nudgecursor(same
, scan
, new, lno
)
620 int same
; /* number of chars to be skipped over */
621 char *scan
; /* where the same chars end */
622 char *new; /* where the visible part of the line starts */
623 long lno
; /* line number of this line */
631 /* move the cursor by overwriting */
640 /* move the cursor by calling move() */
641 col
= (int)(scan
- new);
644 move((int)(lno
- topline
), col
);
648 #endif /* not CRUNCH */
650 /* This function draws a single line of text on the screen, possibly with
651 * some cursor optimization. The cursor is repositioned before drawing
652 * begins, so its position before doesn't really matter.
654 static void smartdrawtext(text
, lno
, showit
)
655 REG
char *text
; /* the text to draw */
656 long lno
; /* line number of the text */
657 int showit
; /* boolean: output line? (else just remember it) */
660 move((int)(lno
- topline
), 0);
663 drawtext(text
, lno
, TRUE
);
665 #else /* not CRUNCH */
666 static char old
[256]; /* how the line looked last time */
667 char new[256]; /* how it looks now */
668 char *build
; /* used to put chars into new[] */
669 char *scan
; /* used for moving thru new[] or old[] */
670 char *end
; /* last non-blank changed char */
671 char *shift
; /* used to insert/delete chars */
672 int same
; /* length of a run of unchanged chars */
679 /* if this line has attributes, do it the dumb way instead */
680 if (hasattr(lno
, text
))
682 move((int)(lno
- topline
), 0);
683 drawtext(text
, lno
, TRUE
);
688 /* if this line is a format line, & we're hiding format lines, then
689 * let the dumb drawtext() function handle it
691 if (*o_hideformat
&& *text
== '.')
693 move((int)(lno
- topline
), 0);
694 drawtext(text
, lno
, TRUE
);
701 move((int)(lno
- topline
), 0);
702 drawtext(text
, lno
, TRUE
);
708 /* skip stuff that was scrolled off left edge */
711 (i
= *text
) && col
< limitcol
; /* yes, ASSIGNMENT! */
714 if (i
== '\t' && !*o_list
)
716 col
= col
+ *o_tabstop
- (col
% *o_tabstop
);
718 else if (i
>= 0 && i
< ' ' || i
== '\177')
728 /* adjust for control char that was partially visible */
730 while (col
> limitcol
)
736 /* now for the visible characters */
737 limitcol
= leftcol
+ COLS
;
740 for (; (i
= *text
) && col
< limitcol
; text
++)
742 if (i
== '\t' && !*o_list
)
744 i
= col
+ *o_tabstop
- (col
% *o_tabstop
);
745 while (col
< i
&& col
< limitcol
)
751 else if (i
>= 0 && i
< ' ' || i
== '\177')
757 *build
++ = (i
^ '@');
766 if (col
< limitcol
&& *o_list
)
772 while (col
< limitcol
)
778 /* if we're just supposed to remember this line, then remember it */
782 strncpy(old
, new, COLS
);
786 /* locate the last non-blank character */
787 while (end
> new && end
[-1] == ' ')
792 /* can we optimize the displaying of this line? */
795 /* nope, can't optimize - different line */
796 move((int)(lno
- topline
), 0);
798 /* show the line number, if necessary */
801 sprintf(numstr
, "%6ld |", lno
);
805 /* show the new line */
806 for (scan
= new, build
= old
; scan
< end
; )
811 if (end
< new + COLS
- (*o_number
? 8 : 0))
814 while (build
< old
+ COLS
)
823 /* skip any initial unchanged characters */
824 for (scan
= new, build
= old
; scan
< end
&& *scan
== *build
; scan
++, build
++)
830 move((int)(lno
- topline
), i
);
832 /* The in-between characters must be changed */
836 /* is this character a match? */
837 if (scan
[0] == build
[0])
841 else /* do we want to insert? */
842 if (scan
< end
- 1 && scan
[1] == build
[0] && (has_IC
|| has_IM
))
844 nudgecursor(same
, scan
, new, lno
);
848 for (shift
= old
+ COLS
; --shift
> build
; )
850 shift
[0] = shift
[-1];
854 else /* do we want to delete? */
855 if (build
< old
+ COLS
- 1 && scan
[0] == build
[1] && has_DC
)
857 nudgecursor(same
, scan
, new, lno
);
862 for (shift
= build
; shift
< old
+ COLS
- 1; shift
++)
870 else /* we must overwrite */
872 nudgecursor(same
, scan
, new, lno
);
883 /* maybe clear to EOL */
884 end
= old
+ COLS
- (*o_number
? 8 : 0);
885 while (build
< end
&& *build
== ' ')
891 nudgecursor(same
, scan
, new, lno
);
895 while (build
< old
+ COLS
)
900 #endif /* not CRUNCH */
904 /* This function is used in visual mode for drawing the screen (or just parts
905 * of the screen, if that's all thats needed). It also takes care of
908 void redraw(curs
, inputting
)
909 MARK curs
; /* where to leave the screen's cursor */
910 int inputting
; /* boolean: being called from input() ? */
912 char *text
; /* a line of text to display */
913 static long chgs
; /* previous changes level */
917 static long showtop
; /* top line in window */
918 static long showbottom
; /* bottom line in window */
921 /* if curs == MARK_UNSET, then we should reset internal vars */
922 if (curs
== MARK_UNSET
)
924 if (topline
< 1 || topline
> nlines
)
935 redrawafter
= INFINITY
;
941 vizlow
= vizhigh
= 0L;
946 showbottom
= INFINITY
;
952 /* adjustments to hilited area may force extra lines to be redrawn. */
956 /* figure out which column the cursor will be in */
959 mark2phys(curs
, text
, inputting
);
965 /* adjust topline, if necessary, to get the cursor on the screen */
966 if (l
>= topline
&& l
<= botline
)
968 /* it is on the screen already */
970 /* if the file was changed but !mustredraw, then redraw line */
971 if (!mustredraw
&& (chgs
!= changes
976 || l
< showtop
|| l
> showbottom
980 smartdrawtext(text
, l
, (chgs
!= changes
));
983 else if (l
< topline
&& l
> topline
- LINES
&& (has_SR
|| has_AL
))
985 /* near top - scroll down */
1000 text
= fetchline(topline
);
1001 drawtext(text
, topline
, FALSE
);
1005 /* blank out the last line */
1012 redrawrange(0L, INFINITY
, INFINITY
);
1015 else if (l
> topline
&& l
< botline
+ LINES
)
1017 /* near bottom -- scroll up */
1024 topline
++; /* <-- also adjusts botline */
1025 text
= fetchline(botline
);
1026 drawtext(text
, botline
, FALSE
);
1034 topline
= l
- (LINES
- 2);
1035 redrawrange(0L, INFINITY
, INFINITY
);
1040 /* distant line - center it & force a redraw */
1041 topline
= l
- (LINES
/ 2) - 1;
1046 redrawrange(0L, INFINITY
, INFINITY
);
1051 /* make sure the current line is included in the "window" */
1054 redrawrange(l
, showtop
, showtop
);
1059 redrawrange(showbottom
, l
, l
);
1065 /* Now... do we really have to redraw? */
1068 /* If redrawfter (and friends) aren't set, assume we should
1069 * redraw everything.
1071 if (redrawafter
== INFINITY
)
1074 preredraw
= postredraw
= INFINITY
;
1078 /* shrink the window, if possible */
1079 if (showtop
< topline
)
1083 if (showbottom
> botline
)
1085 showbottom
= botline
;
1087 if (postredraw
== INFINITY
)
1089 /* these will be set to more reasonable values later */
1095 /* adjust smartlno to correspond with inserted/deleted lines */
1096 if (smartlno
>= redrawafter
)
1098 if (smartlno
< preredraw
&& postredraw
!= preredraw
) /*!!!*/
1104 smartlno
+= (postredraw
- preredraw
);
1108 /* should we insert some lines into the screen? */
1109 if (preredraw
< postredraw
&& preredraw
<= botline
)
1111 /* lines were inserted into the file */
1113 /* decide where insertion should start */
1114 if (preredraw
< topline
)
1123 /* insert the lines... maybe */
1124 if (l
+ postredraw
- preredraw
> botline
|| !has_AL
|| *o_number
)
1126 /* Whoa! a whole screen full - just redraw */
1127 preredraw
= postredraw
= INFINITY
;
1131 /* really insert 'em */
1132 move((int)(l
- topline
), 0);
1133 for (i
= postredraw
- preredraw
; i
> 0; i
--)
1138 /* NOTE: the contents of those lines will be
1139 * drawn as part of the regular redraw loop.
1142 /* clear the last line */
1148 /* do we want to delete some lines from the screen? */
1149 if (preredraw
> postredraw
&& postredraw
<= botline
)
1151 if (preredraw
> botline
|| !has_DL
|| *o_number
)
1153 postredraw
= preredraw
= INFINITY
;
1155 else /* we'd best delete some lines from the screen */
1157 /* clear the last line, so it doesn't look
1158 * ugly as it gets pulled up into the screen
1163 /* delete the lines */
1164 move((int)(postredraw
- topline
), 0);
1165 for (l
= postredraw
;
1166 l
< preredraw
&& l
<= botline
;
1172 /* draw the lines that are now newly visible
1173 * at the bottom of the screen
1175 i
= LINES
- 1 + (postredraw
- preredraw
);
1177 for (l
= topline
+ i
; l
<= botline
; l
++)
1179 /* clear this line */
1182 /* draw the line, or ~ for non-lines */
1185 text
= fetchline(l
);
1186 drawtext(text
, l
, FALSE
);
1196 /* redraw the current line */
1199 smartdrawtext(ptext
, l
, TRUE
);
1202 /* decide which lines must be in the "window" around the cursor */
1204 if ((*o_window
& 0xff) + 1 == LINES
)
1207 showbottom
= INFINITY
;
1209 else if (l
< showtop
|| l
> showbottom
)
1211 l
-= (*o_window
& 0xff) / 2;
1220 l
+= (*o_window
& 0xff) - 1;
1223 showtop
= showtop
- l
+ botline
;
1233 /* decide where we should start redrawing from */
1234 if (redrawafter
< topline
)
1242 if (l
<= botline
&& l
< postredraw
&& (l
!= smartlno
|| botline
!= smartlno
))
1244 /* draw the other lines */
1245 move((int)(l
- topline
), 0);
1246 for (; l
<= botline
&& l
< postredraw
; l
++)
1248 /* we already drew the current line, so skip it now */
1259 /* draw the line, or ~ for non-lines */
1267 else if (l
< showtop
|| l
> showbottom
)
1276 text
= fetchline(l
);
1277 drawtext(text
, l
, TRUE
);
1285 /* force total (non-partial) redraw next time if not set */
1286 redrawafter
= INFINITY
;
1290 /* move the cursor to where it belongs */
1291 move((int)(markline(curs
) - topline
), physcol
);