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 void
28 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 accidentally
38 * 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 else
83 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();
108 }else if((mousep->buttons&2) && which){
109 if(scr)
110 scroll(which, 2);
111 else
112 menu2hit();
113 }else if((mousep->buttons&4)){
114 if(scr)
115 scroll(which, 3);
116 else
117 menu3hit();
119 mouseunblock();
125 void
126 resize(void)
128 int i;
130 flresize(screen->clipr);
131 for(i = 0; i<nname; i++)
132 if(text[i])
133 hcheck(text[i]->tag);
136 void
137 current(Flayer *nw)
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;
153 which = nw;
156 void
157 closeup(Flayer *l)
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)));
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;
182 panic("close");
186 Flayer *
187 findl(Text *t)
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;
196 void
197 duplicate(Flayer *l, Rectangle r, Font *f, int close)
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 }else
216 t->nwin++;
217 current(nl);
218 hcheck(t->tag);
220 setcursor(mousectl, cursor);
223 void
224 buttons(int updown)
226 while(((mousep->buttons&7)!=0) != updown)
227 getmouse();
230 int
231 getr(Rectangle *rp)
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;
252 return rectclip(rp, screen->r) &&
253 rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40;
256 void
257 snarf(Text *t, int w)
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);
267 void
268 cut(Text *t, int w, int save, int check)
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);
290 void
291 paste(Text *t, int w)
293 if(snarflen){
294 cut(t, w, 0, 0);
295 t->lock++;
296 outTsl(Tpaste, t->tag, t->l[w].p0);
300 void
301 scrorigin(Flayer *l, int but, long p0)
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);
317 int
318 alnum(int c)
320 /*
321 * Hard to get absolutely right. Use what we know about ASCII
322 * and assume anything above the Latin control characters is
323 * 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;
334 int
335 raspc(Rasp *r, long p)
337 ulong n;
338 rload(r, p, p+1, &n);
339 if(n)
340 return scratch[0];
341 return 0;
344 long
345 ctlw(Rasp *r, long o, long p)
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)
358 return p>=o? p : o;
361 long
362 ctlu(Rasp *r, long o, long p)
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)
370 return p>=o? p : o;
373 int
374 center(Flayer *l, long a)
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;
385 return 0;
388 int
389 onethird(Flayer *l, long a)
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;
406 return 0;
409 void
410 flushtyping(int clearesc)
412 Text *t;
413 ulong n;
415 if(clearesc)
416 typeesc = -1;
417 if(typestart == typeend) {
418 modified = 0;
419 return;
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();
430 outTslS(Ttype, t->tag, typestart, scratch);
431 typestart = -1;
432 typeend = -1;
435 #define SCROLLKEY Kdown
436 #define BACKSCROLLKEY Kup
437 #define ESC 0x1B
439 void
440 type(Flayer *l, int res) /* what a bloody mess this is */
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;
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 */
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;
474 *p++ = c;
475 if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0]))
476 break;
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);
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;
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);
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;
544 }else{
545 if(c==ESC && typeesc>=0){
546 l->p0 = typeesc;
547 l->p1 = a;
548 flushtyping(1);
550 for(l=t->l; l<&t->l[NL]; l++)
551 if(l->textfn)
552 flsetselect(l, l->p0, l->p1);
557 void
558 outcmd(void){
559 if(work)
560 outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1);
563 void
564 panic(char *s)
566 panic1(display, s);
569 void
570 panic1(Display *d, char *s)
572 fprint(2, "samterm:panic: ");
573 perror(s);
574 abort();
577 Rune*
578 gettext(Flayer *l, long n, ulong *np)
580 Text *t;
582 t = l->user1;
583 rload(&t->rasp, l->origin, l->origin+n, np);
584 return scratch;
587 long
588 scrtotal(Flayer *l)
590 return ((Text *)l->user1)->rasp.nrunes;
593 void*
594 alloc(ulong n)
596 void *p;
598 p = malloc(n);
599 if(p == 0)
600 panic("alloc");
601 memset(p, 0, n);
602 return p;