shithub: riscv

Download patch

ref: de9aa721f6b481d74f437035bedbaee6fffa2627
parent: 4596959f3b59f1048556e6ca421a6b5141773ded
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Sep 3 16:05:26 EDT 2018

vt: implement proper selections (thanks Ori_B)

Ori Bernstein wrote:
> I finally got around to taking another shot at this vt patch. This change
> gets rid of implicit snarfing, and instead makes selection the way you
> select text for snarfing or plumbing. Select, then use a menu entry.
>
> It would probably be nice to have double click to expand the selection,
> rio-style, along with plumbing implicitly taking the current word, but
> that can be a separate patch.
>
> This change also punts on scrolling for simplicity -- it clears the
> selection instead of trying to handle the cases where the selection
> goes offscreen.

little amendments:

- fix line selection (point min/max inversion)
- clear selection when switching linesel/blocksel
- move selection on scroll

--- a/sys/src/cmd/vt/main.c
+++ b/sys/src/cmd/vt/main.c
@@ -11,25 +11,48 @@
 #include <bio.h>
 #include <mouse.h>
 #include <keyboard.h>
+#include <plumb.h>
 
+enum menuact2{
+	Mbackup,
+	Mforward,
+	Mreset,
+	Mclear,
+	Mpaste,
+	Msnarf,
+	Mplumb,
+	Mpage,
+};
+
+enum menuact3{
+	M24x80,
+	Mcrnl,
+	Mnl,
+	Mraw,
+	Mblocksel,
+	Mexit,
+};
+
 char	*menutext2[] = {
-	"backup",
-	"forward",
-	"reset",
-	"clear",
-	"paste",
-	"page",
-	0
+	[Mbackup]	"backup",
+	[Mforward]	"forward",
+	[Mreset]	"reset",
+	[Mclear]	"clear",
+	[Mpaste]	"paste",
+	[Msnarf]	"snarf",
+	[Mplumb]	"plumb",
+	[Mpage]		"page",
+	nil
 };
 
 char	*menutext3[] = {
-	"24x80",
-	"crnl",
-	"nl",
-	"raw",
-	"blocksel",
-	"exit",
-	0
+	[M24x80]	"24x80",
+	[Mcrnl]		"crnl",
+	[Mnl]		"nl",
+	[Mraw]		"raw",
+	[Mblocksel]	"blocksel",
+	[Mexit]		"exit",
+	nil
 };
 
 /* variables associated with the screen */
@@ -68,6 +91,8 @@
 int	yscrmin, yscrmax;
 int	attr, defattr;
 
+Rectangle selrect;
+
 Image	*cursorsave;
 Image	*bordercol;
 Image	*colors[8];
@@ -76,6 +101,8 @@
 Image	*green;
 Image	*fgcolor;
 Image	*bgcolor;
+Image	*fgselected;
+Image	*bgselected;
 Image	*highlight;
 
 uint rgbacolors[8] = {
@@ -138,11 +165,15 @@
 void	bigscroll(void);
 void	readmenu(void);
 void	selection(void);
+int	selected(int, int);
 void	resize(void);
 void	drawcursor(void);
 void	send_interrupt(void);
 int	alnum(int);
 void	escapedump(int,uchar *,int);
+void	paste(void);
+void	snarfsel(void);
+void	plumbsel(void);
 
 static Channel *pidchan;
 
@@ -296,6 +327,8 @@
 	}
 	bgcolor = (blkbg? display->black: display->white);
 	fgcolor = (blkbg? display->white: display->black);
+	bgselected = allocimage(display, Rect(0,0,1,1), CMAP8, 1, blkbg ? 0x333333FF : 0xCCCCCCFF);
+	fgselected = allocimage(display, Rect(0,0,1,1), CMAP8, 1, blkbg ? 0xCCCCCCFF : 0x333333FF);;
 	resize();
 
 	pidchan = chancreate(sizeof(int), 0);
@@ -306,8 +339,10 @@
 }
 
 Image*
-bgcol(int a, int c)
+bgcol(int a, int c, int sel)
 {
+	if(sel)
+		return bgselected;
 	if(nocolor || (c & (1<<0)) == 0){
 		if(a & TReverse)
 			return fgcolor;
@@ -319,8 +354,10 @@
 }
 
 Image*
-fgcol(int a, int c)
+fgcol(int a, int c, int sel)
 {
+	if(sel)
+		return fgselected;
 	if(nocolor || (c & (1<<4)) == 0){
 		if(a & TReverse)
 			return bgcolor;
@@ -366,8 +403,8 @@
 		for(x = 0; x <= xmax; x += n){
 			cp = onscreenc(x, y);
 			ap = onscreena(x, y);
-			c = bgcol(*ap, *cp);
-			for(n = 1; x+n <= xmax && bgcol(ap[n], cp[n]) == c; n++)
+			c = bgcol(*ap, *cp, selected(x, y));
+			for(n = 1; x+n <= xmax && bgcol(ap[n], cp[n], selected(x + n, y)) == c; n++)
 				;
 			draw(screen, Rpt(pt(x, y), pt(x+n, y+1)), c, nil, ZP);
 		}
@@ -381,8 +418,8 @@
 			}
 			ap = onscreena(x, y);
 			cp = onscreenc(x, y);
-			c = fgcol(*ap, *cp);
-			for(n = 1; x+n <= xmax && rp[n] != 0 && fgcol(ap[n], cp[n]) == c
+			c = fgcol(*ap, *cp, selected(x, y));
+			for(n = 1; x+n <= xmax && rp[n] != 0 && fgcol(ap[n], cp[n], selected(x + n, y)) == c
 			&& ((ap[n] ^ *ap) & TUnderline) == 0; n++)
 				;
 			p = pt(x, y);
@@ -451,7 +488,7 @@
 	nbacklines--;
 	if(y >= yscrmax) {
 		y = yscrmax;
-		if(pagemode && olines >= yscrmax) {
+		if(pagemode && olines >= yscrmax){
 			blocked = 1;
 			return;
 		}
@@ -472,7 +509,7 @@
 	while(c <= 0) {
 		if(backp) {
 			c = *backp;
-			if(c && nbacklines >= 0) {
+			if(c && nbacklines >= 0){
 				backp++;
 				if(backp >= &hist[HISTSIZ])
 					backp = hist;
@@ -876,110 +913,152 @@
 	werrstr("");		/* clear spurious error messages */
 }
 
-void
-sendsnarf(void)
+Rune *
+selrange(Rune *r, int x0, int y0, int x1, int y1)
 {
-	if(snarffp == nil)
-		snarffp = Bopen("/dev/snarf",OREAD);
+	Rune *p, *sr, *er;
+
+	p = r;
+	sr = onscreenr(x0, y0);
+	er = onscreenr(x1, y1);
+	for(; sr != er; sr++)
+		if(*sr)
+			*p++ = *sr;
+	*p = 0;
+	return p;
 }
 
-void
-seputrunes(Biobuf *b, Rune *s, Rune *e)
+Rune*
+selrunes(void)
 {
-	int z, p;
+	Rune *r, *p;
+	int sz;
+	int y;
 
-	if(s >= e)
-		return;
-	for(z = p = 0; s < e; s++){
-		if(*s){
-			if(*s == '\n')
-				z = p = 0;
-			else if(p++ == 0){
-				while(z-- > 0) Bputc(b, ' ');
-			}
-			Bputrune(b, *s);
-		} else {
-			z++;
+	/* generous, but we can spare a few bytes for a few microseconds */
+	sz = xmax*(selrect.max.y - selrect.min.y + 2) + 1;
+	r = p = malloc(sizeof(Rune)*sz + 1);
+	if(!r)
+		return nil;
+	if(blocksel){
+		for(y = selrect.min.y; y <= selrect.max.y; y++){
+			p = selrange(p, selrect.min.x, y, selrect.max.x, y);
+			*p++ = '\n';
 		}
+		*p = 0;
 	}
+	else
+		selrange(r, selrect.min.x, selrect.min.y, selrect.max.x, selrect.max.y);
+	return r;
 }
 
-int
-snarfrect(Rectangle r)
+void
+snarfsel(void)
 {
 	Biobuf *b;
+	Rune *r;
 
 	b = Bopen("/dev/snarf", OWRITE|OTRUNC);
 	if(b == nil)
-		return 0;
-	if(blocksel){
-		while(r.min.y <= r.max.y){
-			seputrunes(b, onscreenr(r.min.x, r.min.y), onscreenr(r.max.x, r.min.y));
-			Bputrune(b, L'\n');
-			r.min.y++;
-		}
-	} else {
-		seputrunes(b, onscreenr(r.min.x, r.min.y), onscreenr(r.max.x, r.max.y));
-	}
+		return;
+	r = selrunes();
+	if(!r)
+		return;
+	Bprint(b, "%S", r);
 	Bterm(b);
-	return 1;
+	free(r);
+
 }
 
-Rectangle
-drawselection(Rectangle r, Rectangle d, Image *color)
+void
+plumbsel(void)
 {
-	if(!blocksel){
-		while(r.min.y < r.max.y){
-			d = drawselection(Rect(r.min.x, r.min.y, xmax+1, r.min.y), d, color);
-			r.min.x = 0;
-			r.min.y++;
-		}
+	char buf[1024], wdir[512];
+	Rune *r;
+	int plumb;
+
+	print("plumb\n");
+	if(getwd(wdir, sizeof wdir) == 0)
+		return;
+	if((r = selrunes()) == nil)
+		return;
+	print("wdir: %s, runes: %S\n", wdir, r);
+	if((plumb = plumbopen("send", OWRITE)) != -1){
+		snprint(buf, sizeof buf, "%S", r);
+		print("buf: '%s'\n", buf);
+		plumbsendtext(plumb, "vt", nil, wdir, buf);
 	}
-	if(r.min.x >= r.max.x)
-		return d;
-	r = Rpt(pt(r.min.x, r.min.y), pt(r.max.x, r.max.y+1));
-	draw(screen, r, color, highlight, r.min);
-	combinerect(&d, r);
-	return d;
+	close(plumb);
+	free(r);
 }
 
 void
+paste(void)
+{
+	if(snarffp == nil)
+		snarffp = Bopen("/dev/snarf",OREAD);
+}
+
+void
+unselect(void)
+{
+	int y;
+
+	for(y = selrect.min.y; y <= selrect.max.y; y++)
+		screenchange(y) = 1;
+	selrect = ZR;
+}
+
+void
 selection(void)
 {
 	Point p, q;
-	Rectangle r, d;
-	Image *backup;
+	int y;
 
-	backup = allocimage(display, screen->r, screen->chan, 0, DNofill);
-	draw(backup, backup->r, screen, nil, backup->r.min);
+
 	p = pos(mc->xy);
-	do {
+	do{
+		/* Clear the old selection rectangle. */
+		unselect();
 		q = pos(mc->xy);
 		if(onscreenr(p.x, p.y) > onscreenr(q.x, q.y)){
-			r.min = q;
-			r.max = p;
+			selrect.min = q;
+			selrect.max = p;
 		} else {
-			r.min = p;
-			r.max = q;
+			selrect.min = p;
+			selrect.max = q;
 		}
-		if(r.max.y > ymax)
-			r.max.x = 0;
-		d = drawselection(r, ZR, red);
-		flushimage(display, 1);
+		/* And mark the new one as changed. */
+		for(y = selrect.min.y; y <= selrect.max.y; y++)
+			screenchange(y) = 1;
 		readmouse(mc);
-		draw(screen, d, backup, nil, d.min);
+		drawscreen();
 	} while(button1());
-	if((mc->buttons & 07) == 5)
-		sendsnarf();
-	else if(snarfrect(r)){
-		d = drawselection(r, ZR, green);
-		flushimage(display, 1);
-		sleep(200);
-		draw(screen, d, backup, nil, d.min);
+	switch(mc->buttons & 0x7){
+	case 3:	snarfsel();	break;
+	case 5:	paste();	break;
 	}
-	freeimage(backup);
 }
 
+int
+selected(int x, int y)
+{
+	int s;
+
+	s = y >= selrect.min.y && y <= selrect.max.y;
+	if (blocksel)
+		s = s && x >= selrect.min.x && x < selrect.max.x;
+	else{
+		if(y == selrect.min.y)
+			s = s && x >= selrect.min.x;
+		if(y == selrect.max.y)
+			s = s && x < selrect.max.x;
+		if(y > selrect.min.y && y < selrect.max.y)
+			s = 1;
+	}
+	return s;
+}
+
 void
 readmenu(void)
 {
@@ -990,39 +1069,39 @@
 		menu3.item[4] = blocksel ? "linesel" : "blocksel";
 
 		switch(menuhit(3, mc, &menu3, nil)) {
-		case 0:		/* 24x80 */
+		case M24x80:		/* 24x80 */
 			setdim(24, 80);
 			return;
-		case 1:		/* newline after cr? */
+		case Mcrnl:		/* newline after cr? */
 			ttystate[cs->raw].crnl = !ttystate[cs->raw].crnl;
 			return;
-		case 2:		/* cr after newline? */
+		case Mnl:		/* cr after newline? */
 			ttystate[cs->raw].nlcr = !ttystate[cs->raw].nlcr;
 			return;
-		case 3:		/* switch raw mode */
+		case Mraw:		/* switch raw mode */
 			cs->raw = !cs->raw;
 			return;
-		case 4:
+		case Mblocksel:
+			unselect();
 			blocksel = !blocksel;
 			return;
-		case 5:
+		case Mexit:
 			exits(0);
 		}
 		return;
 	}
 
-	menu2.item[5] = pagemode? "scroll": "page";
+	menu2.item[Mpage] = pagemode? "scroll": "page";
 
 	switch(menuhit(2, mc, &menu2, nil)) {
-
-	case 0:		/* back up */
-		if(atend == 0) {
+	case Mbackup:		/* back up */
+		if(atend == 0){
 			backc++;
 			backup(backc);
 		}
 		return;
 
-	case 1:		/* move forward */
+	case Mforward:		/* move forward */
 		backc--;
 		if(backc >= 0)
 			backup(backc);
@@ -1030,20 +1109,28 @@
 			backc = 0;
 		return;
 
-	case 2:		/* reset */
+	case Mreset:		/* reset */
 		backc = 0;
 		backup(0);
 		return;
 
-	case 3:		/* clear screen */
+	case Mclear:		/* clear screen */
 		resize_flag = 1;
 		return;
 
-	case 4:		/* send the snarf buffer */
-		sendsnarf();
+	case Mpaste:		/* paste the snarf buffer */
+		paste();
 		return;
 
-	case 5:		/* pause and clear at end of screen */
+	case Msnarf:		/* send the snarf buffer */
+		snarfsel();
+		return;
+
+	case Mplumb:
+		plumbsel();
+		return;
+
+	case Mpage:		/* pause and clear at end of screen */
 		pagemode = 1-pagemode;
 		if(blocked && !pagemode) {
 			resize_flag = 1;
@@ -1059,6 +1146,8 @@
 	Rune *cp;
 	int n;
 
+	unselect();
+
 	resize_flag = 1;
 	if(count == 0 && !pagemode) {
 		n = ymax;
@@ -1154,6 +1243,22 @@
 		memmove(onscreenc(0, dy), onscreenc(0, sy), n*(xmax+2));
 	}
 
+	/* move selection */
+	selrect.min.y -= d;
+	selrect.max.y -= d;
+	if(selrect.max.y < 0 || selrect.min.y > ymax)
+		selrect = ZR;
+	else {
+		if(selrect.min.y < 0){
+			selrect.min.y = 0;
+			if(!blocksel) selrect.min.x = 0;
+		}
+		if(selrect.max.y > ymax){
+			selrect.max.y = ymax;
+			if(!blocksel) selrect.max.x = xmax+1;
+		}
+	}
+	
 	clear(0, cy, xmax+1, cy+1);
 }