From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eigenstate.org ([206.124.132.107]) by ewsd; Mon Sep 3 04:33:44 EDT 2018 Received: from eigenstate.org (localhost [127.0.0.1]) by eigenstate.org (OpenSMTPD) with ESMTP id 77b5c48a for <9front@9front.org>; Mon, 3 Sep 2018 01:33:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=eigenstate.org; h=date :from:to:subject:message-id:mime-version:content-type :content-transfer-encoding; s=mail; bh=Ya6dATkYW4YMptxeSvQ+EeQj8 6E=; b=cOYwOCT4bsiCGZdaXMB3CnUUp3fhrM9ZtgRNp7h6PBGSr9t7WO/7kIepr B0ZXVu4rTE0M+WwTB3PaALTzZol9xO7nzWbKeOrnN2KK1ShT1LFUljEaavuuPy8V b4ksNeW3kIpi+nfhzTIoC2yt0lev8BNrSPViTXHCN/OdVJrm1U= DomainKey-Signature: a=rsa-sha1; c=nofws; d=eigenstate.org; h=date:from :to:subject:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=mail; b=X1lOJ3wOjaI1wt+mTG0 CeDxzcLeQXMErowyZDRaDYmqho4jP9SNOaqKsKNbdtWU5NTHEmF2j7ct9odqOZzh GNveN5c/DV8dFrVPuWQLw2vfvJAEW5/YHJ7ScDGl4FhQUpCUugiNTXQi2pNTt/XB ECzxmlRr9PgV/9kzVO+Zaewc= Received: from oneeye (c-98-207-157-125.hsd1.ca.comcast.net [98.207.157.125]) by eigenstate.org (OpenSMTPD) with ESMTPSA id 25edbc58 (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256:NO) for <9front@9front.org>; Mon, 3 Sep 2018 01:33:44 -0700 (PDT) Date: Mon, 3 Sep 2018 01:33:43 -0700 From: Ori Bernstein To: 9front@9front.org Subject: vt selection patch Message-Id: <20180903013343.ba43a69ca7bc0ca8057f1d7c@eigenstate.org> X-Mailer: Sylpheed 3.7.0 (GTK+ 2.24.32; amd64-portbld-freebsd11.1) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: optimized ISO-certified GPU engine-scale ACPI persistence callback full-stack interface 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. diff -r 3d56a0fc4645 sys/src/cmd/vt/main.c --- a/sys/src/cmd/vt/main.c Fri Aug 31 22:39:46 2018 +0200 +++ b/sys/src/cmd/vt/main.c Mon Sep 03 00:35:16 2018 -0700 @@ -11,25 +11,48 @@ #include #include #include +#include + +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 */ @@ -60,6 +83,9 @@ #define onscreena(x, y) &onscreenabuf[((y)*(xmax+2) + (x))] #define onscreenc(x, y) &onscreencbuf[((y)*(xmax+2) + (x))] +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + uchar *screenchangebuf; uint scrolloff; @@ -68,6 +94,8 @@ int yscrmin, yscrmax; int attr, defattr; +Rectangle selrect; + Image *cursorsave; Image *bordercol; Image *colors[8]; @@ -76,6 +104,8 @@ Image *green; Image *fgcolor; Image *bgcolor; +Image *fgselected; +Image *bgselected; Image *highlight; uint rgbacolors[8] = { @@ -138,11 +168,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 +330,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 +342,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 +357,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 +406,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 +421,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 +491,7 @@ nbacklines--; if(y >= yscrmax) { y = yscrmax; - if(pagemode && olines >= yscrmax) { + if(pagemode && olines >= yscrmax){ blocked = 1; return; } @@ -472,7 +512,7 @@ while(c <= 0) { if(backp) { c = *backp; - if(c && nbacklines >= 0) { + if(c && nbacklines >= 0){ backp++; if(backp >= &hist[HISTSIZ]) backp = hist; @@ -876,108 +916,138 @@ werrstr(""); /* clear spurious error messages */ } +Rune * +selrange(Rune *r, int x0, int y0, int x1, int y1) +{ + 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; +} + +Rune* +selrunes(void) +{ + Rune *r, *p; + int sz; + int y; + + /* 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; +} + void -sendsnarf(void) +snarfsel(void) +{ + Biobuf *b; + Rune *r; + + b = Bopen("/dev/snarf", OWRITE|OTRUNC); + if(b == nil) + return; + r = selrunes(); + if(!r) + return; + Bprint(b, "%S", r); + Bterm(b); + free(r); + +} + +void +plumbsel(void) +{ + 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); + } + close(plumb); + free(r); +} + +void +paste(void) { if(snarffp == nil) snarffp = Bopen("/dev/snarf",OREAD); } void -seputrunes(Biobuf *b, Rune *s, Rune *e) +selection(void) { - int z, p; + Point p, q; + 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++; - } + + p = pos(mc->xy); + do{ + /* Clear the old selection rectangle. */ + for(y = selrect.min.y; y <= selrect.max.y; y++) + screenchange(y) = 1; + q = pos(mc->xy); + selrect.min.x = MIN(p.x, q.x); + selrect.min.y = MIN(p.y, q.y); + selrect.max.x = MAX(p.x, q.x); + selrect.max.y = MAX(p.y, q.y); + /* And mark the new one as changed. */ + for(y = selrect.min.y; y <= selrect.max.y; y++) + screenchange(y) = 1; + readmouse(mc); + drawscreen(); + } while(button1()); + switch(mc->buttons & 0x7){ + case 3: snarfsel(); break; + case 5: paste(); break; } } int -snarfrect(Rectangle r) +selected(int x, int y) { - Biobuf *b; + int s; - 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)); + 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; } - Bterm(b); - return 1; -} - -Rectangle -drawselection(Rectangle r, Rectangle d, Image *color) -{ - 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++; - } - } - 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; -} - -void -selection(void) -{ - Point p, q; - Rectangle r, d; - Image *backup; - - backup = allocimage(display, screen->r, screen->chan, 0, DNofill); - draw(backup, backup->r, screen, nil, backup->r.min); - p = pos(mc->xy); - do { - q = pos(mc->xy); - if(onscreenr(p.x, p.y) > onscreenr(q.x, q.y)){ - r.min = q; - r.max = p; - } else { - r.min = p; - r.max = q; - } - if(r.max.y > ymax) - r.max.x = 0; - d = drawselection(r, ZR, red); - flushimage(display, 1); - readmouse(mc); - draw(screen, d, backup, nil, d.min); - } 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); - } - freeimage(backup); + return s; } void @@ -990,39 +1060,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: blocksel = !blocksel; + selrect = ZR; 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 +1100,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; @@ -1060,6 +1138,7 @@ int n; resize_flag = 1; + selrect = ZR; /* punt for now: scrolling clears selection */ if(count == 0 && !pagemode) { n = ymax; nbacklines = HISTSIZ; /* make sure we scroll to the very end */ @@ -1135,6 +1214,7 @@ if(sy < 0 || sy > ymax || dy < 0 || dy > ymax) return; + selrect = ZR; n = ly - sy; if(sy + n > ymax+1) n = ymax+1 - sy; -- Ori Bernstein