diff options
| author | rsc <devnull@localhost> | 2005-11-06 22:16:48 +0000 |
|---|---|---|
| committer | rsc <devnull@localhost> | 2005-11-06 22:16:48 +0000 |
| commit | e830a908498c8f0270948fd08c50f6d773315880 (patch) | |
| tree | a16fe62419a4e3a95ab2d8d3a70f1a870d0bb55c /src/cmd/9term/9term.c | |
| parent | a6c0ff35ee294c0a808e1792eb4f43820fed8f16 (diff) | |
| download | plan9port-e830a908498c8f0270948fd08c50f6d773315880.tar.gz plan9port-e830a908498c8f0270948fd08c50f6d773315880.zip | |
New 9term using rio sources more directly.
Diffstat (limited to 'src/cmd/9term/9term.c')
| -rw-r--r-- | src/cmd/9term/9term.c | 2072 |
1 files changed, 291 insertions, 1781 deletions
diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c index 33104df1..285878e8 100644 --- a/src/cmd/9term/9term.c +++ b/src/cmd/9term/9term.c @@ -10,208 +10,37 @@ #include <frame.h> #include <plumb.h> #include <complete.h> +#define Extern +#include "dat.h" +#include "fns.h" #include "term.h" -enum -{ - STACK = 32768 -}; - -int noecho = 0; - -void servedevtext(void); -void listenproc(void*); -void textthread(void*); - -typedef struct Text Text; -typedef struct Readbuf Readbuf; - -enum -{ - HiWater = 640000, /* max size of history */ - LoWater = 400000, /* min size of history after max'ed */ - MinWater = 20000, -}; - -/* various geometric paramters */ -enum -{ - Scrollwid = 12, /* width of scroll bar */ - Scrollgap = 4, /* gap right of scroll bar */ - Maxtab = 4, -}; - -enum -{ - Cut, - Paste, - Snarf, - Send, - Plumb, - Scroll, - Cooked, -}; - -#define ESC 0x1B -#define CUT 0x18 /* ctrl-x */ -#define COPY 0x03 /* crtl-c */ -#define PASTE 0x16 /* crtl-v */ - -#define READBUFSIZE 8192 -#define TRUE 1 -#define FALSE 0 - - -struct Text -{ - Frame *f; /* frame ofr terminal */ - Mouse m; - uint nr; /* num of runes in term */ - uint maxr; /* max num of runes in r */ - Rune *r; /* runes for term */ - uint nraw; /* num of runes in raw buffer */ - Rune *raw; /* raw buffer */ - uint org; /* first rune on the screen */ - uint q0; /* start of selection region */ - uint q1; /* end of selection region */ - uint qh; /* unix point */ - int npart; /* partial runes read from console */ - char part[UTFmax]; - int nsnarf; /* snarf buffer */ - Rune *snarf; -}; - -struct Readbuf -{ - short n; /* # bytes in buf */ - uchar data[READBUFSIZE]; /* data bytes */ -}; - -void mouse(void); -void domenu2(int); -void loop(void); -void geom(void); -void fill(void); -void tcheck(void); -void updatesel(void); -void doreshape(void); -void runewrite(Rune*, int); -void consread(void); -void conswrite(char*, int); -int bswidth(Rune c, uint start, int eatnl); -void cut(void); -void paste(Rune*, int, int); -void snarfupdate(void); -void snarf(void); -void show(uint); -void key(Rune); -void setorigin(uint org, int exact); -uint line2q(uint); -uint backnl(uint, uint); -int cansee(uint); -uint backnl(uint, uint); -void addraw(Rune*, int); -void mselect(void); -void doubleclick(uint *q0, uint *q1); -int clickmatch(int cl, int cr, int dir, uint *q); -Rune *strrune(Rune *s, Rune c); -int consready(void); -Rectangle scrpos(Rectangle r, ulong p0, ulong p1, ulong tot); -void scrdraw(void); -void scroll(int); -void hostproc(void *arg); -void hoststart(void); -void plumbstart(void); -void plumb(uint, uint); -void plumbclick(uint*, uint*); -uint insert(Rune*, int, uint, int); -void scrolldown(int); -void scrollup(int); - -#define runemalloc(n) malloc((n)*sizeof(Rune)) -#define runerealloc(a, n) realloc(a, (n)*sizeof(Rune)) -#define runemove(a, b, n) memmove(a, b, (n)*sizeof(Rune)) -Rectangle scrollr; /* scroll bar rectangle */ -Rectangle lastsr; /* used for scroll bar */ -int holdon; /* hold mode */ -int rawon(void); /* raw mode */ -int cooked; /* force cooked */ -int scrolling; /* window scrolls */ -int clickmsec; /* time of last click */ -uint clickq0; /* point of last click */ -int rcfd; -int sfd; /* slave fd, to get/set terminal mode */ -int rcpid; -int maxtab; -int use9wm; -Mousectl* mc; -Keyboardctl* kc; -Channel* hostc; -Readbuf rcbuf[2]; -int mainpid; -int acmecolors; -int plumbfd; -int button2exec; -int label(Rune*, int); -char wdir[1024]; -char childwdir[1024]; -void hangupnote(void*, char*); -char thesocket[100]; - -char *menu2str[] = { - "cut", - "paste", - "snarf", - "send", - "plumb", - "scroll", - "cooked", - 0 -}; - -Image* cols[NCOL]; -Image* hcols[NCOL]; -Image* palegrey; -Image* paleblue; -Image* blue; -Image *plumbcolor; -Image *execcolor; - -Menu menu2 = -{ - menu2str -}; - -Text t; - -Cursor whitearrow = { - {0, 0}, - {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, - 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, - 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }, - {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, - 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, - 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, - 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, } -}; - -Cursor query = { - {-7,-7}, - {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, - 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, - 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, - 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, }, - {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, - 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, - 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, - 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } -}; +int use9wm; +int mainpid; +int plumbfd; +int rcpid; +int rcfd; +int sfd; +int noecho; +Window *w; +char *fontname; + +void derror(Display*, char*); +void mousethread(void*); +void keyboardthread(void*); +void winclosethread(void*); +void deletethread(void*); +void rcoutputproc(void*); +void rcinputproc(void*); +void hangupnote(void*, char*); +void resizethread(void*); + +int errorshouldabort = 0; void usage(void) { - fprint(2, "usage: 9term [-ars] [-W winsize] [cmd ...]\n"); + fprint(2, "usage: 9term [-s] [-f font] [-W winsize] [cmd ...]\n"); threadexitsall("usage"); } @@ -219,95 +48,79 @@ void threadmain(int argc, char *argv[]) { char *p, *font; - char buf[32]; - + rfork(RFNOTEG); font = nil; _wantfocuschanges = 1; mainpid = getpid(); + messagesize = 8192; + ARGBEGIN{ default: usage(); - case 'a': /* acme mode */ - button2exec++; - break; case 'f': font = EARGF(usage()); break; case 's': - scrolling++; + scrolling = TRUE; break; - case 'w': /* started from "rio" window manager */ - use9wm = 1; + case 'w': /* started from rio or 9wm */ + use9wm = TRUE; break; case 'W': winsize = EARGF(usage()); break; }ARGEND - + if(font) putenv("font", font); - + p = getenv("tabstop"); if(p == 0) p = getenv("TABSTOP"); - if(p != 0 && maxtab <= 0) + if(p && maxtab <= 0) maxtab = strtoul(p, 0, 0); if(maxtab <= 0) - maxtab = 4; /* be like rio */ - - snprint(buf, sizeof buf, "%d", maxtab); - putenv("tabstop", buf); - - initdraw(0, nil, "9term"); + maxtab = 4; + free(p); + + startdir = "."; + + initdraw(derror, nil, "9term"); notify(hangupnote); noteenable("sys: child"); - servedevtext(); - - mc = initmouse(nil, screen); - kc = initkeyboard(nil); - rcpid = rcstart(argc, argv, &rcfd, &sfd); - hoststart(); - plumbstart(); - - t.f = mallocz(sizeof(Frame), 1); - - if(acmecolors){ - cols[BACK] = allocimagemix(display, DPaleyellow, DWhite); - cols[HIGH] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DDarkyellow); - cols[BORD] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DYellowgreen); - }else{ - cols[BACK] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DWhite); - cols[HIGH] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF); - cols[BORD] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x999999FF); - } - cols[TEXT] = display->black; - cols[HTEXT] = display->black; - palegrey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x666666FF); - - hcols[BACK] = cols[BACK]; - hcols[HIGH] = cols[HIGH]; - blue = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DMedblue); - paleblue = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DGreyblue); +// servedevtext(); + + mousectl = initmouse(nil, screen); + if(mousectl == nil) + error("cannot find mouse"); + keyboardctl = initkeyboard(nil); + if(keyboardctl == nil) + error("cannot find keyboard"); + if((plumbfd = plumbopen("send", OWRITE)) < 0) + fprint(2, "9term: plumbopen: %r\n"); + mouse = &mousectl->m; - hcols[BORD] = blue; - hcols[TEXT] = hcols[BORD]; - hcols[HTEXT] = hcols[TEXT]; + winclosechan = chancreate(sizeof(Window*), 0); + deletechan = chancreate(sizeof(char*), 0); - plumbcolor = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x006600FF); - execcolor = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAA0000FF); + timerinit(); + rcpid = rcstart(argc, argv, &rcfd, &sfd); + w = new(screen, FALSE, scrolling, rcpid, ".", nil, nil); - if(!blue || !palegrey || !paleblue || !plumbcolor || !execcolor) - sysfatal("alloc colors: %r"); - draw(screen, screen->r, cols[BACK], nil, ZP); - geom(); - loop(); + threadcreate(keyboardthread, nil, STACK); + threadcreate(mousethread, nil, STACK); + threadcreate(resizethread, nil, STACK); + + proccreate(rcoutputproc, nil, STACK); + proccreate(rcinputproc, nil, STACK); } -int -isexpand(Rune r) +void +derror(Display *d, char *errorstr) { - return r=='_' || ('0' <= r && r <= '9') || isalpharune(r); + USED(d); + error(errorstr); } void @@ -335,1518 +148,275 @@ hangupnote(void *a, char *msg) } void -hostproc(void *arg) +keyboardthread(void *v) { - Channel *c; - int i, n, which; - - c = arg; + Rune buf[2][20], *rp; + int i, n; - i = 0; + USED(v); + threadsetname("keyboardthread"); + n = 0; for(;;){ - /* Let typing have a go -- maybe there's a rubout waiting. */ - yield(); - - i = 1-i; /* toggle */ - n = read(rcfd, rcbuf[i].data, sizeof rcbuf[i].data); - if(n <= 0){ - if(n < 0) - fprint(2, "9term: host read error: %r\n"); - threadexitsall("host"); - } - rcbuf[i].n = n; - which = i; - send(c, &which); + rp = buf[n]; + n = 1-n; + recv(keyboardctl->c, rp); + for(i=1; i<nelem(buf[0])-1; i++) + if(nbrecv(keyboardctl->c, rp+i) <= 0) + break; + rp[i] = L'\0'; + sendp(w->ck, rp); } } void -hoststart(void) +resizethread(void *v) { - hostc = chancreate(sizeof(int), 0); - proccreate(hostproc, hostc, 32*1024); -} - -void -loop(void) -{ - Rune r; - int i; - Alt a[5]; - - a[0].c = mc->c; - a[0].v = &mc->m; - a[0].op = CHANRCV; - - a[1].c = kc->c; - a[1].v = &r; - a[1].op = CHANRCV; - - a[2].c = hostc; - a[2].v = &i; - a[2].op = CHANRCV; - - a[3].c = mc->resizec; - a[3].v = nil; - a[3].op = CHANRCV; - - a[4].c = nil; - a[4].v = nil; - a[4].op = CHANEND; - - for(;;) { - tcheck(); - - scrdraw(); - flushimage(display, 1); - a[2].op = CHANRCV; - if(!scrolling && t.qh > t.org+t.f->nchars) - a[2].op = CHANNOP;; - switch(alt(a)) { - default: - sysfatal("impossible"); - case 0: - t.m = mc->m; - mouse(); - break; - case 1: - key(r); - break; - case 2: - conswrite((char*)rcbuf[i].data, rcbuf[i].n); - break; - case 3: - doreshape(); - break; - } + USED(v); + + while(recv(mousectl->resizec, nil) == 1){ + if(getwindow(display, Refnone) < 0) + sysfatal("can't reattach to window"); + wresize(w, screen, 0); } } - + void -doreshape(void) +mousethread(void *v) { - if(getwindow(display, Refnone) < 0) - sysfatal("can't reattach to window"); - draw(screen, screen->r, cols[BACK], nil, ZP); - geom(); - scrdraw(); -} + int sending; + Mouse tmp; -void -geom(void) -{ - Point p; - Rectangle r; + USED(v); - if(!acmecolors){ - if(_windowhasfocus){ - cols[TEXT] = cols[HTEXT] = display->black; - hcols[TEXT] = hcols[HTEXT] = blue; - }else{ - cols[TEXT] = cols[HTEXT] = palegrey; - hcols[TEXT] = hcols[HTEXT] = paleblue; + sending = FALSE; + threadsetname("mousethread"); + while(readmouse(mousectl) >= 0){ + if(sending){ + Send: + /* send to window */ + if(mouse->buttons == 0) + sending = FALSE; + else + wsetcursor(w, 0); + tmp = mousectl->m; + send(w->mc.c, &tmp); + continue; } + if(mouse->buttons&1){ + sending = TRUE; + goto Send; + }else if(mouse->buttons&2) + button2menu(w); + else + /* send to rio */; } - - r = screen->r; - r.min.y++; - r.max.y--; - - scrollr = r; - scrollr.max.x = r.min.x+Scrollwid; - lastsr = Rect(0,0,0,0); - - r.min.x += Scrollwid+Scrollgap; - - frclear(t.f, 0); - frinit(t.f, r, font, screen, holdon ? hcols : cols); - t.f->maxtab = maxtab*stringwidth(font, "0"); - fill(); - updatesel(); - - p = stringsize(font, "0"); - if(p.x == 0 || p.y == 0) - return; - - updatewinsize(Dy(r)/p.y, Dx(r)/p.x, Dx(r), Dy(r)); } - + void -drawhold(int holdon) +wborder(Window *w, int type) { - if(holdon) - setcursor(mc, &whitearrow); - else - setcursor(mc, nil); - - draw(screen, screen->r, cols[BACK], nil, ZP); - geom(); - scrdraw(); } -void -wordclick(uint *q0, uint *q1) +Window* +wpointto(Point pt) { - while(*q1<t.nr && !isspace(t.r[*q1])) - (*q1)++; - while(*q0>0 && !isspace(t.r[*q0-1])) - (*q0)--; + return w; } -int -aselect(uint *q0, uint *q1, Image *color) +Window* +new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd, char **argv) { - int cancel; - uint oldq0, oldq1, newq0, newq1; - - /* save old selection */ - oldq0 = t.q0; - oldq1 = t.q1; - - /* sweep out area and record it */ - t.f->cols[HIGH] = color; - t.f->cols[HTEXT] = display->white; - mselect(); - newq0 = t.q0; - newq1 = t.q1; - - cancel = 0; - if(t.m.buttons != 0){ - while(t.m.buttons){ - readmouse(mc); - t.m = mc->m; - } - cancel = 1; - } - - /* restore old selection */ - t.f->cols[HIGH] = cols[HIGH]; - t.f->cols[HTEXT] = cols[HTEXT]; - t.q0 = oldq0; - t.q1 = oldq1; - updatesel(); + Window *w; + Mousectl *mc; + Channel *cm, *ck, *cctl; - if(cancel) - return -1; - - /* selected a region */ - if(newq0 < newq1){ - *q0 = newq0; - *q1 = newq1; - return 0; - } - - /* clicked inside previous selection */ - /* the "<=" in newq0 <= oldq1 allows us to click the right edge */ - if(oldq0 <= newq0 && newq0 <= oldq1){ - *q0 = oldq0; - *q1 = oldq1; - return 0; - } - - /* just a click */ - *q0 = newq0; - *q1 = newq1; - return 0; + if(i == nil) + return nil; + cm = chancreate(sizeof(Mouse), 0); + ck = chancreate(sizeof(Rune*), 0); + cctl = chancreate(sizeof(Wctlmesg), 4); + if(cm==nil || ck==nil || cctl==nil) + error("new: channel alloc failed"); + mc = emalloc(sizeof(Mousectl)); + *mc = *mousectl; +// mc->image = i; + mc->c = cm; + w = wmk(i, mc, ck, cctl, scrollit); + free(mc); /* wmk copies *mc */ + window = erealloc(window, ++nwindow*sizeof(Window*)); + window[nwindow-1] = w; + if(hideit){ + hidden[nhidden++] = w; + w->screenr = ZR; + } + threadcreate(winctl, w, 8192); + if(!hideit) + wcurrent(w); + flushimage(display, 1); + wsetpid(w, pid, 1); + wsetname(w); + if(dir) + w->dir = estrdup(dir); + return w; } -static Rune Lnl[1] = { '\n' }; +/* + * Button 2 menu. Extra entry for always cook + */ +int cooked; -void -mouse(void) +enum { - int but; - uint q0, q1; + Cut, + Paste, + Snarf, + Plumb, + Send, + Scroll, + Cook, +}; - but = t.m.buttons; +char *menu2str[] = { + "cut", + "paste", + "snarf", + "plumb", + "send", + "scroll", + "cook", + nil +}; - if(but != 1 && but != 2 && but != 4 && but != 8 && but != 16) - return; - if (ptinrect(t.m.xy, scrollr)) { - scroll(but); - if(t.qh<=t.org+t.f->nchars) - consread(); - return; - } - - switch(but) { - case 1: - mselect(); - break; - case 2: - if(button2exec){ - if(aselect(&q0, &q1, execcolor) >= 0){ - if(q0 == q1) - wordclick(&q0, &q1); - if(q0 == q1) - break; - t.q0 = t.q1 = t.nr; - updatesel(); - paste(t.r+q0, q1-q0, 1); - if(t.r[q1-1] != '\n') - paste(Lnl, 1, 1); - } - break; - } - domenu2(2); - break; - case 4: - bouncemouse(&t.m); - break; - /* - if(aselect(&q0, &q1, plumbcolor) >= 0) - plumb(q0, q1); - break; - */ - case 8: - scrollup(mousescrollsize(t.f->maxlines)); - break; - case 16: - scrolldown(mousescrollsize(t.f->maxlines)); - break; - } -} - -void -mselect(void) +Menu menu2 = { - int b, x, y; - uint q0; - - b = t.m.buttons; - q0 = frcharofpt(t.f, t.m.xy) + t.org; - if(t.m.msec-clickmsec<500 && clickq0==q0 && t.q0==t.q1 && b==1){ - doubleclick(&t.q0, &t.q1); - updatesel(); -/* t.t.i->flush(); */ - x = t.m.xy.x; - y = t.m.xy.y; - /* stay here until something interesting happens */ - do { - readmouse(mc); - t.m = mc->m; - } while(t.m.buttons==b && abs(t.m.xy.x-x)<4 && abs(t.m.xy.y-y)<4); - t.m.xy.x = x; /* in case we're calling frselect */ - t.m.xy.y = y; - clickmsec = 0; - } - - if(t.m.buttons == b) { - frselect(t.f, mc); - t.m = mc->m; - t.q0 = t.f->p0 + t.org; - t.q1 = t.f->p1 + t.org; - clickmsec = t.m.msec; - clickq0 = t.q0; - } - if((t.m.buttons != b) &&(b&1)){ - enum{Cancut = 1, Canpaste = 2} state = Cancut | Canpaste; - while(t.m.buttons){ - if(t.m.buttons&2){ - if(state&Cancut){ - snarf(); - cut(); - state = Canpaste; - } - }else if(t.m.buttons&4){ - if(state&Canpaste){ - snarfupdate(); - if(t.nsnarf){ - paste(t.snarf, t.nsnarf, 0); - } - state = Cancut; - } - } - readmouse(mc); - t.m = mc->m; - } - } -} + menu2str +}; -Rune newline[] = { '\n', 0 }; +Rune newline[] = { '\n' }; void -domenu2(int but) +button2menu(Window *w) { - if(scrolling) - menu2str[Scroll] = "+ scroll"; + if(w->deleted) + return; + incref(&w->ref); + if(w->scrolling) + menu2str[Scroll] = "noscroll"; else - menu2str[Scroll] = "- scroll"; + menu2str[Scroll] = "scroll"; if(cooked) - menu2str[Cooked] = "+ mustecho"; + menu2str[Cook] = "nocook"; else - menu2str[Cooked] = "- mustecho"; + menu2str[Cook] = "cook"; - switch(menuhit(but, mc, &menu2, nil)){ - case -1: - break; + switch(menuhit(2, mousectl, &menu2, wscreen)){ case Cut: - snarf(); - cut(); - if(scrolling) - show(t.q0); - break; - case Paste: - snarfupdate(); - paste(t.snarf, t.nsnarf, 0); - if(scrolling) - show(t.q0); + wsnarf(w); + wcut(w); + wscrdraw(w); break; + case Snarf: - snarf(); - if(scrolling) - show(t.q0); - break; - case Send: - if(t.q0 != t.q1) - snarf(); - else - snarfupdate(); - t.q0 = t.q1 = t.nr; - updatesel(); - paste(t.snarf, t.nsnarf, 1); - if(t.nsnarf == 0 || t.snarf[t.nsnarf-1] != '\n') - paste(newline, 1, 1); - show(t.nr); - consread(); + wsnarf(w); break; - case Scroll: - scrolling = !scrolling; - if (scrolling) { - show(t.nr); - consread(); - } + + case Paste: + //XXX getsnarf(); + wpaste(w); + wscrdraw(w); break; + case Plumb: - plumb(t.q0, t.q1); + wplumb(w); break; - case Cooked: - cooked = !cooked; - break; - default: - sysfatal("bad menu item"); - } -} -int -windfilewidth(uint q0, int oneelement) -{ - uint q; - Rune r; - - q = q0; - while(q > 0){ - r = t.r[q-1]; - if(r<=' ') - break; - if(oneelement && r=='/') + case Send: + //XXX getsnarf(); + wsnarf(w); + if(nsnarf == 0) break; - --q; - } - return q0-q; -} - -void -showcandidates(Completion *c) -{ - int i; - Fmt f; - Rune *rp; - uint nr, qline, q0; - char *s; - - runefmtstrinit(&f); - if (c->nmatch == 0) - s = "[no matches in "; - else - s = "["; - if(c->nfile > 32) - fmtprint(&f, "%s%d files]\n", s, c->nfile); - else{ - fmtprint(&f, "%s", s); - for(i=0; i<c->nfile; i++){ - if(i > 0) - fmtprint(&f, " "); - fmtprint(&f, "%s", c->filename[i]); - } - fmtprint(&f, "]\n"); - } - /* place text at beginning of line before host point */ - qline = t.qh; - while(qline>0 && t.r[qline-1] != '\n') - qline--; - - rp = runefmtstrflush(&f); - nr = runestrlen(rp); - - q0 = t.q0; - q0 += insert(rp, nr, qline, 0) - qline; - free(rp); - t.q0 = q0+nr; - t.q1 = q0+nr; - updatesel(); -} - -Rune* -namecomplete(void) -{ - int nstr, npath; - Rune *rp, *path, *str; - Completion *c; - char *s, *dir, *root; - - /* control-f: filename completion; works back to white space or / */ - if(t.q0<t.nr && t.r[t.q0]>' ') /* must be at end of word */ - return nil; - nstr = windfilewidth(t.q0, TRUE); - str = runemalloc(nstr); - runemove(str, t.r+(t.q0-nstr), nstr); - npath = windfilewidth(t.q0-nstr, FALSE); - path = runemalloc(npath); - runemove(path, t.r+(t.q0-nstr-npath), npath); - rp = nil; - - /* is path rooted? if not, we need to make it relative to window path */ - if(npath>0 && path[0]=='/'){ - dir = malloc(UTFmax*npath+1); - sprint(dir, "%.*S", npath, path); - }else{ - if(strcmp(wdir, "") == 0) - root = "."; - else - root = wdir; - dir = malloc(strlen(root)+1+UTFmax*npath+1); - sprint(dir, "%s/%.*S", root, npath, path); - } - dir = cleanname(dir); - - s = smprint("%.*S", nstr, str); - c = complete(dir, s); - free(s); - if(c == nil) - goto Return; - - if(!c->advance) - showcandidates(c); - - if(c->advance) - rp = runesmprint("%s", c->string); - - Return: - freecompletion(c); - free(dir); - free(path); - free(str); - return rp; -} - -void -scrollup(int n) -{ - setorigin(backnl(t.org, n), 1); -} - -void -scrolldown(int n) -{ - setorigin(line2q(n), 1); - if(t.qh<=t.org+t.f->nchars) - consread(); -} - -void -key(Rune r) -{ - Rune *rp; - int nr; - - if(r == 0) - return; - switch(r){ - case Kpgup: - scrollup(t.f->maxlines*2/3); - return; - case Kpgdown: - scrolldown(t.f->maxlines*2/3); - return; - case Kup: - scrollup(t.f->maxlines/3); - return; - case Kdown: - scrolldown(t.f->maxlines/3); - return; - case Kleft: - if(t.q0 > 0){ - t.q0--; - t.q1 = t.q0; - updatesel(); - show(t.q0); - } - return; - case Kright: - if(t.q1 < t.nr){ - t.q1++; - t.q0 = t.q1; - updatesel(); - show(t.q1); - } - return; - case Khome: - show(0); - return; - case Kend: - case 0x05: - show(t.nr); - return; - - /* - * Non-standard extensions. - */ - case CUT: - snarf(); - cut(); - if(scrolling) - show(t.q0); - return; - case COPY: - snarf(); - if(scrolling) - show(t.q0); - return; - case PASTE: - snarfupdate(); - paste(t.snarf, t.nsnarf, 0); - if(scrolling) - show(t.q0); - return; - } - - /* - * This if used to be below the if(rawon() && t.q0==t.nr), - * but let's try putting it here. This will allow ESC-processing - * to toggle hold mode even in remote SSH connections. - * The drawback is that vi-style processing gets harder. - * If you find yourself in some weird readline mode, good - * luck getting out without ESC. Let's see who complains. - */ - if(r==ESC){ /* toggle hold */ - holdon = !holdon; - drawhold(holdon); - /* replaceintegerproperty("_9WM_HOLD_MODE", 1, 32, holdon); */ - if(!holdon) - consread(); - return; - } - - if(!holdon && rawon() && t.q0 == t.nr){ - addraw(&r, 1); - consread(); - return; - } - - if(r == 0x7F){ /* DEL: send interrupt; what a mess */ - char rubout[1]; - - if(holdon){ - holdon = 0; - drawhold(holdon); + if(w->rawing){ + waddraw(w, snarf, nsnarf); + if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004') + waddraw(w, newline, 1); + }else{ + winsert(w, snarf, nsnarf, w->nr); + if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004') + winsert(w, newline, 1, w->nr); } - t.qh = t.q0 = t.q1 = t.nr; - show(t.q0); - rubout[0] = getintr(sfd); - write(rcfd, rubout, 1); - return; - } - - snarf(); + wsetselect(w, w->nr, w->nr); + wshow(w, w->nr); + break; - switch(r) { - case 0x06: /* ^F: file name completion */ - case Kins: /* Insert: file name completion */ - rp = namecomplete(); - if(rp == nil) - return; - nr = runestrlen(rp); - paste(rp, nr, 1); - free(rp); - return; - case 0x08: /* ^H: erase character */ - case 0x15: /* ^U: erase line */ - case 0x17: /* ^W: erase word */ - if (t.q0 != 0 && t.q0 != t.qh) - t.q0 -= bswidth(r, t.q0, 1); - cut(); + case Scroll: + if(w->scrolling ^= 1) + wshow(w, w->nr); break; - default: - paste(&r, 1, 1); + + case Cook: + cooked ^= 1; break; } - if(scrolling) - show(t.q0); -} - -int -bswidth(Rune c, uint start, int eatnl) -{ - uint q, eq, stop; - Rune r; - int skipping; - - /* there is known to be at least one character to erase */ - if(c == 0x08) /* ^H: erase character */ - return 1; - q = start; - stop = 0; - if(q > t.qh) - stop = t.qh; - skipping = 1; - while(q > stop){ - r = t.r[q-1]; - if(r == '\n'){ /* eat at most one more character */ - if(q == start && eatnl) /* eat the newline */ - --q; - break; - } - if(c == 0x17){ - eq = isexpand(r); - if(eq && skipping) /* found one; stop skipping */ - skipping = 0; - else if(!eq && !skipping) - break; - } - --q; - } - return start-q; + wclose(w); + wsendctlmesg(w, Wakeup, ZR, nil); + flushimage(display, 1); } int -consready(void) -{ - int i, c; - - if(holdon) - return 0; - - if(rawon()) - return t.nraw != 0 || t.qh < t.nr; - - /* look to see if there is a complete line */ - for(i=t.qh; i<t.nr; i++){ - c = t.r[i]; - if(c=='\n' || c=='\004' || c==0x7F) - return 1; - } - return 0; -} - - -void -consread(void) -{ - char buf[8000], *p; - int c, width, n; - int s, raw; - - raw = rawon(); - for(;;) { - if(!consready()) - return; - n = sizeof(buf); - p = buf; - c = 0; - while(n >= UTFmax && (t.qh<t.nr || t.nraw > 0)) { - if(t.qh == t.nr){ - width = runetochar(p, &t.raw[0]); - t.nraw--; - runemove(t.raw, t.raw+1, t.nraw); - }else - width = runetochar(p, &t.r[t.qh++]); - c = *p; - p += width; - n -= width; - if(c == 0x7F){ - *(p-1) = getintr(sfd); - if(!raw) - break; - } - if(!raw && (c == '\n' || c == '\004')) - break; - } - n = p-buf; - - /* - * If we've been echoing, make sure the terminal isn't - * while we do the write. This screws up if someone - * else tries to turn off echo at the same time we do - * (we'll turn it on again after the write), but that's not - * too likely. - */ - s = setecho(sfd, 0); - if(write(rcfd, buf, n) < 0) - threadexitsall(0); - if(s) - setecho(sfd, s); - } -} - -void -conswrite(char *p, int n) -{ - int n2, i; - Rune buf2[1000], *q; - - /* convert to runes */ - i = t.npart; - if(i > 0){ - /* handle partial runes */ - while(i < UTFmax && n>0) { - t.part[i] = *p; - i++; - p++; - n--; - if(fullrune(t.part, i)) { - t.npart = 0; - chartorune(buf2, t.part); - runewrite(buf2, 1); - break; - } - } - /* there is a little extra room in a message buf */ - } - - while(n >= UTFmax || fullrune(p, n)) { - n2 = nelem(buf2); - q = buf2; - - while(n2) { - if(n < UTFmax && !fullrune(p, n)) - break; - i = chartorune(q, p); - p += i; - n -= i; - n2--; - q++; - } - runewrite(buf2, q-buf2); - } - - if(n != 0) { - assert(n+t.npart < UTFmax); - memcpy(t.part+t.npart, p, n); - t.npart += n; - } - - if(scrolling) - show(t.qh); -} - -void -runewrite(Rune *r, int n) -{ - static int havecr; - int i; - uint initial; - uint q0, q1; - uint p0, p1; - Rune *p, *q; - - n = label(r, n); - if(n == 0) - return; - - /* process trailing \r from previous write */ - initial = 0; - if(havecr && *r != '\r' && *r != '\n') - initial = bswidth(0x15, t.qh, 0); - havecr = 0; - - /* get rid of backspaces */ - p = q = r; - for(i=0; i<n; i++) { - if(*p == '\b') { - if(q == r) - initial++; - else - --q; - } else if(*p == '\r') { /* treat like ^U */ - /* convert CR without NL into erased line */ - /* i feel really sleazy about this but it helps */ - while(i<n-1 && *(p+1) == '\r'){ - i++; - p++; - } - if(i<n-1 && *(p+1) != '\n'){ - while(q > r && *(q-1) != '\n') - q--; - if(q==r) - initial = bswidth(0x15, t.qh, 0); - }else if(i == n-1) - havecr = 1; - } else if(*p) - *q++ = *p; - p++; - } - n = q-r; - - if(initial){ - /* write turned into a delete */ - - if(initial > t.qh) - initial = t.qh; - q0 = t.qh-initial; - q1 = t.qh; - - runemove(t.r+q0, t.r+q1, t.nr-q1); - t.nr -= initial; - t.qh -= initial; - if(t.q0 > q1) - t.q0 -= initial; - else if(t.q0 > q0) - t.q0 = q0; - if(t.q1 > q1) - t.q1 -= initial; - else if(t.q1 > q0) - t.q1 = q0; - if(t.org > q1) - t.org -= initial; - else if(q0 < t.org+t.f->nchars){ - if(t.org < q0) - p0 = q0 - t.org; - else { - t.org = q0; - p0 = 0; - } - p1 = q1 - t.org; - if(p1 > t.f->nchars) - p1 = t.f->nchars; - frdelete(t.f, p0, p1); - fill(); - } - updatesel(); - } - - insert(r, n, t.qh, 1); -} - - -void -cut(void) -{ - uint n, p0, p1; - uint q0, q1; - - q0 = t.q0; - q1 = t.q1; - - if (q0 < t.org && q1 >= t.org) - show(q0); - - n = q1-q0; - if(n == 0) - return; - runemove(t.r+q0, t.r+q1, t.nr-q1); - t.nr -= n; - t.q0 = t.q1 = q0; - if(q1 < t.qh) - t.qh -= n; - else if(q0 < t.qh) - t.qh = q0; - if(q1 < t.org) - t.org -= n; - else if(q0 < t.org+t.f->nchars){ - assert(q0 >= t.org); - p0 = q0 - t.org; - p1 = q1 - t.org; - if(p1 > t.f->nchars) - p1 = t.f->nchars; - frdelete(t.f, p0, p1); - fill(); - } - updatesel(); -} - -void -snarfupdate(void) -{ - char *pp; - int n, i; - Rune *p; - - pp = getsnarf(); - if(pp == nil) - return; - n = strlen(pp); - if(n <= 0) { - /*t.nsnarf = 0;*/ - return; - } - t.snarf = runerealloc(t.snarf, n); - for(i=0,p=t.snarf; i<n; p++) - i += chartorune(p, pp+i); - t.nsnarf = p-t.snarf; - -} - -char sbuf[SnarfSize]; -void -snarf(void) -{ - char *p; - int i, n; - Rune *rp; - - if(t.q1 == t.q0) - return; - n = t.q1-t.q0; - t.snarf = runerealloc(t.snarf, n); - for(i=0,p=sbuf,rp=t.snarf; i<n && p < sbuf+SnarfSize-UTFmax; i++){ - *rp++ = *(t.r+t.q0+i); - p += runetochar(p, t.r+t.q0+i); - } - t.nsnarf = rp-t.snarf; - *p = '\0'; - putsnarf(sbuf); -} - -uint -min(uint x, uint y) -{ - if(x < y) - return x; - return y; -} - -uint -max(uint x, uint y) -{ - if(x > y) - return x; - return y; -} - -uint -insert(Rune *r, int n, uint q0, int hostwrite) -{ - uint m; - - if(n == 0) - return q0; - if(t.nr+n>HiWater && q0>=t.org && q0>=t.qh){ - m = min(HiWater-LoWater, min(t.org, t.qh)); - t.org -= m; - t.qh -= m; - if(t.q0 > m) - t.q0 -= m; - else - t.q0 = 0; - if(t.q1 > m) - t.q1 -= m; - else - t.q1 = 0; - t.nr -= m; - runemove(t.r, t.r+m, t.nr); - q0 -= m; - } - if(t.nr+n > t.maxr){ - /* - * Minimize realloc breakage: - * Allocate at least MinWater - * Double allocation size each time - * But don't go much above HiWater - */ - m = max(min(2*(t.nr+n), HiWater), t.nr+n)+MinWater; - if(m > HiWater) - m = max(HiWater+MinWater, t.nr+n); - if(m > t.maxr){ - t.r = runerealloc(t.r, m); - t.maxr = m; - } - } - runemove(t.r+q0+n, t.r+q0, t.nr-q0); - runemove(t.r+q0, r, n); - t.nr += n; - /* if output touches, advance selection, not qh; works best for keyboard and output */ - if(q0 <= t.q1) - t.q1 += n; - if(q0 <= t.q0) - t.q0 += n; - if(q0 < t.qh || (q0==t.qh && hostwrite)) - t.qh += n; - else - consread(); - if(q0 < t.org) - t.org += n; - else if(q0 <= t.org+t.f->nchars) - frinsert(t.f, r, r+n, q0-t.org); - return q0; -} - -void -paste(Rune *r, int n, int advance) -{ - Rune *rbuf; - - if(!holdon && rawon() && t.q0==t.nr){ - addraw(r, n); - consread(); - return; - } - - cut(); - if(n == 0) - return; - - /* - * if this is a button2 execute then we might have been passed - * runes inside the buffer. must save them before realloc. - */ - rbuf = nil; - if(t.r <= r && r < t.r+n){ - rbuf = runemalloc(n); - runemove(rbuf, r, n); - r = rbuf; - } - - insert(r, n, t.q0, 0); - updatesel(); - free(rbuf); -} - -void -fill(void) +rawon(void) { - if (t.f->nlines >= t.f->maxlines) - return; - frinsert(t.f, t.r + t.org + t.f->nchars, t.r + t.nr, t.f->nchars); + return !cooked && !isecho(sfd); } -void -updatesel(void) -{ - Frame *f; - uint n; - - f = t.f; - if(t.org+f->p0 == t.q0 && t.org+f->p1 == t.q1) - return; - - n = t.f->nchars; - - frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 0); - if (t.q0 >= t.org) - f->p0 = t.q0-t.org; - else - f->p0 = 0; - if(f->p0 > n) - f->p0 = n; - if (t.q1 >= t.org) - f->p1 = t.q1-t.org; - else - f->p1 = 0; - if(f->p1 > n) - f->p1 = n; - frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 1); - /* - if(t.qh<=t.org+t.f.nchars && t.cwqueue != 0) - t.cwqueue->wakeup <-= 0; -*/ - - tcheck(); -} - -void -show(uint q0) -{ - int nl; - uint q, oq; - - if(cansee(q0)) - return; - - if (q0<t.org) - nl = t.f->maxlines/5; - else - nl = 4*t.f->maxlines/5; - q = backnl(q0, nl); - /* avoid going in the wrong direction */ - if (q0>t.org && q<t.org) - q = t.org; - setorigin(q, 0); - /* keep trying until q0 is on the screen */ - while(!cansee(q0)) { - assert(q0 >= t.org); - oq = q; - q = line2q(t.f->maxlines-nl); - assert(q > oq); - setorigin(q, 1); - } -} - -int -cansee(uint q0) -{ - uint qe; - - qe = t.org+t.f->nchars; - - if(q0>=t.org && q0 < qe) - return 1; - if (q0 != qe) - return 0; - if (t.f->nlines < t.f->maxlines) - return 1; - if (q0 > 0 && t.r[t.nr-1] == '\n') - return 0; - return 1; -} + * I/O with child rc. + */ +int label(Rune*, int); void -setorigin(uint org, int exact) +rcoutputproc(void *arg) { - int i, a; - uint n; + int i, cnt, n, nb, nr; + static char data[9000]; + Conswritemesg cwm; + Rune *r; + Stringpair pair; - if(org>0 && !exact){ - /* try and start after a newline */ - /* don't try harder than 256 chars */ - for(i=0; i<256 && org<t.nr; i++){ - if(t.r[org-1] == '\n') - break; - org++; - } - } - a = org-t.org; - - if(a>=0 && a<t.f->nchars) - frdelete(t.f, 0, a); - else if(a<0 && -a<100*t.f->maxlines){ - n = t.org - org; - frinsert(t.f, t.r+org, t.r+org+n, 0); - }else - frdelete(t.f, 0, t.f->nchars); - t.org = org; - fill(); - updatesel(); -} - - -uint -line2q(uint n) -{ - Frame *f; - - f = t.f; - return frcharofpt(f, Pt(f->r.min.x, f->r.min.y + n*font->height))+t.org; -} - -uint -backnl(uint p, uint n) -{ - int i, j; - - for (i = n;; i--) { - /* at 256 chars, call it a line anyway */ - for(j=256; --j>0 && p>0; p--) - if(t.r[p-1]=='\n') - break; - if (p == 0 || i == 0) - return p; - p--; - } -} - -void -addraw(Rune *r, int nr) -{ - t.raw = runerealloc(t.raw, t.nraw+nr); - runemove(t.raw+t.nraw, r, nr); - t.nraw += nr; -/* - if(t.crqueue != nil) - t.crqueue->wakeup <-= 0; -*/ -} - - -Rune left1[] = { '{', '[', '(', '<', 0xab, 0 }; -Rune right1[] = { '}', ']', ')', '>', 0xbb, 0 }; -Rune left2[] = { '\n', 0 }; -Rune left3[] = { '\'', '"', '`', 0 }; - -Rune *left[] = { - left1, - left2, - left3, - 0 -}; - -Rune *right[] = { - right1, - left2, - left3, - 0 -}; - -void -doubleclick(uint *q0, uint *q1) -{ - int c, i; - Rune *r, *l, *p; - uint q; - - for(i=0; left[i]!=0; i++){ - q = *q0; - l = left[i]; - r = right[i]; - /* try matching character to left, looking right */ - if(q == 0) - c = '\n'; - else - c = t.r[q-1]; - p = strrune(l, c); - if(p != 0){ - if(clickmatch(c, r[p-l], 1, &q)) - *q1 = q-(c!='\n'); - return; - } - /* try matching character to right, looking left */ - if(q == t.nr) - c = '\n'; - else - c = t.r[q]; - p = strrune(r, c); - if(p != 0){ - if(clickmatch(c, l[p-r], -1, &q)){ - *q1 = *q0+(*q0<t.nr && c=='\n'); - *q0 = q; - if(c!='\n' || q!=0 || t.r[0]=='\n') - (*q0)++; - } - return; - } - } - /* try filling out word to right */ - while(*q1<t.nr && isexpand(t.r[*q1])) - (*q1)++; - /* try filling out word to left */ - while(*q0>0 && isexpand(t.r[*q0-1])) - (*q0)--; -} - -int -clickmatch(int cl, int cr, int dir, uint *q) -{ - Rune c; - int nest; - - nest = 1; + i = 0; + cnt = 0; for(;;){ - if(dir > 0){ - if(*q == t.nr) - break; - c = t.r[*q]; - (*q)++; - }else{ - if(*q == 0) - break; - (*q)--; - c = t.r[*q]; + /* XXX Let typing have a go -- maybe there's a rubout waiting. */ + i = 1-i; + n = read(rcfd, data+cnt, sizeof data-cnt); + if(n <= 0){ + if(n < 0) + fprint(2, "9term: rc read error: %r\n"); + threadexitsall("eof on rc output"); } - if(c == cr){ - if(--nest==0) - return 1; - }else if(c == cl) - nest++; - } - return cl=='\n' && nest==1; -} - -void -tcheck(void) -{ - Frame *f; - - f = t.f; - - assert(t.q0 <= t.q1 && t.q1 <= t.nr); - assert(t.org <= t.nr && t.qh <= t.nr); - assert(f->p0 <= f->p1 && f->p1 <= f->nchars); - assert(t.org + f->nchars <= t.nr); - assert(t.org+f->nchars==t.nr || (f->nlines >= f->maxlines)); -} - -Rune* -strrune(Rune *s, Rune c) -{ - Rune c1; - - if(c == 0) { - while(*s++) - ; - return s-1; - } - - while(c1 = *s++) - if(c1 == c) - return s-1; - return 0; -} - -void -scrdraw(void) -{ - Rectangle r, r1, r2; - static Image *scrx; - - r = scrollr; - r.min.x += 1; /* border between margin and bar */ - r1 = r; - if(scrx==0 || scrx->r.max.y < r.max.y){ - if(scrx) - freeimage(scrx); - scrx = allocimage(display, Rect(0, 0, 32, r.max.y), screen->chan, 1, DPaleyellow); - if(scrx == 0) - sysfatal("scroll balloc"); - } - r1.min.x = 0; - r1.max.x = Dx(r); - r2 = scrpos(r1, t.org, t.org+t.f->nchars, t.nr); - if(!eqrect(r2, lastsr)){ - lastsr = r2; - draw(scrx, r1, cols[BORD], nil, ZP); - draw(scrx, r2, cols[BACK], nil, r2.min); -// r2 = r1; -// r2.min.x = r2.max.x-1; -// draw(scrx, r2, cols[BORD], nil, ZP); - draw(screen, r, scrx, nil, r1.min); - } -} - -Rectangle -scrpos(Rectangle r, ulong p0, ulong p1, ulong tot) -{ - long h; - Rectangle q; - - q = insetrect(r, 1); - h = q.max.y-q.min.y; - if(tot == 0) - return q; - if(tot > 1024L*1024L) - tot >>= 10, p0 >>= 10, p1 >>= 10; - if(p0 > 0) - q.min.y += h*p0/tot; - if(p1 < tot) - q.max.y -= h*(tot-p1)/tot; - if(q.max.y < q.min.y+2){ - if(q.min.y+2 <= r.max.y) - q.max.y = q.min.y+2; - else - q.min.y = q.max.y-2; - } - return q; -} - -void -scroll(int but) -{ - uint p0, oldp0; - Rectangle s; - int x, y, my, h, first, exact; - - s = insetrect(scrollr, 1); - h = s.max.y-s.min.y; - x = (s.min.x+s.max.x)/2; - oldp0 = ~0; - first = 1; - do{ - if(t.m.xy.x<s.min.x || s.max.x<=t.m.xy.x){ - readmouse(mc); - t.m = mc->m; - }else{ - my = t.m.xy.y; - if(my < s.min.y) - my = s.min.y; - if(my >= s.max.y) - my = s.max.y; -// if(!eqpt(t.m.xy, Pt(x, my))) -// cursorset(Pt(x, my)); - exact = 1; - if(but == 2){ - y = my; - if(y > s.max.y-2) - y = s.max.y-2; - if(t.nr > 1024*1024) - p0 = ((t.nr>>10)*(y-s.min.y)/h)<<10; - else - p0 = t.nr*(y-s.min.y)/h; - exact = 0; - } else if(but == 1) - p0 = backnl(t.org, (my-s.min.y)/font->height); - else - p0 = t.org+frcharofpt(t.f, Pt(s.max.x, my)); - - if(oldp0 != p0) - setorigin(p0, exact); - oldp0 = p0; - scrdraw(); - readmouse(mc); - t.m = mc->m; + cnt += n; + r = runemalloc(cnt); + cvttorunes(data, cnt-UTFmax, r, &nb, &nr, nil); + /* approach end of buffer */ + while(fullrune(data+nb, cnt-nb)){ + nb += chartorune(&r[nr], data+nb); + if(r[nr]) + nr++; } - }while(t.m.buttons & (1<<(but-1))); -} - -void -plumbstart(void) -{ - if((plumbfd = plumbopen("send", OWRITE)) < 0) - fprint(2, "9term: plumbopen: %r\n"); -} - -void -plumb(uint q0, uint q1) -{ - Plumbmsg *pm; - char *p; - int i, p0, n; - char cbuf[100]; + if(nb < cnt) + memmove(data, data+nb, cnt-nb); + cnt -= nb; + + nr = label(r, nr); + if(nr == 0) + continue; - pm = malloc(sizeof(Plumbmsg)); - pm->src = strdup("9term"); - pm->dst = 0; - pm->wdir = strdup(wdir); - pm->type = strdup("text"); - pm->data = nil; - if(q1 > q0) - pm->attr = nil; - else{ - p0 = q0; - wordclick(&q0, &q1); - sprint(cbuf, "click=%d", p0-q0); - pm->attr = plumbunpackattr(cbuf); + recv(w->conswrite, &cwm); + pair.s = r; + pair.ns = nr; + send(cwm.cw, &pair); } - if(q0==q1){ - plumbfree(pm); - return; - } - pm->data = malloc(SnarfSize); - n = q1 - q0; - for(i=0,p=pm->data; i<n && p < pm->data + SnarfSize-UTFmax; i++) - p += runetochar(p, t.r+q0+i); - *p = '\0'; - pm->ndata = strlen(pm->data); - if(plumbsend(plumbfd, pm) < 0){ - setcursor(mc, &query); - sleep(500); - if(holdon) - setcursor(mc, &whitearrow); - else - setcursor(mc, nil); - } - plumbfree(pm); } /* @@ -1862,7 +432,7 @@ int label(Rune *sr, int n) { Rune *sl, *el, *er, *r; - char *p; + char *p, *dir; er = sr+n; for(r=er-1; r>=sr; r--) @@ -1872,21 +442,23 @@ label(Rune *sr, int n) return n; el = r+1; - if(el-sr > sizeof wdir) - sr = el - sizeof wdir; for(sl=el-3; sl>=sr; sl--) if(sl[0]=='\033' && sl[1]==']' && sl[2]==';') break; if(sl < sr) return n; - snprint(wdir, sizeof wdir, "%.*S", (el-1)-(sl+3), sl+3); - drawsetlabel(wdir); + dir = smprint("%.*S", (el-1)-(sl+3), sl+3); + if(dir){ + drawsetlabel(dir); + free(w->dir); + w->dir = dir; + } /* remove trailing /-sysname if present */ - p = strrchr(wdir, '/'); + p = strrchr(dir, '/'); if(p && *(p+1) == '-'){ - if(p == wdir) + if(p == dir) p++; *p = 0; } @@ -1896,92 +468,30 @@ label(Rune *sr, int n) return n; } -int -rawon(void) -{ - return !cooked && !isecho(sfd); -} - -/* - * Clumsy hack to make " and "" work. - * Then again, what's not a clumsy hack here in Unix land? - */ - -char adir[100]; -int afd; - -void -removethesocket(void) -{ - if(thesocket[0]) - if(remove(thesocket) < 0) - fprint(2, "remove %s: %r\n", thesocket); -} - -void -servedevtext(void) -{ - char buf[100]; - - snprint(buf, sizeof buf, "unix!/tmp/9term-text.%d", getpid()); - - if((afd = announce(buf, adir)) < 0){ - putenv("text9term", ""); - return; - } - - putenv("text9term", buf); - proccreate(listenproc, nil, STACK); - strcpy(thesocket, buf+5); - atexit(removethesocket); -} - void -listenproc(void *arg) +rcinputproc(void *arg) { - int fd; - char dir[100]; + static char data[9000]; + int s; + Consreadmesg crm; + Channel *c1, *c2; + Stringpair pair; - USED(arg); for(;;){ - fd = listen(adir, dir); - if(fd < 0){ - close(afd); - return; - } - proccreate(textthread, (void*)fd, STACK); + recv(w->consread, &crm); + c1 = crm.c1; + c2 = crm.c2; + + pair.s = data; + pair.ns = sizeof data; + send(c1, &pair); + recv(c2, &pair); + + s = setecho(sfd, 0); + if(write(rcfd, pair.s, pair.ns) < 0) + threadexitsall(nil); + if(s) + setecho(sfd, s); } } -void -textthread(void *arg) -{ - int fd, i, x, n, end; - Rune r; - char buf[4096], *p, *ep; - - fd = (int)arg; - p = buf; - ep = buf+sizeof buf; - end = t.org+t.nr; /* avoid possible output loop */ - for(i=t.org;; i++){ - if(i >= end || ep-p < UTFmax){ - for(x=0; x<p-buf; x+=n) - if((n = write(fd, buf+x, (p-x)-buf)) <= 0) - goto break2; - - if(i >= end) - break; - p = buf; - } - if(i < t.org) - i = t.org; - r = t.r[i-t.org]; - if(r < Runeself) - *p++ = r; - else - p += runetochar(p, &r); - } -break2: - close(fd); -} |
