aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/samterm/main.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2003-09-30 17:47:44 +0000
committerrsc <devnull@localhost>2003-09-30 17:47:44 +0000
commit84b1cb73b3f0837f5b959579818158fbb2b1b206 (patch)
tree7e27c119d2c2fe00a70a39985c3715b3d8ca363b /src/cmd/samterm/main.c
parenta59ea66fa99f7b6f03eac71dc0713c33f912b6ab (diff)
downloadplan9port-84b1cb73b3f0837f5b959579818158fbb2b1b206.tar.gz
plan9port-84b1cb73b3f0837f5b959579818158fbb2b1b206.tar.bz2
plan9port-84b1cb73b3f0837f5b959579818158fbb2b1b206.zip
Initial revision
Diffstat (limited to 'src/cmd/samterm/main.c')
-rw-r--r--src/cmd/samterm/main.c585
1 files changed, 585 insertions, 0 deletions
diff --git a/src/cmd/samterm/main.c b/src/cmd/samterm/main.c
new file mode 100644
index 00000000..ef958d78
--- /dev/null
+++ b/src/cmd/samterm/main.c
@@ -0,0 +1,585 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <frame.h>
+#include "flayer.h"
+#include "samterm.h"
+
+Text cmd;
+Rune *scratch;
+long nscralloc;
+Cursor *cursor;
+Flayer *which = 0;
+Flayer *work = 0;
+long snarflen;
+long typestart = -1;
+long typeend = -1;
+long typeesc = -1;
+long modified = 0; /* strange lookahead for menus */
+char hostlock = 1;
+char hasunlocked = 0;
+int maxtab = 8;
+
+void
+threadmain(int argc, char *argv[])
+{
+ int i, got, scr;
+ Text *t;
+ Rectangle r;
+ Flayer *nwhich;
+
+ getscreen(argc, argv);
+ iconinit();
+ initio();
+ scratch = alloc(100*RUNESIZE);
+ nscralloc = 100;
+ r = screen->r;
+ r.max.y = r.min.y+Dy(r)/5;
+ flstart(screen->clipr);
+ rinit(&cmd.rasp);
+ flnew(&cmd.l[0], gettext, 1, &cmd);
+ flinit(&cmd.l[0], r, font, cmdcols);
+ cmd.nwin = 1;
+ which = &cmd.l[0];
+ cmd.tag = Untagged;
+ outTs(Tversion, VERSION);
+ startnewfile(Tstartcmdfile, &cmd);
+
+ got = 0;
+ for(;;got = waitforio()){
+ if(hasunlocked && RESIZED())
+ resize();
+ if(got&(1<<RHost))
+ rcv();
+ if(got&(1<<RPlumb)){
+ for(i=0; cmd.l[i].textfn==0; i++)
+ ;
+ current(&cmd.l[i]);
+ flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes);
+ type(which, RPlumb);
+ }
+ if(got&(1<<RKeyboard))
+ if(which)
+ type(which, RKeyboard);
+ else
+ kbdblock();
+ if(got&(1<<RMouse)){
+ if(hostlock==2 || !ptinrect(mousep->xy, screen->r)){
+ mouseunblock();
+ continue;
+ }
+ nwhich = flwhich(mousep->xy);
+ scr = which && ptinrect(mousep->xy, which->scroll);
+ if(mousep->buttons)
+ flushtyping(1);
+ if(mousep->buttons&1){
+ if(nwhich){
+ if(nwhich!=which)
+ current(nwhich);
+ else if(scr)
+ scroll(which, 1);
+ else{
+ t=(Text *)which->user1;
+ if(flselect(which)){
+ outTsl(Tdclick, t->tag, which->p0);
+ t->lock++;
+ }else if(t!=&cmd)
+ outcmd();
+ }
+ }
+ }else if((mousep->buttons&2) && which){
+ if(scr)
+ scroll(which, 2);
+ else
+ menu2hit();
+ }else if((mousep->buttons&4)){
+ if(scr)
+ scroll(which, 3);
+ else
+ menu3hit();
+ }
+ mouseunblock();
+ }
+ }
+}
+
+
+void
+resize(void)
+{
+ int i;
+
+ flresize(screen->clipr);
+ for(i = 0; i<nname; i++)
+ if(text[i])
+ hcheck(text[i]->tag);
+}
+
+void
+current(Flayer *nw)
+{
+ Text *t;
+
+ if(which)
+ flborder(which, 0);
+ if(nw){
+ flushtyping(1);
+ flupfront(nw);
+ flborder(nw, 1);
+ buttons(Up);
+ t = (Text *)nw->user1;
+ t->front = nw-&t->l[0];
+ if(t != &cmd)
+ work = nw;
+ }
+ which = nw;
+}
+
+void
+closeup(Flayer *l)
+{
+ Text *t=(Text *)l->user1;
+ int m;
+
+ m = whichmenu(t->tag);
+ if(m < 0)
+ return;
+ flclose(l);
+ if(l == which){
+ which = 0;
+ current(flwhich(Pt(0, 0)));
+ }
+ if(l == work)
+ work = 0;
+ if(--t->nwin == 0){
+ rclear(&t->rasp);
+ free((uchar *)t);
+ text[m] = 0;
+ }else if(l == &t->l[t->front]){
+ for(m=0; m<NL; m++) /* find one; any one will do */
+ if(t->l[m].textfn){
+ t->front = m;
+ return;
+ }
+ panic("close");
+ }
+}
+
+Flayer *
+findl(Text *t)
+{
+ int i;
+ for(i = 0; i<NL; i++)
+ if(t->l[i].textfn==0)
+ return &t->l[i];
+ return 0;
+}
+
+void
+duplicate(Flayer *l, Rectangle r, Font *f, int close)
+{
+ Text *t=(Text *)l->user1;
+ Flayer *nl = findl(t);
+ Rune *rp;
+ ulong n;
+
+ if(nl){
+ flnew(nl, gettext, l->user0, (char *)t);
+ flinit(nl, r, f, l->f.cols);
+ nl->origin = l->origin;
+ rp = (*l->textfn)(l, l->f.nchars, &n);
+ flinsert(nl, rp, rp+n, l->origin);
+ flsetselect(nl, l->p0, l->p1);
+ if(close){
+ flclose(l);
+ if(l==which)
+ which = 0;
+ }else
+ t->nwin++;
+ current(nl);
+ hcheck(t->tag);
+ }
+ setcursor(mousectl, cursor);
+}
+
+void
+buttons(int updown)
+{
+ while(((mousep->buttons&7)!=0) != updown)
+ getmouse();
+}
+
+int
+getr(Rectangle *rp)
+{
+ Point p;
+ Rectangle r;
+
+ *rp = getrect(3, mousectl);
+ if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){
+ p = rp->min;
+ r = cmd.l[cmd.front].entire;
+ *rp = screen->r;
+ if(cmd.nwin==1){
+ if (p.y <= r.min.y)
+ rp->max.y = r.min.y;
+ else if (p.y >= r.max.y)
+ rp->min.y = r.max.y;
+ if (p.x <= r.min.x)
+ rp->max.x = r.min.x;
+ else if (p.x >= r.max.x)
+ rp->min.x = r.max.x;
+ }
+ }
+ return rectclip(rp, screen->r) &&
+ rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40;
+}
+
+void
+snarf(Text *t, int w)
+{
+ Flayer *l = &t->l[w];
+
+ if(l->p1>l->p0){
+ snarflen = l->p1-l->p0;
+ outTsll(Tsnarf, t->tag, l->p0, l->p1);
+ }
+}
+
+void
+cut(Text *t, int w, int save, int check)
+{
+ long p0, p1;
+ Flayer *l;
+
+ l = &t->l[w];
+ p0 = l->p0;
+ p1 = l->p1;
+ if(p0 == p1)
+ return;
+ if(p0 < 0)
+ panic("cut");
+ if(save)
+ snarf(t, w);
+ outTsll(Tcut, t->tag, p0, p1);
+ flsetselect(l, p0, p0);
+ t->lock++;
+ hcut(t->tag, p0, p1-p0);
+ if(check)
+ hcheck(t->tag);
+}
+
+void
+paste(Text *t, int w)
+{
+ if(snarflen){
+ cut(t, w, 0, 0);
+ t->lock++;
+ outTsl(Tpaste, t->tag, t->l[w].p0);
+ }
+}
+
+void
+scrorigin(Flayer *l, int but, long p0)
+{
+ Text *t=(Text *)l->user1;
+
+ switch(but){
+ case 1:
+ outTsll(Torigin, t->tag, l->origin, p0);
+ break;
+ case 2:
+ outTsll(Torigin, t->tag, p0, 1L);
+ break;
+ case 3:
+ horigin(t->tag,p0);
+ }
+}
+
+int
+alnum(int c)
+{
+ /*
+ * Hard to get absolutely right. Use what we know about ASCII
+ * and assume anything above the Latin control characters is
+ * potentially an alphanumeric.
+ */
+ if(c<=' ')
+ return 0;
+ if(0x7F<=c && c<=0xA0)
+ return 0;
+ if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
+ return 0;
+ return 1;
+}
+
+int
+raspc(Rasp *r, long p)
+{
+ ulong n;
+ rload(r, p, p+1, &n);
+ if(n)
+ return scratch[0];
+ return 0;
+}
+
+long
+ctlw(Rasp *r, long o, long p)
+{
+ int c;
+
+ if(--p < o)
+ return o;
+ if(raspc(r, p)=='\n')
+ return p;
+ for(; p>=o && !alnum(c=raspc(r, p)); --p)
+ if(c=='\n')
+ return p+1;
+ for(; p>o && alnum(raspc(r, p-1)); --p)
+ ;
+ return p>=o? p : o;
+}
+
+long
+ctlu(Rasp *r, long o, long p)
+{
+ for(; p-1>=o && raspc(r, p-1)!='\n'; --p)
+ ;
+ return p>=o? p : o;
+}
+
+int
+center(Flayer *l, long a)
+{
+ Text *t;
+
+ t = l->user1;
+ if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
+ if(a > t->rasp.nrunes)
+ a = t->rasp.nrunes;
+ outTsll(Torigin, t->tag, a, 2L);
+ return 1;
+ }
+ return 0;
+}
+
+int
+onethird(Flayer *l, long a)
+{
+ Text *t;
+ Rectangle s;
+ long lines;
+
+ t = l->user1;
+ if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
+ if(a > t->rasp.nrunes)
+ a = t->rasp.nrunes;
+ s = insetrect(l->scroll, 1);
+ lines = ((s.max.y-s.min.y)/l->f.font->height+1)/3;
+ if (lines < 2)
+ lines = 2;
+ outTsll(Torigin, t->tag, a, lines);
+ return 1;
+ }
+ return 0;
+}
+
+void
+flushtyping(int clearesc)
+{
+ Text *t;
+ ulong n;
+
+ if(clearesc)
+ typeesc = -1;
+ if(typestart == typeend) {
+ modified = 0;
+ return;
+ }
+ t = which->user1;
+ if(t != &cmd)
+ modified = 1;
+ rload(&t->rasp, typestart, typeend, &n);
+ scratch[n] = 0;
+ if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){
+ setlock();
+ outcmd();
+ }
+ outTslS(Ttype, t->tag, typestart, scratch);
+ typestart = -1;
+ typeend = -1;
+}
+
+#define SCROLLKEY Kdown
+#define BACKSCROLLKEY Kup
+#define ESC 0x1B
+
+void
+type(Flayer *l, int res) /* what a bloody mess this is */
+{
+ Text *t = (Text *)l->user1;
+ Rune buf[100];
+ Rune *p = buf;
+ int c, backspacing;
+ long a, a0;
+ int scrollkey;
+
+ scrollkey = 0;
+ if(res == RKeyboard)
+ scrollkey = (qpeekc()==SCROLLKEY || qpeekc()==BACKSCROLLKEY); /* ICK */
+
+ if(hostlock || t->lock){
+ kbdblock();
+ return;
+ }
+ a = l->p0;
+ if(a!=l->p1 && !scrollkey){
+ flushtyping(1);
+ cut(t, t->front, 1, 1);
+ return; /* it may now be locked */
+ }
+ backspacing = 0;
+ while((c = kbdchar())>0){
+ if(res == RKeyboard){
+ if(c==SCROLLKEY || c==BACKSCROLLKEY || c==ESC)
+ break;
+ /* backspace, ctrl-u, ctrl-w, del */
+ if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){
+ backspacing = 1;
+ break;
+ }
+ }
+ *p++ = c;
+ if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0]))
+ break;
+ }
+ if(p > buf){
+ if(typestart < 0)
+ typestart = a;
+ if(typeesc < 0)
+ typeesc = a;
+ hgrow(t->tag, a, p-buf, 0);
+ t->lock++; /* pretend we Trequest'ed for hdatarune*/
+ hdatarune(t->tag, a, buf, p-buf);
+ a += p-buf;
+ l->p0 = a;
+ l->p1 = a;
+ typeend = a;
+ if(c=='\n' || typeend-typestart>100)
+ flushtyping(0);
+ onethird(l, a);
+ }
+ if(c == SCROLLKEY){
+ flushtyping(0);
+ center(l, l->origin+l->f.nchars+1);
+ /* backspacing immediately after outcmd(): sorry */
+ }else if(c == BACKSCROLLKEY){
+ flushtyping(0);
+ a0 = l->origin-l->f.nchars;
+ if(a0 < 0)
+ a0 = 0;
+ center(l, a0);
+ }else if(backspacing && !hostlock){
+ if(l->f.p0>0 && a>0){
+ switch(c){
+ case '\b':
+ case 0x7F: /* del */
+ l->p0 = a-1;
+ break;
+ case 0x15: /* ctrl-u */
+ l->p0 = ctlu(&t->rasp, l->origin, a);
+ break;
+ case 0x17: /* ctrl-w */
+ l->p0 = ctlw(&t->rasp, l->origin, a);
+ break;
+ }
+ l->p1 = a;
+ if(l->p1 != l->p0){
+ /* cut locally if possible */
+ if(typestart<=l->p0 && l->p1<=typeend){
+ t->lock++; /* to call hcut */
+ hcut(t->tag, l->p0, l->p1-l->p0);
+ /* hcheck is local because we know rasp is contiguous */
+ hcheck(t->tag);
+ }else{
+ flushtyping(0);
+ cut(t, t->front, 0, 1);
+ }
+ }
+ if(typeesc >= l->p0)
+ typeesc = l->p0;
+ if(typestart >= 0){
+ if(typestart >= l->p0)
+ typestart = l->p0;
+ typeend = l->p0;
+ if(typestart == typeend){
+ typestart = -1;
+ typeend = -1;
+ modified = 0;
+ }
+ }
+ }
+ }else{
+ if(c==ESC && typeesc>=0){
+ l->p0 = typeesc;
+ l->p1 = a;
+ flushtyping(1);
+ }
+ for(l=t->l; l<&t->l[NL]; l++)
+ if(l->textfn)
+ flsetselect(l, l->p0, l->p1);
+ }
+}
+
+
+void
+outcmd(void){
+ if(work)
+ outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1);
+}
+
+void
+panic(char *s)
+{
+ panic1(display, s);
+}
+
+void
+panic1(Display *d, char *s)
+{
+ fprint(2, "samterm:panic: ");
+ perror(s);
+ abort();
+}
+
+Rune*
+gettext(Flayer *l, long n, ulong *np)
+{
+ Text *t;
+
+ t = l->user1;
+ rload(&t->rasp, l->origin, l->origin+n, np);
+ return scratch;
+}
+
+long
+scrtotal(Flayer *l)
+{
+ return ((Text *)l->user1)->rasp.nrunes;
+}
+
+void*
+alloc(ulong n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == 0)
+ panic("alloc");
+ memset(p, 0, n);
+ return p;
+}