URI:
       tacme: preserve window position and selection during Get - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 3d6e5cb56a6249e7f3001091fe81c171cd501319
   DIR parent 805d91d359d67676a89edc9789ee8267bb7da6e1
  HTML Author: Russ Cox <rsc@swtch.com>
       Date:   Thu,  2 Nov 2017 11:58:07 -0400
       
       acme: preserve window position and selection during Get
       
       Before, executing Get in a file rewound the window offset and
       selection to the start of the file.
       
       After this CL, Get preserves the window offset and selection,
       where preserve is defined as "the same line number and rune
       offset within the line". So if the window started at line 10
       before and the selection was line 13 chars 5-7, then that
       will still be true after Get, provided the new content is large
       enough.
       
       This should help the common situation of plumbing a
       compiler error, realizing the window is out of date,
       clicking Get, and then losing the positioning from the
       plumb operation.
       
       Diffstat:
         M src/cmd/acme/addr.c                 |      21 +++++++++++++++++++++
         M src/cmd/acme/ecmd.c                 |      66 +++++++++++++++++++++++--------
         M src/cmd/acme/exec.c                 |      30 ++++++++++++++++++++++++++++++
         M src/cmd/acme/fns.h                  |       2 ++
         M src/cmd/acme/text.c                 |       2 +-
       
       5 files changed, 103 insertions(+), 18 deletions(-)
       ---
   DIR diff --git a/src/cmd/acme/addr.c b/src/cmd/acme/addr.c
       t@@ -49,6 +49,27 @@ isregexc(int r)
                return FALSE;
        }
        
       +// nlcounttopos starts at q0 and advances nl lines,
       +// being careful not to walk past the end of the text,
       +// and then nr chars, being careful not to walk past
       +// the end of the current line.
       +// It returns the final position.
       +long
       +nlcounttopos(Text *t, long q0, long nl, long nr)
       +{
       +        while(nl > 0 && q0 < t->file->b.nc) {
       +                if(textreadc(t, q0++) == '\n')
       +                        nl--;
       +        }
       +        if(nl > 0)
       +                return q0;
       +        while(nr > 0 && q0 < t->file->b.nc && textreadc(t, q0) != '\n') {
       +                q0++;
       +                nr--;
       +        }
       +        return q0;
       +}
       +
        Range
        number(uint showerr, Text *t, Range r, int line, int dir, int size, int *evalp)
        {
   DIR diff --git a/src/cmd/acme/ecmd.c b/src/cmd/acme/ecmd.c
       t@@ -661,15 +661,16 @@ pipe_cmd(Text *t, Cmd *cp)
        }
        
        long
       -nlcount(Text *t, long q0, long q1)
       +nlcount(Text *t, long q0, long q1, long *pnr)
        {
       -        long nl;
       +        long nl, start;
                Rune *buf;
                int i, nbuf;
        
                buf = fbufalloc();
                nbuf = 0;
                i = nl = 0;
       +        start = q0;
                while(q0 < q1){
                        if(i == nbuf){
                                nbuf = q1-q0;
       t@@ -678,24 +679,44 @@ nlcount(Text *t, long q0, long q1)
                                bufread(&t->file->b, q0, buf, nbuf);
                                i = 0;
                        }
       -                if(buf[i++] == '\n')
       +                if(buf[i++] == '\n') {
       +                        start = q0+1;
                                nl++;
       +                }
                        q0++;
                }
                fbuffree(buf);
       +        if(pnr != nil)
       +                *pnr = q0 - start;
                return nl;
        }
        
       +enum {
       +        PosnLine = 0,
       +        PosnChars = 1,
       +        PosnLineChars = 2,
       +};
       +
        void
       -printposn(Text *t, int charsonly)
       +printposn(Text *t, int mode)
        {
       -        long l1, l2;
       +        long l1, l2, r1, r2;
        
                if (t != nil && t->file != nil && t->file->name != nil)
                        warning(nil, "%.*S:", t->file->nname, t->file->name);
       -        if(!charsonly){
       -                l1 = 1+nlcount(t, 0, addr.r.q0);
       -                l2 = l1+nlcount(t, addr.r.q0, addr.r.q1);
       +        
       +        switch(mode) {
       +        case PosnChars:
       +                warning(nil, "#%d", addr.r.q0);
       +                if(addr.r.q1 != addr.r.q0)
       +                        warning(nil, ",#%d", addr.r.q1);
       +                warning(nil, "\n");
       +                return;
       +        
       +        default:
       +        case PosnLine:
       +                l1 = 1+nlcount(t, 0, addr.r.q0, nil);
       +                l2 = l1+nlcount(t, addr.r.q0, addr.r.q1, nil);
                        /* check if addr ends with '\n' */
                        if(addr.r.q1>0 && addr.r.q1>addr.r.q0 && textreadc(t, addr.r.q1-1)=='\n')
                                --l2;
       t@@ -704,32 +725,43 @@ printposn(Text *t, int charsonly)
                                warning(nil, ",%lud", l2);
                        warning(nil, "\n");
                        return;
       +
       +        case PosnLineChars:
       +                l1 = 1+nlcount(t, 0, addr.r.q0, &r1);
       +                l2 = l1+nlcount(t, addr.r.q0, addr.r.q1, &r2);
       +                if(l2 == l1)
       +                        r2 += r1;
       +                warning(nil, "%lud+#%d", l1, r1);
       +                if(l2 != l1)
       +                        warning(nil, ",%lud+#%d", l2, r2);
       +                warning(nil, "\n");
       +                return;
                }
       -        warning(nil, "#%d", addr.r.q0);
       -        if(addr.r.q1 != addr.r.q0)
       -                warning(nil, ",#%d", addr.r.q1);
       -        warning(nil, "\n");
        }
        
        int
        eq_cmd(Text *t, Cmd *cp)
        {
       -        int charsonly;
       +        int mode;
        
                switch(cp->u.text->n){
                case 0:
       -                charsonly = FALSE;
       +                mode = PosnLine;
                        break;
                case 1:
                        if(cp->u.text->r[0] == '#'){
       -                        charsonly = TRUE;
       +                        mode = PosnChars;
       +                        break;
       +                }
       +                if(cp->u.text->r[0] == '+'){
       +                        mode = PosnLineChars;
                                break;
                        }
                default:
       -                SET(charsonly);
       +                SET(mode);
                        editerror("newline expected");
                }
       -        printposn(t, charsonly);
       +        printposn(t, mode);
                return TRUE;
        }
        
   DIR diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
       t@@ -573,15 +573,27 @@ zeroxx(Text *et, Text *t, Text *_1, int _2, int _3, Rune *_4, int _5)
                        winunlock(t->w);
        }
        
       +typedef struct TextAddr TextAddr;
       +struct TextAddr {
       +        long lorigin; // line+rune for origin
       +        long rorigin;
       +        long lq0; // line+rune for q0
       +        long rq0;
       +        long lq1; // line+rune for q1
       +        long rq1;
       +};
       +
        void
        get(Text *et, Text *t, Text *argt, int flag1, int _0, Rune *arg, int narg)
        {
                char *name;
                Rune *r;
                int i, n, dirty, samename, isdir;
       +        TextAddr *addr, *a;
                Window *w;
                Text *u;
                Dir *d;
       +        long q0, q1;
        
                USED(_0);
        
       t@@ -606,6 +618,14 @@ get(Text *et, Text *t, Text *argt, int flag1, int _0, Rune *arg, int narg)
                                return;
                        }
                }
       +        addr = emalloc((t->file->ntext)*sizeof(TextAddr));
       +        for(i=0; i<t->file->ntext; i++) {
       +                a = &addr[i];
       +                u = t->file->text[i];
       +                a->lorigin = nlcount(u, 0, u->org, &a->rorigin);
       +                a->lq0 = nlcount(u, 0, u->q0, &a->rq0);
       +                a->lq1 = nlcount(u, u->q0, u->q1, &a->rq1);
       +        }
                r = bytetorune(name, &n);
                for(i=0; i<t->file->ntext; i++){
                        u = t->file->text[i];
       t@@ -631,8 +651,18 @@ get(Text *et, Text *t, Text *argt, int flag1, int _0, Rune *arg, int narg)
                for(i=0; i<t->file->ntext; i++){
                        u = t->file->text[i];
                        textsetselect(&u->w->tag, u->w->tag.file->b.nc, u->w->tag.file->b.nc);
       +                if(samename) {
       +                        a = &addr[i];
       +                        // warning(nil, "%d %d %d %d %d %d\n", a->lorigin, a->rorigin, a->lq0, a->rq0, a->lq1, a->rq1);
       +                        q0 = nlcounttopos(u, 0, a->lq0, a->rq0);
       +                        q1 = nlcounttopos(u, q0, a->lq1, a->rq1);
       +                        textsetselect(u, q0, q1);
       +                        q0 = nlcounttopos(u, 0, a->lorigin, a->rorigin);
       +                        textsetorigin(u, q0, FALSE);
       +                }
                        textscrdraw(u);
                }
       +        free(addr);
                xfidlog(w, "get");
        }
        
   DIR diff --git a/src/cmd/acme/fns.h b/src/cmd/acme/fns.h
       t@@ -93,6 +93,8 @@ Rune*        findbl(Rune*, int, int*);
        char*        edittext(Window*, int, Rune*, int);
        void                flushwarnings(void);
        void                startplumbing(void);
       +long        nlcount(Text*, long, long, long*);
       +long        nlcounttopos(Text*, long, long, long);
        
        Runestr        runestr(Rune*, uint);
        Range range(int, int);
   DIR diff --git a/src/cmd/acme/text.c b/src/cmd/acme/text.c
       t@@ -1615,7 +1615,7 @@ textsetorigin(Text *t, uint org, int exact)
                Rune *r;
                uint n;
        
       -        if(org>0 && !exact){
       +        if(org>0 && !exact && textreadc(t, org-1) != '\n'){
                        /* org is an estimate of the char posn; find a newline */
                        /* don't try harder than 256 chars */
                        for(i=0; i<256 && org<t->file->b.nc; i++){