diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-09-03 20:05:26 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-09-03 20:05:26 +0200 |
commit | de9aa721f6b481d74f437035bedbaee6fffa2627 (patch) | |
tree | eec3247c5cdc6b768557506090ce56b01bee7be1 /sys/src/cmd/vt | |
parent | 4596959f3b59f1048556e6ca421a6b5141773ded (diff) |
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
Diffstat (limited to 'sys/src/cmd/vt')
-rw-r--r-- | sys/src/cmd/vt/main.c | 319 |
1 files changed, 212 insertions, 107 deletions
diff --git a/sys/src/cmd/vt/main.c b/sys/src/cmd/vt/main.c index 528191bf4..199ee8409 100644 --- 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 @@ uint scrolloff; int yscrmin, yscrmax; int attr, defattr; +Rectangle selrect; + Image *cursorsave; Image *bordercol; Image *colors[8]; @@ -76,6 +101,8 @@ Image *red; Image *green; Image *fgcolor; Image *bgcolor; +Image *fgselected; +Image *bgselected; Image *highlight; uint rgbacolors[8] = { @@ -138,11 +165,15 @@ int rcvchar(void); 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 @@ threadmain(int argc, char **argv) } 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 @@ threadmain(int argc, char **argv) } 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 @@ bgcol(int a, int c) } 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 @@ drawscreen(void) 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 @@ drawscreen(void) } 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 @@ newline(void) nbacklines--; if(y >= yscrmax) { y = yscrmax; - if(pagemode && olines >= yscrmax) { + if(pagemode && olines >= yscrmax){ blocked = 1; return; } @@ -472,7 +509,7 @@ get_next_char(void) while(c <= 0) { if(backp) { c = *backp; - if(c && nbacklines >= 0) { + if(c && nbacklines >= 0){ backp++; if(backp >= &hist[HISTSIZ]) backp = hist; @@ -876,108 +913,150 @@ resize(void) 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; - - 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++; + 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; } -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; + } +} + +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; } - freeimage(backup); + return s; } void @@ -990,39 +1069,39 @@ readmenu(void) 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 @@ readmenu(void) 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 Msnarf: /* send the snarf buffer */ + snarfsel(); return; - case 5: /* pause and clear at end of screen */ + 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 @@ backup(int count) Rune *cp; int n; + unselect(); + resize_flag = 1; if(count == 0 && !pagemode) { n = ymax; @@ -1154,6 +1243,22 @@ scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to cle 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); } |