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);
}