summaryrefslogtreecommitdiff
path: root/sys/src/cmd/acme
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2020-09-22 11:42:15 -0700
committerOri Bernstein <ori@eigenstate.org>2020-09-22 11:42:15 -0700
commit313aebb96478c37be8f39754875c02dcb3f896cc (patch)
tree880c9ba449631562b136135e3e9a7e6169d178f6 /sys/src/cmd/acme
parentc1c904776c1536e854c5c1717a104353f885c3cd (diff)
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
Diffstat (limited to 'sys/src/cmd/acme')
-rw-r--r--sys/src/cmd/acme/acme.c19
-rw-r--r--sys/src/cmd/acme/addr.c21
-rw-r--r--sys/src/cmd/acme/cols.c8
-rw-r--r--sys/src/cmd/acme/ecmd.c90
-rw-r--r--sys/src/cmd/acme/exec.c30
-rw-r--r--sys/src/cmd/acme/fns.h2
-rw-r--r--sys/src/cmd/acme/rows.c21
-rw-r--r--sys/src/cmd/acme/scrl.c4
-rw-r--r--sys/src/cmd/acme/text.c2
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; i<c->nw; 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; i<loopstruct.nw; i++)
- cmdexec(&loopstruct.w[i]->body, 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; i<loopstruct.nw; i++){
+ targ = &loopstruct.w[i]->body;
+ 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; 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];
@@ -562,8 +582,18 @@ get(Text *et, Text *t, Text *argt, int flag1, int, 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->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(n<m && r[n]!='\n')
- n++;
- r[n++] = '\n';
- Bprint(b, "%.*S", n, r);
+ while(n<m) {
+ start = n;
+ while(n<m && r[n]!='\n')
+ n++;
+ Bprint(b, "%.*S", n-start, r+start);
+ if(n<m) {
+ Bputc(b, 0xff); // \n in tag becomes 0xff byte (invalid UTF)
+ n++;
+ }
+ }
+ Bprint(b, "\n");
if(dumped){
q0 = 0;
q1 = t->file->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; n<nr; n++){
diff --git a/sys/src/cmd/acme/scrl.c b/sys/src/cmd/acme/scrl.c
index 1310bc763..0d4173968 100644
--- a/sys/src/cmd/acme/scrl.c
+++ b/sys/src/cmd/acme/scrl.c
@@ -132,7 +132,7 @@ textscroll(Text *t, int but)
readmouse(mousectl);
continue;
}
- if(but == 1)
+ if(but == 1 || but == 4)
p0 = textbacknl(t, t->org, (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 && org<t->file->nc; i++){