tvi: undo and redo move to the first changed line - 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 195dc5459fae177fba03ed32db9e0e1dd57fb972
 (DIR) parent 36dab822780af2effa399289db2caa52398de43e
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Thu,  4 Jun 2015 08:49:39 +0430
       
       vi: undo and redo move to the first changed line
       
       Also '[ and '] point to the first and last changed lines.
       
       Diffstat:
         M ex.c                                |       2 +-
         M lbuf.c                              |      46 +++++++++++++++++++++++--------
         M vi.c                                |      26 ++++++++++++++++----------
         M vi.h                                |       6 +++---
       
       4 files changed, 55 insertions(+), 25 deletions(-)
       ---
 (DIR) diff --git a/ex.c b/ex.c
       t@@ -118,7 +118,7 @@ static int ex_lineno(char *num)
                if (num[0] == '+')
                        n = xrow + (num[1] ? ex_lineno(num + 1) : 1);
                if (num[0] == '\'')
       -                lbuf_markpos(xb, num[1], &n, NULL);
       +                lbuf_jump(xb, num[1], &n, NULL);
                if (num[0] == '/' && num[1])
                        n = ex_search(num);
                if (num[0] == '?' && num[1])
 (DIR) diff --git a/lbuf.c b/lbuf.c
       t@@ -4,7 +4,7 @@
        #include <unistd.h>
        #include "vi.h"
        
       -#define MARK(c)                ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' : 30)
       +#define NMARKS                128
        
        /* line operations */
        struct lopt {
       t@@ -16,14 +16,15 @@ struct lopt {
        
        /* line buffers */
        struct lbuf {
       -        int mark[32];                /* mark lines */
       -        int mark_off[32];        /* mark line offsets */
       +        int mark[NMARKS];        /* mark lines */
       +        int mark_off[NMARKS];        /* mark line offsets */
                struct lopt hist[128];        /* buffer history */
                int undo;                /* current index into hist[] */
                int useq;                /* current operation sequence */
                char **ln;                /* lines */
                int ln_n;                /* number of lbuf in l[] */
                int ln_sz;                /* size of l[] */
       +        int mark_mod;                /* clear modification marks */
        };
        
        struct lbuf *lbuf_make(void)
       t@@ -70,6 +71,7 @@ static void lbuf_insert(struct lbuf *lb, int pos, char *s)
                int len = strlen(s);
                struct sbuf *sb;
                int lb_len = lbuf_len(lb);
       +        int beg = pos, end;
                int i;
                sb = sbuf_make();
                for (i = 0; i < len; i++) {
       t@@ -83,6 +85,12 @@ static void lbuf_insert(struct lbuf *lb, int pos, char *s)
                for (i = 0; i < LEN(lb->mark); i++)        /* updating marks */
                        if (lb->mark[i] >= pos)
                                lb->mark[i] += lbuf_len(lb) - lb_len;
       +        end = beg + lbuf_len(lb) - lb_len;
       +        if (lb->mark_mod || lb->mark['['] < 0 || lb->mark['['] > beg)
       +                lbuf_mark(lb, '[', beg, 0);
       +        if (lb->mark_mod || lb->mark[']'] < 0 || lb->mark[']'] < end - 1)
       +                lbuf_mark(lb, ']', end - 1, 0);
       +        lb->mark_mod = 0;
        }
        
        /* low-level deletion */
       t@@ -96,6 +104,11 @@ static void lbuf_delete(struct lbuf *lb, int beg, int end)
                for (i = 0; i < LEN(lb->mark); i++)        /* updating marks */
                        if (lb->mark[i] > beg)
                                lb->mark[i] = MAX(beg, lb->mark[i] + beg - end);
       +        if (lb->mark_mod || lb->mark['['] < 0 || lb->mark['['] > beg)
       +                lbuf_mark(lb, '[', beg, 0);
       +        if (lb->mark_mod || lb->mark[']'] < 0 || lb->mark[']'] < beg)
       +                lbuf_mark(lb, ']', beg, 0);
       +        lb->mark_mod = 0;
        }
        
        /* append undo/redo history */
       t@@ -180,17 +193,19 @@ int lbuf_len(struct lbuf *lb)
        
        void lbuf_mark(struct lbuf *lbuf, int mark, int pos, int off)
        {
       -        lbuf->mark[MARK(mark)] = pos;
       -        lbuf->mark_off[MARK(mark)] = off;
       +        if (mark >= NMARKS)
       +                return;
       +        lbuf->mark[mark] = pos;
       +        lbuf->mark_off[mark] = off;
        }
        
       -int lbuf_markpos(struct lbuf *lbuf, int mark, int *pos, int *off)
       +int lbuf_jump(struct lbuf *lbuf, int mark, int *pos, int *off)
        {
       -        if (lbuf->mark[MARK(mark)] < 0)
       +        if (mark >= NMARKS || lbuf->mark[mark] < 0)
                        return 1;
       -        *pos = lbuf->mark[MARK(mark)];
       +        *pos = lbuf->mark[mark];
                if (off)
       -                *off = lbuf->mark_off[MARK(mark)];
       +                *off = lbuf->mark_off[mark];
                return 0;
        }
        
       t@@ -200,10 +215,13 @@ static struct lopt *lbuf_lopt(struct lbuf *lb, int i)
                return i >= 0 && i < LEN(lb->hist) && lo->buf ? lo : NULL;
        }
        
       -void lbuf_undo(struct lbuf *lb)
       +int lbuf_undo(struct lbuf *lb)
        {
                struct lopt *lo = lbuf_lopt(lb, lb->undo);
                int useq = lo ? lo->seq : 0;
       +        if (!lo)
       +                return 1;
       +        lb->mark_mod = 1;
                while (lo && lo->seq == useq) {
                        lb->undo++;
                        if (lo->ins)
       t@@ -212,12 +230,16 @@ void lbuf_undo(struct lbuf *lb)
                                lbuf_insert(lb, lo->beg, lo->buf);
                        lo = lbuf_lopt(lb, lb->undo);
                }
       +        return 0;
        }
        
       -void lbuf_redo(struct lbuf *lb)
       +int lbuf_redo(struct lbuf *lb)
        {
                struct lopt *lo = lbuf_lopt(lb, lb->undo - 1);
                int useq = lo ? lo->seq : 0;
       +        if (!lo)
       +                return 1;
       +        lb->mark_mod = 1;
                while (lo && lo->seq == useq) {
                        lb->undo--;
                        if (lo->ins)
       t@@ -226,6 +248,7 @@ void lbuf_redo(struct lbuf *lb)
                                lbuf_delete(lb, lo->beg, lo->end);
                        lo = lbuf_lopt(lb, lb->undo - 1);
                }
       +        return 0;
        }
        
        void lbuf_undofree(struct lbuf *lb)
       t@@ -239,5 +262,6 @@ void lbuf_undofree(struct lbuf *lb)
        
        void lbuf_undomark(struct lbuf *lbuf)
        {
       +        lbuf->mark_mod = 1;
                lbuf->useq++;
        }
 (DIR) diff --git a/vi.c b/vi.c
       t@@ -233,9 +233,7 @@ static int vi_motionln(int *row, int cmd)
                case '\'':
                        if ((mark = vi_read()) <= 0)
                                return -1;
       -                if (!islower(mark) && !strchr("'`", mark))
       -                        return -1;
       -                if (lbuf_markpos(xb, mark, &mark_row, &mark_off))
       +                if (lbuf_jump(xb, mark, &mark_row, &mark_off))
                                return -1;
                        *row = mark_row;
                        break;
       t@@ -467,9 +465,7 @@ static int vi_motion(int *row, int *off)
                case '`':
                        if ((mark = vi_read()) <= 0)
                                return -1;
       -                if (!islower(mark) && !strchr("'`", mark))
       -                        return -1;
       -                if (lbuf_markpos(xb, mark, &mark_row, &mark_off))
       +                if (lbuf_jump(xb, mark, &mark_row, &mark_off))
                                return -1;
                        *row = mark_row;
                        *off = mark_off;
       t@@ -1020,12 +1016,22 @@ static void vi(void)
                                        redraw = 1;
                                        break;
                                case 'u':
       -                                lbuf_undo(xb);
       -                                redraw = 1;
       +                                if (!lbuf_undo(xb)) {
       +                                        lbuf_jump(xb, '[', &xrow, &xoff);
       +                                        xoff = lbuf_indents(xb, xrow);
       +                                        redraw = 1;
       +                                } else {
       +                                        snprintf(vi_msg, sizeof(vi_msg), "undo failed\n");
       +                                }
                                        break;
                                case TK_CTL('r'):
       -                                lbuf_redo(xb);
       -                                redraw = 1;
       +                                if (!lbuf_redo(xb)) {
       +                                        lbuf_jump(xb, '[', &xrow, &xoff);
       +                                        xoff = lbuf_indents(xb, xrow);
       +                                        redraw = 1;
       +                                } else {
       +                                        snprintf(vi_msg, sizeof(vi_msg), "redo failed\n");
       +                                }
                                        break;
                                case TK_CTL('g'):
                                        vc_status();
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -16,9 +16,9 @@ void lbuf_put(struct lbuf *lbuf, int pos, char *s);
        char *lbuf_get(struct lbuf *lbuf, int pos);
        int lbuf_len(struct lbuf *lbuf);
        void lbuf_mark(struct lbuf *lbuf, int mark, int pos, int off);
       -int lbuf_markpos(struct lbuf *lbuf, int mark, int *pos, int *off);
       -void lbuf_undo(struct lbuf *lbuf);
       -void lbuf_redo(struct lbuf *lbuf);
       +int lbuf_jump(struct lbuf *lbuf, int mark, int *pos, int *off);
       +int lbuf_undo(struct lbuf *lbuf);
       +int lbuf_redo(struct lbuf *lbuf);
        void lbuf_undomark(struct lbuf *lbuf);
        void lbuf_undofree(struct lbuf *lbuf);
        int lbuf_indents(struct lbuf *lb, int r);