tvi: more efficient screen updating - neatvi - [fork] simple vi-type editor with UTF-8 support
 (HTM) git clone git://src.adamsgaard.dk/neatvi
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit b4991eb46ce9f36f73591c62ef1cf20e4f915b7d
 (DIR) parent 5414a8da8715d46a50c3ae8d56445c38fa156824
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Wed,  3 Feb 2016 20:29:21 +0330
       
       vi: more efficient screen updating
       
       Scrolling commands do not re-render visible lines.
       
       Diffstat:
         M vi.c                                |     102 +++++++++++++++++++------------
       
       1 file changed, 63 insertions(+), 39 deletions(-)
       ---
 (DIR) diff --git a/vi.c b/vi.c
       t@@ -1,7 +1,7 @@
        /*
         * neatvi editor
         *
       - * Copyright (C) 2015 Ali Gholami Rudi <ali at rudi dot ir>
       + * Copyright (C) 2015-2016 Ali Gholami Rudi <ali at rudi dot ir>
         *
         * This program is released under the Modified BSD license.
         */
       t@@ -40,20 +40,49 @@ static void vi_drawmsg(void)
                xleft = oleft;
        }
        
       +static void vi_drawrow(int row)
       +{
       +        char *s = lbuf_get(xb, row);
       +        led_print(s ? s : (row ? "~" : ""), row - xtop);
       +}
       +
        /* redraw the screen */
       -static void vi_draw(int xcol)
       +static void vi_drawagain(int xcol, int lineonly)
        {
                int i;
                term_record();
       -        for (i = xtop; i < xtop + xrows; i++) {
       -                char *s = lbuf_get(xb, i);
       -                led_print(s ? s : (i ? "~" : ""), i - xtop);
       -        }
       +        for (i = xtop; i < xtop + xrows; i++)
       +                if (!lineonly || i == xrow)
       +                        vi_drawrow(i);
                vi_drawmsg();
                term_pos(xrow, led_pos(lbuf_get(xb, i), xcol));
                term_commit();
        }
        
       +/* update the screen */
       +static void vi_drawupdate(int xcol, int otop)
       +{
       +        int i;
       +        if (otop != xtop) {
       +                term_record();
       +                term_pos(0, 0);
       +                term_room(otop - xtop);
       +                if (xtop > otop) {
       +                        int n = MIN(xtop - otop, xrows);
       +                        for (i = 0; i < n; i++)
       +                                vi_drawrow(xtop + xrows - n + i);
       +                } else {
       +                        int n = MIN(otop - xtop, xrows);
       +                        for (i = 0; i < n; i++)
       +                                vi_drawrow(xtop + i);
       +                }
       +                term_pos(xrow, led_pos(lbuf_get(xb, i), xcol));
       +                term_commit();
       +        }
       +        vi_drawmsg();
       +        term_pos(xrow, led_pos(lbuf_get(xb, i), xcol));
       +}
       +
        /* update the screen by removing lines r1 to r2 before an input command */
        static void vi_drawrm(int r1, int r2, int newln)
        {
       t@@ -1002,10 +1031,10 @@ static void vi(void)
                xtop = MAX(0, xrow - xrows / 2);
                xoff = 0;
                xcol = vi_off2col(xb, xrow, xoff);
       -        vi_draw(xcol);
       +        vi_drawagain(xcol, 0);
                term_pos(xrow - xtop, led_pos(lbuf_get(xb, xrow), xcol));
                while (!xquit) {
       -                int redraw = 0;
       +                int mod = 0;        /* screen should be redrawn */
                        int nrow = xrow;
                        int noff = ren_noeol(lbuf_get(xb, xrow), xoff);
                        int otop = xtop;
       t@@ -1046,23 +1075,19 @@ static void vi(void)
                                        if (vi_scrollbackward(MAX(1, vi_arg1) * (xrows - 1)))
                                                break;
                                        xoff = lbuf_indents(xb, xrow);
       -                                redraw = 1;
                                        break;
                                case TK_CTL('f'):
                                        if (vi_scrollforeward(MAX(1, vi_arg1) * (xrows - 1)))
                                                break;
                                        xoff = lbuf_indents(xb, xrow);
       -                                redraw = 1;
                                        break;
                                case TK_CTL('e'):
                                        if (vi_scrollforeward(MAX(1, vi_arg1)))
                                                break;
       -                                redraw = 1;
                                        break;
                                case TK_CTL('y'):
                                        if (vi_scrollbackward(MAX(1, vi_arg1)))
                                                break;
       -                                redraw = 1;
                                        break;
                                case TK_CTL('u'):
                                        if (xrow == 0)
       t@@ -1073,7 +1098,6 @@ static void vi(void)
                                        xrow = MAX(0, xrow - n);
                                        if (xtop > 0)
                                                xtop = MAX(0, xtop - n);
       -                                redraw = 1;
                                        xoff = lbuf_indents(xb, xrow);
                                        break;
                                case TK_CTL('d'):
       t@@ -1085,18 +1109,17 @@ static void vi(void)
                                        xrow = MIN(MAX(0, lbuf_len(xb) - 1), xrow + n);
                                        if (xtop < lbuf_len(xb) - xrows)
                                                xtop = MIN(lbuf_len(xb) - xrows, xtop + n);
       -                                redraw = 1;
                                        xoff = lbuf_indents(xb, xrow);
                                        break;
                                case TK_CTL('z'):
                                        term_pos(xrows, 0);
                                        term_suspend();
       -                                redraw = 1;
       +                                mod = 1;
                                        break;
                                case 'u':
                                        if (!lbuf_undo(xb)) {
                                                lbuf_jump(xb, '*', &xrow, &xoff);
       -                                        redraw = 1;
       +                                        mod = 1;
                                        } else {
                                                snprintf(vi_msg, sizeof(vi_msg), "undo failed\n");
                                        }
       t@@ -1104,7 +1127,7 @@ static void vi(void)
                                case TK_CTL('r'):
                                        if (!lbuf_redo(xb)) {
                                                lbuf_jump(xb, '*', &xrow, &xoff);
       -                                        redraw = 1;
       +                                        mod = 1;
                                        } else {
                                                snprintf(vi_msg, sizeof(vi_msg), "redo failed\n");
                                        }
       t@@ -1114,13 +1137,13 @@ static void vi(void)
                                        break;
                                case TK_CTL('^'):
                                        ex_command("e #");
       -                                redraw = 1;
       +                                mod = 1;
                                        break;
                                case ':':
                                        ln = vi_prompt(":", &kmap);
                                        if (ln && ln[0]) {
                                                ex_command(ln);
       -                                        redraw = 1;
       +                                        mod = 1;
                                        }
                                        free(ln);
                                        if (xquit)
       t@@ -1133,7 +1156,7 @@ static void vi(void)
                                case '>':
                                case '<':
                                        if (!vc_motion(c))
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case 'i':
                                case 'I':
       t@@ -1142,14 +1165,14 @@ static void vi(void)
                                case 'o':
                                case 'O':
                                        if (!vc_insert(c))
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case 'J':
                                        if (!vc_join())
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case TK_CTL('l'):
       -                                redraw = 1;
       +                                mod = 1;
                                        break;
                                case 'm':
                                        if ((mark = vi_read()) > 0 && islower(mark))
       t@@ -1158,7 +1181,7 @@ static void vi(void)
                                case 'p':
                                case 'P':
                                        if (!vc_put(c))
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case 'z':
                                        k = vi_read();
       t@@ -1183,52 +1206,51 @@ static void vi(void)
                                                xdir = k == 'R' ? -2 : +2;
                                                break;
                                        }
       -                                redraw = 1;
       +                                mod = 1;
                                        break;
                                case 'g':
                                        k = vi_read();
                                        if (k == '~' || k == 'u' || k == 'U')
                                                if (!vc_motion(k))
       -                                                redraw = 1;
       +                                                mod = 1;
                                        break;
                                case 'x':
                                        vi_back(' ');
                                        if (!vc_motion('d'))
       -                                        redraw = 1;
       +                                        mod = 2;
                                        break;
                                case 'X':
                                        vi_back(TK_CTL('h'));
                                        if (!vc_motion('d'))
       -                                        redraw = 1;
       +                                        mod = 2;
                                        break;
                                case 'C':
                                        vi_back('$');
                                        if (!vc_motion('c'))
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case 'D':
                                        vi_back('$');
                                        if (!vc_motion('d'))
       -                                        redraw = 1;
       +                                        mod = 2;
                                        break;
                                case 'r':
                                        if (!vc_replace())
       -                                        redraw = 1;
       +                                        mod = 2;
                                        break;
                                case 's':
                                        vi_back(' ');
                                        if (!vc_motion('c'))
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case 'S':
                                        vi_back('c');
                                        if (!vc_motion('c'))
       -                                        redraw = 1;
       +                                        mod = 1;
                                        break;
                                case 'Y':
                                        vi_back('y');
       -                                if (!vc_motion('y'))
       -                                        redraw = 1;
       +                                vc_motion('y');
                                        break;
                                case 'Z':
                                        k = vi_read();
       t@@ -1238,7 +1260,7 @@ static void vi(void)
                                case '~':
                                        vi_back(' ');
                                        if (!vc_motion('~'))
       -                                        redraw = 1;
       +                                        mod = 2;
                                        break;
                                case '.':
                                        vc_repeat();
       t@@ -1266,15 +1288,17 @@ static void vi(void)
                                xtop = xtop + xrows + xrows / 2 <= xrow ?
                                                xrow - xrows / 2 : xrow - xrows + 1;
                        xoff = ren_noeol(lbuf_get(xb, xrow), xoff);
       -                if (redraw)
       +                if (mod)
                                xcol = vi_off2col(xb, xrow, xoff);
                        if (xcol >= xleft + xcols)
                                xleft = xcol - xcols / 2;
                        if (xcol < xleft)
                                xleft = xcol < xcols ? 0 : xcol - xcols / 2;
                        vi_wait();
       -                if (redraw || xtop != otop || xleft != oleft)
       -                        vi_draw(xcol);
       +                if (mod || xleft != oleft)
       +                        vi_drawagain(xcol, mod == 2);
       +                else if (xtop != otop)
       +                        vi_drawupdate(xcol, otop);
                        if (vi_msg[0])
                                vi_drawmsg();
                        term_pos(xrow - xtop, led_pos(lbuf_get(xb, xrow),