From 313aebb96478c37be8f39754875c02dcb3f896cc Mon Sep 17 00:00:00 2001 From: Ori Bernstein Date: Tue, 22 Sep 2020 11:42:15 -0700 Subject: [PATCH] acme: import changes from plan9port (thanks jxy) Import the following improvements and bugfixes from plan9port: 4650064a acme: scale window bodies on resize, not including tag space d28913a9 acme: save/restore multiline tags in Dump/Load d2df5d6c acme: fix crash in X |cat with multiple windows 3d6e5cb5 acme: preserve window position and selection during Get --- sys/src/cmd/acme/acme.c | 19 +++------ sys/src/cmd/acme/addr.c | 21 ++++++++++ sys/src/cmd/acme/cols.c | 8 ++-- sys/src/cmd/acme/ecmd.c | 90 ++++++++++++++++++++++++++++++----------- sys/src/cmd/acme/exec.c | 30 ++++++++++++++ sys/src/cmd/acme/fns.h | 2 + sys/src/cmd/acme/rows.c | 21 +++++++--- sys/src/cmd/acme/scrl.c | 4 +- sys/src/cmd/acme/text.c | 2 +- 9 files changed, 150 insertions(+), 47 deletions(-) diff --git a/sys/src/cmd/acme/acme.c b/sys/src/cmd/acme/acme.c index e874d3554..96a7d6b03 100644 --- a/sys/src/cmd/acme/acme.c +++ b/sys/src/cmd/acme/acme.c @@ -513,8 +513,13 @@ mousethread(void *) but = 2; else if(m.buttons == 4) but = 3; + else if(m.buttons == 8) + but = 4; + else if(m.buttons == 16) + but = 5; barttext = t; - if(t->what==Body && ptinrect(m.xy, t->scrollr)){ + if(t->what==Body && w != nil + && (ptinrect(m.xy, t->scrollr) || (m.buttons & (8|16)))){ if(but){ winlock(w, 'M'); t->eq0 = ~0; @@ -523,18 +528,6 @@ mousethread(void *) } goto Continue; } - /* scroll buttons, wheels, etc. */ - if(t->what==Body && w != nil && (m.buttons & (8|16))){ - if(m.buttons & 8) - but = Kscrolloneup; - else - but = Kscrollonedown; - winlock(w, 'M'); - t->eq0 = ~0; - texttype(t, but); - winunlock(w); - goto Continue; - } if(ptinrect(m.xy, t->scrollr)){ if(but){ if(t->what == Columntag) diff --git a/sys/src/cmd/acme/addr.c b/sys/src/cmd/acme/addr.c index 94dd88cde..0637fab64 100644 --- a/sys/src/cmd/acme/addr.c +++ b/sys/src/cmd/acme/addr.c @@ -48,6 +48,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->nc) { + if(textreadc(t, q0++) == '\n') + nl--; + } + if(nl > 0) + return q0; + while(nr > 0 && q0 < t->file->nc && textreadc(t, q0) != '\n') { + q0++; + nr--; + } + return q0; +} + Range number(Mntdir *md, Text *t, Range r, int line, int dir, int size, int *evalp) { diff --git a/sys/src/cmd/acme/cols.c b/sys/src/cmd/acme/cols.c index 6beb2edb0..7ac1e1500 100644 --- a/sys/src/cmd/acme/cols.c +++ b/sys/src/cmd/acme/cols.c @@ -186,7 +186,7 @@ colmousebut(Column *c) void colresize(Column *c, Rectangle r) { - int i; + int i, old, new; Rectangle r1, r2; Window *w; @@ -199,6 +199,8 @@ colresize(Column *c, Rectangle r) r1.max.y += Border; draw(screen, r1, display->black, nil, ZP); r1.max.y = r.max.y; + new = Dy(r) - c->nw*(Border + font->height); + old = Dy(c->r) - c->nw*(Border + font->height); for(i=0; inw; i++){ w = c->w[i]; w->maxlines = 0; @@ -206,8 +208,8 @@ colresize(Column *c, Rectangle r) r1.max.y = r.max.y; else { r1.max.y = r1.min.y; - if(Dy(c->r) != 0) - r1.max.y += (Dy(w->r)+Border)*Dy(r)/Dy(c->r); + if(new > 0 && old > 0 && Dy(w->r) > Border+font->height) + r1.max.y += (Dy(w->r)-Border-font->height)*new/old + Border + font->height; } r2 = r1; r2.max.y = r2.min.y+Border; diff --git a/sys/src/cmd/acme/ecmd.c b/sys/src/cmd/acme/ecmd.c index f0266c942..06d09f38b 100644 --- a/sys/src/cmd/acme/ecmd.c +++ b/sys/src/cmd/acme/ecmd.c @@ -27,7 +27,7 @@ int append(File*, Cmd*, long); int pdisplay(File*); void pfilename(File*); void looper(File*, Cmd*, int); -void filelooper(Cmd*, int); +void filelooper(Text*, Cmd*, int); void linelooper(File*, Cmd*); Address lineaddr(long, Address, int); int filematch(File*, String*); @@ -575,9 +575,9 @@ x_cmd(Text *t, Cmd *cp) } int -X_cmd(Text*, Cmd *cp) +X_cmd(Text *t, Cmd *cp) { - filelooper(cp, cp->cmdc=='X'); + filelooper(t, cp, cp->cmdc=='X'); return TRUE; } @@ -636,15 +636,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; @@ -653,24 +654,42 @@ nlcount(Text *t, long q0, long q1) bufread(t->file, 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; @@ -679,32 +698,42 @@ 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+#%lud", l1, r1); + if(l2 != l1) + warning(nil, ",%lud+#%lud", 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->text->n){ case 0: - charsonly = FALSE; + mode = PosnLine; break; case 1: if(cp->text->r[0] == '#'){ - charsonly = TRUE; + mode = PosnChars; + break; + } + if(cp->text->r[0] == '+'){ + mode = PosnLineChars; break; } default: - SET(charsonly); + SET(mode); editerror("newline expected"); } - printposn(t, charsonly); + printposn(t, mode); return TRUE; } @@ -921,9 +950,10 @@ alllocker(Window *w, void *v) } void -filelooper(Cmd *cp, int XY) +filelooper(Text *t, Cmd *cp, int XY) { int i; + Text *targ; if(Glooping++) editerror("can't nest %c command", "YX"[XY]); @@ -944,8 +974,22 @@ filelooper(Cmd *cp, int XY) */ allwindows(alllocker, (void*)1); globalincref = 1; - for(i=0; ibody, cp->cmd); + /* + * Unlock the window running the X command. + * We'll need to lock and unlock each target window in turn. + */ + if(t && t->w) + winunlock(t->w); + for(i=0; ibody; + if(targ && targ->w) + winlock(targ->w, cp->cmdc); + cmdexec(targ, cp->cmd); + if(targ && targ->w) + winunlock(targ->w); + } + if(t && t->w) + winlock(t->w, cp->cmdc); allwindows(alllocker, (void*)0); globalincref = 0; free(loopstruct.w); diff --git a/sys/src/cmd/acme/exec.c b/sys/src/cmd/acme/exec.c index 7011ad7b3..cff114312 100644 --- a/sys/src/cmd/acme/exec.c +++ b/sys/src/cmd/acme/exec.c @@ -506,15 +506,27 @@ zeroxx(Text *et, Text *t, Text*, int, int, Rune*, int) 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, 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; if(flag1) if(et==nil || et->w==nil) @@ -537,6 +549,14 @@ get(Text *et, Text *t, Text *argt, int flag1, int, Rune *arg, int narg) return; } } + addr = emalloc((t->file->ntext)*sizeof(TextAddr)); + for(i=0; ifile->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; ifile->ntext; i++){ u = t->file->text[i]; @@ -562,8 +582,18 @@ get(Text *et, Text *t, Text *argt, int flag1, int, Rune *arg, int narg) for(i=0; ifile->ntext; i++){ u = t->file->text[i]; textsetselect(&u->w->tag, u->w->tag.file->nc, u->w->tag.file->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"); } diff --git a/sys/src/cmd/acme/fns.h b/sys/src/cmd/acme/fns.h index 5b5b7ac21..02cc06da8 100644 --- a/sys/src/cmd/acme/fns.h +++ b/sys/src/cmd/acme/fns.h @@ -88,6 +88,8 @@ Rune* skipbl(Rune*, int, int*); Rune* findbl(Rune*, int, int*); char* edittext(Window*, int, Rune*, int); void flushwarnings(void); +long nlcount(Text*, long, long, long*); +long nlcounttopos(Text*, long, long, long); #define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune)) #define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune)) diff --git a/sys/src/cmd/acme/rows.c b/sys/src/cmd/acme/rows.c index 172dfaa99..9c2b64000 100644 --- a/sys/src/cmd/acme/rows.c +++ b/sys/src/cmd/acme/rows.c @@ -293,7 +293,7 @@ rowclean(Row *row) void rowdump(Row *row, char *file) { - int i, j, fd, m, n, dumped; + int i, j, fd, m, n, start, dumped; uint q0, q1; Biobuf *b; char *buf, *a, *fontname; @@ -396,10 +396,17 @@ rowdump(Row *row, char *file) m = min(RBUFSIZE, w->tag.file->nc); bufread(w->tag.file, 0, r, m); n = 0; - while(nfile->nc; @@ -639,6 +646,10 @@ rowload(Row *row, char *file, int initing) if(l == nil) goto Rescue2; l[Blinelen(b)-1] = 0; + /* convert 0xff in multiline tag back to \n */ + for(i=0; l[i]!=0; i++) + if((uchar)l[i] == 0xff) + l[i] = '\n'; r = bytetorune(l+5*12, &nr); ns = -1; for(n=0; norg, (my-s.min.y)/t->font->height); else p0 = t->org+frcharofpt(t, Pt(s.max.x, my)); @@ -140,7 +140,7 @@ textscroll(Text *t, int but) textsetorigin(t, p0, TRUE); oldp0 = p0; /* debounce */ - if(first){ + if(first && but < 4){ flushimage(display, 1); sleep(200); nbrecv(mousectl->c, &mousectl->Mouse); diff --git a/sys/src/cmd/acme/text.c b/sys/src/cmd/acme/text.c index ebbc5dcfd..484ec3de1 100644 --- a/sys/src/cmd/acme/text.c +++ b/sys/src/cmd/acme/text.c @@ -1411,7 +1411,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 && orgfile->nc; i++){