shithub: front

Download patch

ref: 10522cecea250586efa3bda353f555211bef3a67
parent: bfcd6944a21217315bd79810dd5482b73ebeef6a
author: Jacob Moody <moody@posixcafe.org>
date: Sat Apr 19 17:39:08 EDT 2025

vdiff: fix scrolling and clean up

* accept list of patches from argv
* fix issue where menu would take precedence over scrolling
* fix issues when collapsing and expanding would scroll awkwardly

--- a/sys/man/1/vdiff
+++ b/sys/man/1/vdiff
@@ -11,12 +11,12 @@
 .I nstrip
 ]
 [
-.I file
+.I patches...
 ]
 .SH DESCRIPTION
-.I vdiff
-reads unified diff output from
-.I file
+.I Vdiff
+reads unified diff output from the list of
+.I patches
 or standard input and displays a colored version.
 Each file within the diff is displayed in a separate block that can be collapsed by clicking on the file name.
 Right clicking on a line will send a
@@ -34,6 +34,9 @@
 A menu may be summoned with button 2 of the mouse.
 It provides menu items for collapsing and expanding all files,
 as well as items for each patch present in the input.
+.I Vdiff
+understands terminators supplied by
+.IR git/export (2).
 .PP
 The
 .B -b
--- a/sys/src/cmd/vdiff.c
+++ b/sys/src/cmd/vdiff.c
@@ -245,12 +245,16 @@
 }
 
 void
-clampoffset(void)
+clampoffset(int off)
 {
 	if(offset<0)
 		offset = 0;
-	if(offset+viewh>totalh)
-		offset = totalh - viewh;
+	if(offset+viewh>totalh){
+		if(off > 0)
+			offset = totalh - viewh;
+		else
+			offset = 0;
+	}
 }
 
 void
@@ -261,7 +265,7 @@
 	if(off>0 && offset+viewh>totalh)
 		return;
 	offset += off;
-	clampoffset();
+	clampoffset(off);
 	redraw();
 }
 
@@ -312,8 +316,10 @@
 	}
 	totalh = totalh - Margin + Vpadding;
 	scrollsize = viewh / 2.0;
-	if(offset > 0 && offset+viewh>totalh)
-		offset = totalh - viewh;
+	if(viewh <= totalh)
+		clampoffset(1);
+	else
+		clampoffset(0);
 	redraw();
 }
 
@@ -362,7 +368,7 @@
 		return "expand";
 	default:
 		i -= Nmenu;
-		if(i >= npatches)
+		if(i >= npatches || npatches == 1)
 			return nil;
 		if(patches[i].name == nil)
 			patches[i].name = smprint("%d", i);
@@ -387,7 +393,23 @@
 	}
 }
 
+Menu menu = {
+	nil,
+	genmenu,
+};
+
 void
+collapse(int v)
+{
+	int i;
+
+	for(i = 0; i < cur->nblocks; i++)
+		if(cur->blocks[i]->f != nil)
+			cur->blocks[i]->v = v;
+	eresize(0);
+}
+
+void
 emouse(Mouse m)
 {
 	Block *b;
@@ -406,12 +428,30 @@
 		}else if(m.buttons&2){
 			offset = (m.xy.y - scrollr.min.y) * totalh/Dy(scrollr);
 			offset = offset/lineh * lineh;
-			clampoffset();
+			if(viewh <= totalh)
+				clampoffset(1);
+			else
+				clampoffset(0);
 			redraw();
 		}else if(m.buttons&4){
 			scroll(n);
 			return;
 		}
+	}else if(!scrolling && m.buttons&2){
+		n = menuhit(2, mctl, &menu, nil);
+		switch(n){
+		case -1:
+			break;
+		case Mexpand: case Mcollapse:
+			collapse(n);
+			break;
+		default:
+			n -= Nmenu;
+			if(cur == patches+n)
+				break;
+			cur = patches+n;
+			eresize(0);
+		}
 	}else if(m.buttons&8){
 		scroll(-n);
 	}else if(m.buttons&16){
@@ -564,19 +604,8 @@
 }
 
 void
-collapse(int v)
+parse(int fd, char *name)
 {
-	int i;
-
-	for(i = 0; i < cur->nblocks; i++)
-		if(cur->blocks[i]->f != nil)
-			cur->blocks[i]->v = v;
-	eresize(0);
-}
-
-void
-parse(int fd)
-{
 	Biobuf *bp;
 	Block *b;
 	char *s, *f, *tab;
@@ -605,7 +634,7 @@
 			cur = patches+npatches-1;
 			cur->blocks = nil;
 			cur->nblocks = 0;
-			cur->name = nil;
+			cur->name = name;
 			b = addblock();
 			n = 0;
 			ab = 0;		
@@ -640,8 +669,10 @@
 			if(f != nil && (f = strchr(f+1, ' '))){
 				f++;
 				if(strcmp(f, "uncommitted") != 0){
-					cur->name = strdup(f);
-					cur->name[9] = '\0';
+					if(name != nil)
+						cur->name = smprint("%s %.*s", name, 9, f);
+					else
+						cur->name = smprint("%.*s", 9, f);
 				}
 			}
 			t = Lnone;
@@ -659,13 +690,13 @@
 	}
 	if(gotterm)
 		npatches--;
-	cur = patches;
+	Bterm(bp);
 }
 
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-b] [-p nstrip] [file]\n", argv0);
+	fprint(2, "usage: %s [-b] [-p nstrip] [patches...]\n", argv0);
 	exits("usage");
 }
 
@@ -681,11 +712,7 @@
 		{ nil, &k,  CHANRCV },
 		{ nil, nil, CHANEND },
 	};
-	Menu menu = {
-		nil,
-		genmenu,
-	};
-	int b, n;
+	int i, b, fd;
 
 	b = 0;
 	ARGBEGIN{
@@ -699,17 +726,16 @@
 		usage();
 		break;
 	}ARGEND;
-	switch(argc){
-	default:
-		usage();
-	case 1:
-		close(0);
-		if(open(argv[0], OREAD) < 0)
+	if(argc == 0)
+		parse(0, nil);
+	else for(i = 0; i < argc; i++){
+		fd = open(argv[i], OREAD);
+		if(fd < 0)
 			sysfatal("open: %r");
-	case 0:
-		break;
+		parse(fd, argv[i]);
+		close(fd);
 	}
-	parse(0);
+	cur = patches;
 	if(cur->nblocks==1 && cur->blocks[0]->nlines==0){
 		fprint(2, "no diff\n");
 		exits(nil);
@@ -731,23 +757,7 @@
 	for(;;){
 		switch(alt(a)){
 		case Emouse:
-			if((m.buttons&2) != 0){
-				n = menuhit(2, mctl, &menu, nil);
-				switch(n){
-				case -1:
-					break;
-				case Mexpand: case Mcollapse:
-					collapse(n);
-					break;
-				default:
-					n -= Nmenu;
-					if(cur == patches+n)
-						break;
-					cur = patches+n;
-					eresize(0);
-				}
-			} else
-				emouse(m);
+			emouse(m);
 			break;
 		case Eresize:
 			eresize(1);
--