tex: mark the region before executing glob commands - 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 57077e595860fb487d95316fc8dfc41df965342f
 (DIR) parent d3b961346505dc8b1be900ce63a5a593f2ff9895
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Thu, 30 Jun 2016 10:52:06 +0430
       
       ex: mark the region before executing glob commands
       
       Diffstat:
         M ex.c                                |      45 ++++++++++++++++++++-----------
         M lbuf.c                              |      85 ++++++++++++++++++-------------
         M vi.h                                |       1 +
       
       3 files changed, 79 insertions(+), 52 deletions(-)
       ---
 (DIR) diff --git a/ex.c b/ex.c
       t@@ -185,14 +185,6 @@ static char *ex_argeol(char *ec)
                return s;
        }
        
       -static char *ex_line(char *s, char *ln)
       -{
       -        while (*s && *s != '|' && *s != '\n')
       -                *ln++ = *s++;
       -        *ln = '\0';
       -        return *s ? s + 1 : s;
       -}
       -
        /* the previous search keyword */
        int ex_kwd(char **kwd, int *dir)
        {
       t@@ -825,18 +817,22 @@ static int ec_glob(char *ec)
                        return 1;
                if (!(re = rset_make(1, pats, xic ? RE_ICASE : 0)))
                        return 1;
       +        for (i = beg + 1; i < end; i++)
       +                lbuf_glob(xb, i, 1);
                i = beg;
       -        while (i < end) {
       +        while (i < lbuf_len(xb)) {
                        char *ln = lbuf_get(xb, i);
                        if ((rset_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == not) {
       -                        int len = lbuf_len(xb);
                                xrow = i;
       -                        ex_exec(s);
       -                        i = xrow;
       -                        end += lbuf_len(xb) - len;
       +                        if (ex_exec(s))
       +                                break;
       +                        i = MIN(i, xrow);
                        }
       -                i++;
       +                while (i < lbuf_len(xb) && !lbuf_glob(xb, i, 0))
       +                        i++;
                }
       +        for (i = 0; i < lbuf_len(xb); i++)
       +                lbuf_glob(xb, i, 0);
                rset_free(re);
                return 0;
        }
       t@@ -945,6 +941,21 @@ static struct excmd {
                {"", "", ec_null},
        };
        
       +/* read an ex command and its arguments from src into dst */
       +static void ex_line(int (*ec)(char *s), char *dst, char **src)
       +{
       +        if (!ec || ec != ec_glob) {
       +                while (**src && **src != '|' && **src != '\n')
       +                        *dst++ = *(*src)++;
       +                *dst = '\0';
       +                if (**src)
       +                        (*src)++;
       +        } else {        /* the rest of the line for :g */
       +                strcpy(dst, *src);
       +                *src = strchr(*src, '\0');
       +        }
       +}
       +
        /* execute a single ex command */
        static int ex_exec(char *ln)
        {
       t@@ -953,17 +964,19 @@ static int ex_exec(char *ln)
                int i;
                int ret = 0;
                while (*ln) {
       -                ln = ex_line(ln, ec);
       -                ex_cmd(ec, cmd);
       +                ex_cmd(ln, cmd);
                        for (i = 0; i < LEN(excmds); i++) {
                                if (!strcmp(excmds[i].abbr, cmd) ||
                                                !strcmp(excmds[i].name, cmd)) {
       +                                ex_line(excmds[i].ec, ec, &ln);
                                        ret = excmds[i].ec(ec);
                                        break;
                                }
                        }
                        if (!xvis && !cmd[0])
                                ret = ec_print(ec);
       +                if (i == LEN(excmds))
       +                        ex_line(NULL, ec, &ln);
                }
                return ret;
        }
 (DIR) diff --git a/lbuf.c b/lbuf.c
       t@@ -23,6 +23,7 @@ struct lbuf {
                int mark[NMARKS];        /* mark lines */
                int mark_off[NMARKS];        /* mark line offsets */
                char **ln;                /* buffer lines */
       +        char *ln_glob;                /* line global mark */
                int ln_n;                /* number of lines in ln[] */
                int ln_sz;                /* size of ln[] */
                int useq;                /* current operation sequence */
       t@@ -110,48 +111,61 @@ void lbuf_free(struct lbuf *lb)
                        lopt_done(&lb->hist[i]);
                free(lb->hist);
                free(lb->ln);
       +        free(lb->ln_glob);
                free(lb);
        }
        
       -/* insert a line at pos */
       -static void lbuf_insertline(struct lbuf *lb, int pos, char *s)
       +static int linelength(char *s)
        {
       -        if (lb->ln_n == lb->ln_sz) {
       +        char *r = strchr(s, '\n');
       +        return r ? r - s + 1 : strlen(s);
       +}
       +
       +static int linecount(char *s)
       +{
       +        int n;
       +        for (n = 0; s && *s; n++)
       +                s += linelength(s);
       +        return n;
       +}
       +
       +
       +/* low-level line replacement */
       +static void lbuf_replace(struct lbuf *lb, char *s, int pos, int n_del)
       +{
       +        int n_ins = linecount(s);
       +        int i;
       +        while (lb->ln_n + n_ins - n_del >= lb->ln_sz) {
                        int nsz = lb->ln_sz + 512;
                        char **nln = malloc(nsz * sizeof(nln[0]));
       +                char *nln_glob = malloc(nsz * sizeof(nln_glob[0]));
                        memcpy(nln, lb->ln, lb->ln_n * sizeof(lb->ln[0]));
       +                memcpy(nln_glob, lb->ln_glob, lb->ln_n * sizeof(lb->ln_glob[0]));
                        free(lb->ln);
       +                free(lb->ln_glob);
                        lb->ln = nln;
       +                lb->ln_glob = nln_glob;
                        lb->ln_sz = nsz;
                }
       -        memmove(lb->ln + pos + 1, lb->ln + pos,
       -                (lb->ln_n - pos) * sizeof(lb->ln[0]));
       -        lb->ln_n++;
       -        lb->ln[pos] = s;
       -}
       -
       -/* low-level replacement */
       -static void lbuf_replace(struct lbuf *lb, char *s, int pos, int n_del)
       -{
       -        char *r, *n;
       -        int n_ins = 0;
       -        int i;
                for (i = 0; i < n_del; i++)
                        free(lb->ln[pos + i]);
       -        memmove(lb->ln + pos, lb->ln + pos + n_del,
       +        memmove(lb->ln + pos + n_ins, lb->ln + pos + n_del,
                        (lb->ln_n - pos - n_del) * sizeof(lb->ln[0]));
       -        lb->ln_n -= n_del;
       -        while (s && *s) {
       -                r = strchr(s, '\n');
       -                if (!r)                                /* no eol */
       -                        r = strchr(s, '\0');
       -                n = malloc(r - s + 2);
       -                memcpy(n, s, r - s);
       -                n[r - s + 0] = '\n';
       -                n[r - s + 1] = '\0';
       -                lbuf_insertline(lb, pos + n_ins++, n);
       -                s = *r ? r + 1 : r;
       +        memmove(lb->ln_glob + pos + n_ins, lb->ln_glob + pos + n_del,
       +                (lb->ln_n - pos - n_del) * sizeof(lb->ln_glob[0]));
       +        lb->ln_n += n_ins - n_del;
       +        for (i = 0; i < n_ins; i++) {
       +                int l = s ? linelength(s) : 0;
       +                int l_nonl = l - (s[l - 1] == '\n');
       +                char *n = malloc(l_nonl + 2);
       +                memcpy(n, s, l_nonl);
       +                n[l_nonl + 0] = '\n';
       +                n[l_nonl + 1] = '\0';
       +                lb->ln[pos + i] = n;
       +                s += l;
                }
       +        for (i = n_del; i < n_ins; i++)
       +                lb->ln_glob[pos + i] = 0;
                for (i = 0; i < LEN(lb->mark); i++) {        /* updating marks */
                        if (!s && lb->mark[i] >= pos && lb->mark[i] < pos + n_del)
                                lb->mark[i] = -1;
       t@@ -164,14 +178,6 @@ static void lbuf_replace(struct lbuf *lb, char *s, int pos, int n_del)
                lbuf_mark(lb, ']', pos + (n_ins ? n_ins - 1 : 0), 0);
        }
        
       -static int uc_newlines(char *s)
       -{
       -        int n;
       -        for (n = 0; (s = strchr(s, '\n')); n++)
       -                s++;
       -        return n;
       -}
       -
        /* append undo/redo history */
        static void lbuf_opt(struct lbuf *lb, char *buf, int pos, int n_del)
        {
       t@@ -195,7 +201,7 @@ static void lbuf_opt(struct lbuf *lb, char *buf, int pos, int n_del)
                lo->pos = pos;
                lo->n_del = n_del;
                lo->del = n_del ? lbuf_cp(lb, pos, pos + n_del) : NULL;
       -        lo->n_ins = buf ? uc_newlines(buf) : 0;
       +        lo->n_ins = buf ? linecount(buf) : 0;
                lo->ins = buf ? uc_dup(buf) : NULL;
                lo->seq = lb->useq;
                lbuf_savepos(lb, lo);
       t@@ -344,3 +350,10 @@ int lbuf_modified(struct lbuf *lb)
                lb->useq++;
                return lbuf_seq(lb) != lb->useq_zero;
        }
       +
       +int lbuf_glob(struct lbuf *lb, int pos, int v)
       +{
       +        int o = lb->ln_glob[pos];
       +        lb->ln_glob[pos] = v;
       +        return o;
       +}
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -22,6 +22,7 @@ int lbuf_modified(struct lbuf *lb);
        void lbuf_saved(struct lbuf *lb, int clear);
        int lbuf_indents(struct lbuf *lb, int r);
        int lbuf_eol(struct lbuf *lb, int r);
       +int lbuf_glob(struct lbuf *lb, int pos, int v);
        /* motions */
        int lbuf_findchar(struct lbuf *lb, char *cs, int cmd, int n, int *r, int *o);
        int lbuf_search(struct lbuf *lb, char *kw, int dir, int *r, int *o, int *len);