Blob
1 #include <u.h>2 #include <libc.h>3 #include <draw.h>4 #include <thread.h>5 #include <mouse.h>6 #include <cursor.h>7 #include <keyboard.h>8 #include <frame.h>9 #include "flayer.h"10 #include "samterm.h"12 Text cmd;13 Rune *scratch;14 long nscralloc;15 Cursor *cursor;16 Flayer *which = 0;17 Flayer *work = 0;18 long snarflen;19 long typestart = -1;20 long typeend = -1;21 long typeesc = -1;22 long modified = 0; /* strange lookahead for menus */23 char hostlock = 1;24 char hasunlocked = 0;25 int maxtab = 8;27 void28 threadmain(int argc, char *argv[])29 {30 int i, got, scr;31 Text *t;32 Rectangle r;33 Flayer *nwhich;35 /*36 * sam is talking to us on fd 0 and 1.37 * move these elsewhere so that if we accidentally38 * use 0 and 1 in other code, nothing bad happens.39 */40 dup(0, 3);41 dup(1, 4);42 hostfd[0] = 3;43 hostfd[1] = 4;44 close(0);45 close(1);46 open("/dev/null", OREAD);47 dup(2, 1);49 getscreen(argc, argv);50 iconinit();51 initio();52 scratch = alloc(100*RUNESIZE);53 nscralloc = 100;54 r = screen->r;55 r.max.y = r.min.y+Dy(r)/5;56 flstart(screen->clipr);57 rinit(&cmd.rasp);58 flnew(&cmd.l[0], gettext, 1, &cmd);59 flinit(&cmd.l[0], r, font, cmdcols);60 cmd.nwin = 1;61 which = &cmd.l[0];62 cmd.tag = Untagged;63 outTs(Tversion, VERSION);64 startnewfile(Tstartcmdfile, &cmd);66 got = 0;67 for(;;got = waitforio()){68 if(hasunlocked && RESIZED())69 resize();70 if(got&(1<<RHost))71 rcv();72 if(got&(1<<RPlumb)){73 for(i=0; cmd.l[i].textfn==0; i++)74 ;75 current(&cmd.l[i]);76 flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes);77 type(which, RPlumb);78 }79 if(got&(1<<RKeyboard))80 if(which)81 type(which, RKeyboard);82 else83 kbdblock();84 if(got&(1<<RMouse)){85 if(hostlock==2 || !ptinrect(mousep->xy, screen->r)){86 mouseunblock();87 continue;88 }89 nwhich = flwhich(mousep->xy);90 scr = which && ptinrect(mousep->xy, which->scroll);91 if(mousep->buttons)92 flushtyping(1);93 if(mousep->buttons&1){94 if(nwhich){95 if(nwhich!=which)96 current(nwhich);97 else if(scr)98 scroll(which, 1);99 else{100 t=(Text *)which->user1;101 if(flselect(which)){102 outTsl(Tdclick, t->tag, which->p0);103 t->lock++;104 }else if(t!=&cmd)105 outcmd();106 }107 }108 }else if((mousep->buttons&2) && which){109 if(scr)110 scroll(which, 2);111 else112 menu2hit();113 }else if((mousep->buttons&4)){114 if(scr)115 scroll(which, 3);116 else117 menu3hit();118 }119 mouseunblock();120 }121 }122 }125 void126 resize(void)127 {128 int i;130 flresize(screen->clipr);131 for(i = 0; i<nname; i++)132 if(text[i])133 hcheck(text[i]->tag);134 }136 void137 current(Flayer *nw)138 {139 Text *t;141 if(which)142 flborder(which, 0);143 if(nw){144 flushtyping(1);145 flupfront(nw);146 flborder(nw, 1);147 buttons(Up);148 t = (Text *)nw->user1;149 t->front = nw-&t->l[0];150 if(t != &cmd)151 work = nw;152 }153 which = nw;154 }156 void157 closeup(Flayer *l)158 {159 Text *t=(Text *)l->user1;160 int m;162 m = whichmenu(t->tag);163 if(m < 0)164 return;165 flclose(l);166 if(l == which){167 which = 0;168 current(flwhich(Pt(0, 0)));169 }170 if(l == work)171 work = 0;172 if(--t->nwin == 0){173 rclear(&t->rasp);174 free((uchar *)t);175 text[m] = 0;176 }else if(l == &t->l[t->front]){177 for(m=0; m<NL; m++) /* find one; any one will do */178 if(t->l[m].textfn){179 t->front = m;180 return;181 }182 panic("close");183 }184 }186 Flayer *187 findl(Text *t)188 {189 int i;190 for(i = 0; i<NL; i++)191 if(t->l[i].textfn==0)192 return &t->l[i];193 return 0;194 }196 void197 duplicate(Flayer *l, Rectangle r, Font *f, int close)198 {199 Text *t=(Text *)l->user1;200 Flayer *nl = findl(t);201 Rune *rp;202 ulong n;204 if(nl){205 flnew(nl, gettext, l->user0, (char *)t);206 flinit(nl, r, f, l->f.cols);207 nl->origin = l->origin;208 rp = (*l->textfn)(l, l->f.nchars, &n);209 flinsert(nl, rp, rp+n, l->origin);210 flsetselect(nl, l->p0, l->p1);211 if(close){212 flclose(l);213 if(l==which)214 which = 0;215 }else216 t->nwin++;217 current(nl);218 hcheck(t->tag);219 }220 setcursor(mousectl, cursor);221 }223 void224 buttons(int updown)225 {226 while(((mousep->buttons&7)!=0) != updown)227 getmouse();228 }230 int231 getr(Rectangle *rp)232 {233 Point p;234 Rectangle r;236 *rp = getrect(3, mousectl);237 if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){238 p = rp->min;239 r = cmd.l[cmd.front].entire;240 *rp = screen->r;241 if(cmd.nwin==1){242 if (p.y <= r.min.y)243 rp->max.y = r.min.y;244 else if (p.y >= r.max.y)245 rp->min.y = r.max.y;246 if (p.x <= r.min.x)247 rp->max.x = r.min.x;248 else if (p.x >= r.max.x)249 rp->min.x = r.max.x;250 }251 }252 return rectclip(rp, screen->r) &&253 rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40;254 }256 void257 snarf(Text *t, int w)258 {259 Flayer *l = &t->l[w];261 if(l->p1>l->p0){262 snarflen = l->p1-l->p0;263 outTsll(Tsnarf, t->tag, l->p0, l->p1);264 }265 }267 void268 cut(Text *t, int w, int save, int check)269 {270 long p0, p1;271 Flayer *l;273 l = &t->l[w];274 p0 = l->p0;275 p1 = l->p1;276 if(p0 == p1)277 return;278 if(p0 < 0)279 panic("cut");280 if(save)281 snarf(t, w);282 outTsll(Tcut, t->tag, p0, p1);283 flsetselect(l, p0, p0);284 t->lock++;285 hcut(t->tag, p0, p1-p0);286 if(check)287 hcheck(t->tag);288 }290 void291 paste(Text *t, int w)292 {293 if(snarflen){294 cut(t, w, 0, 0);295 t->lock++;296 outTsl(Tpaste, t->tag, t->l[w].p0);297 }298 }300 void301 scrorigin(Flayer *l, int but, long p0)302 {303 Text *t=(Text *)l->user1;305 switch(but){306 case 1:307 outTsll(Torigin, t->tag, l->origin, p0);308 break;309 case 2:310 outTsll(Torigin, t->tag, p0, 1L);311 break;312 case 3:313 horigin(t->tag,p0);314 }315 }317 int318 alnum(int c)319 {320 /*321 * Hard to get absolutely right. Use what we know about ASCII322 * and assume anything above the Latin control characters is323 * potentially an alphanumeric.324 */325 if(c<=' ')326 return 0;327 if(0x7F<=c && c<=0xA0)328 return 0;329 if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))330 return 0;331 return 1;332 }334 int335 raspc(Rasp *r, long p)336 {337 ulong n;338 rload(r, p, p+1, &n);339 if(n)340 return scratch[0];341 return 0;342 }344 long345 ctlw(Rasp *r, long o, long p)346 {347 int c;349 if(--p < o)350 return o;351 if(raspc(r, p)=='\n')352 return p;353 for(; p>=o && !alnum(c=raspc(r, p)); --p)354 if(c=='\n')355 return p+1;356 for(; p>o && alnum(raspc(r, p-1)); --p)357 ;358 return p>=o? p : o;359 }361 long362 ctlu(Rasp *r, long o, long p)363 {364 if(--p < o)365 return o;366 if(raspc(r, p)=='\n')367 return p;368 for(; p-1>=o && raspc(r, p-1)!='\n'; --p)369 ;370 return p>=o? p : o;371 }373 int374 center(Flayer *l, long a)375 {376 Text *t;378 t = l->user1;379 if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){380 if(a > t->rasp.nrunes)381 a = t->rasp.nrunes;382 outTsll(Torigin, t->tag, a, 2L);383 return 1;384 }385 return 0;386 }388 int389 onethird(Flayer *l, long a)390 {391 Text *t;392 Rectangle s;393 long lines;395 t = l->user1;396 if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){397 if(a > t->rasp.nrunes)398 a = t->rasp.nrunes;399 s = insetrect(l->scroll, 1);400 lines = ((s.max.y-s.min.y)/l->f.font->height+1)/3;401 if (lines < 2)402 lines = 2;403 outTsll(Torigin, t->tag, a, lines);404 return 1;405 }406 return 0;407 }409 void410 flushtyping(int clearesc)411 {412 Text *t;413 ulong n;415 if(clearesc)416 typeesc = -1;417 if(typestart == typeend) {418 modified = 0;419 return;420 }421 t = which->user1;422 if(t != &cmd)423 modified = 1;424 rload(&t->rasp, typestart, typeend, &n);425 scratch[n] = 0;426 if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){427 setlock();428 outcmd();429 }430 outTslS(Ttype, t->tag, typestart, scratch);431 typestart = -1;432 typeend = -1;433 }435 #define SCROLLKEY Kdown436 #define BACKSCROLLKEY Kup437 #define ESC 0x1B439 void440 type(Flayer *l, int res) /* what a bloody mess this is */441 {442 Text *t = (Text *)l->user1;443 Rune buf[100];444 Rune *p = buf;445 int c, backspacing;446 long a, a0;447 int scrollkey;449 scrollkey = 0;450 if(res == RKeyboard)451 scrollkey = (qpeekc()==SCROLLKEY || qpeekc()==BACKSCROLLKEY); /* ICK */453 if(hostlock || t->lock){454 kbdblock();455 return;456 }457 a = l->p0;458 if(a!=l->p1 && !scrollkey){459 flushtyping(1);460 cut(t, t->front, 1, 1);461 return; /* it may now be locked */462 }463 backspacing = 0;464 while((c = kbdchar())>0){465 if(res == RKeyboard){466 if(c==SCROLLKEY || c==BACKSCROLLKEY || c==ESC)467 break;468 /* backspace, ctrl-u, ctrl-w, del */469 if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){470 backspacing = 1;471 break;472 }473 }474 *p++ = c;475 if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0]))476 break;477 }478 if(p > buf){479 if(typestart < 0)480 typestart = a;481 if(typeesc < 0)482 typeesc = a;483 hgrow(t->tag, a, p-buf, 0);484 t->lock++; /* pretend we Trequest'ed for hdatarune*/485 hdatarune(t->tag, a, buf, p-buf);486 a += p-buf;487 l->p0 = a;488 l->p1 = a;489 typeend = a;490 if(c=='\n' || typeend-typestart>100)491 flushtyping(0);492 onethird(l, a);493 }494 if(c == SCROLLKEY){495 flushtyping(0);496 center(l, l->origin+l->f.nchars+1);497 /* backspacing immediately after outcmd(): sorry */498 }else if(c == BACKSCROLLKEY){499 flushtyping(0);500 a0 = l->origin-l->f.nchars;501 if(a0 < 0)502 a0 = 0;503 center(l, a0);504 }else if(backspacing && !hostlock){505 if(l->f.p0>0 && a>0){506 switch(c){507 case '\b':508 case 0x7F: /* del */509 l->p0 = a-1;510 break;511 case 0x15: /* ctrl-u */512 l->p0 = ctlu(&t->rasp, l->origin, a);513 break;514 case 0x17: /* ctrl-w */515 l->p0 = ctlw(&t->rasp, l->origin, a);516 break;517 }518 l->p1 = a;519 if(l->p1 != l->p0){520 /* cut locally if possible */521 if(typestart<=l->p0 && l->p1<=typeend){522 t->lock++; /* to call hcut */523 hcut(t->tag, l->p0, l->p1-l->p0);524 /* hcheck is local because we know rasp is contiguous */525 hcheck(t->tag);526 }else{527 flushtyping(0);528 cut(t, t->front, 0, 1);529 }530 }531 if(typeesc >= l->p0)532 typeesc = l->p0;533 if(typestart >= 0){534 if(typestart >= l->p0)535 typestart = l->p0;536 typeend = l->p0;537 if(typestart == typeend){538 typestart = -1;539 typeend = -1;540 modified = 0;541 }542 }543 }544 }else{545 if(c==ESC && typeesc>=0){546 l->p0 = typeesc;547 l->p1 = a;548 flushtyping(1);549 }550 for(l=t->l; l<&t->l[NL]; l++)551 if(l->textfn)552 flsetselect(l, l->p0, l->p1);553 }554 }557 void558 outcmd(void){559 if(work)560 outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1);561 }563 void564 panic(char *s)565 {566 panic1(display, s);567 }569 void570 panic1(Display *d, char *s)571 {572 fprint(2, "samterm:panic: ");573 perror(s);574 abort();575 }577 Rune*578 gettext(Flayer *l, long n, ulong *np)579 {580 Text *t;582 t = l->user1;583 rload(&t->rasp, l->origin, l->origin+n, np);584 return scratch;585 }587 long588 scrtotal(Flayer *l)589 {590 return ((Text *)l->user1)->rasp.nrunes;591 }593 void*594 alloc(ulong n)595 {596 void *p;598 p = malloc(n);599 if(p == 0)600 panic("alloc");601 memset(p, 0, n);602 return p;603 }