source: trunk/third/nvi/vi/vs_refresh.c @ 14302

Revision 14302, 23.8 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14301, which included commits to RCS files with non-trunk default branches.
Line 
1/*-
2 * Copyright (c) 1992, 1993, 1994
3 *      The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 *      Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "@(#)vs_refresh.c  10.44 (Berkeley) 10/13/96";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/time.h>
19
20#include <bitstring.h>
21#include <ctype.h>
22#include <limits.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "../common/common.h"
28#include "vi.h"
29
30#define UPDATE_CURSOR   0x01                    /* Update the cursor. */
31#define UPDATE_SCREEN   0x02                    /* Flush to screen. */
32
33static void     vs_modeline __P((SCR *));
34static int      vs_paint __P((SCR *, u_int));
35
36/*
37 * v_repaint --
38 *      Repaint selected lines from the screen.
39 *
40 * PUBLIC: int vs_repaint __P((SCR *, EVENT *));
41 */
42int
43vs_repaint(sp, evp)
44        SCR *sp;
45        EVENT *evp;
46{
47        SMAP *smp;
48
49        for (; evp->e_flno <= evp->e_tlno; ++evp->e_flno) {
50                smp = HMAP + evp->e_flno - 1;
51                SMAP_FLUSH(smp);
52                if (vs_line(sp, smp, NULL, NULL))
53                        return (1);
54        }
55        return (0);
56}
57
58/*
59 * vs_refresh --
60 *      Refresh all screens.
61 *
62 * PUBLIC: int vs_refresh __P((SCR *, int));
63 */
64int
65vs_refresh(sp, forcepaint)
66        SCR *sp;
67        int forcepaint;
68{
69        GS *gp;
70        SCR *tsp;
71        int need_refresh;
72        u_int priv_paint, pub_paint;
73
74        gp = sp->gp;
75
76        /*
77         * 1: Refresh the screen.
78         *
79         * If SC_SCR_REDRAW is set in the current screen, repaint everything
80         * that we can find, including status lines.
81         */
82        if (F_ISSET(sp, SC_SCR_REDRAW))
83                for (tsp = gp->dq.cqh_first;
84                    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
85                        if (tsp != sp)
86                                F_SET(tsp, SC_SCR_REDRAW | SC_STATUS);
87
88        /*
89         * 2: Related or dirtied screens, or screens with messages.
90         *
91         * If related screens share a view into a file, they may have been
92         * modified as well.  Refresh any screens that aren't exiting that
93         * have paint or dirty bits set.  Always update their screens, we
94         * are not likely to get another chance.  Finally, if we refresh any
95         * screens other than the current one, the cursor will be trashed.
96         */
97        pub_paint = SC_SCR_REFORMAT | SC_SCR_REDRAW;
98        priv_paint = VIP_CUR_INVALID | VIP_N_REFRESH;
99        if (O_ISSET(sp, O_NUMBER))
100                priv_paint |= VIP_N_RENUMBER;
101        for (tsp = gp->dq.cqh_first;
102            tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
103                if (tsp != sp && !F_ISSET(tsp, SC_EXIT | SC_EXIT_FORCE) &&
104                    (F_ISSET(tsp, pub_paint) ||
105                    F_ISSET(VIP(tsp), priv_paint))) {
106                        (void)vs_paint(tsp,
107                            (F_ISSET(VIP(tsp), VIP_CUR_INVALID) ?
108                            UPDATE_CURSOR : 0) | UPDATE_SCREEN);
109                        F_SET(VIP(sp), VIP_CUR_INVALID);
110                }
111
112        /*
113         * 3: Refresh the current screen.
114         *
115         * Always refresh the current screen, it may be a cursor movement.
116         * Also, always do it last -- that way, SC_SCR_REDRAW can be set
117         * in the current screen only, and the screen won't flash.
118         */
119        if (vs_paint(sp, UPDATE_CURSOR | (!forcepaint &&
120            F_ISSET(sp, SC_SCR_VI) && KEYS_WAITING(sp) ? 0 : UPDATE_SCREEN)))
121                return (1);
122
123        /*
124         * 4: Paint any missing status lines.
125         *
126         * XXX
127         * This is fairly evil.  Status lines are written using the vi message
128         * mechanism, since we have no idea how long they are.  Since we may be
129         * painting screens other than the current one, we don't want to make
130         * the user wait.  We depend heavily on there not being any other lines
131         * currently waiting to be displayed and the message truncation code in
132         * the msgq_status routine working.
133         *
134         * And, finally, if we updated any status lines, make sure the cursor
135         * gets back to where it belongs.
136         */
137        for (need_refresh = 0, tsp = gp->dq.cqh_first;
138            tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
139                if (F_ISSET(tsp, SC_STATUS)) {
140                        need_refresh = 1;
141                        vs_resolve(tsp, sp, 0);
142                }
143        if (need_refresh)
144                (void)gp->scr_refresh(sp, 0);
145
146        /*
147         * A side-effect of refreshing the screen is that it's now ready
148         * for everything else, i.e. messages.
149         */
150        F_SET(sp, SC_SCR_VI);
151        return (0);
152}
153
154/*
155 * vs_paint --
156 *      This is the guts of the vi curses screen code.  The idea is that
157 *      the SCR structure passed in contains the new coordinates of the
158 *      screen.  What makes this hard is that we don't know how big
159 *      characters are, doing input can put the cursor in illegal places,
160 *      and we're frantically trying to avoid repainting unless it's
161 *      absolutely necessary.  If you change this code, you'd better know
162 *      what you're doing.  It's subtle and quick to anger.
163 */
164static int
165vs_paint(sp, flags)
166        SCR *sp;
167        u_int flags;
168{
169        GS *gp;
170        SMAP *smp, tmp;
171        VI_PRIVATE *vip;
172        recno_t lastline, lcnt;
173        size_t cwtotal, cnt, len, notused, off, y;
174        int ch, didpaint, isempty, leftright_warp;
175        char *p;
176
177#define  LNO    sp->lno                 /* Current file line. */
178#define OLNO    vip->olno               /* Remembered file line. */
179#define  CNO    sp->cno                 /* Current file column. */
180#define OCNO    vip->ocno               /* Remembered file column. */
181#define SCNO    vip->sc_col             /* Current screen column. */
182
183        gp = sp->gp;
184        vip = VIP(sp);
185        didpaint = leftright_warp = 0;
186
187        /*
188         * 5: Reformat the lines.
189         *
190         * If the lines themselves have changed (:set list, for example),
191         * fill in the map from scratch.  Adjust the screen that's being
192         * displayed if the leftright flag is set.
193         */
194        if (F_ISSET(sp, SC_SCR_REFORMAT)) {
195                /* Invalidate the line size cache. */
196                VI_SCR_CFLUSH(vip);
197
198                /* Toss vs_line() cached information. */
199                if (F_ISSET(sp, SC_SCR_TOP)) {
200                        if (vs_sm_fill(sp, LNO, P_TOP))
201                                return (1);
202                }
203                else if (F_ISSET(sp, SC_SCR_CENTER)) {
204                        if (vs_sm_fill(sp, LNO, P_MIDDLE))
205                                return (1);
206                } else
207                        if (vs_sm_fill(sp, OOBLNO, P_TOP))
208                                return (1);
209                F_SET(sp, SC_SCR_REDRAW);
210        }
211
212        /*
213         * 6: Line movement.
214         *
215         * Line changes can cause the top line to change as well.  As
216         * before, if the movement is large, the screen is repainted.
217         *
218         * 6a: Small screens.
219         *
220         * Users can use the window, w300, w1200 and w9600 options to make
221         * the screen artificially small.  The behavior of these options
222         * in the historic vi wasn't all that consistent, and, in fact, it
223         * was never documented how various screen movements affected the
224         * screen size.  Generally, one of three things would happen:
225         *      1: The screen would expand in size, showing the line
226         *      2: The screen would scroll, showing the line
227         *      3: The screen would compress to its smallest size and
228         *              repaint.
229         * In general, scrolling didn't cause compression (200^D was handled
230         * the same as ^D), movement to a specific line would (:N where N
231         * was 1 line below the screen caused a screen compress), and cursor
232         * movement would scroll if it was 11 lines or less, and compress if
233         * it was more than 11 lines.  (And, no, I have no idea where the 11
234         * comes from.)
235         *
236         * What we do is try and figure out if the line is less than half of
237         * a full screen away.  If it is, we expand the screen if there's
238         * room, and then scroll as necessary.  The alternative is to compress
239         * and repaint.
240         *
241         * !!!
242         * This code is a special case from beginning to end.  Unfortunately,
243         * home modems are still slow enough that it's worth having.
244         *
245         * XXX
246         * If the line a really long one, i.e. part of the line is on the
247         * screen but the column offset is not, we'll end up in the adjust
248         * code, when we should probably have compressed the screen.
249         */
250        if (IS_SMALL(sp))
251                if (LNO < HMAP->lno) {
252                        lcnt = vs_sm_nlines(sp, HMAP, LNO, sp->t_maxrows);
253                        if (lcnt <= HALFSCREEN(sp))
254                                for (; lcnt && sp->t_rows != sp->t_maxrows;
255                                     --lcnt, ++sp->t_rows) {
256                                        ++TMAP;
257                                        if (vs_sm_1down(sp))
258                                                return (1);
259                                }
260                        else
261                                goto small_fill;
262                } else if (LNO > TMAP->lno) {
263                        lcnt = vs_sm_nlines(sp, TMAP, LNO, sp->t_maxrows);
264                        if (lcnt <= HALFSCREEN(sp))
265                                for (; lcnt && sp->t_rows != sp->t_maxrows;
266                                     --lcnt, ++sp->t_rows) {
267                                        if (vs_sm_next(sp, TMAP, TMAP + 1))
268                                                return (1);
269                                        ++TMAP;
270                                        if (vs_line(sp, TMAP, NULL, NULL))
271                                                return (1);
272                                }
273                        else {
274small_fill:                     (void)gp->scr_move(sp, LASTLINE(sp), 0);
275                                (void)gp->scr_clrtoeol(sp);
276                                for (; sp->t_rows > sp->t_minrows;
277                                    --sp->t_rows, --TMAP) {
278                                        (void)gp->scr_move(sp, TMAP - HMAP, 0);
279                                        (void)gp->scr_clrtoeol(sp);
280                                }
281                                if (vs_sm_fill(sp, LNO, P_FILL))
282                                        return (1);
283                                F_SET(sp, SC_SCR_REDRAW);
284                                goto adjust;
285                        }
286                }
287
288        /*
289         * 6b: Line down, or current screen.
290         */
291        if (LNO >= HMAP->lno) {
292                /* Current screen. */
293                if (LNO <= TMAP->lno)
294                        goto adjust;
295                if (F_ISSET(sp, SC_SCR_TOP))
296                        goto top;
297                if (F_ISSET(sp, SC_SCR_CENTER))
298                        goto middle;
299
300                /*
301                 * If less than half a screen above the line, scroll down
302                 * until the line is on the screen.
303                 */
304                lcnt = vs_sm_nlines(sp, TMAP, LNO, HALFTEXT(sp));
305                if (lcnt < HALFTEXT(sp)) {
306                        while (lcnt--)
307                                if (vs_sm_1up(sp))
308                                        return (1);
309                        goto adjust;
310                }
311                goto bottom;
312        }
313
314        /*
315         * 6c: If not on the current screen, may request center or top.
316         */
317        if (F_ISSET(sp, SC_SCR_TOP))
318                goto top;
319        if (F_ISSET(sp, SC_SCR_CENTER))
320                goto middle;
321
322        /*
323         * 6d: Line up.
324         */
325        lcnt = vs_sm_nlines(sp, HMAP, LNO, HALFTEXT(sp));
326        if (lcnt < HALFTEXT(sp)) {
327                /*
328                 * If less than half a screen below the line, scroll up until
329                 * the line is the first line on the screen.  Special check so
330                 * that if the screen has been emptied, we refill it.
331                 */
332                if (db_exist(sp, HMAP->lno)) {
333                        while (lcnt--)
334                                if (vs_sm_1down(sp))
335                                        return (1);
336                        goto adjust;
337                }
338
339                /*
340                 * If less than a half screen from the bottom of the file,
341                 * put the last line of the file on the bottom of the screen.
342                 */
343bottom:         if (db_last(sp, &lastline))
344                        return (1);
345                tmp.lno = LNO;
346                tmp.coff = HMAP->coff;
347                tmp.soff = 1;
348                lcnt = vs_sm_nlines(sp, &tmp, lastline, sp->t_rows);
349                if (lcnt < HALFTEXT(sp)) {
350                        if (vs_sm_fill(sp, lastline, P_BOTTOM))
351                                return (1);
352                        F_SET(sp, SC_SCR_REDRAW);
353                        goto adjust;
354                }
355                /* It's not close, just put the line in the middle. */
356                goto middle;
357        }
358
359        /*
360         * If less than half a screen from the top of the file, put the first
361         * line of the file at the top of the screen.  Otherwise, put the line
362         * in the middle of the screen.
363         */
364        tmp.lno = 1;
365        tmp.coff = HMAP->coff;
366        tmp.soff = 1;
367        lcnt = vs_sm_nlines(sp, &tmp, LNO, HALFTEXT(sp));
368        if (lcnt < HALFTEXT(sp)) {
369                if (vs_sm_fill(sp, 1, P_TOP))
370                        return (1);
371        } else
372middle:         if (vs_sm_fill(sp, LNO, P_MIDDLE))
373                        return (1);
374        if (0) {
375top:            if (vs_sm_fill(sp, LNO, P_TOP))
376                        return (1);
377        }
378        F_SET(sp, SC_SCR_REDRAW);
379
380        /*
381         * At this point we know part of the line is on the screen.  Since
382         * scrolling is done using logical lines, not physical, all of the
383         * line may not be on the screen.  While that's not necessarily bad,
384         * if the part the cursor is on isn't there, we're going to lose.
385         * This can be tricky; if the line covers the entire screen, lno
386         * may be the same as both ends of the map, that's why we test BOTH
387         * the top and the bottom of the map.  This isn't a problem for
388         * left-right scrolling, the cursor movement code handles the problem.
389         *
390         * There's a performance issue here if editing *really* long lines.
391         * This gets to the right spot by scrolling, and, in a binary, by
392         * scrolling hundreds of lines.  If the adjustment looks like it's
393         * going to be a serious problem, refill the screen and repaint.
394         */
395adjust: if (!O_ISSET(sp, O_LEFTRIGHT) &&
396            (LNO == HMAP->lno || LNO == TMAP->lno)) {
397                cnt = vs_screens(sp, LNO, &CNO);
398                if (LNO == HMAP->lno && cnt < HMAP->soff)
399                        if ((HMAP->soff - cnt) > HALFTEXT(sp)) {
400                                HMAP->soff = cnt;
401                                vs_sm_fill(sp, OOBLNO, P_TOP);
402                                F_SET(sp, SC_SCR_REDRAW);
403                        } else
404                                while (cnt < HMAP->soff)
405                                        if (vs_sm_1down(sp))
406                                                return (1);
407                if (LNO == TMAP->lno && cnt > TMAP->soff)
408                        if ((cnt - TMAP->soff) > HALFTEXT(sp)) {
409                                TMAP->soff = cnt;
410                                vs_sm_fill(sp, OOBLNO, P_BOTTOM);
411                                F_SET(sp, SC_SCR_REDRAW);
412                        } else
413                                while (cnt > TMAP->soff)
414                                        if (vs_sm_1up(sp))
415                                                return (1);
416        }
417
418        /*
419         * If the screen needs to be repainted, skip cursor optimization.
420         * However, in the code above we skipped leftright scrolling on
421         * the grounds that the cursor code would handle it.  Make sure
422         * the right screen is up.
423         */
424        if (F_ISSET(sp, SC_SCR_REDRAW)) {
425                if (O_ISSET(sp, O_LEFTRIGHT))
426                        goto slow;
427                goto paint;
428        }
429
430        /*
431         * 7: Cursor movements (current screen only).
432         */
433        if (!LF_ISSET(UPDATE_CURSOR))
434                goto number;
435
436        /*
437         * Decide cursor position.  If the line has changed, the cursor has
438         * moved over a tab, or don't know where the cursor was, reparse the
439         * line.  Otherwise, we've just moved over fixed-width characters,
440         * and can calculate the left/right scrolling and cursor movement
441         * without reparsing the line.  Note that we don't know which (if any)
442         * of the characters between the old and new cursor positions changed.
443         *
444         * XXX
445         * With some work, it should be possible to handle tabs quickly, at
446         * least in obvious situations, like moving right and encountering
447         * a tab, without reparsing the whole line.
448         *
449         * If the line we're working with has changed, reread it..
450         */
451        if (F_ISSET(vip, VIP_CUR_INVALID) || LNO != OLNO)
452                goto slow;
453
454        /* Otherwise, if nothing's changed, ignore the cursor. */
455        if (CNO == OCNO)
456                goto fast;
457
458        /*
459         * Get the current line.  If this fails, we either have an empty
460         * file and can just repaint, or there's a real problem.  This
461         * isn't a performance issue because there aren't any ways to get
462         * here repeatedly.
463         */
464        if (db_eget(sp, LNO, &p, &len, &isempty)) {
465                if (isempty)
466                        goto slow;
467                return (1);
468        }
469
470#ifdef DEBUG
471        /* Sanity checking. */
472        if (CNO >= len && len != 0) {
473                msgq(sp, M_ERR, "Error: %s/%d: cno (%u) >= len (%u)",
474                     tail(__FILE__), __LINE__, CNO, len);
475                return (1);
476        }
477#endif
478        /*
479         * The basic scheme here is to look at the characters in between
480         * the old and new positions and decide how big they are on the
481         * screen, and therefore, how many screen positions to move.
482         */
483        if (CNO < OCNO) {
484                /*
485                 * 7a: Cursor moved left.
486                 *
487                 * Point to the old character.  The old cursor position can
488                 * be past EOL if, for example, we just deleted the rest of
489                 * the line.  In this case, since we don't know the width of
490                 * the characters we traversed, we have to do it slowly.
491                 */
492                p += OCNO;
493                cnt = (OCNO - CNO) + 1;
494                if (OCNO >= len)
495                        goto slow;
496
497                /*
498                 * Quick sanity check -- it's hard to figure out exactly when
499                 * we cross a screen boundary as we do in the cursor right
500                 * movement.  If cnt is so large that we're going to cross the
501                 * boundary no matter what, stop now.
502                 */
503                if (SCNO + 1 + MAX_CHARACTER_COLUMNS < cnt)
504                        goto slow;
505
506                /*
507                 * Count up the widths of the characters.  If it's a tab
508                 * character, go do it the the slow way.
509                 */
510                for (cwtotal = 0; cnt--; cwtotal += KEY_LEN(sp, ch))
511                        if ((ch = *(u_char *)p--) == '\t')
512                                goto slow;
513
514                /*
515                 * Decrement the screen cursor by the total width of the
516                 * characters minus 1.
517                 */
518                cwtotal -= 1;
519
520                /*
521                 * If we're moving left, and there's a wide character in the
522                 * current position, go to the end of the character.
523                 */
524                if (KEY_LEN(sp, ch) > 1)
525                        cwtotal -= KEY_LEN(sp, ch) - 1;
526
527                /*
528                 * If the new column moved us off of the current logical line,
529                 * calculate a new one.  If doing leftright scrolling, we've
530                 * moved off of the current screen, as well.
531                 */
532                if (SCNO < cwtotal)
533                        goto slow;
534                SCNO -= cwtotal;
535        } else {
536                /*
537                 * 7b: Cursor moved right.
538                 *
539                 * Point to the first character to the right.
540                 */
541                p += OCNO + 1;
542                cnt = CNO - OCNO;
543
544                /*
545                 * Count up the widths of the characters.  If it's a tab
546                 * character, go do it the the slow way.  If we cross a
547                 * screen boundary, we can quit.
548                 */
549                for (cwtotal = SCNO; cnt--;) {
550                        if ((ch = *(u_char *)p++) == '\t')
551                                goto slow;
552                        if ((cwtotal += KEY_LEN(sp, ch)) >= SCREEN_COLS(sp))
553                                break;
554                }
555
556                /*
557                 * Increment the screen cursor by the total width of the
558                 * characters.
559                 */
560                SCNO = cwtotal;
561
562                /* See screen change comment in section 6a. */
563                if (SCNO >= SCREEN_COLS(sp))
564                        goto slow;
565        }
566
567        /*
568         * 7c: Fast cursor update.
569         *
570         * We have the current column, retrieve the current row.
571         */
572fast:   (void)gp->scr_cursor(sp, &y, &notused);
573        goto done_cursor;
574
575        /*
576         * 7d: Slow cursor update.
577         *
578         * Walk through the map and find the current line.
579         */
580slow:   for (smp = HMAP; smp->lno != LNO; ++smp);
581
582        /*
583         * 7e: Leftright scrolling adjustment.
584         *
585         * If doing left-right scrolling and the cursor movement has changed
586         * the displayed screen, scroll the screen left or right, unless we're
587         * updating the info line in which case we just scroll that one line.
588         * We adjust the offset up or down until we have a window that covers
589         * the current column, making sure that we adjust differently for the
590         * first screen as compared to subsequent ones.
591         */
592        if (O_ISSET(sp, O_LEFTRIGHT)) {
593                /*
594                 * Get the screen column for this character, and correct
595                 * for the number option offset.
596                 */
597                cnt = vs_columns(sp, NULL, LNO, &CNO, NULL);
598                if (O_ISSET(sp, O_NUMBER))
599                        cnt -= O_NUMBER_LENGTH;
600
601                /* Adjust the window towards the beginning of the line. */
602                off = smp->coff;
603                if (off >= cnt) {
604                        do {
605                                if (off >= O_VAL(sp, O_SIDESCROLL))
606                                        off -= O_VAL(sp, O_SIDESCROLL);
607                                else {
608                                        off = 0;
609                                        break;
610                                }
611                        } while (off >= cnt);
612                        goto shifted;
613                }
614
615                /* Adjust the window towards the end of the line. */
616                if (off == 0 && off + SCREEN_COLS(sp) < cnt ||
617                    off != 0 && off + sp->cols < cnt) {
618                        do {
619                                off += O_VAL(sp, O_SIDESCROLL);
620                        } while (off + sp->cols < cnt);
621
622shifted:                /* Fill in screen map with the new offset. */
623                        if (F_ISSET(sp, SC_TINPUT_INFO))
624                                smp->coff = off;
625                        else {
626                                for (smp = HMAP; smp <= TMAP; ++smp)
627                                        smp->coff = off;
628                                leftright_warp = 1;
629                        }
630                        goto paint;
631                }
632
633                /*
634                 * We may have jumped here to adjust a leftright screen because
635                 * redraw was set.  If so, we have to paint the entire screen.
636                 */
637                if (F_ISSET(sp, SC_SCR_REDRAW))
638                        goto paint;
639        }
640
641        /*
642         * Update the screen lines for this particular file line until we
643         * have a new screen cursor position.
644         */
645        for (y = -1,
646            vip->sc_smap = NULL; smp <= TMAP && smp->lno == LNO; ++smp) {
647                if (vs_line(sp, smp, &y, &SCNO))
648                        return (1);
649                if (y != -1) {
650                        vip->sc_smap = smp;
651                        break;
652                }
653        }
654        goto done_cursor;
655
656        /*
657         * 8: Repaint the entire screen.
658         *
659         * Lost big, do what you have to do.  We flush the cache, since
660         * SC_SCR_REDRAW gets set when the screen isn't worth fixing, and
661         * it's simpler to repaint.  So, don't trust anything that we
662         * think we know about it.
663         */
664paint:  for (smp = HMAP; smp <= TMAP; ++smp)
665                SMAP_FLUSH(smp);
666        for (y = -1, vip->sc_smap = NULL, smp = HMAP; smp <= TMAP; ++smp) {
667                if (vs_line(sp, smp, &y, &SCNO))
668                        return (1);
669                if (y != -1 && vip->sc_smap == NULL)
670                        vip->sc_smap = smp;
671        }
672        /*
673         * If it's a small screen and we're redrawing, clear the unused lines,
674         * ex may have overwritten them.
675         */
676        if (F_ISSET(sp, SC_SCR_REDRAW) && IS_SMALL(sp))
677                for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) {
678                        (void)gp->scr_move(sp, cnt, 0);
679                        (void)gp->scr_clrtoeol(sp);
680                }
681
682        didpaint = 1;
683
684done_cursor:
685        /*
686         * Sanity checking.  When the repainting code messes up, the usual
687         * result is we don't repaint the cursor and so sc_smap will be
688         * NULL.  If we're debugging, die, otherwise restart from scratch.
689         */
690#ifdef DEBUG
691        if (vip->sc_smap == NULL)
692                abort();
693#else
694        if (vip->sc_smap == NULL) {
695                F_SET(sp, SC_SCR_REFORMAT);
696                return (vs_paint(sp, flags));
697        }
698#endif
699
700        /*
701         * 9: Set the remembered cursor values.
702         */
703        OCNO = CNO;
704        OLNO = LNO;
705
706        /*
707         * 10: Repaint the line numbers.
708         *
709         * If O_NUMBER is set and the VIP_N_RENUMBER bit is set, and we
710         * didn't repaint the screen, repaint all of the line numbers,
711         * they've changed.
712         */
713number: if (O_ISSET(sp, O_NUMBER) &&
714            F_ISSET(vip, VIP_N_RENUMBER) && !didpaint && vs_number(sp))
715                return (1);
716
717        /*
718         * 11: Update the mode line, position the cursor, and flush changes.
719         *
720         * If we warped the screen, we have to refresh everything.
721         */
722        if (leftright_warp)
723                LF_SET(UPDATE_CURSOR | UPDATE_SCREEN);
724
725        if (LF_ISSET(UPDATE_SCREEN) && !IS_ONELINE(sp) &&
726            !F_ISSET(vip, VIP_S_MODELINE) && !F_ISSET(sp, SC_TINPUT_INFO))
727                vs_modeline(sp);
728
729        if (LF_ISSET(UPDATE_CURSOR)) {
730                (void)gp->scr_move(sp, y, SCNO);
731
732                /*
733                 * XXX
734                 * If the screen shifted, we recalculate the "most favorite"
735                 * cursor position.  Vi won't know that we've warped the
736                 * screen, so it's going to have a wrong idea about where the
737                 * cursor should be.  This is vi's problem, and fixing it here
738                 * is a gross layering violation.
739                 */
740                if (leftright_warp)
741                        (void)vs_column(sp, &sp->rcm);
742        }
743
744        if (LF_ISSET(UPDATE_SCREEN))
745                (void)gp->scr_refresh(sp, F_ISSET(vip, VIP_N_EX_PAINT));
746
747        /* 12: Clear the flags that are handled by this routine. */
748        F_CLR(sp, SC_SCR_CENTER | SC_SCR_REDRAW | SC_SCR_REFORMAT | SC_SCR_TOP);
749        F_CLR(vip, VIP_CUR_INVALID |
750            VIP_N_EX_PAINT | VIP_N_REFRESH | VIP_N_RENUMBER | VIP_S_MODELINE);
751
752        return (0);
753
754#undef   LNO
755#undef  OLNO
756#undef   CNO
757#undef  OCNO
758#undef  SCNO
759}
760
761/*
762 * vs_modeline --
763 *      Update the mode line.
764 */
765static void
766vs_modeline(sp)
767        SCR *sp;
768{
769        static char * const modes[] = {
770                "215|Append",                   /* SM_APPEND */
771                "216|Change",                   /* SM_CHANGE */
772                "217|Command",                  /* SM_COMMAND */
773                "218|Insert",                   /* SM_INSERT */
774                "219|Replace",                  /* SM_REPLACE */
775        };
776        GS *gp;
777        size_t cols, curcol, curlen, endpoint, len, midpoint;
778        const char *t;
779        int ellipsis;
780        char *p, buf[20];
781
782        gp = sp->gp;
783
784        /*
785         * We put down the file name, the ruler, the mode and the dirty flag.
786         * If there's not enough room, there's not enough room, we don't play
787         * any special games.  We try to put the ruler in the middle and the
788         * mode and dirty flag at the end.
789         *
790         * !!!
791         * Leave the last character blank, in case it's a really dumb terminal
792         * with hardware scroll.  Second, don't paint the last character in the
793         * screen, SunOS 4.1.1 and Ultrix 4.2 curses won't let you.
794         *
795         * Move to the last line on the screen.
796         */
797        (void)gp->scr_move(sp, LASTLINE(sp), 0);
798
799        /* If more than one screen in the display, show the file name. */
800        curlen = 0;
801        if (IS_SPLIT(sp)) {
802                for (p = sp->frp->name; *p != '\0'; ++p);
803                for (ellipsis = 0, cols = sp->cols / 2; --p > sp->frp->name;) {
804                        if (*p == '/') {
805                                ++p;
806                                break;
807                        }
808                        if ((curlen += KEY_LEN(sp, *p)) > cols) {
809                                ellipsis = 3;
810                                curlen +=
811                                    KEY_LEN(sp, '.') * 3 + KEY_LEN(sp, ' ');
812                                while (curlen > cols) {
813                                        ++p;
814                                        curlen -= KEY_LEN(sp, *p);
815                                }
816                                break;
817                        }
818                }
819                if (ellipsis) {
820                        while (ellipsis--)
821                                (void)gp->scr_addstr(sp,
822                                    KEY_NAME(sp, '.'), KEY_LEN(sp, '.'));
823                        (void)gp->scr_addstr(sp,
824                            KEY_NAME(sp, ' '), KEY_LEN(sp, ' '));
825                }
826                for (; *p != '\0'; ++p)
827                        (void)gp->scr_addstr(sp,
828                            KEY_NAME(sp, *p), KEY_LEN(sp, *p));
829        }
830
831        /* Clear the rest of the line. */
832        (void)gp->scr_clrtoeol(sp);
833
834        /*
835         * Display the ruler.  If we're not at the midpoint yet, move there.
836         * Otherwise, add in two extra spaces.
837         *
838         * Adjust the current column for the fact that the editor uses it as
839         * a zero-based number.
840         *
841         * XXX
842         * Assume that numbers, commas, and spaces only take up a single
843         * column on the screen.
844         */
845        cols = sp->cols - 1;
846        if (O_ISSET(sp, O_RULER)) {
847                vs_column(sp, &curcol);
848                len =
849                    snprintf(buf, sizeof(buf), "%lu,%lu", sp->lno, curcol + 1);
850
851                midpoint = (cols - ((len + 1) / 2)) / 2;
852                if (curlen < midpoint) {
853                        (void)gp->scr_move(sp, LASTLINE(sp), midpoint);
854                        curlen += len;
855                } else if (curlen + 2 + len < cols) {
856                        (void)gp->scr_addstr(sp, "  ", 2);
857                        curlen += 2 + len;
858                }
859                (void)gp->scr_addstr(sp, buf, len);
860        }
861
862        /*
863         * Display the mode and the modified flag, as close to the end of the
864         * line as possible, but guaranteeing at least two spaces between the
865         * ruler and the modified flag.
866         */
867#define MODESIZE        9
868        endpoint = cols;
869        if (O_ISSET(sp, O_SHOWMODE)) {
870                if (F_ISSET(sp->ep, F_MODIFIED))
871                        --endpoint;
872                t = msg_cat(sp, modes[sp->showmode], &len);
873                endpoint -= len;
874        }
875
876        if (endpoint > curlen + 2) {
877                (void)gp->scr_move(sp, LASTLINE(sp), endpoint);
878                if (O_ISSET(sp, O_SHOWMODE)) {
879                        if (F_ISSET(sp->ep, F_MODIFIED))
880                                (void)gp->scr_addstr(sp,
881                                    KEY_NAME(sp, '*'), KEY_LEN(sp, '*'));
882                        (void)gp->scr_addstr(sp, t, len);
883                }
884        }
885}
Note: See TracBrowser for help on using the repository browser.