URI:
       tmain.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tmain.c (12993B)
       ---
            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"
           11 
           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;
           26 int        chord;
           27 int        autoindent;
           28 
           29 #define chording 0        /* code here for reference but it causes deadlocks */
           30 
           31 void
           32 notifyf(void *a, char *msg)
           33 {
           34         if(strcmp(msg, "interrupt") == 0)
           35                 noted(NCONT);
           36         noted(NDFLT);
           37 }
           38 
           39 void
           40 threadmain(int argc, char *argv[])
           41 {
           42         int i, got, scr, w;
           43         Text *t;
           44         Rectangle r;
           45         Flayer *nwhich;
           46 
           47         /*
           48          * sam is talking to us on fd 0 and 1.
           49          * move these elsewhere so that if we accidentally
           50          * use 0 and 1 in other code, nothing bad happens.
           51          */
           52         dup(0, 3);
           53         dup(1, 4);
           54         hostfd[0] = 3;
           55         hostfd[1] = 4;
           56         close(0);
           57         close(1);
           58         open("/dev/null", OREAD);
           59         if(open("/dev/tty", OWRITE) < 0)
           60                 open("/dev/null", OWRITE);
           61 
           62         notify(notifyf);
           63 
           64         if(protodebug) print("getscreen\n");
           65         getscreen(argc, argv);
           66         if(protodebug) print("iconinit\n");
           67         iconinit();
           68         if(protodebug) print("initio\n");
           69         initio();
           70         if(protodebug) print("scratch\n");
           71         scratch = alloc(100*RUNESIZE);
           72         nscralloc = 100;
           73         r = screen->r;
           74         r.max.y = r.min.y+Dy(r)/5;
           75         if(protodebug) print("flstart\n");
           76         flstart(screen->clipr);
           77         rinit(&cmd.rasp);
           78         flnew(&cmd.l[0], gettext, 1, &cmd);
           79         flinit(&cmd.l[0], r, font, cmdcols);
           80         cmd.nwin = 1;
           81         which = &cmd.l[0];
           82         cmd.tag = Untagged;
           83         outTs(Tversion, VERSION);
           84         startnewfile(Tstartcmdfile, &cmd);
           85 
           86         got = 0;
           87         if(protodebug) print("loop\n");
           88         for(;;got = waitforio()){
           89                 if(hasunlocked && RESIZED())
           90                         resize();
           91                 if(got&(1<<RHost))
           92                         rcv();
           93                 if(got&(1<<RPlumb)){
           94                         for(i=0; cmd.l[i].textfn==0; i++)
           95                                 ;
           96                         current(&cmd.l[i]);
           97                         flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes);
           98                         type(which, RPlumb);
           99                 }
          100                 if(got&(1<<RKeyboard))
          101                         if(which)
          102                                 type(which, RKeyboard);
          103                         else
          104                                 kbdblock();
          105                 if(got&(1<<RMouse)){
          106                         if(hostlock==2 || !ptinrect(mousep->xy, screen->r)){
          107                                 mouseunblock();
          108                                 continue;
          109                         }
          110                         nwhich = flwhich(mousep->xy);
          111                         scr = which && ptinrect(mousep->xy, which->scroll);
          112                         if(mousep->buttons)
          113                                 flushtyping(1);
          114                         if(chording && chord==1 && !mousep->buttons)
          115                                 chord = 0;
          116                         if(chording && chord)
          117                                 chord |= mousep->buttons;
          118                         else if(mousep->buttons&1){
          119                                 if(nwhich){
          120                                         if(nwhich!=which)
          121                                                 current(nwhich);
          122                                         else if(scr)
          123                                                 scroll(which, 1);
          124                                         else{
          125                                                 t=(Text *)which->user1;
          126                                                 if(flselect(which)){
          127                                                         outTsl(Tdclick, t->tag, which->p0);
          128                                                         t->lock++;
          129                                                 }else if(t!=&cmd)
          130                                                         outcmd();
          131                                                 if(mousep->buttons&1)
          132                                                         chord = mousep->buttons;
          133                                         }
          134                                 }
          135                         }else if((mousep->buttons&2) && which){
          136                                 if(scr)
          137                                         scroll(which, 2);
          138                                 else
          139                                         menu2hit();
          140                         }else if((mousep->buttons&4)){
          141                                 if(scr)
          142                                         scroll(which, 3);
          143                                 else
          144                                         menu3hit();
          145                         }
          146                         mouseunblock();
          147                 }
          148                 if(chording && chord){
          149                         t = (Text*)which->user1;
          150                         if(!t->lock && !hostlock){
          151                                 w = which-t->l;
          152                                 if(chord&2){
          153                                         cut(t, w, 1, 1);
          154                                         chord &= ~2;
          155                                 }else if(chord&4){
          156                                         paste(t, w);
          157                                         chord &= ~4;
          158                                 }
          159                         }
          160                 }
          161         }
          162 }
          163 
          164 void
          165 resize(void)
          166 {
          167         int i;
          168 
          169         flresize(screen->clipr);
          170         for(i = 0; i<nname; i++)
          171                 if(text[i])
          172                         hcheck(text[i]->tag);
          173 }
          174 
          175 void
          176 current(Flayer *nw)
          177 {
          178         Text *t;
          179 
          180         if(which)
          181                 flborder(which, 0);
          182         if(nw){
          183                 flushtyping(1);
          184                 flupfront(nw);
          185                 flborder(nw, 1);
          186                 buttons(Up);
          187                 t = (Text *)nw->user1;
          188                 t->front = nw-&t->l[0];
          189                 if(t != &cmd)
          190                         work = nw;
          191         }
          192         which = nw;
          193 }
          194 
          195 void
          196 closeup(Flayer *l)
          197 {
          198         Text *t=(Text *)l->user1;
          199         int m;
          200 
          201         m = whichmenu(t->tag);
          202         if(m < 0)
          203                 return;
          204         flclose(l);
          205         if(l == which){
          206                 which = 0;
          207                 current(flwhich(Pt(0, 0)));
          208         }
          209         if(l == work)
          210                 work = 0;
          211         if(--t->nwin == 0){
          212                 rclear(&t->rasp);
          213                 free((uchar *)t);
          214                 text[m] = 0;
          215         }else if(l == &t->l[t->front]){
          216                 for(m=0; m<NL; m++)        /* find one; any one will do */
          217                         if(t->l[m].textfn){
          218                                 t->front = m;
          219                                 return;
          220                         }
          221                 panic("close");
          222         }
          223 }
          224 
          225 Flayer *
          226 findl(Text *t)
          227 {
          228         int i;
          229         for(i = 0; i<NL; i++)
          230                 if(t->l[i].textfn==0)
          231                         return &t->l[i];
          232         return 0;
          233 }
          234 
          235 void
          236 duplicate(Flayer *l, Rectangle r, Font *f, int close)
          237 {
          238         Text *t=(Text *)l->user1;
          239         Flayer *nl = findl(t);
          240         Rune *rp;
          241         ulong n;
          242 
          243         if(nl){
          244                 flnew(nl, gettext, l->user0, (char *)t);
          245                 flinit(nl, r, f, l->f.cols);
          246                 nl->origin = l->origin;
          247                 rp = (*l->textfn)(l, l->f.nchars, &n);
          248                 flinsert(nl, rp, rp+n, l->origin);
          249                 flsetselect(nl, l->p0, l->p1);
          250                 if(close){
          251                         flclose(l);
          252                         if(l==which)
          253                                 which = 0;
          254                 }else
          255                         t->nwin++;
          256                 current(nl);
          257                 hcheck(t->tag);
          258         }
          259         setcursor(mousectl, cursor);
          260 }
          261 
          262 void
          263 buttons(int updown)
          264 {
          265         while(((mousep->buttons&7)!=0) != updown)
          266                 getmouse();
          267 }
          268 
          269 int
          270 getr(Rectangle *rp)
          271 {
          272         Point p;
          273         Rectangle r;
          274 
          275         *rp = getrect(3, mousectl);
          276         if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){
          277                 p = rp->min;
          278                 r = cmd.l[cmd.front].entire;
          279                 *rp = screen->r;
          280                 if(cmd.nwin==1){
          281                         if (p.y <= r.min.y)
          282                                 rp->max.y = r.min.y;
          283                         else if (p.y >= r.max.y)
          284                                 rp->min.y = r.max.y;
          285                         if (p.x <= r.min.x)
          286                                 rp->max.x = r.min.x;
          287                         else if (p.x >= r.max.x)
          288                                 rp->min.x = r.max.x;
          289                 }
          290         }
          291         return rectclip(rp, screen->r) &&
          292            rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40;
          293 }
          294 
          295 void
          296 snarf(Text *t, int w)
          297 {
          298         Flayer *l = &t->l[w];
          299 
          300         if(l->p1>l->p0){
          301                 snarflen = l->p1-l->p0;
          302                 outTsll(Tsnarf, t->tag, l->p0, l->p1);
          303         }
          304 }
          305 
          306 void
          307 cut(Text *t, int w, int save, int check)
          308 {
          309         long p0, p1;
          310         Flayer *l;
          311 
          312         l = &t->l[w];
          313         p0 = l->p0;
          314         p1 = l->p1;
          315         if(p0 == p1)
          316                 return;
          317         if(p0 < 0)
          318                 panic("cut");
          319         if(save)
          320                 snarf(t, w);
          321         outTsll(Tcut, t->tag, p0, p1);
          322         flsetselect(l, p0, p0);
          323         t->lock++;
          324         hcut(t->tag, p0, p1-p0);
          325         if(check)
          326                 hcheck(t->tag);
          327 }
          328 
          329 void
          330 paste(Text *t, int w)
          331 {
          332         if(snarflen){
          333                 cut(t, w, 0, 0);
          334                 t->lock++;
          335                 outTsl(Tpaste, t->tag, t->l[w].p0);
          336         }
          337 }
          338 
          339 void
          340 scrorigin(Flayer *l, int but, long p0)
          341 {
          342         Text *t=(Text *)l->user1;
          343 
          344         switch(but){
          345         case 1:
          346                 outTsll(Torigin, t->tag, l->origin, p0);
          347                 break;
          348         case 2:
          349                 outTsll(Torigin, t->tag, p0, 1L);
          350                 break;
          351         case 3:
          352                 horigin(t->tag,p0);
          353         }
          354 }
          355 
          356 int
          357 alnum(int c)
          358 {
          359         /*
          360          * Hard to get absolutely right.  Use what we know about ASCII
          361          * and assume anything above the Latin control characters is
          362          * potentially an alphanumeric.
          363          */
          364         if(c<=' ')
          365                 return 0;
          366         if(0x7F<=c && c<=0xA0)
          367                 return 0;
          368         if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
          369                 return 0;
          370         return 1;
          371 }
          372 
          373 int
          374 raspc(Rasp *r, long p)
          375 {
          376         ulong n;
          377         rload(r, p, p+1, &n);
          378         if(n)
          379                 return scratch[0];
          380         return 0;
          381 }
          382 
          383 long
          384 ctlw(Rasp *r, long o, long p)
          385 {
          386         int c;
          387 
          388         if(--p < o)
          389                 return o;
          390         if(raspc(r, p)=='\n')
          391                 return p;
          392         for(; p>=o && !alnum(c=raspc(r, p)); --p)
          393                 if(c=='\n')
          394                         return p+1;
          395         for(; p>o && alnum(raspc(r, p-1)); --p)
          396                 ;
          397         return p>=o? p : o;
          398 }
          399 
          400 long
          401 ctlu(Rasp *r, long o, long p)
          402 {
          403         if(--p < o)
          404                 return o;
          405         if(raspc(r, p)=='\n')
          406                 return p;
          407         for(; p-1>=o && raspc(r, p-1)!='\n'; --p)
          408                 ;
          409         return p>=o? p : o;
          410 }
          411 
          412 int
          413 center(Flayer *l, long a)
          414 {
          415         Text *t;
          416 
          417         t = l->user1;
          418         if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
          419                 if(a > t->rasp.nrunes)
          420                         a = t->rasp.nrunes;
          421                 outTsll(Torigin, t->tag, a, 2L);
          422                 return 1;
          423         }
          424         return 0;
          425 }
          426 
          427 int
          428 thirds(Flayer *l, long a, int n)
          429 {
          430         Text *t;
          431         Rectangle s;
          432         long lines;
          433 
          434         t = l->user1;
          435         if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
          436                 if(a > t->rasp.nrunes)
          437                         a = t->rasp.nrunes;
          438                 s = insetrect(l->scroll, 1);
          439                 lines = (n*(s.max.y-s.min.y)/l->f.font->height+1)/3;
          440                 if (lines < 2)
          441                         lines = 2;
          442                 outTsll(Torigin, t->tag, a, lines);
          443                 return 1;
          444         }
          445         return 0;
          446 }
          447 
          448 int
          449 onethird(Flayer *l, long a)
          450 {
          451         return thirds(l, a, 1);
          452 }
          453 
          454 int
          455 twothirds(Flayer *l, long a)
          456 {
          457         return thirds(l, a, 2);
          458 }
          459 
          460 void
          461 flushtyping(int clearesc)
          462 {
          463         Text *t;
          464         ulong n;
          465 
          466         if(clearesc)
          467                 typeesc = -1;
          468         if(typestart == typeend) {
          469                 modified = 0;
          470                 return;
          471         }
          472         t = which->user1;
          473         if(t != &cmd)
          474                 modified = 1;
          475         rload(&t->rasp, typestart, typeend, &n);
          476         scratch[n] = 0;
          477         if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){
          478                 setlock();
          479                 outcmd();
          480         }
          481         outTslS(Ttype, t->tag, typestart, scratch);
          482         typestart = -1;
          483         typeend = -1;
          484 }
          485 
          486 #define        BACKSCROLLKEY        Kup
          487 #define        ENDKEY        Kend
          488 #define        ESC                0x1B
          489 #define        HOMEKEY        Khome
          490 #define        LEFTARROW        Kleft
          491 #define        LINEEND        0x05
          492 #define        LINESTART        0x01
          493 #define        PAGEDOWN        Kpgdown
          494 #define        PAGEUP        Kpgup
          495 #define        RIGHTARROW        Kright
          496 #define        SCROLLKEY        Kdown
          497 #define        CUT        (Kcmd+'x')
          498 #define        COPY        (Kcmd+'c')
          499 #define        PASTE        (Kcmd+'v')
          500 
          501 int
          502 nontypingkey(int c)
          503 {
          504         switch(c){
          505         case BACKSCROLLKEY:
          506         case ENDKEY:
          507         case HOMEKEY:
          508         case LEFTARROW:
          509         case LINEEND:
          510         case LINESTART:
          511         case PAGEDOWN:
          512         case PAGEUP:
          513         case RIGHTARROW:
          514         case SCROLLKEY:
          515         case CUT:
          516         case COPY:
          517         case PASTE:
          518                 return 1;
          519         }
          520         return 0;
          521 }
          522 
          523 void
          524 type(Flayer *l, int res)        /* what a bloody mess this is */
          525 {
          526         Text *t = (Text *)l->user1;
          527         Rune buf[100];
          528         Rune *p = buf;
          529         int c, backspacing;
          530         long a, a0;
          531         int scrollkey;
          532 
          533         scrollkey = 0;
          534         if(res == RKeyboard)
          535                 scrollkey = nontypingkey(qpeekc());        /* ICK */
          536 
          537         if(hostlock || t->lock){
          538                 kbdblock();
          539                 return;
          540         }
          541         a = l->p0;
          542         if(a!=l->p1 && !scrollkey){
          543                 flushtyping(1);
          544                 cut(t, t->front, 1, 1);
          545                 return;        /* it may now be locked */
          546         }
          547         backspacing = 0;
          548         while((c = kbdchar())>0){
          549                 if(res == RKeyboard){
          550                         if(nontypingkey(c) || c==ESC)
          551                                 break;
          552                         /* backspace, ctrl-u, ctrl-w, del */
          553                         if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){
          554                                 backspacing = 1;
          555                                 break;
          556                         }
          557                 }
          558                 *p++ = c;
          559                 if(autoindent)
          560                 if(c == '\n'){
          561                         /* autoindent */
          562                         int cursor, ch;
          563                         cursor = ctlu(&t->rasp, 0, a+(p-buf)-1);
          564                         while(p < buf+nelem(buf)){
          565                                 ch = raspc(&t->rasp, cursor++);
          566                                 if(ch == ' ' || ch == '\t')
          567                                         *p++ = ch;
          568                                 else
          569                                         break;
          570                         }
          571                 }
          572                 if(c == '\n' || p >= buf+nelem(buf))
          573                         break;
          574         }
          575         if(p > buf){
          576                 if(typestart < 0)
          577                         typestart = a;
          578                 if(typeesc < 0)
          579                         typeesc = a;
          580                 hgrow(t->tag, a, p-buf, 0);
          581                 t->lock++;        /* pretend we Trequest'ed for hdatarune*/
          582                 hdatarune(t->tag, a, buf, p-buf);
          583                 a += p-buf;
          584                 l->p0 = a;
          585                 l->p1 = a;
          586                 typeend = a;
          587                 if(c=='\n' || typeend-typestart>100)
          588                         flushtyping(0);
          589                 onethird(l, a);
          590         }
          591         if(c==SCROLLKEY || c==PAGEDOWN){
          592                 flushtyping(0);
          593                 center(l, l->origin+l->f.nchars+1);
          594         }else if(c==BACKSCROLLKEY || c==PAGEUP){
          595                 flushtyping(0);
          596                 a0 = l->origin-l->f.nchars;
          597                 if(a0 < 0)
          598                         a0 = 0;
          599                 center(l, a0);
          600         }else if(c == RIGHTARROW){
          601                 flushtyping(0);
          602                 a0 = l->p0;
          603                 if(a0 < t->rasp.nrunes)
          604                         a0++;
          605                 flsetselect(l, a0, a0);
          606                 center(l, a0);
          607         }else if(c == LEFTARROW){
          608                 flushtyping(0);
          609                 a0 = l->p0;
          610                 if(a0 > 0)
          611                         a0--;
          612                 flsetselect(l, a0, a0);
          613                 center(l, a0);
          614         }else if(c == HOMEKEY){
          615                 flushtyping(0);
          616                 center(l, 0);
          617         }else if(c == ENDKEY){
          618                 flushtyping(0);
          619                 center(l, t->rasp.nrunes);
          620         }else if(c == LINESTART || c == LINEEND){
          621                 flushtyping(1);
          622                 if(c == LINESTART)
          623                         while(a > 0 && raspc(&t->rasp, a-1)!='\n')
          624                                 a--;
          625                 else
          626                         while(a < t->rasp.nrunes && raspc(&t->rasp, a)!='\n')
          627                                 a++;
          628                 l->p0 = l->p1 = a;
          629                 for(l=t->l; l<&t->l[NL]; l++)
          630                         if(l->textfn)
          631                                 flsetselect(l, l->p0, l->p1);
          632         }else if(backspacing && !hostlock){
          633                 /* backspacing immediately after outcmd(): sorry */
          634                 if(l->f.p0>0 && a>0){
          635                         switch(c){
          636                         case '\b':
          637                         case 0x7F:        /* del */
          638                                 l->p0 = a-1;
          639                                 break;
          640                         case 0x15:        /* ctrl-u */
          641                                 l->p0 = ctlu(&t->rasp, l->origin, a);
          642                                 break;
          643                         case 0x17:        /* ctrl-w */
          644                                 l->p0 = ctlw(&t->rasp, l->origin, a);
          645                                 break;
          646                         }
          647                         l->p1 = a;
          648                         if(l->p1 != l->p0){
          649                                 /* cut locally if possible */
          650                                 if(typestart<=l->p0 && l->p1<=typeend){
          651                                         t->lock++;        /* to call hcut */
          652                                         hcut(t->tag, l->p0, l->p1-l->p0);
          653                                         /* hcheck is local because we know rasp is contiguous */
          654                                         hcheck(t->tag);
          655                                 }else{
          656                                         flushtyping(0);
          657                                         cut(t, t->front, 0, 1);
          658                                 }
          659                         }
          660                         if(typeesc >= l->p0)
          661                                 typeesc = l->p0;
          662                         if(typestart >= 0){
          663                                 if(typestart >= l->p0)
          664                                         typestart = l->p0;
          665                                 typeend = l->p0;
          666                                 if(typestart == typeend){
          667                                         typestart = -1;
          668                                         typeend = -1;
          669                                         modified = 0;
          670                                 }
          671                         }
          672                 }
          673         }else{
          674                 if(c==ESC && typeesc>=0){
          675                         l->p0 = typeesc;
          676                         l->p1 = a;
          677                         flushtyping(1);
          678                 }
          679                 for(l=t->l; l<&t->l[NL]; l++)
          680                         if(l->textfn)
          681                                 flsetselect(l, l->p0, l->p1);
          682                 switch(c) {
          683                 case CUT:
          684                         flushtyping(0);
          685                         cut(t, t->front, 1, 1);
          686                         break;
          687                 case COPY:
          688                         flushtyping(0);
          689                         snarf(t, t->front);
          690                         break;
          691                 case PASTE:
          692                         flushtyping(0);
          693                         paste(t, t->front);
          694                         break;
          695                 }
          696         }
          697 }
          698 
          699 
          700 void
          701 outcmd(void){
          702         if(work)
          703                 outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1);
          704 }
          705 
          706 void
          707 panic(char *s)
          708 {
          709         panic1(display, s);
          710 }
          711 
          712 void
          713 panic1(Display *d, char *s)
          714 {
          715         fprint(2, "samterm:panic: ");
          716         perror(s);
          717         abort();
          718 }
          719 
          720 Rune*
          721 gettext(Flayer *l, long n, ulong *np)
          722 {
          723         Text *t;
          724 
          725         t = l->user1;
          726         rload(&t->rasp, l->origin, l->origin+n, np);
          727         return scratch;
          728 }
          729 
          730 long
          731 scrtotal(Flayer *l)
          732 {
          733         return ((Text *)l->user1)->rasp.nrunes;
          734 }
          735 
          736 void*
          737 alloc(ulong n)
          738 {
          739         void *p;
          740 
          741         p = malloc(n);
          742         if(p == 0)
          743                 panic("alloc");
          744         memset(p, 0, n);
          745         return p;
          746 }