ref: 5e71f30fd31f4a5920354dddcd492e9601b09b65
parent: 4d9bf39b0435d7b1626255963093addc7af6280f
	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);
--
⑨