shithub: aplenty

Download patch

ref: 4dcc894ba6700ac9ade6a46b64334a1a59784229
author: B. Wilson <x@wilsonb.com>
date: Tue Jul 15 08:08:00 EDT 2025

Initial proof-of-concept

--- /dev/null
+++ b/aplenty.c
@@ -1,0 +1,227 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <bio.h>
+#include <json.h>
+#include <regexp.h>
+
+int debug;
+vlong caddr;
+
+void
+handlerideevents(int in, int out, int text){
+	Biobuf *bin;
+	char *b, k;   /* event buffer, kind */
+	long t, n, o; /*       type, length, offset */
+
+	bin = Bfdopen(in, OREAD);
+	while(b = Brdline(bin, '\n')){
+		Bseek(bin, Blinelen(bin), 1);
+		k = b[0]; b++;
+		t = atol(strtok(b, " \n"));
+		n = atol(strtok(nil, " \n"));
+		o = atol(strtok(nil, " \n"));
+		b = malloc(n);
+		seek(text, o, 0);
+		readn(text, b, n);
+		if(debug > 1)
+			fprintf(stderr, "ride: %c %ld %ld %ld\n", k, t, n, o);
+
+		if(strchr("po", k))
+			write(out, b, n);
+
+		free(b);
+	}
+}
+
+void
+handlerootevents(int wid, int in, int out){
+	Biobuf *bin, *bxdata, *btag;
+	int fdctl, fdevent, fdaddr, fdbody;
+	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];
+	int i;
+
+	/* 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);
+	bin     = Bfdopen(in, OREAD);
+	rerrstr(s, sizeof(s));
+	if(s[0] != 0)
+		exits(s);
+
+	/* initial prompt not setup by ride */
+	write(fdbody, "      ", 6);
+	write(fdaddr, "$", 1);
+	fprint(fdctl, "dot=addr");
+
+	/* event handle loop: cf acme(4):/event */
+	r = malloc((2+4*12 + 256)*sizeof(*r));
+	while((o = Bgetc(bin)) != EOF){
+		t = Bgetc(bin);
+		n = atol(Brdline(bin, ' '));
+		m = atol(Brdline(bin, ' '));
+		f = atol(Brdline(bin, ' '));
+		l = atol(Brdline(bin, ' '));
+		for(i = 0; i < l+1; i++) /* trailing LF not counted by l */
+			Bgetrune(bin);
+		if(debug > 1)
+			fprintf(stderr, "acme: %c%c%ld %ld %ld %ld\n", o, t, n , m, f, l);
+
+		/* Ride-triggered edits */
+		if(o == 'E'){
+			seek(fdaddr, 0, 0);
+			write(fdaddr, "$", 1);
+			read(fdaddr, s, 12);
+			n = atol(strtok(s, " "));
+			caddr = n;
+			continue;
+		}
+
+		/* trailing text may be elided; read canonical source */
+		if(!strchr("Dd", t)){
+			fprint(fdaddr, "#%ld,#%ld", n, m);
+			if(strchr("ILX", t)){
+				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);
+			}
+			r[i] = t == 'X' ? '\n' : 0;
+	
+			/* XXX: Only execute first line if multiline input */
+			if(t == 'I' && n >= caddr || t == 'X'){
+				fprint(fdaddr, "#%lld,$", caddr);
+				bxdata  = Bopen("xdata", OREAD);
+				ln = Brdline(bxdata, '\n');
+				if(ln) write(out, ln, Blinelen(bxdata));
+				Bterm(bxdata);
+			}
+		}
+
+		if(strchr("ID", t))
+		if((t == 'D') + m < caddr)
+			caddr += t == 'D' ? n-m : m-n;
+
+		if(f%2 == 0 && strchr("Lidlx", t))
+			fprint(fdevent, "%c%c%ld %ld\n", o, t, n, m);
+	}
+}
+
+char*
+errmsg(char *err){
+	if(err == nil){
+		err = malloc(ERRMAX);
+		rerrstr(err, ERRMAX);
+	}
+	fprintf(stderr, "%s\n", err);
+	return err;
+}
+
+void
+usage(void){
+	fprintf(stderr, "Usage: %s [-d] addr\n", argv0);
+}
+
+void
+main(int argc, char **argv){
+	char *err, *addr, b[256], p[256];
+	int rid, rctl, rin, rout, rtext; /* ride */
+	int wid, wctl, win, wout; /* root window */
+
+	if(argc < 1){
+		usage();
+		exits("requires address argument");
+	}
+
+	ARGBEGIN{
+	case 'd': debug++; break;
+	case 'h': usage(); exits(nil);
+	}ARGEND
+
+	if(argc == 0)
+		addr = getenv("rideaddr");
+	else
+		addr = argv[0];
+	if(addr == nil){
+		usage();
+		exits(errmsg("no ride address"));
+	}
+
+	err = nil;
+
+	/* new ride connection */
+	if((rctl = open("/mnt/ride/clone", ORDWR)) < 0)
+		exits(errmsg(err));
+	sprintf(b, "connect %s\n", addr);
+	write(rctl, b, strlen(b));
+
+	/* connection id */
+	seek(rctl, 0, 0);
+	read(rctl, b, sizeof(b));
+	sprintf(p, "\n");
+	rid = atoi(strtok(b, p));
+
+	/* establish connection */
+	snprintf(p, sizeof(p), "/mnt/ride/%i/text", rid);
+	if((rout = open(p, OWRITE)) < 0)
+		exits(errmsg(err));
+	if((rtext = open(p, OREAD)) < 0)
+		exits(errmsg(err));
+
+	/* ride i/o files */
+	snprintf(p, sizeof(p), "/mnt/ride/%i/event", rid);
+	if((rin = open(p, OREAD)) < 0)
+		exits(errmsg(err));
+
+	/* new acme window */
+	if((wctl = open("/mnt/acme/new/ctl", OREAD)) < 0)
+		exits(errmsg(err));
+	readn(wctl, b, 12);
+	wid = atoi(strtok(b, " "));
+
+	/* window i/o files */
+	snprintf(p, sizeof(p), "/mnt/acme/%i/event", wid);
+	if((win = open(p, OREAD)) < 0)
+		exits(errmsg(err));
+	snprintf(p, sizeof(p), "/mnt/acme/%i/body", wid);
+	if((wout = open(p, OWRITE)) < 0)
+		exits(errmsg(err));
+
+	JSONfmtinstall();
+
+	rfork(RFNOTEG);
+
+	switch(rfork(RFPROC|RFMEM)){
+	case -1: err = "unable to start ride message handler"; break;
+	case 0:
+		handlerideevents(rin, wout, rtext);
+		exits(nil);
+	default: break;
+	}
+
+	switch(rfork(RFPROC|RFMEM)){
+	case -1: err = "unable to start root window event handler"; break;
+	case 0:
+		handlerootevents(wid, win, rout);
+		exits(nil);
+	default: break;
+	}
+
+	wait();
+	postnote(PNGROUP, getpid(), "exit");
+
+	exits(errmsg(err));
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=aplenty
+OFILES=aplenty.$O
+
+</sys/src/cmd/mkone
\ No newline at end of file
--