ref: 82e4bed4981039799aae9c21dcc8f07d3aa3dde5
parent: 666191d45413d79a7a462998ebfd300e12af6f13
author: B. Wilson <x@wilsonb.com>
date: Sat Jul 19 10:46:33 EDT 2025
Support multi-line execute and paste
--- a/aplenty.c
+++ b/aplenty.c
@@ -6,16 +6,28 @@
#include <regexp.h>
QLock lwin;
+vlong iaddr[256]; /* input line addresses */
+int fndx, lndx; /* first, last indices */
+#define NXT(i) ((i+1) % sizeof(iaddr))
+
char *rdir;
-vlong caddr;
int debug;
void
-hevride(int in, int ev, int out, int addr){
+hride(int in, int ev, int out, int addr){
Biobuf *bev;
- char *b, s[32], k; /* event buffer, kind */
- long t, n, o; /* type, length, offset */
+ char k, *b, *d; /* event kind, buffer, data */
+ long t, n, o; /* type, length, offset */
+ int i;
+ /* Session I/O is line-oriented and sequential. The event response chain
+ * to an execute request happens in the following order:
+ *
+ * 1. k == 'o' && t == 14: Input line echo;
+ * 2. k == 'p' && t != 1: Result start, if applicable;
+ * 3. k == 'o' && t != 14: Result output, if applicable;
+ * 4. k == 'p' && t == 1: Begin new input line.
+ */
bev = Bfdopen(ev, OREAD);
while(b = Brdline(bev, '\n')){
Bseek(bev, Blinelen(bev), 1);
@@ -24,65 +36,68 @@
n = atol(strtok(nil, " \n"));
o = atol(b = strtok(nil, " \n"));
for(; *b != '\0'; b++); b++;
+ d = malloc(n);
+ switch(k){
+ case 'p': memmove(d, b, n); break; /* prompt */
+ case 'o': pread(in, d, n, o); break; /* output */
+ }
+
+ qlock(&lwin); /* window resources shared */
if(debug)
fprintf(stderr, "ride: %c %ld %ld %ld\n", k, t, n, o);
- qlock(&lwin);
+ /* Usual prompt signals start of new I/O round */
+ if(k == 'p' && t == 1)
+ fndx = fndx == lndx ? fndx : NXT(fndx);
- if(k == 'p'){
- fprint(addr, "#%lld,$", caddr);
- write(out, b, n);
- }
+ /* Target address range */
+ fprint(addr, "#%lld", iaddr[fndx]);
+ if(k == 'o' && t == 14)
+ fprint(addr, ".,.-+");
- if(k == 'o'){
- b = malloc(n);
- pread(in, b, n, o);
- if(t == 14)
- fprint(addr, "#%lld,$", caddr);
- else
- fprint(addr, "$");
- write(out, b, n);
- free(b);
- }
+ /* Write response data */
+ write(out, d, n);
- write(addr, "$-/^/", 5);
- pread(addr, s, 12, 0);
- caddr = atol(strtok(s, " "));
+ /* Update input addresses */
+ o = iaddr[NXT(fndx)] - iaddr[fndx];
+ if(k == 'o') iaddr[fndx] += n = utfnlen(d, n);
+ for(i = NXT(fndx); i != NXT(lndx); i = NXT(i))
+ iaddr[i] += n - o;
+ free(d);
qunlock(&lwin);
}
}
void
-hevroot(int wid, int in, int out){
- Biobuf *bin, *bxdata, *btag;
- int fdctl, fdevent, fdaddr, fdbody;
+hsession(int wid, int in, int out){
+ Biobuf *bin;
+ int fdctl, fdaddr, fddata, fdxdata, fdevent;
char o, t; /* event origin, type */
long n, m, f, l; /* addr n, addr m, flag, len */
- Rune *r; /* runes */
- long c;
- char *ln, s[256];
+ char *b; /* buffer */
+ char *ln, *e, s[256];
int i;
- /* setup files */
+ /* Setup files */
snprintf(s, sizeof(s), "/mnt/acme/%i", wid);
chdir(s);
fdctl = open("ctl", OWRITE);
- fdevent = open("event", OWRITE);
fdaddr = open("addr", ORDWR);
- fdbody = open("body", OWRITE);
+ fddata = open("data", OWRITE);
+ fdxdata = open("xdata", OREAD);
+ fdevent = open("event", OWRITE);
bin = Bfdopen(in, OREAD);
rerrstr(s, sizeof(s));
if(s[0] != 0)
exits(s);
- /* initial prompt not setup by ride */
- fprint(fdctl, "name %s/-aplenty\n", rdir);
- fprint(fdbody, " ");
- caddr = 0;
+ /* Initialize window */
+ fprint(fdctl, "name %s/-%s\n", rdir, argv0);
+ fprint(fddata, " "); /* first prompt not written by ride */
- /* event handle loop: cf acme(4):/event */
- r = malloc((2+4*12 + 256)*sizeof(*r));
+ /* Event handle loop: cf acme(4):/event */
+ iaddr[0] = 0; fndx = lndx = 0;
while((o = Bgetc(bin)) != EOF){
t = Bgetc(bin);
n = atol(Brdline(bin, ' '));
@@ -91,49 +106,57 @@
l = atol(Brdline(bin, ' '));
for(i = 0; i < l+1; i++) /* trailing LF not counted by l */
Bgetrune(bin);
+
+ /* Ignore self-triggered edits */
+ if(strchr("F", o))
+ continue;
+
+ qlock(&lwin); /* window resources shared */
if(debug)
fprintf(stderr, "acme: %c%c%ld %ld %ld %ld\n", o, t, n , m, f, l);
- qlock(&lwin);
-
- /* trailing event text may be elided; read canonical source */
- if(!strchr("Dd", t)){
- if(strchr("ILX", t)){
- fprint(fdaddr, "#%ld,#%ld", n, m);
- bxdata = Bopen("xdata", OREAD);
- for(i = 0, c = Bgetrune(bxdata); c >= 0; i++, c = Bgetrune(bxdata))
- r[i] = c;
- Bterm(bxdata);
- } else if(strchr("ilx", t)) {
- btag = Bopen("tag", OREAD);
- for(i = 0, c = Bgetrune(btag); c >= 0; i++, c = Bgetrune(btag))
- r[i] = c;
- Bterm(btag);
- }
+ /* Find executable input */
+ b = nil;
+ if(t == 'I' && n >= iaddr[lndx] || t == 'X'){
+ if(t == 'I') n = iaddr[lndx];
+ fprint(fdaddr, "#%ld,#%ld", n, m);
+ l = UTFmax*(m - n); /* n, m count runes */
+ b = malloc(l+1);
+ l = read(fdxdata, b, l);
+ b[l] = '\0';
}
- /* Ride-triggered edits */
- if(strchr("EF", o))
- goto end;
+ /* Execute target lines */
+ if(b){
+ for(i = lndx, ln = b; e = strchr(ln, '\n'); i = NXT(i), ln += l){
+ l = 1 + e-ln;
- /* XXX: Only execute first line if multiline input */
- if(t == 'I' && n >= caddr || t == 'X'){
- fprint(fdaddr, "#%lld,#%ld", caddr, m);
- bxdata = Bopen("xdata", OREAD);
- ln = Brdline(bxdata, '\n');
- if(ln)
- write(out, ln, Blinelen(bxdata));
- Bterm(bxdata);
+ fprint(fdaddr, "#%ld,#%ld-+", n, n);
+ write(out, ln, l);
+
+ pread(fdaddr, s, 24, 0);
+ n = atol(strtok(s, " "));
+ m = atol(strtok(nil, " "));
+ iaddr[i] = t == 'X' ? iaddr[lndx] : n;
+ n = m;
+
+ lndx = i;
+ if(NXT(i) == fndx) break; /* XXX: excess lines simply ignored */
+ }
+
+ free(b);
}
+ /* Update input addresses */
if(strchr("ID", t))
- if((t == 'D') + m < caddr)
- caddr += t == 'D' ? n-m : m-n;
+ for(i = fndx; i != NXT(lndx); i = NXT(i))
+ if(n < iaddr[i])
+ iaddr[i] += t == 'D' ? n-m : m-n;
+ /* Let acme handle non-repl events */
if(f%2 == 0 && strchr("Lidlx", t))
fprint(fdevent, "%c%c%ld %ld\n", o, t, n, m);
- end:
qunlock(&lwin);
}
}
@@ -188,7 +211,7 @@
/* new acme window */
if((wctl = open("/mnt/acme/new/ctl", OREAD)) < 0)
exits(errmsg(err));
- readn(wctl, b, 12);
+ pread(wctl, b, 12, 0);
wid = atoi(strtok(b, " "));
JSONfmtinstall();
@@ -195,7 +218,7 @@
rfork(RFNOTEG);
switch(rfork(RFPROC|RFMEM)){
- case -1: err = "unable to start ride message handler"; break;
+ case -1: err = "unable to start ride event handler"; break;
case 0:
snprintf(p, sizeof(p), "/mnt/ride/%i/text", rid);
rin = open(p, OREAD); /* establishes connection */
@@ -206,13 +229,13 @@
snprintf(p, sizeof(p), "/mnt/acme/%i/addr", wid);
waddr = open(p, ORDWR);
- hevride(rin, revent, wout, waddr);
+ hride(rin, revent, wout, waddr);
exits(nil);
default: break;
}
switch(rfork(RFPROC|RFMEM)){
- case -1: err = "unable to start root window event handler"; break;
+ case -1: err = "unable to start session window event handler"; break;
case 0:
snprintf(p, sizeof(p), "/mnt/acme/%i/event", wid);
win = open(p, OREAD);
@@ -219,10 +242,12 @@
snprintf(p, sizeof(p), "/mnt/ride/%i/text", rid);
rout = open(p, OWRITE);
- hevroot(wid, win, rout);
+ hsession(wid, win, rout);
exits(nil);
default: break;
}
+
+ print("%d\n", wid);
wait();
postnote(PNGROUP, getpid(), "exit");
--
⑨