This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.bin / elvis / redraw.c
CommitLineData
15637ed4
RG
1/* redraw.c */
2
3/* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
8 */
9
10
11/* This file contains functions that draw text on the screen. The major entry
12 * points are:
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.
18 */
19
20#include "config.h"
21#include "vi.h"
78ed81a3 22#ifdef CRUNCH
23# define NEAR LINES
24#else
25# define NEAR (*o_nearscroll&0xff)
26#endif
15637ed4
RG
27
28/* This variable contains the line number that smartdrawtext() knows best */
29static long smartlno;
30
31/* This function remembers where changes were made, so that the screen can be
32 * redraw in a more efficient manner.
33 */
34static long redrawafter; /* line# of first line that must be redrawn */
35static long preredraw; /* line# of last line changed, before change */
36static long postredraw; /* line# of last line changed, after change */
37static int mustredraw; /* boolean: anything forcing a screen update? */
38void redrawrange(after, pre, post)
39 long after; /* lower bound of redrawafter */
40 long pre; /* upper bound of preredraw */
41 long post; /* upper bound of postredraw */
42{
43 if (after == redrawafter)
44 {
45 /* multiple insertions/deletions at the same place -- combine
46 * them
47 */
48 preredraw -= (post - pre);
49 if (postredraw < post)
50 {
51 preredraw += (post - postredraw);
52 postredraw = post;
53 }
54 if (redrawafter > preredraw)
55 {
56 redrawafter = preredraw;
57 }
58 if (redrawafter < 1L)
59 {
60 redrawafter = 0L;
61 preredraw = postredraw = INFINITY;
62 }
63 }
64 else if (postredraw > 0L)
65 {
66 /* multiple changes in different places -- redraw everything
67 * after "after".
68 */
69 postredraw = preredraw = INFINITY;
70 if (after < redrawafter)
71 redrawafter = after;
72 }
73 else
74 {
75 /* first change */
76 redrawafter = after;
77 preredraw = pre;
78 postredraw = post;
79 }
80 mustredraw = TRUE;
81}
82
83
84#ifndef NO_CHARATTR
85/* see if a given line uses character attribute strings */
86static int hasattr(lno, text)
87 long lno; /* the line# of the cursor */
88 REG char *text; /* the text of the line, from fetchline */
89{
90 static long plno; /* previous line number */
91 static long chgs; /* previous value of changes counter */
92 static int panswer;/* previous answer */
93 char *scan;
94
95 /* if charattr is off, then the answer is "no, it doesn't" */
96 if (!*o_charattr)
97 {
98 chgs = 0; /* <- forces us to check if charattr is later set */
99 return FALSE;
100 }
101
102 /* if we already know the answer, return it... */
103 if (lno == plno && chgs == changes)
104 {
105 return panswer;
106 }
107
108 /* get the line & look for "\fX" */
109 if (!text[0] || !text[1] || !text[2])
110 {
111 panswer = FALSE;
112 }
113 else
114 {
115 for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
116 {
117 }
118 panswer = (scan[2] != '\0');
119 }
120
121 /* save the results */
122 plno = lno;
123 chgs = changes;
124
125 /* return the results */
126 return panswer;
127}
128#endif
129
130
131#ifndef NO_VISIBLE
132/* This function checks to make sure that the correct lines are shown in
133 * reverse-video. This is used to handle the "v" and "V" commands.
134 */
135static long vizlow, vizhigh; /* the starting and ending lines */
136static int vizleft, vizright; /* starting & ending indicies */
137static int vizchange; /* boolean: must use stupid drawtext? */
138static void setviz(curs)
139 MARK curs;
140{
141 long newlow, newhigh;
142 long extra = 0L;
143
144 /* for now, assume the worst... */
145 vizchange = TRUE;
146
147 /* set newlow & newhigh according to V_from and cursor */
148 if (!V_from)
149 {
150 /* no lines should have reverse-video */
151 if (vizlow)
152 {
153 redrawrange(vizlow, vizhigh + 1L, vizhigh + 1L);
154 vizlow = vizhigh = 0L;
155 }
156 else
157 {
158 vizchange = FALSE;
159 }
160 return;
161 }
162
163 /* figure out which lines *SHOULD* have hilites */
164 if (V_from < curs)
165 {
166 newlow = markline(V_from);
167 newhigh = markline(curs);
168 vizleft = markidx(V_from);
169 vizright = markidx(curs) + 1;
170 }
171 else
172 {
173 newlow = markline(curs);
174 newhigh = markline(V_from);
175 vizleft = markidx(curs);
176 vizright = markidx(V_from) + 1;
177 }
178
179 /* adjust for line-mode hiliting */
180 if (V_linemd)
181 {
182 vizleft = 0;
183 vizright = BLKSIZE - 1;
184 }
185 else
186 {
187 extra = 1L;
188 }
189
190 /* arrange for the necessary lines to be redrawn */
191 if (vizlow == 0L)
192 {
193 /* just starting to redraw */
194 redrawrange(newlow, newhigh, newhigh);
195 }
196 else
197 {
198 /* Were new lines added/removed at the front? */
199 if (newlow != vizlow)
200 {
201 if (newlow < vizlow)
202 redrawrange(newlow, vizlow + extra, vizlow + extra);
203 else
204 redrawrange(vizlow, newlow + extra, newlow + extra);
205 }
206
207 /* Were new lines added/removed at the back? */
208 if (newhigh != vizhigh)
209 {
210 if (newhigh < vizhigh)
211 redrawrange(newhigh + 1L - extra, vizhigh + 1L, vizhigh + 1L);
212 else
213 redrawrange(vizhigh + 1L - extra, newhigh, newhigh);
214 }
215 }
216
217 /* remember which lines will contain hilighted text now */
218 vizlow = newlow;
219 vizhigh = newhigh;
220}
221#endif /* !NO_VISIBLE */
222
223
224/* This function converts a MARK to a column number. It doesn't automatically
225 * adjust for leftcol; that must be done by the calling function
226 */
227int idx2col(curs, text, inputting)
228 MARK curs; /* the line# & index# of the cursor */
229 REG char *text; /* the text of the line, from fetchline */
230 int inputting; /* boolean: called from input() ? */
231{
232 static MARK pcursor;/* previous cursor, for possible shortcut */
233 static MARK pcol; /* column number for pcol */
234 static long chgs; /* previous value of changes counter */
235 REG int col; /* used to count column numbers */
236 REG int idx; /* used to count down the index */
237 REG int i;
238
239 /* for now, assume we have to start counting at the left edge */
240 col = 0;
241 idx = markidx(curs);
242
243 /* if the file hasn't changed & line number is the same & it has no
244 * embedded character attribute strings, can we do shortcuts?
245 */
246 if (chgs == changes
247 && !((curs ^ pcursor) & ~(BLKSIZE - 1))
248#ifndef NO_CHARATTR
249 && !hasattr(markline(curs), text)
250#endif
251 )
252 {
253 /* no movement? */
254 if (curs == pcursor)
255 {
256 /* return the column of the char; for tabs, return its last column */
257 if (text[idx] == '\t' && !inputting && !*o_list)
258 {
259 return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
260 }
261 else
262 {
263 return pcol;
264 }
265 }
266
267 /* movement to right? */
268 if (curs > pcursor)
269 {
270 /* start counting from previous place */
271 col = pcol;
272 idx = markidx(curs) - markidx(pcursor);
273 text += markidx(pcursor);
274 }
275 }
276
277 /* count over to the char after the idx position */
278 while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
279 {
280 if (i == '\t' && !*o_list)
281 {
282 col += *o_tabstop;
283 col -= col % *o_tabstop;
284 }
285 else if (i >= '\0' && i < ' ' || i == '\177')
286 {
287 col += 2;
288 }
289#ifndef NO_CHARATTR
290 else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
291 {
292 text += 2; /* plus one more at bottom of loop */
293 idx -= 2;
294 }
295#endif
296 else
297 {
298 col++;
299 }
300 text++;
301 idx--;
302 }
303
304 /* save stuff to speed next call */
305 pcursor = curs;
306 pcol = col;
307 chgs = changes;
308
309 /* return the column of the char; for tabs, return its last column */
310 if (*text == '\t' && !inputting && !*o_list)
311 {
312 return col + *o_tabstop - (col % *o_tabstop) - 1;
313 }
314 else
315 {
316 return col;
317 }
318}
319
320
321/* This function is similar to idx2col except that it takes care of sideways
322 * scrolling - for the given line, at least.
323 */
324int mark2phys(m, text, inputting)
325 MARK m; /* a mark to convert */
326 char *text; /* the line that m refers to */
327 int inputting; /* boolean: caled from input() ? */
328{
329 int i;
330
331 i = idx2col(m, text, inputting);
332 while (i < leftcol)
333 {
334 leftcol -= *o_sidescroll;
335 mustredraw = TRUE;
336 redrawrange(1L, INFINITY, INFINITY);
337 }
338 while (i > rightcol)
339 {
340 leftcol += *o_sidescroll;
341 mustredraw = TRUE;
342 redrawrange(1L, INFINITY, INFINITY);
343 }
344 physrow = markline(m) - topline;
345 physcol = i - leftcol;
346 if (*o_number)
347 physcol += 8;
348
349 return physcol;
350}
351
352/* This function draws a single line of text on the screen. The screen's
353 * cursor is assumed to be located at the leftmost column of the appropriate
354 * row.
355 */
356static void drawtext(text, lno, clr)
357 REG char *text; /* the text to draw */
358 long lno; /* the number of the line to draw */
359 int clr; /* boolean: do a clrtoeol? */
360{
361 REG int col; /* column number */
362 REG int i;
363 REG int tabstop; /* *o_tabstop */
364 REG int limitcol; /* leftcol or leftcol + COLS */
365 int abnormal; /* boolean: charattr != A_NORMAL? */
366#ifndef NO_VISIBLE
367 int rev; /* boolean: standout mode, too? */
368 int idx = 0;
369#endif
370 char numstr[9];
371
372 /* show the line number, if necessary */
373 if (*o_number)
374 {
78ed81a3 375 sprintf(numstr, "%6ld ", lno);
15637ed4
RG
376 qaddstr(numstr);
377 }
378
379#ifndef NO_SENTENCE
380 /* if we're hiding format lines, and this is one of them, then hide it */
381 if (*o_hideformat && *text == '.')
382 {
383 clrtoeol();
384#if OSK
385 qaddch('\l');
386#else
387 qaddch('\n');
388#endif
389 return;
390 }
391#endif
392
393 /* move some things into registers... */
394 limitcol = leftcol;
395 tabstop = *o_tabstop;
396 abnormal = FALSE;
397
398#ifndef CRUNCH
399 if (clr)
400 clrtoeol();
401#endif
402
403 /* skip stuff that was scrolled off left edge */
404 for (col = 0;
405 (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
406 text++)
407 {
408#ifndef NO_VISIBLE
409 idx++;
410#endif
411 if (i == '\t' && !*o_list)
412 {
413 col = col + tabstop - (col % tabstop);
414 }
415 else if (i >= 0 && i < ' ' || i == '\177')
416 {
417 col += 2;
418 }
419#ifndef NO_CHARATTR
420 else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
421 {
422 text += 2; /* plus one more as part of "for" loop */
423
424 /* since this attribute might carry over, we need it */
425 switch (*text)
426 {
427 case 'R':
428 case 'P':
429 attrset(A_NORMAL);
430 abnormal = FALSE;
431 break;
432
433 case 'B':
434 attrset(A_BOLD);
435 abnormal = TRUE;
436 break;
437
438 case 'U':
439 attrset(A_UNDERLINE);
440 abnormal = TRUE;
441 break;
442
443 case 'I':
444 attrset(A_ALTCHARSET);
445 abnormal = TRUE;
446 break;
447 }
448 }
449#endif
450 else
451 {
452 col++;
453 }
454 }
455
456#ifndef NO_VISIBLE
457 /* Should we start hiliting at the first char of this line? */
458 if ((lno > vizlow && lno <= vizhigh
459 || lno == vizlow && vizleft < idx)
460 && !(lno == vizhigh && vizright < idx))
461 {
462 do_VISIBLE();
463 rev = TRUE;
464 }
465#endif
466
467 /* adjust for control char that was partially visible */
468 while (col > limitcol)
469 {
470 qaddch(' ');
471 limitcol++;
472 }
473
474 /* now for the visible characters */
475 limitcol = leftcol + COLS;
476 if (*o_number)
477 limitcol -= 8;
478 for (; (i = *text) && col < limitcol; text++)
479 {
480#ifndef NO_VISIBLE
481 /* maybe turn hilite on/off in the middle of the line */
482 if (lno == vizlow && vizleft == idx)
483 {
484 do_VISIBLE();
485 rev = TRUE;
486 }
487 if (lno == vizhigh && vizright == idx)
488 {
489 do_SE();
490 rev = FALSE;
491 }
492 idx++;
493
494 /* if hiliting, never emit physical tabs */
495 if (rev && i == '\t' && !*o_list)
496 {
497 i = col + tabstop - (col % tabstop);
498 do
499 {
500 qaddch(' ');
501 col++;
78ed81a3 502 } while (col < i && col < limitcol);
15637ed4
RG
503 }
504 else
505#endif /* !NO_VISIBLE */
506 if (i == '\t' && !*o_list)
507 {
508 i = col + tabstop - (col % tabstop);
509 if (i < limitcol)
510 {
511#ifdef CRUNCH
512 if (!clr && has_PT && !((i - leftcol) & 7))
513#else
514 if (has_PT && !((i - leftcol) & 7))
515#endif
516 {
517 do
518 {
519 qaddch('\t');
520 col += 8; /* not exact! */
521 } while (col < i);
522 col = i; /* NOW it is exact */
523 }
524 else
525 {
526 do
527 {
528 qaddch(' ');
529 col++;
78ed81a3 530 } while (col < i && col < limitcol);
15637ed4
RG
531 }
532 }
533 else /* tab ending after screen? next line! */
534 {
78ed81a3 535#ifdef CRUNCH
536 /* needed at least when scrolling the screen right -nox */
537 if (clr && col < limitcol)
538 clrtoeol();
539#endif
15637ed4
RG
540 col = limitcol;
541 if (has_AM)
542 {
543 addch('\n'); /* GB */
544 }
545 }
546 }
547 else if (i >= 0 && i < ' ' || i == '\177')
548 {
549 col += 2;
550 qaddch('^');
551 if (col <= limitcol)
552 {
553 qaddch(i ^ '@');
554 }
555 }
556#ifndef NO_CHARATTR
557 else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
558 {
559 text += 2; /* plus one more as part of "for" loop */
560 switch (*text)
561 {
562 case 'R':
563 case 'P':
564 attrset(A_NORMAL);
565 abnormal = FALSE;
566 break;
567
568 case 'B':
569 attrset(A_BOLD);
570 abnormal = TRUE;
571 break;
572
573 case 'U':
574 attrset(A_UNDERLINE);
575 abnormal = TRUE;
576 break;
577
578 case 'I':
579 attrset(A_ALTCHARSET);
580 abnormal = TRUE;
581 break;
582 }
583 }
584#endif
585 else
586 {
587 col++;
588 qaddch(i);
589 }
590 }
591
592 /* get ready for the next line */
593#ifndef NO_CHARATTR
594 if (abnormal)
595 {
596 attrset(A_NORMAL);
597 }
598#endif
599 if (*o_list && col < limitcol)
600 {
601 qaddch('$');
602 col++;
603 }
604
605#ifndef NO_VISIBLE
606 /* did we hilite this whole line? If so, STOP! */
607 if (rev)
608 {
609 do_SE();
610 }
611#endif
612
613#ifdef CRUNCH
614 if (clr && col < limitcol)
615 {
616 clrtoeol();
617 }
618#endif
619 if (!has_AM || col < limitcol)
620 {
621 addch('\n');
622 }
623
624 wqrefresh();
625}
626
627
628#ifndef CRUNCH
629static void nudgecursor(same, scan, new, lno)
630 int same; /* number of chars to be skipped over */
631 char *scan; /* where the same chars end */
632 char *new; /* where the visible part of the line starts */
633 long lno; /* line number of this line */
634{
635 int col;
636
637 if (same > 0)
638 {
639 if (same < 5)
640 {
641 /* move the cursor by overwriting */
642 while (same > 0)
643 {
644 qaddch(scan[-same]);
645 same--;
646 }
647 }
648 else
649 {
650 /* move the cursor by calling move() */
651 col = (int)(scan - new);
652 if (*o_number)
653 col += 8;
654 move((int)(lno - topline), col);
655 }
656 }
657}
658#endif /* not CRUNCH */
659
660/* This function draws a single line of text on the screen, possibly with
661 * some cursor optimization. The cursor is repositioned before drawing
662 * begins, so its position before doesn't really matter.
663 */
664static void smartdrawtext(text, lno, showit)
665 REG char *text; /* the text to draw */
666 long lno; /* line number of the text */
667 int showit; /* boolean: output line? (else just remember it) */
668{
669#ifdef CRUNCH
670 move((int)(lno - topline), 0);
671 if (showit)
672 {
673 drawtext(text, lno, TRUE);
674 }
675#else /* not CRUNCH */
676 static char old[256]; /* how the line looked last time */
677 char new[256]; /* how it looks now */
678 char *build; /* used to put chars into new[] */
679 char *scan; /* used for moving thru new[] or old[] */
680 char *end; /* last non-blank changed char */
681 char *shift; /* used to insert/delete chars */
682 int same; /* length of a run of unchanged chars */
683 int limitcol;
684 int col;
685 int i;
686 char numstr[9];
687
688# ifndef NO_CHARATTR
689 /* if this line has attributes, do it the dumb way instead */
690 if (hasattr(lno, text))
691 {
692 move((int)(lno - topline), 0);
693 drawtext(text, lno, TRUE);
694 return;
695 }
696# endif
697# ifndef NO_SENTENCE
698 /* if this line is a format line, & we're hiding format lines, then
699 * let the dumb drawtext() function handle it
700 */
701 if (*o_hideformat && *text == '.')
702 {
703 move((int)(lno - topline), 0);
704 drawtext(text, lno, TRUE);
705 return;
706 }
707# endif
708# ifndef NO_VISIBLE
709 if (vizchange)
710 {
711 move((int)(lno - topline), 0);
712 drawtext(text, lno, TRUE);
713 smartlno = 0L;
714 return;
715 }
716# endif
717
718 /* skip stuff that was scrolled off left edge */
719 limitcol = leftcol;
720 for (col = 0;
721 (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
722 text++)
723 {
724 if (i == '\t' && !*o_list)
725 {
726 col = col + *o_tabstop - (col % *o_tabstop);
727 }
728 else if (i >= 0 && i < ' ' || i == '\177')
729 {
730 col += 2;
731 }
732 else
733 {
734 col++;
735 }
736 }
737
738 /* adjust for control char that was partially visible */
739 build = new;
740 while (col > limitcol)
741 {
742 *build++ = ' ';
743 limitcol++;
744 }
745
746 /* now for the visible characters */
747 limitcol = leftcol + COLS;
748 if (*o_number)
749 limitcol -= 8;
750 for (; (i = *text) && col < limitcol; text++)
751 {
752 if (i == '\t' && !*o_list)
753 {
754 i = col + *o_tabstop - (col % *o_tabstop);
755 while (col < i && col < limitcol)
756 {
757 *build++ = ' ';
758 col++;
759 }
760 }
761 else if (i >= 0 && i < ' ' || i == '\177')
762 {
763 col += 2;
764 *build++ = '^';
765 if (col <= limitcol)
766 {
767 *build++ = (i ^ '@');
768 }
769 }
770 else
771 {
772 col++;
773 *build++ = i;
774 }
775 }
776 if (col < limitcol && *o_list)
777 {
778 *build++ = '$';
779 col++;
780 }
781 end = build;
782 while (col < limitcol)
783 {
784 *build++ = ' ';
785 col++;
786 }
787
788 /* if we're just supposed to remember this line, then remember it */
789 if (!showit)
790 {
791 smartlno = lno;
792 strncpy(old, new, COLS);
793 return;
794 }
795
796 /* locate the last non-blank character */
797 while (end > new && end[-1] == ' ')
798 {
799 end--;
800 }
801
802 /* can we optimize the displaying of this line? */
803 if (lno != smartlno)
804 {
805 /* nope, can't optimize - different line */
806 move((int)(lno - topline), 0);
807
808 /* show the line number, if necessary */
809 if (*o_number)
810 {
78ed81a3 811 sprintf(numstr, "%6ld ", lno);
15637ed4
RG
812 qaddstr(numstr);
813 }
814
815 /* show the new line */
816 for (scan = new, build = old; scan < end; )
817 {
818 qaddch(*scan);
819 *build++ = *scan++;
820 }
821 if (end < new + COLS - (*o_number ? 8 : 0))
822 {
823 clrtoeol();
824 while (build < old + COLS)
825 {
826 *build++ = ' ';
827 }
828 }
829 smartlno = lno;
830 return;
831 }
832
833 /* skip any initial unchanged characters */
834 for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
835 {
836 }
837 i = (scan - new);
838 if (*o_number)
839 i += 8;
840 move((int)(lno - topline), i);
841
842 /* The in-between characters must be changed */
843 same = 0;
844 while (scan < end)
845 {
846 /* is this character a match? */
847 if (scan[0] == build[0])
848 {
849 same++;
850 }
851 else /* do we want to insert? */
852 if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
853 {
854 nudgecursor(same, scan, new, lno);
855 same = 0;
856
857 insch(*scan);
858 for (shift = old + COLS; --shift > build; )
859 {
860 shift[0] = shift[-1];
861 }
862 *build = *scan;
863 }
864 else /* do we want to delete? */
865 if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
866 {
867 nudgecursor(same, scan, new, lno);
868 same = 0;
869
870 delch();
871 same++;
872 for (shift = build; shift < old + COLS - 1; shift++)
873 {
874 shift[0] = shift[1];
875 }
876 if (*o_number)
877 shift -= 8;
878 *shift = ' ';
879 }
880 else /* we must overwrite */
881 {
882 nudgecursor(same, scan, new, lno);
883 same = 0;
884
885 addch(*scan);
886 *build = *scan;
887 }
888
889 build++;
890 scan++;
891 }
892
893 /* maybe clear to EOL */
894 end = old + COLS - (*o_number ? 8 : 0);
895 while (build < end && *build == ' ')
896 {
897 build++;
898 }
899 if (build < end)
900 {
901 nudgecursor(same, scan, new, lno);
902 same = 0;
903
904 clrtoeol();
905 while (build < old + COLS)
906 {
907 *build++ = ' ';
908 }
909 }
910#endif /* not CRUNCH */
911}
912
913
914/* This function is used in visual mode for drawing the screen (or just parts
915 * of the screen, if that's all thats needed). It also takes care of
916 * scrolling.
917 */
918void redraw(curs, inputting)
919 MARK curs; /* where to leave the screen's cursor */
920 int inputting; /* boolean: being called from input() ? */
921{
922 char *text; /* a line of text to display */
923 static long chgs; /* previous changes level */
924 long l;
925 int i;
926#ifndef CRUNCH
927 static long showtop; /* top line in window */
928 static long showbottom; /* bottom line in window */
929#endif
930
931 /* if curs == MARK_UNSET, then we should reset internal vars */
932 if (curs == MARK_UNSET)
933 {
934 if (topline < 1 || topline > nlines)
935 {
936 topline = 1L;
937 }
938 else
939 {
940 move(LINES - 1, 0);
941 clrtoeol();
942 }
943 leftcol = 0;
944 mustredraw = TRUE;
945 redrawafter = INFINITY;
946 preredraw = 0L;
947 postredraw = 0L;
948 chgs = 0;
949 smartlno = 0L;
950#ifndef NO_VISIBLE
951 vizlow = vizhigh = 0L;
952 vizchange = FALSE;
953#endif
954#ifndef CRUNCH
955 showtop = 0;
956 showbottom = INFINITY;
957#endif
958 return;
959 }
960
961#ifndef NO_VISIBLE
962 /* adjustments to hilited area may force extra lines to be redrawn. */
963 setviz(curs);
964#endif
965
966 /* figure out which column the cursor will be in */
967 l = markline(curs);
968 text = fetchline(l);
969 mark2phys(curs, text, inputting);
970
971#ifndef NO_COLOR
972 fixcolor();
973#endif
974
975 /* adjust topline, if necessary, to get the cursor on the screen */
976 if (l >= topline && l <= botline)
977 {
978 /* it is on the screen already */
979
980 /* if the file was changed but !mustredraw, then redraw line */
981 if (!mustredraw && (chgs != changes
982#ifndef NO_VISIBLE
983 || V_from
984#endif
985#ifndef CRUNCH
986 || l < showtop || l > showbottom
987#endif
988 ))
989 {
990 smartdrawtext(text, l, (chgs != changes));
991 }
992 }
78ed81a3 993 else if (l < topline && l >= topline - NEAR && (has_SR || has_AL))
15637ed4
RG
994 {
995 /* near top - scroll down */
996 if (!mustredraw)
997 {
998 move(0,0);
999 while (l < topline)
1000 {
1001 topline--;
1002 if (has_SR)
1003 {
1004 do_SR();
1005 }
1006 else
1007 {
1008 insertln();
1009 }
1010 text = fetchline(topline);
1011 drawtext(text, topline, FALSE);
1012 do_UP();
1013 }
1014
1015 /* blank out the last line */
1016 move(LINES - 1, 0);
1017 clrtoeol();
1018 }
1019 else
1020 {
1021 topline = l;
1022 redrawrange(0L, INFINITY, INFINITY);
1023 }
1024 }
78ed81a3 1025 else if (l > topline && l <= botline + NEAR)
15637ed4
RG
1026 {
1027 /* near bottom -- scroll up */
1028 if (!mustredraw)
1029 {
1030 move(LINES - 1,0);
1031 clrtoeol();
1032 while (l > botline)
1033 {
1034 topline++; /* <-- also adjusts botline */
1035 text = fetchline(botline);
1036 drawtext(text, botline, FALSE);
1037 }
1038#ifndef CRUNCH
1039 showbottom = l;
1040#endif
1041 }
1042 else
1043 {
1044 topline = l - (LINES - 2);
1045 redrawrange(0L, INFINITY, INFINITY);
1046 }
1047 }
1048 else
1049 {
1050 /* distant line - center it & force a redraw */
78ed81a3 1051 topline = l - (LINES - 1) / 2;
15637ed4
RG
1052 if (topline < 1)
1053 {
1054 topline = 1;
1055 }
1056 redrawrange(0L, INFINITY, INFINITY);
78ed81a3 1057 smartlno = 0L;
15637ed4
RG
1058 changes++;
1059 }
1060
1061#ifndef CRUNCH
1062 /* make sure the current line is included in the "window" */
1063 if (l < showtop)
1064 {
1065 redrawrange(l, showtop, showtop);
1066 showtop = l;
1067 }
1068 if (l > showbottom)
1069 {
1070 redrawrange(showbottom, l, l);
1071 showbottom = l;
1072 }
1073#endif
1074
1075
1076 /* Now... do we really have to redraw? */
1077 if (mustredraw)
1078 {
1079 /* If redrawfter (and friends) aren't set, assume we should
1080 * redraw everything.
1081 */
1082 if (redrawafter == INFINITY)
1083 {
1084 redrawafter = 0L;
1085 preredraw = postredraw = INFINITY;
1086 }
1087
1088#ifndef CRUNCH
1089 /* shrink the window, if possible */
1090 if (showtop < topline)
1091 {
1092 showtop = topline;
1093 }
1094 if (showbottom > botline)
1095 {
1096 showbottom = botline;
1097 }
1098 if (postredraw == INFINITY)
1099 {
1100 /* these will be set to more reasonable values later */
1101 showtop = INFINITY;
1102 showbottom = 0L;
1103 }
1104#endif
1105
1106 /* adjust smartlno to correspond with inserted/deleted lines */
1107 if (smartlno >= redrawafter)
1108 {
1109 if (smartlno < preredraw && postredraw != preredraw) /*!!!*/
1110 {
1111 smartlno = 0L;
1112 }
1113 else
1114 {
1115 smartlno += (postredraw - preredraw);
1116 }
1117 }
1118
1119 /* should we insert some lines into the screen? */
1120 if (preredraw < postredraw && preredraw <= botline)
1121 {
1122 /* lines were inserted into the file */
1123
1124 /* decide where insertion should start */
1125 if (preredraw < topline)
1126 {
1127 l = topline;
1128 }
1129 else
1130 {
1131 l = preredraw;
1132 }
1133
1134 /* insert the lines... maybe */
1135 if (l + postredraw - preredraw > botline || !has_AL || *o_number)
1136 {
1137 /* Whoa! a whole screen full - just redraw */
1138 preredraw = postredraw = INFINITY;
1139 }
1140 else
1141 {
1142 /* really insert 'em */
1143 move((int)(l - topline), 0);
1144 for (i = postredraw - preredraw; i > 0; i--)
1145 {
1146 insertln();
1147 }
1148
1149 /* NOTE: the contents of those lines will be
1150 * drawn as part of the regular redraw loop.
1151 */
1152
1153 /* clear the last line */
1154 move(LINES - 1, 0);
1155 clrtoeol();
1156 }
1157 }
1158
1159 /* do we want to delete some lines from the screen? */
1160 if (preredraw > postredraw && postredraw <= botline)
1161 {
1162 if (preredraw > botline || !has_DL || *o_number)
1163 {
1164 postredraw = preredraw = INFINITY;
1165 }
1166 else /* we'd best delete some lines from the screen */
1167 {
1168 /* clear the last line, so it doesn't look
1169 * ugly as it gets pulled up into the screen
1170 */
1171 move(LINES - 1, 0);
1172 clrtoeol();
1173
1174 /* delete the lines */
1175 move((int)(postredraw - topline), 0);
1176 for (l = postredraw;
1177 l < preredraw && l <= botline;
1178 l++)
1179 {
1180 deleteln();
1181 }
1182
1183 /* draw the lines that are now newly visible
1184 * at the bottom of the screen
1185 */
1186 i = LINES - 1 + (postredraw - preredraw);
1187 move(i, 0);
1188 for (l = topline + i; l <= botline; l++)
1189 {
1190 /* clear this line */
1191 clrtoeol();
1192
1193 /* draw the line, or ~ for non-lines */
1194 if (l <= nlines)
1195 {
1196 text = fetchline(l);
1197 drawtext(text, l, FALSE);
1198 }
1199 else
1200 {
1201 addstr("~\n");
1202 }
1203 }
1204 }
1205 }
1206
1207 /* redraw the current line */
1208 l = markline(curs);
1209 pfetch(l);
1210 smartdrawtext(ptext, l, TRUE);
1211
1212#ifndef CRUNCH
1213 /* decide which lines must be in the "window" around the cursor */
1214 l = markline(curs);
1215 if ((*o_window & 0xff) + 1 == LINES)
1216 {
1217 showtop = 1;
1218 showbottom = INFINITY;
1219 }
1220 else if (l < showtop || l > showbottom)
1221 {
1222 l -= (*o_window & 0xff) / 2;
1223 if (l < topline)
1224 {
1225 l = topline;
1226 }
1227 if (l < showtop)
1228 {
1229 showtop = l;
1230 }
1231 l += (*o_window & 0xff) - 1;
1232 if (l > botline)
1233 {
1234 showtop = showtop - l + botline;
1235 l = botline;
1236 }
1237 if (l > showbottom)
1238 {
1239 showbottom = l;
1240 }
1241 }
1242#endif
1243
1244 /* decide where we should start redrawing from */
1245 if (redrawafter < topline)
1246 {
1247 l = topline;
1248 }
1249 else
1250 {
1251 l = redrawafter;
1252 }
1253 if (l <= botline && l < postredraw && (l != smartlno || botline != smartlno))
1254 {
1255 /* draw the other lines */
1256 move((int)(l - topline), 0);
1257 for (; l <= botline && l < postredraw; l++)
1258 {
1259 /* we already drew the current line, so skip it now */
1260 if (l == smartlno)
1261 {
1262#if OSK
1263 qaddch('\l');
1264#else
1265 qaddch('\n');
1266#endif
1267 continue;
1268 }
1269
1270 /* draw the line, or ~ for non-lines */
1271 if (l > nlines)
1272 {
1273 qaddch('~');
1274 clrtoeol();
1275 addch('\n');
1276 }
1277#ifndef CRUNCH
1278 else if (l < showtop || l > showbottom)
1279 {
1280 qaddch('@');
1281 clrtoeol();
1282 addch('\n');
1283 }
1284#endif
1285 else
1286 {
1287 text = fetchline(l);
1288 drawtext(text, l, TRUE);
1289 }
1290 }
1291 }
1292
1293 mustredraw = FALSE;
1294 }
1295
1296 /* force total (non-partial) redraw next time if not set */
1297 redrawafter = INFINITY;
1298 preredraw = 0L;
1299 postredraw = 0L;
1300
1301 /* move the cursor to where it belongs */
1302 move((int)(markline(curs) - topline), physcol);
1303 wqrefresh();
1304
1305 chgs = changes;
1306}