tex: save edit buffer state when editing different files - 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 b531d476541da6bdec69e574dc703985c4637cd9
 (DIR) parent ebe8300559aa61f5a7c2f8933f96e04cb13eace1
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Sat,  6 Jun 2015 16:23:03 +0430
       
       ex: save edit buffer state when editing different files
       
       Diffstat:
         M ex.c                                |     189 ++++++++++++++++++++++++-------
         M led.c                               |       2 +-
         M vi.c                                |      11 +++--------
         M vi.h                                |      14 ++++++++------
       
       4 files changed, 160 insertions(+), 56 deletions(-)
       ---
 (DIR) diff --git a/ex.c b/ex.c
       t@@ -9,22 +9,89 @@
        
        #define EXLEN                512
        
       -char xpath[PATHLEN];                /* current file */
       -char xpath_alt[PATHLEN];        /* alternate file */
       -char xft[32];                        /* filetype */
       +int xrow, xoff, xtop;                /* current row, column, and top row */
        int xquit;                        /* exit if set */
        int xvis;                        /* visual mode */
        int xai = 1;                        /* autoindent option */
        int xic = 1;                        /* ignorecase option */
        int xaw;                        /* autowrite option */
       -struct lbuf *xb;                /* current buffer */
       -int xrow, xoff, xtop;                /* current row, column, and top row */
       -int xrow_alt;                        /* alternate row, column, and top row */
        int xled = 1;                        /* use the line editor */
        int xdir = +1;                        /* current direction context */
        int xshape = 1;                        /* perform letter shaping */
        int xorder = 1;                        /* change the order of characters */
        
       +static struct buf {
       +        char ft[32];
       +        char *path;
       +        struct lbuf *lb;
       +        int row;
       +} bufs[8];
       +
       +static int bufs_find(char *path)
       +{
       +        int i;
       +        for (i = 0; i < LEN(bufs); i++)
       +                if (bufs[i].lb && !strcmp(bufs[i].path, path))
       +                        return i;
       +        return -1;
       +}
       +
       +static void bufs_free(int idx)
       +{
       +        if (bufs[idx].lb) {
       +                free(bufs[idx].path);
       +                lbuf_free(bufs[idx].lb);
       +                memset(&bufs[idx], 0, sizeof(bufs[idx]));
       +        }
       +}
       +
       +static int bufs_open(char *path)
       +{
       +        int i;
       +        for (i = 0; i < LEN(bufs) - 1; i++)
       +                if (!bufs[i].lb)
       +                        break;
       +        bufs_free(i);
       +        bufs[i].path = uc_dup(path);
       +        bufs[i].lb = lbuf_make();
       +        bufs[i].row = 0;
       +        strcpy(bufs[i].ft, syn_filetype(path));
       +        return i;
       +}
       +
       +static void bufs_swap(int i, int j)
       +{
       +        struct buf tmp;
       +        if (i == j)
       +                return;
       +        memcpy(&tmp, &bufs[i], sizeof(tmp));
       +        memcpy(&bufs[i], &bufs[j], sizeof(tmp));
       +        memcpy(&bufs[j], &tmp, sizeof(tmp));
       +}
       +
       +static void bufs_switch(int idx)
       +{
       +        if (idx > 1)
       +                bufs_swap(0, 1);
       +        bufs_swap(0, idx);
       +        xrow = bufs[0].row;
       +}
       +
       +char *ex_path(void)
       +{
       +        return bufs[0].path;
       +}
       +
       +struct lbuf *ex_lbuf(void)
       +{
       +        return bufs[0].lb;
       +}
       +
       +char *ex_filetype(void)
       +{
       +        return bufs[0].ft;
       +}
       +
        /* read ex command location */
        static char *ex_loc(char *s, char *loc)
        {
       t@@ -170,7 +237,7 @@ static int ex_modifiedbuffer(char *msg)
        {
                if (!lbuf_modified(xb))
                        return 0;
       -        if (xaw && xpath[0])
       +        if (xaw && ex_path()[0])
                        return ec_write("w");
                if (msg)
                        ex_show(msg);
       t@@ -188,50 +255,68 @@ static int ec_quit(char *ec)
                return 0;
        }
        
       +static int ex_expand(char *d, char *s)
       +{
       +        while (*s) {
       +                int c = (unsigned char) *s++;
       +                if (c == '%') {
       +                        if (!bufs[0].path || !bufs[0].path[0]) {
       +                                ex_show("\"%\" is unset\n");
       +                                return 1;
       +                        }
       +                        strcpy(d, bufs[0].path);
       +                        d = strchr(d, '\0');
       +                        continue;
       +                }
       +                if (c == '#') {
       +                        if (!bufs[1].path || !bufs[1].path[0]) {
       +                                ex_show("\"#\" is unset\n");
       +                                return 1;
       +                        }
       +                        strcpy(d, bufs[1].path);
       +                        d = strchr(d, '\0');
       +                        continue;
       +                }
       +                if (c == '\\' && (*s == '%' || *s == '#'))
       +                        c = *s++;
       +                *d++ = c;
       +        }
       +        *d = '\0';
       +        return 0;
       +}
       +
        static int ec_edit(char *ec)
        {
                char msg[128];
                char arg[EXLEN], cmd[EXLEN];
       +        char path[PATHLEN];
                int fd;
                ex_cmd(ec, cmd);
                ex_arg(ec, arg);
                if (!strchr(cmd, '!'))
       -                if (ex_modifiedbuffer("buffer modified\n"))
       -                        return 1;
       -        if (!arg[0] || !strcmp(arg, "%") || !strcmp(xpath, arg)) {
       -                strcpy(arg, xpath);
       -        } else if (!strcmp(arg, "#")) {
       -                char xpath_tmp[PATHLEN];
       -                int xrow_tmp = xrow;
       -                if (!xpath_alt[0]) {
       -                        ex_show("\"#\" is unset\n");
       +                if (xb && ex_modifiedbuffer("buffer modified\n"))
                                return 1;
       -                }
       -                strcpy(xpath_tmp, xpath_alt);
       -                strcpy(xpath_alt, xpath);
       -                strcpy(xpath, xpath_tmp);
       -                xrow = xrow_alt;
       -                xrow_alt = xrow_tmp;
       -                xoff = 0;
       -                xtop = 0;
       -        } else {
       -                strcpy(xpath_alt, xpath);
       -                snprintf(xpath, PATHLEN, "%s", arg);
       -                xrow_alt = xrow;
       -                xrow = xvis ? 0 : 1 << 20;
       +        if (ex_expand(path, arg))
       +                return 1;
       +        bufs[0].row = xrow;
       +        if (arg[0] && bufs_find(path) >= 0) {
       +                bufs_switch(bufs_find(path));
       +                return 0;
                }
       -        strcpy(xft, syn_filetype(xpath));
       -        fd = open(xpath, O_RDONLY);
       -        lbuf_rm(xb, 0, lbuf_len(xb));
       +        if (path[0] || !bufs[0].path)
       +                bufs_switch(bufs_open(path));
       +        fd = open(ex_path(), O_RDONLY);
                if (fd >= 0) {
       +                lbuf_rm(xb, 0, lbuf_len(xb));
                        lbuf_rd(xb, fd, 0);
                        close(fd);
                        snprintf(msg, sizeof(msg), "\"%s\"  %d lines  [r]\n",
       -                                xpath, lbuf_len(xb));
       +                                ex_path(), lbuf_len(xb));
                        ex_show(msg);
                }
                xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
       -        lbuf_saved(xb, 1);
       +        lbuf_modified(xb);
       +        lbuf_saved(xb, path[0] != '\0');
                return 0;
        }
        
       t@@ -245,7 +330,7 @@ static int ec_read(char *ec)
                int n = lbuf_len(xb);
                ex_arg(ec, arg);
                ex_loc(ec, loc);
       -        path = arg[0] ? arg : xpath;
       +        path = arg[0] ? arg : ex_path();
                fd = open(path, O_RDONLY);
                if (fd < 0) {
                        ex_show("read failed\n");
       t@@ -272,7 +357,7 @@ static int ec_write(char *ec)
                ex_cmd(ec, cmd);
                ex_arg(ec, arg);
                ex_loc(ec, loc);
       -        path = arg[0] ? arg : xpath;
       +        path = arg[0] ? arg : ex_path();
                if (ex_region(loc, &beg, &end))
                        return 1;
                if (!loc[0]) {
       t@@ -289,9 +374,11 @@ static int ec_write(char *ec)
                snprintf(msg, sizeof(msg), "\"%s\"  %d lines  [w]\n",
                                path, end - beg);
                ex_show(msg);
       -        if (!xpath[0])
       -                strcpy(xpath, path);
       -        if (!strcmp(xpath, path))
       +        if (!ex_path()[0]) {
       +                free(bufs[0].path);
       +                bufs[0].path = uc_dup(path);
       +        }
       +        if (!strcmp(ex_path(), path))
                        lbuf_saved(xb, 0);
                if (!strcmp("wq", cmd))
                        ec_quit("wq");
       t@@ -500,16 +587,22 @@ static int ec_substitute(char *ec)
        static int ec_exec(char *ec)
        {
                char cmd[EXLEN];
       +        char arg[EXLEN];
                ex_modifiedbuffer(NULL);
       -        return cmd_exec(ex_cmd(ec, cmd));
       +        if (ex_expand(arg, ex_cmd(ec, cmd)))
       +                return 1;
       +        return cmd_exec(arg);
        }
        
        static int ec_make(char *ec)
        {
                char cmd[EXLEN];
       +        char arg[EXLEN];
                char make[EXLEN];
                ex_modifiedbuffer(NULL);
       -        sprintf(make, "make %s", ex_cmd(ec, cmd));
       +        if (ex_expand(arg, ex_cmd(ec, cmd)))
       +                return 1;
       +        sprintf(make, "make %s", arg);
                return cmd_exec(make);
        }
        
       t@@ -635,3 +728,17 @@ void ex(void)
                if (xled)
                        term_done();
        }
       +
       +void ex_init(char **files)
       +{
       +        char cmd[EXLEN];
       +        snprintf(cmd, sizeof(cmd), "e %s", files[0] ? files[0] : "");
       +        ec_edit(cmd);
       +}
       +
       +void ex_done(void)
       +{
       +        int i;
       +        for (i = 0; i < LEN(bufs); i++)
       +                bufs_free(i);
       +}
 (DIR) diff --git a/led.c b/led.c
       t@@ -96,7 +96,7 @@ static char *led_render(char *s0)
                                }
                        }
                }
       -        att = syn_highlight(xft, s0);
       +        att = syn_highlight(ex_filetype(), s0);
                led_markrev(n, chrs, pos, att);
                out = sbuf_make();
                i = 0;
 (DIR) diff --git a/vi.c b/vi.c
       t@@ -879,7 +879,7 @@ static void vc_status(void)
                int col = vi_off2col(xb, xrow, xoff);
                snprintf(vi_msg, sizeof(vi_msg),
                        "\"%s\"%c %d lines  L%d C%d\n",
       -                xpath[0] ? xpath : "unnamed",
       +                ex_path()[0] ? ex_path() : "unnamed",
                        lbuf_modified(xb) ? '*' : ' ',
                        lbuf_len(xb), xrow + 1,
                        ren_cursor(lbuf_get(xb, xrow), col) + 1);
       t@@ -1201,9 +1201,7 @@ static void vi(void)
        
        int main(int argc, char *argv[])
        {
       -        char ecmd[PATHLEN];
                int i;
       -        xb = lbuf_make();
                xvis = 1;
                for (i = 1; i < argc && argv[i][0] == '-'; i++) {
                        if (argv[i][1] == 's')
       t@@ -1215,15 +1213,12 @@ int main(int argc, char *argv[])
                }
                dir_init();
                syn_init();
       -        if (i < argc) {
       -                snprintf(ecmd, PATHLEN, "e %s", argv[i]);
       -                ex_command(ecmd);
       -        }
       +        ex_init(argv + i);
                if (xvis)
                        vi();
                else
                        ex();
       -        lbuf_free(xb);
       +        ex_done();
                reg_done();
                syn_done();
                dir_done();
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -135,6 +135,13 @@ void ex(void);
        void ex_command(char *cmd);
        char *ex_read(char *msg);
        void ex_show(char *msg);
       +void ex_init(char **files);
       +void ex_done(void);
       +char *ex_path(void);
       +char *ex_filetype(void);
       +struct lbuf *ex_lbuf(void);
       +
       +#define xb         ex_lbuf()
        
        /* process management */
        char *cmd_pipe(char *cmd, char *s);
       t@@ -165,19 +172,14 @@ int conf_highlight_revdir(int *att);
        /* global variables */
        #define PATHLEN                512
        
       -extern int xvis;
       -extern struct lbuf *xb;
        extern int xrow;
        extern int xoff;
        extern int xtop;
       +extern int xvis;
        extern int xled;
       -extern int xrow_alt;
       -extern char xpath[];
       -extern char xpath_alt[];
        extern int xquit;
        extern int xic;
        extern int xai;
        extern int xdir;
        extern int xshape;
        extern int xorder;
       -extern char xft[];