shithub: pplay

Download patch

ref: 951fd81dd334fa33718bf7699cf1c6faed289c48
parent: faa5d55642c8bbd26151561eef13b6525f786154
author: qwx <qwx@sciops.net>
date: Sun Jan 1 14:07:15 EST 2023

tentative undo implementation and fix cut/paste not snarfing

--- a/chunk.c
+++ b/chunk.c
@@ -12,22 +12,61 @@
 };
 static Chunk *norris;
 
+int
+Δfmt(Fmt *fmt)
+{
+	Dot *d;
+
+	d = va_arg(fmt->args, Dot*);
+	if(d == nil)
+		return fmtstrcpy(fmt, "[??:??:??]");
+	return fmtprint(fmt, "[from=%08zux cur=%08zux to=%08zux]",
+		d->from, d->pos, d->to);
+}
+
+int
+χfmt(Fmt *fmt)
+{
+	Chunk *c;
+
+	c = va_arg(fmt->args, Chunk*);
+	if(c == nil)
+		return fmtstrcpy(fmt, "[]");
+	return fmtprint(fmt, "0x%08p:%08zux::0x%08p:0x%08p", c, c->len, c->left, c->right);
+}
+
 static void
 printchunks(Chunk *r)
 {
+	usize len;
 	Chunk *c;
 
-	fprint(2, "chunklist dot %zux %zux %zux: ", 
-		dot.from.pos, dot.pos, dot.to.pos);
 	c = r;
+	len = 0;
 	do{
-		fprint(2, "[%#p:%zd:←%#p→%#p] ", c, c->len, c->left, c->right);
+		fprint(2, "\t%χ\toff=%08zux\n", c, len);
 		assert(c->right->left == c);
+		len += c->len;
 		c = c->right;
 	}while(c != r);
 	fprint(2, "\n");
 }
 
+void
+dprint(Chunk *c, char *fmt, ...)
+{
+	char s[256];
+	va_list arg;
+
+	if(!debug)
+		return;
+	va_start(arg, fmt);
+	vseprint(s, s+sizeof s, fmt, arg);
+	va_end(arg);
+	fprint(2, "%s", s);
+	printchunks(c == nil ? norris : c);
+}
+
 static Chunk *
 newchunk(Buf *b)
 {
@@ -172,8 +211,8 @@
 {
 	Chunk *left, *right;
 
-	left = p2c(dot.from.pos, off);
-	right = p2c(dot.to.pos, nil);
+	left = p2c(dot.from, off);
+	right = p2c(dot.to, nil);
 	if(left == right)
 		return left;
 	while(left->right != right)
@@ -182,15 +221,25 @@
 }
 #endif
 
+usize
+chunklen(Chunk *c)
+{
+	usize n;
+	Chunk *cp;
+
+	for(cp=c, n=cp->len, cp=cp->right; cp!=c; cp=cp->right)
+		n += cp->len;
+	return n;
+}
+
 Chunk *
 p2c(usize p, usize *off)
 {
-	int x;
 	Chunk *c;
 
-	for(c=norris, x=0; p>=c->len; c=c->right){
-		if(c == norris && ++x > 1){
-			c = norris->left;
+	for(c=norris; p>=c->len; c=c->right){
+		if(c == norris->left){
+			assert(p == c->len);
 			break;
 		}
 		p -= c->len;
@@ -216,10 +265,11 @@
 	int n;
 
 	n = c2p(norris->left) + norris->left->len;
-	if(dot.to.pos == totalsz || dot.to.pos > n)
-		dot.to.pos = n;
-	if(dot.pos < dot.from.pos || dot.pos > dot.to.pos)
-		dot.pos = dot.from.pos;
+	if(dot.to == totalsz || dot.to > n)
+		dot.to = n;
+	if(dot.pos < dot.from || dot.pos > dot.to)
+		dot.pos = dot.from;
+	dprint(nil, "final %Δ\n", &dot);
 	totalsz = n;
 }
 
@@ -231,7 +281,7 @@
 	Chunk *c, *pc;
 	Buf *b;
 
-	ASSERT(dot.pos >= dot.from.pos && dot.pos < dot.to.pos);
+	ASSERT(dot.pos >= dot.from && dot.pos < dot.to);
 	for(pc=norris, n=pc->len, c=pc->right; c!=norris; pc=c, c=c->right){
 		b = c->b;
 		ASSERT(b != nil);
@@ -244,7 +294,7 @@
 	}
 	if(exact){
 		ASSERT(n <= totalsz);
-		ASSERT(dot.to.pos <= totalsz);
+		ASSERT(dot.to <= totalsz);
 	}
 }
 #undef ASSERT
@@ -252,19 +302,34 @@
 void
 setdot(Dot *dot, Chunk *right)
 {
-	dot->from.pos = 0;
+	dot->from = 0;
 	if(right == nil)
-		dot->to.pos = c2p(norris->left) + norris->left->len;
+		dot->to = c2p(norris->left) + norris->left->len;
 	else
-		dot->to.pos = c2p(right);
+		dot->to = c2p(right);
 }
 
+void
+fixroot(Chunk *rc, usize off)
+{
+	Chunk *c;
+
+	dprint(rc, "fixroot [%χ] %08zux\n", rc, off);
+	for(c=rc->left; off>0; off-=c->len, c=c->left){
+		if(off - c->len == 0)
+			break;
+		assert(off - c->len < off);
+	}
+	norris = c;
+}
+
 Chunk *
 splitchunk(Chunk *c, usize off)
 {
 	Chunk *nc;
 
-	if(off == 0)
+	dprint(nil, "splitchunk %Δ [%χ] off=%08zux\n", &dot, c, off);
+	if(off == 0 || c == norris->left && off == c->len)
 		return c;
 	assert(off <= c->len);
 	nc = clonechunk(c);
@@ -282,6 +347,7 @@
 	usize off;
 	Chunk *c;
 
+	dprint(nil, "splitrange from=%08zux to=%08zux\n", from, to);
 	c = p2c(from, &off);
 	if(off > 0){
 		splitchunk(c, off);
@@ -302,6 +368,7 @@
 {
 	Chunk *c, *left, *right;
 
+	dprint(nil, "cutrange from=%08zux to=%08zux\n", from, to);
 	if(splitrange(from, to, &left, &right) < 0)
 		return nil;
 	c = left->left;
@@ -316,12 +383,15 @@
 Chunk *
 croprange(usize from, usize to, Chunk **latch)
 {
-	Chunk *left, *right;
+	Chunk *cut, *left, *right;
 
+	dprint(nil, "croprange from=%08zux to=%08zux\n", from, to);
 	if(splitrange(from, to, &left, &right) < 0)
 		return nil;
 	norris = left;
-	*latch = right->right;
+	cut = right->right;
+	if(latch != nil)
+		*latch = cut;
 	unlink(right->right, left->left);
 	return left;
 }
@@ -332,8 +402,10 @@
 {
 	Chunk *left;
 
+	dprint(c, "inserton from=%08zux to=%08zux\n", from, to);
 	left = cutrange(from, to, latch);
 	linkchunk(left, c);
+	dprint(nil, "done\n");
 	return left;
 }
 
@@ -343,6 +415,7 @@
 	usize off;
 	Chunk *left;
 
+	dprint(c, "insertat cur=%08zux\n", pos);
 	if(pos == 0){
 		left = norris->left;
 		norris = c;
@@ -350,6 +423,8 @@
 		left = p2c(pos, &off);
 		splitchunk(left, off);
 	}
+	if(off == 0)
+		left = left->left;
 	linkchunk(left, c);
 	return left;
 }
@@ -366,7 +441,7 @@
 		return nil;
 	}
 	c = p2c(d->pos, &off);
-	Δloop = d->to.pos - d->pos;
+	Δloop = d->to - d->pos;
 	Δbuf = c->len - off;
 	if(n < Δloop && n < Δbuf){
 		*sz = n;
@@ -373,7 +448,7 @@
 		d->pos += n;
 	}else if(Δloop <= Δbuf){
 		*sz = Δloop;
-		d->pos = d->from.pos;
+		d->pos = d->from;
 	}else{
 		*sz = Δbuf;
 		d->pos += Δbuf;
--- a/cmd.c
+++ b/cmd.c
@@ -12,43 +12,94 @@
 // FIXME: crazy idea, multisnarf with addressable elements; $n registers; fork pplay to display them → ?
 
 enum{
-	Nhold = 64,
+	OPins,
+	OPdel,
+	OPcrop,
+
+	Nops = 128,
 };
-static Chunk *hold[Nhold], *snarf;
 static int epfd[2];
 
+typedef struct Op Op;
+struct Op{
+	int type;
+	usize from;
+	usize to;
+	Chunk *c;
+};
+static int ohead, otail;
+static Chunk *hold;
+static Op ops[Nops];
+
 void
 setrange(usize from, usize to)
 {
 	assert((from & 3) == 0);
 	assert((to & 3) == 0);
-	dot.from.pos = from;
-	dot.to.pos = to;
+	dot.from = from;
+	dot.to = to;
 	if(dot.pos < from || dot.pos >= to)
 		dot.pos = from;
 }
 
 int
-setpos(usize off)
+jump(usize off)
 {
-	assert((off & 3) == 0);
-	setrange(0, totalsz);
-	assert(off >= dot.from.pos && off < dot.to.pos);
+	if(off < dot.from || off > dot.to){
+		werrstr("cannot jump outside of loop bounds\n");
+		return -1;
+	}
 	dot.pos = off;
 	return 0;
 }
 
+// FIXME: needs a different way of managing ops
 int
-jump(usize off)
+unpop(char *)
 {
-	if(off < dot.from.pos || off > dot.to.pos){
-		werrstr("cannot jump outside of loop bounds\n");
-		return -1;
-	}
-	dot.pos = off;
 	return 0;
 }
 
+int
+popop(char *)	// FIXME: u[n]
+{
+	Op *op;
+
+	if(otail == ohead)
+		return 0;
+	ohead = ohead - 1 & nelem(ops) - 1;
+	op = ops + ohead;
+	dprint(op->c, "cmd/pop dot=%Δ type=%d from=%08zux to=%08zux c=%#p\n",
+		&dot, op->type, op->from, op->to, op->c);
+	switch(op->type){
+	case OPdel:
+		if(insertat(op->from, op->c) == nil)
+			return -1;
+		break;
+	case OPins:
+		if(cutrange(op->from, op->to, nil) == nil)
+			return -1;
+		break;
+	case OPcrop:
+		if(insertat(op->to - op->from, op->c) == nil)
+			return -1;
+		dprint(nil, "uncropped with loose root\n");
+		fixroot(op->c, op->from + (op->to - op->from));
+		break;
+	default: werrstr("phase error: unknown op %d\n", op->type); return -1;
+	}
+	memset(ops+ohead, 0, sizeof *ops);
+	return 1;
+}
+
+void
+pushop(int type, usize from, usize to, Chunk *c)
+{
+	freechain(ops[ohead].c);
+	ops[ohead] = (Op){type, from, to, c};
+	ohead = ohead + 1 & nelem(ops) - 1;
+}
+
 static int
 replace(char *, Chunk *c)
 {
@@ -58,10 +109,12 @@
 		fprint(2, "replace: nothing to paste\n");
 		return -1;
 	}
-	if((left = inserton(dot.from.pos, dot.to.pos, c, &latch)) == nil){
+	if((left = inserton(dot.from, dot.to, c, &latch)) == nil){
 		fprint(2, "insert: %r\n");
 		return -1;
 	}
+	pushop(OPdel, dot.from, dot.to, latch);
+	pushop(OPins, dot.from, dot.to, nil);
 	setdot(&dot, nil);
 	dot.pos = c2p(left->right);
 	return 1;
@@ -76,6 +129,9 @@
 		fprint(2, "insert: nothing to paste\n");
 		return -1;
 	}
+	dprint(nil, "cmd/insert %Δ\n", &dot);
+	dprint(c, "buffered\n");
+	pushop(OPins, dot.pos, dot.pos+chunklen(c)-1, nil);
 	if((left = insertat(dot.pos, c)) == nil){
 		fprint(2, "insert: %r\n");
 		return -1;
@@ -82,6 +138,7 @@
 	}
 	setdot(&dot, nil);
 	dot.pos = c2p(left->right);
+	dprint(nil, "end\n");
 	return 1;
 }
 
@@ -88,26 +145,34 @@
 static int
 paste(char *s, Chunk *c)
 {
-	if(c == nil && (c = snarf) == nil){
+	if(c == nil && (c = hold) == nil){
 		werrstr("paste: no buffer");
 		return -1;
 	}
 	c = replicate(c, c->left);
-	if(dot.from.pos == 0 && dot.to.pos == totalsz)
+	if(dot.from == 0 && dot.to == totalsz)
 		return insert(s, c);
 	else
 		return replace(s, c);
 }
 
+static void
+snarf(Chunk *c)
+{
+	dprint(hold, "snarf was:\n");
+	freechain(hold);
+	hold = c;
+	dprint(hold, "snarf now:\n");
+}
+
 static int
 copy(char *)
 {
-	Chunk *c, *left, *right;
+	Chunk *left, *right;
 
-	splitrange(dot.from.pos, dot.to.pos, &left, &right);
-	c = replicate(left, right);
-	freechain(snarf);
-	snarf = c;
+	dprint(hold, "cmd/copy %Δ\n", &dot);
+	splitrange(dot.from, dot.to, &left, &right);
+	snarf(replicate(left, right));
 	return 0;
 }
 
@@ -116,11 +181,15 @@
 {
 	Chunk *latch;
 
-	if(dot.from.pos == 0 && dot.to.pos == totalsz){
+	if(dot.from == 0 && dot.to == totalsz){
 		werrstr("cut: no range selected");
 		return -1;
 	}
-	cutrange(dot.from.pos, dot.to.pos, &latch);
+	dprint(nil, "cmd/cut %Δ\n", &dot);
+	cutrange(dot.from, dot.to, &latch);
+	dprint(latch, "latched\n");
+	snarf(replicate(latch, latch->left));
+	pushop(OPdel, dot.from, dot.from+chunklen(latch)-1, latch);
 	setdot(&dot, nil);
 	return 1;
 }
@@ -130,8 +199,11 @@
 {
 	Chunk *latch;
 
-	if(croprange(dot.from.pos, dot.to.pos, &latch) == nil)
+	dprint(nil, "cmd/crop %Δ\n", &dot);
+	if(croprange(dot.from, dot.to, &latch) == nil)
 		return -1;
+	dprint(latch, "latched\n");
+	pushop(OPcrop, dot.from, dot.to, latch);
 	setdot(&dot, nil);
 	dot.pos = 0;
 	return 1;
@@ -165,8 +237,8 @@
 	usize n, m, c, k;
 	Dot d;
 
-	d.pos = d.from.pos = dot.from.pos;
-	d.to.pos = dot.to.pos;
+	d.pos = d.from = dot.from;
+	d.to = dot.to;
 	if((nio = iounit(fd)) == 0)
 		nio = 8192;
 	if(bufsz < nio){
@@ -173,7 +245,7 @@
 		buf = erealloc(buf, nio, bufsz);
 		bufsz = nio;
 	}
-	for(m=d.to.pos-d.from.pos, c=0; m>0;){
+	for(m=d.to-d.from, c=0; m>0;){
 		k = nio < m ? nio : m;
 		if(getbuf(d, k, buf, bufsz) < 0){
 			fprint(2, "writebuf: couldn\'t snarf: %r\n");
@@ -243,8 +315,9 @@
 		threadexits("failed reading from pipe: %r");
 	close(fd);
 	dot = d;
+	pushop(OPins, dot.from, dot.from+chunklen(c)-1, nil);
 	paste(nil, c);
-	dot.pos = dot.from.pos;
+	dot.pos = dot.from;
 	setdot(&dot, nil);
 	recalcsize();
 	redraw(0);
@@ -312,7 +385,7 @@
 {
 	int r, fd;
 
-	if(dot.to.pos - dot.from.pos == 0){
+	if(dot.to - dot.from == 0){
 		werrstr("writeto: dot isn't a range");
 		return -1;
 	}
@@ -356,6 +429,8 @@
 	case 'p': x = paste(s, nil); break;
 	case 'q': threadexitsall(nil);
 	case 'r': x = readfrom(s); break;
+//	case 'U': x = unpop(s); break;
+	case 'u': x = popop(s); break;
 	case 'w': x = writeto(s); break;
 	case 'x': x = crop(s); break;
 	default: werrstr("unknown command %C", r); x = -1; break;
--- a/dat.h
+++ b/dat.h
@@ -1,5 +1,4 @@
 typedef struct Chunk Chunk;
-typedef struct Pos Pos;
 typedef struct Dot Dot;
 typedef struct Buf Buf;
 
@@ -19,13 +18,10 @@
 	Chunk *left;
 	Chunk *right;
 };
-struct Pos{
-	usize pos;	/* bytes */
-};
 extern struct Dot{
-	Pos;
-	Pos from;
-	Pos to;
+	usize pos;
+	usize from;
+	usize to;
 };
 extern Dot dot;
 extern usize totalsz;
--- a/draw.c
+++ b/draw.c
@@ -79,9 +79,9 @@
 		lockdisplay(display);
 		draw(viewbg, viewbg->r, col[Cbg], nil, ZP);
 		unlockdisplay(display);
-		d.from.pos = 0;
+		d.from = 0;
 		d.pos = views;
-		d.to.pos = totalsz;
+		d.to = totalsz;
 		m = viewe - views;
 		x = 0;
 		qlock(&lsync);
@@ -157,16 +157,16 @@
 	b2t(dot.pos, &th, &tm, &ts, &tμ);
 	p = seprint(s, s+sizeof s, "T %zd @ %02d:%02d:%02d.%03d (%zd) ⋅ ",
 		T/4, th, tm, ts, tμ, dot.pos/4);
-	if(dot.from.pos > 0){
-		b2t(dot.from.pos, &th, &tm, &ts, &tμ);
+	if(dot.from > 0){
+		b2t(dot.from, &th, &tm, &ts, &tμ);
 		p = seprint(p, s+sizeof s, "%02d:%02d:%02d.%03d (%zd) ↺ ",
-			th, tm, ts, tμ, dot.from.pos/4);
+			th, tm, ts, tμ, dot.from/4);
 	}else
 		p = seprint(p, s+sizeof s, "0 ↺ ");
-	if(dot.to.pos != totalsz){
-		b2t(dot.to.pos, &th, &tm, &ts, &tμ);
+	if(dot.to != totalsz){
+		b2t(dot.to, &th, &tm, &ts, &tμ);
 		seprint(p, s+sizeof s, "%02d:%02d:%02d.%03d (%zd)",
-			th, tm, ts, tμ, dot.to.pos/4);
+			th, tm, ts, tμ, dot.to/4);
 	}else
 		seprint(p, s+sizeof s, "∞");
 	string(screen, statp, col[Cline], ZP, font, s);
@@ -179,7 +179,7 @@
 	usize left, right;
 	Rectangle r;
 
-	left = dot.from.pos;
+	left = dot.from;
 	draw(view, view->r, viewbg, nil, ZP);
 	if(left != 0 && left >= views){
 		x = (left - views) / T;
@@ -188,7 +188,7 @@
 		r.max.x = r.min.x + 1;
 		draw(view, r, col[Cloop], nil, ZP);
 	}
-	right = dot.to.pos;
+	right = dot.to;
 	if(right != totalsz){
 		x = (right - views) / T;
 		r = view->r;
@@ -285,9 +285,9 @@
 	if(off < 0 || off > totalsz)
 		return;
 	if(off < dot.pos)
-		setrange(off, dot.to.pos);
+		setrange(off, dot.to);
 	else
-		setrange(dot.from.pos, off);
+		setrange(dot.from, off);
 	update();
 }
 
@@ -294,7 +294,7 @@
 static void
 setcur(usize off)
 {
-	if(off < dot.from.pos || off > dot.to.pos - Outsz)
+	if(off < dot.from || off > dot.to - Outsz)
 		return;
 	jump(off);
 	update();
--- a/fns.h
+++ b/fns.h
@@ -1,4 +1,7 @@
+void	fixroot(Chunk*, usize);
+void	dprint(Chunk*, char*, ...);
 void	freechain(Chunk*);
+usize	chunklen(Chunk*);
 void	recalcsize(void);
 void	paranoia(int);
 void	setdot(Dot*, Chunk*);
@@ -30,7 +33,13 @@
 uchar*	getslice(Dot*, usize, usize*);
 vlong	getbuf(Dot, usize, uchar*, usize);
 int	loadin(int);
+int	χfmt(Fmt*);
+int	Δfmt(Fmt*);
 void*	emalloc(usize);
 void*	erealloc(void*, usize, usize);
 char*	estrdup(char*);
 int	setpri(int);
+
+#pragma	varargck	argpos	dprint	2
+#pragma	varargck	type	"χ"	Chunk*
+#pragma	varargck	type	"Δ"	Dot*
--- a/pplay.c
+++ b/pplay.c
@@ -98,6 +98,8 @@
 	}ARGEND
 	if((fd = *argv != nil ? open(*argv, OREAD) : 0) < 0)
 		sysfatal("open: %r");
+	fmtinstall(L'Δ', Δfmt);
+	fmtinstall(L'χ', χfmt);
 	if(loadin(fd) < 0)
 		sysfatal("inittrack: %r");
 	close(fd);
@@ -141,11 +143,11 @@
 			switch(r){
 			case Kdel:
 			case 'q': threadexitsall(nil);
-			case 'D': debugdraw ^= 1; break;
+			case 'D': debug ^= 1; debugdraw ^= 1; break;
 			case ' ': toggleplay(); break;
-			case 'b': setjump(dot.from.pos); break;
+			case 'b': setjump(dot.from); break;
 			case Kesc: setrange(0, totalsz); update(); break;
-			case '\n': zoominto(dot.from.pos, dot.to.pos); break;
+			case '\n': zoominto(dot.from, dot.to); break;
 			case 'z': zoominto(0, totalsz); break;
 			case '-': setzoom(-1, 0); break;
 			case '=': setzoom(1, 0); break;