tex: allow vertical line in substitute command - 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 2302af408305bfaab3123c9c64ff72a2e2102baa
 (DIR) parent cb01fab3ac9abd167109a9d1a6ac1211aaeaf873
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Fri, 24 Sep 2021 11:32:56 +0330
       
       ex: allow vertical line in substitute command
       
       Reported by Kyryl Melekhin <k.melekhin@gmail.com>.
       
       Diffstat:
         M ex.c                                |     197 ++++++++++++++++++-------------
       
       1 file changed, 114 insertions(+), 83 deletions(-)
       ---
 (DIR) diff --git a/ex.c b/ex.c
       t@@ -114,10 +114,14 @@ char *ex_filetype(void)
                return bufs[0].ft;
        }
        
       +static char *ex_loc(char *s, char *loc);
       +static char *ex_cmd(char *s, char *cmd);
       +static char *ex_arg(char *s, char *arg);
       +
        /* read ex command location */
        static char *ex_loc(char *s, char *loc)
        {
       -        while (*s == ':' || isspace((unsigned char) *s))
       +        while (*s == ':' || *s == ' ' || *s == '\t')
                        s++;
                while (*s && !isalpha((unsigned char) *s) && *s != '=' && *s != '!') {
                        if (*s == '\'')
       t@@ -143,7 +147,7 @@ static char *ex_cmd(char *s, char *cmd)
        {
                char *cmd0 = cmd;
                s = ex_loc(s, cmd);
       -        while (isspace((unsigned char) *s))
       +        while (*s == ' ' || *s == '\t')
                        s++;
                while (isalpha((unsigned char) *s))
                        if ((*cmd++ = *s++) == 'k' && cmd == cmd0 + 1)
       t@@ -154,63 +158,36 @@ static char *ex_cmd(char *s, char *cmd)
                return s;
        }
        
       -/* read ex command argument */
       -static char *ex_arg(char *s, char *arg)
       -{
       -        s = ex_cmd(s, arg);
       -        while (isspace((unsigned char) *s))
       -                s++;
       -        while (*s && !isspace((unsigned char) *s)) {
       -                if (*s == '\\' && s[1])
       -                        s++;
       -                *arg++ = *s++;
       -        }
       -        *arg = '\0';
       -        return s;
       -}
       -
        /* read ex file argument */
       -static char *ex_filearg(char *s, char *arg, int spaceallowed)
       +static char *ex_filearg(char *src, char *dst, int spaceallowed)
        {
       -        s = ex_cmd(s, arg);
       -        while (isspace((unsigned char) *s))
       -                s++;
       -        while (*s && (spaceallowed || !isspace((unsigned char) *s))) {
       -                int c = (unsigned char) *s++;
       -                if (c == '%') {
       +        while (*src && *src != '\n' && (spaceallowed || (*src != ' ' && *src != '\t'))) {
       +                if (*src == '%') {
                                if (!bufs[0].path || !bufs[0].path[0]) {
                                        ex_show("\"%\" is unset\n");
                                        return NULL;
                                }
       -                        strcpy(arg, bufs[0].path);
       -                        arg = strchr(arg, '\0');
       +                        strcpy(dst, bufs[0].path);
       +                        dst = strchr(dst, '\0');
       +                        src++;
                                continue;
                        }
       -                if (c == '#') {
       +                if (*src == '#') {
                                if (!bufs[1].path || !bufs[1].path[0]) {
                                        ex_show("\"#\" is unset\n");
                                        return NULL;
                                }
       -                        strcpy(arg, bufs[1].path);
       -                        arg = strchr(arg, '\0');
       +                        strcpy(dst, bufs[1].path);
       +                        dst = strchr(dst, '\0');
       +                        src++;
                                continue;
                        }
       -                if (c == '\\')
       -                        c = *s++;
       -                *arg++ = c;
       +                if (*src == '\\' && src[1])
       +                        src++;
       +                *dst++ = *src++;
                }
       -        *arg = '\0';
       -        return s;
       -}
       -
       -
       -static char *ex_argeol(char *ec)
       -{
       -        char arg[EXLEN];
       -        char *s = ex_cmd(ec, arg);
       -        while (isspace((unsigned char) *s))
       -                s++;
       -        return s;
       +        *dst = '\0';
       +        return src;
        }
        
        /* the previous search keyword */
       t@@ -394,10 +371,12 @@ static int ec_edit(char *ec)
        {
                char msg[128];
                char cmd[EXLEN];
       +        char arg[EXLEN];
                char path[EXLEN];
                int fd;
                ex_cmd(ec, cmd);
       -        if (!ex_filearg(ec, path, 0))
       +        ex_arg(ec, arg);
       +        if (!ex_filearg(arg, path, 0))
                        return 1;
                if (!strchr(cmd, '!'))
                        if (xb && ex_modifiedbuffer("buffer modified\n"))
       t@@ -442,9 +421,10 @@ static int ec_read(char *ec)
                        return 1;
                if (arg[0] == '!') {
                        int pos = MIN(xrow + 1, lbuf_len(xb));
       -                if (!ex_filearg(ec, arg, 1))
       +                char ecmd[EXLEN * 2];
       +                if (!ex_filearg(arg, ecmd, 1))
                                return 1;
       -                obuf = cmd_pipe(arg + 1, NULL, 0, 1);
       +                obuf = cmd_pipe(ecmd + 1, NULL, 0, 1);
                        if (obuf)
                                lbuf_edit(xb, obuf, pos, pos);
                        free(obuf);
       t@@ -489,11 +469,12 @@ static int ec_write(char *ec)
                        end = lbuf_len(xb);
                }
                if (arg[0] == '!') {
       -                if (!ex_filearg(ec, arg, 1))
       +                char ecmd[EXLEN * 2];
       +                if (!ex_filearg(arg, ecmd, 1))
                                return 1;
                        ibuf = lbuf_cp(xb, beg, end);
                        ex_print(NULL);
       -                cmd_pipe(arg + 1, ibuf, 1, 0);
       +                cmd_pipe(ecmd + 1, ibuf, 1, 0);
                        free(ibuf);
                } else {
                        int fd;
       t@@ -711,18 +692,18 @@ static void replace(struct sbuf *dst, char *rep, char *ln, int *offs)
        
        static int ec_substitute(char *ec)
        {
       -        char loc[EXLEN];
       +        char loc[EXLEN], arg[EXLEN];
                struct rset *re;
                int offs[32];
                int beg, end;
                char *pats[1];
                char *pat = NULL, *rep = NULL;
       -        char *s;
       +        char *s = arg;
                int i;
                ex_loc(ec, loc);
       +        ex_arg(ec, arg);
                if (ex_region(loc, &beg, &end))
                        return 1;
       -        s = ex_argeol(ec);
                pat = re_read(&s);
                if (pat && pat[0])
                        ex_kwdset(pat, +1);
       t@@ -770,21 +751,23 @@ static int ec_exec(char *ec)
        {
                char loc[EXLEN];
                char arg[EXLEN];
       +        char ecmd[EXLEN * 2];
                int beg, end;
                char *text;
                char *rep;
                ex_modifiedbuffer(NULL);
                ex_loc(ec, loc);
       -        if (!ex_filearg(ec, arg, 1))
       +        ex_arg(ec, arg);
       +        if (!ex_filearg(arg, ecmd, 1))
                        return 1;
                if (!loc[0]) {
                        ex_print(NULL);
       -                return cmd_exec(arg);
       +                return cmd_exec(ecmd);
                }
                if (ex_region(loc, &beg, &end))
                        return 1;
                text = lbuf_cp(xb, beg, end);
       -        rep = cmd_pipe(arg, text, 1, 1);
       +        rep = cmd_pipe(ecmd, text, 1, 1);
                if (rep)
                        lbuf_edit(xb, rep, beg, end);
                free(text);
       t@@ -796,10 +779,12 @@ static int ec_make(char *ec)
        {
                char arg[EXLEN];
                char make[EXLEN];
       +        char target[EXLEN * 2];
                ex_modifiedbuffer(NULL);
       -        if (!ex_filearg(ec, arg, 1))
       +        ex_arg(ec, arg);
       +        if (!ex_filearg(arg, target, 0))
                        return 1;
       -        sprintf(make, "make %s", arg);
       +        sprintf(make, "make %s", target);
                ex_print(NULL);
                if (cmd_exec(make))
                        return 1;
       t@@ -836,21 +821,22 @@ static int ex_exec(char *ln);
        
        static int ec_glob(char *ec)
        {
       -        char loc[EXLEN], cmd[EXLEN];
       +        char loc[EXLEN], cmd[EXLEN], arg[EXLEN];
                struct rset *re;
                int offs[32];
                int beg, end, not;
                char *pats[1];
       -        char *pat, *s;
       +        char *pat;
       +        char *s = arg;
                int i;
                ex_cmd(ec, cmd);
                ex_loc(ec, loc);
       +        ex_arg(ec, arg);
                if (!loc[0] && !xgdep)
                        strcpy(loc, "%");
                if (ex_region(loc, &beg, &end))
                        return 1;
                not = strchr(cmd, '!') || cmd[0] == 'v';
       -        s = ex_argeol(ec);
                pat = re_read(&s);
                if (pat && pat[0])
                        ex_kwdset(pat, +1);
       t@@ -973,7 +959,7 @@ static struct excmd {
                {"wq", "wq", ec_write},
                {"wq!", "wq!", ec_write},
                {"u", "undo", ec_undo},
       -        {"r", "redo", ec_redo},
       +        {"redo", "redo", ec_redo},
                {"se", "set", ec_set},
                {"s", "substitute", ec_substitute},
                {"x", "xit", ec_write},
       t@@ -987,19 +973,71 @@ 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)
       +static int ex_idx(char *cmd)
       +{
       +        int i;
       +        for (i = 0; i < LEN(excmds); i++)
       +                if (!strcmp(excmds[i].abbr, cmd) || !strcmp(excmds[i].name, cmd))
       +                        return i;
       +        return -1;
       +}
       +
       +/* read ex command argument */
       +static char *ex_arg(char *s, char *arg)
        {
       -        if (!ec || (ec != ec_glob && ec != ec_exec)) {
       -                while (**src && **src != '|' && **src != '\n')
       -                        *dst++ = *(*src)++;
       -                *dst = '\0';
       -                if (**src)
       -                        (*src)++;
       -        } else {        /* the rest of the line for :g and :! */
       -                strcpy(dst, *src);
       -                *src = strchr(*src, '\0');
       +        char loc[EXLEN];
       +        char cmd[EXLEN];
       +        int c0;
       +        ex_loc(s, loc);
       +        s = ex_cmd(s, cmd);
       +        c0 = ex_idx(cmd) >= 0 ? excmds[ex_idx(cmd)].abbr[0] : -1;
       +        while (*s == ' ' || *s == '\t')
       +                s++;
       +        if (c0 == '!' || c0 == 'g' || c0 == 'v' ||
       +                        ((c0 == 'r' || c0 == 'w') && s[0] == '!')) {
       +                while (*s && *s != '\n') {
       +                        if (*s == '\\' && s[1])
       +                                *arg++ = *s++;
       +                        *arg++ = *s++;
       +                }
       +        } else if (c0 == 's') {
       +                int delim = *s;
       +                int cnt = 2;
       +                *arg++ = *s++;
       +                while (*s && *s != '\n' && cnt > 0) {
       +                        if (*s == delim)
       +                                cnt--;
       +                        if (*s == '\\' && s[1])
       +                                *arg++ = *s++;
       +                        *arg++ = *s++;
       +                }
       +        }
       +        while (*s && *s != '\n' && *s != '|' && *s != '"') {
       +                if (*s == '\\' && s[1])
       +                        *arg++ = *s++;
       +                *arg++ = *s++;
       +        }
       +        if (*s == '"') {
       +                while (*s != '\n')
       +                        s++;
                }
       +        if (*s == '\n' || *s == '|')
       +                s++;
       +        *arg = '\0';
       +        return s;
       +}
       +
       +/* read an ex command and its arguments from src into dst */
       +static char *ex_line(char *src, char *dst)
       +{
       +        char loc[EXLEN];
       +        char cmd[EXLEN];
       +        char arg[EXLEN];
       +        ex_loc(src, loc);
       +        ex_cmd(src, cmd);
       +        src = ex_arg(src, arg);
       +        sprintf(dst, "%s%s %s", loc, cmd, arg);
       +        return src;
        }
        
        /* execute a single ex command */
       t@@ -1007,20 +1045,13 @@ static int ex_exec(char *ln)
        {
                char ec[EXLEN];
                char cmd[EXLEN];
       -        int i;
       +        int idx;
                int ret = 0;
                while (*ln) {
                        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 (i == LEN(excmds))
       -                        ex_line(NULL, ec, &ln);
       +                ln = ex_line(ln, ec);
       +                if ((idx = ex_idx(cmd)) >= 0)
       +                        ret = excmds[idx].ec(ec);
                }
                return ret;
        }