1 #include <u.h> 2 #include <libc.h> 3 #include <libg.h> 4 #include <frame.h> 5 #include "flayer.h" 6 #include "samterm.h" 7 8 Text cmd; 9 Rune *scratch; 10 long nscralloc; 11 Cursor *cursor; 12 extern Bitmap screen; 13 Mouse mouse; 14 Flayer *which = 0; 15 Flayer *work = 0; 16 long snarflen; 17 long typestart = -1; 18 long typeend = -1; 19 long typeesc = -1; 20 long modified = 0; /* strange lookahead for menus */ 21 char lock = 1; 22 char hasunlocked = 0; 23 24 void 25 main(int argc, char *argv[]) 26 { 27 int i, got, scr; 28 Text *t; 29 Rectangle r; 30 Flayer *nwhich; 31 32 getscreen(argc, argv); 33 iconinit(); 34 initio(); 35 scratch = alloc(100*RUNESIZE); 36 nscralloc = 100; 37 r = screen.r; 38 r.max.y = r.min.y+Dy(r)/5; 39 flstart(screen.clipr); 40 rinit(&cmd.rasp); 41 flnew(&cmd.l[0], gettext, 1, &cmd); 42 flinit(&cmd.l[0], r, font); 43 cmd.nwin = 1; 44 which = &cmd.l[0]; 45 cmd.tag = Untagged; 46 outTs(Tversion, VERSION); 47 startnewfile(Tstartcmdfile, &cmd); 48 49 got = 0; 50 for(;;got = waitforio()){ 51 if(hasunlocked && RESHAPED()) 52 reshape(); 53 if(got&RHost) 54 rcv(); 55 if(got&RExtern){ 56 for(i=0; cmd.l[i].textfn==0; i++) 57 ; 58 current(&cmd.l[i]); 59 flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes); 60 type(which, RExtern); 61 } 62 if(got&RKeyboard) 63 if(which) 64 type(which, RKeyboard); 65 else 66 kbdblock(); 67 if(got&RMouse){ 68 if(lock==2 || !ptinrect(mouse.xy, screen.r)){ 69 mouseunblock(); 70 continue; 71 } 72 nwhich = flwhich(mouse.xy); 73 scr = which && ptinrect(mouse.xy, which->scroll); 74 if(mouse.buttons) 75 flushtyping(1); 76 if(mouse.buttons&1){ 77 if(nwhich){ 78 if(nwhich!=which) 79 current(nwhich); 80 else if(scr) 81 scroll(which, 1); 82 else{ 83 t=(Text *)which->user1; 84 if(flselect(which)){ 85 outTsl(Tdclick, t->tag, which->p0); 86 t->lock++; 87 }else if(t!=&cmd) 88 outcmd(); 89 } 90 } 91 }else if((mouse.buttons&2) && which){ 92 if(scr) 93 scroll(which, 2); 94 else 95 menu2hit(); 96 }else if((mouse.buttons&4)){ 97 if(scr) 98 scroll(which, 3); 99 else 100 menu3hit(); 101 } 102 mouseunblock(); 103 } 104 } 105 } 106 107 108 void 109 reshape(void){ 110 int i; 111 112 flreshape(screen.clipr); 113 for(i = 0; i<nname; i++) 114 if(text[i]) 115 hcheck(text[i]->tag); 116 } 117 118 void 119 current(Flayer *nw) 120 { 121 Text *t; 122 123 if(which) 124 flborder(which, 0); 125 if(nw){ 126 flushtyping(1); 127 flupfront(nw); 128 flborder(nw, 1); 129 buttons(Up); 130 t = (Text *)nw->user1; 131 t->front = nw-&t->l[0]; 132 if(t != &cmd) 133 work = nw; 134 } 135 which = nw; 136 } 137 138 void 139 closeup(Flayer *l) 140 { 141 Text *t=(Text *)l->user1; 142 int m; 143 144 m = whichmenu(t->tag); 145 if(m < 0) 146 return; 147 flclose(l); 148 if(l == which){ 149 which = 0; 150 current(flwhich(Pt(0, 0))); 151 } 152 if(l == work) 153 work = 0; 154 if(--t->nwin == 0){ 155 rclear(&t->rasp); 156 free((uchar *)t); 157 text[m] = 0; 158 }else if(l == &t->l[t->front]){ 159 for(m=0; m<NL; m++) /* find one; any one will do */ 160 if(t->l[m].textfn){ 161 t->front = m; 162 return; 163 } 164 panic("close"); 165 } 166 } 167 168 Flayer * 169 findl(Text *t) 170 { 171 int i; 172 for(i = 0; i<NL; i++) 173 if(t->l[i].textfn==0) 174 return &t->l[i]; 175 return 0; 176 } 177 178 void 179 duplicate(Flayer *l, Rectangle r, Font *f, int close) 180 { 181 Text *t=(Text *)l->user1; 182 Flayer *nl = findl(t); 183 Rune *rp; 184 ulong n; 185 186 if(nl){ 187 flnew(nl, gettext, l->user0, (char *)t); 188 flinit(nl, r, f); 189 nl->origin = l->origin; 190 rp = (*l->textfn)(l, l->f.nchars, &n); 191 flinsert(nl, rp, rp+n, l->origin); 192 flsetselect(nl, l->p0, l->p1); 193 if(close){ 194 flclose(l); 195 if(l==which) 196 which = 0; 197 }else 198 t->nwin++; 199 current(nl); 200 hcheck(t->tag); 201 } 202 cursorswitch(cursor); 203 } 204 205 void 206 buttons(int updown) 207 { 208 while(((mouse.buttons&7)!=0) != updown) 209 frgetmouse(); 210 } 211 212 int 213 getr(Rectangle *rp) 214 { 215 Point p; 216 Rectangle r; 217 218 *rp = getrect(3, &mouse); 219 if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){ 220 p = rp->min; 221 r = cmd.l[cmd.front].entire; 222 *rp = screen.r; 223 if(cmd.nwin==1){ 224 if (p.y <= r.min.y) 225 rp->max.y = r.min.y; 226 else if (p.y >= r.max.y) 227 rp->min.y = r.max.y; 228 if (p.x <= r.min.x) 229 rp->max.x = r.min.x; 230 else if (p.x >= r.max.x) 231 rp->min.x = r.max.x; 232 } 233 } 234 return rectclip(rp, screen.r) && 235 rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40; 236 } 237 238 void 239 snarf(Text *t, int w) 240 { 241 Flayer *l = &t->l[w]; 242 243 if(l->p1>l->p0){ 244 snarflen = l->p1-l->p0; 245 outTsll(Tsnarf, t->tag, l->p0, l->p1); 246 } 247 } 248 249 void 250 cut(Text *t, int w, int save, int check) 251 { 252 long p0, p1; 253 Flayer *l; 254 255 l = &t->l[w]; 256 p0 = l->p0; 257 p1 = l->p1; 258 if(p0 == p1) 259 return; 260 if(p0 < 0) 261 panic("cut"); 262 if(save) 263 snarf(t, w); 264 outTsll(Tcut, t->tag, p0, p1); 265 flsetselect(l, p0, p0); 266 t->lock++; 267 hcut(t->tag, p0, p1-p0); 268 if(check) 269 hcheck(t->tag); 270 } 271 272 void 273 paste(Text *t, int w) 274 { 275 if(snarflen){ 276 cut(t, w, 0, 0); 277 t->lock++; 278 outTsl(Tpaste, t->tag, t->l[w].p0); 279 } 280 } 281 282 void 283 scrorigin(Flayer *l, int but, long p0) 284 { 285 Text *t=(Text *)l->user1; 286 287 switch(but){ 288 case 1: 289 outTsll(Torigin, t->tag, l->origin, p0); 290 break; 291 case 2: 292 outTsll(Torigin, t->tag, p0, 1L); 293 break; 294 case 3: 295 horigin(t->tag,p0); 296 } 297 } 298 299 int 300 alnum(int c) 301 { 302 /* 303 * Hard to get absolutely right. Use what we know about ASCII 304 * and assume anything above the Latin control characters is 305 * potentially an alphanumeric. 306 */ 307 if(c<=' ') 308 return 0; 309 if(0x7F<=c && c<=0xA0) 310 return 0; 311 if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) 312 return 0; 313 return 1; 314 } 315 316 int 317 raspc(Rasp *r, long p) 318 { 319 ulong n; 320 rload(r, p, p+1, &n); 321 if(n) 322 return scratch[0]; 323 return 0; 324 } 325 326 long 327 ctlw(Rasp *r, long o, long p) 328 { 329 int c; 330 331 if(--p < o) 332 return o; 333 if(raspc(r, p)=='\n') 334 return p; 335 for(; p>=o && !alnum(c=raspc(r, p)); --p) 336 if(c=='\n') 337 return p+1; 338 for(; p>o && alnum(raspc(r, p-1)); --p) 339 ; 340 return p>=o? p : o; 341 } 342 343 long 344 ctlu(Rasp *r, long o, long p) 345 { 346 for(; p-1>=o && raspc(r, p-1)!='\n'; --p) 347 ; 348 return p>=o? p : o; 349 } 350 351 int 352 center(Flayer *l, long a) 353 { 354 Text *t; 355 356 t = l->user1; 357 if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){ 358 if(a > t->rasp.nrunes) 359 a = t->rasp.nrunes; 360 outTsll(Torigin, t->tag, a, 2L); 361 return 1; 362 } 363 return 0; 364 } 365 366 int 367 onethird(Flayer *l, long a) 368 { 369 Text *t; 370 Rectangle s; 371 long lines; 372 373 t = l->user1; 374 if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){ 375 if(a > t->rasp.nrunes) 376 a = t->rasp.nrunes; 377 s = inset(l->scroll, 1); 378 lines = ((s.max.y-s.min.y)/l->f.font->height+1)/3; 379 if (lines < 2) 380 lines = 2; 381 outTsll(Torigin, t->tag, a, lines); 382 return 1; 383 } 384 return 0; 385 } 386 387 void 388 flushtyping(int clearesc) 389 { 390 Text *t; 391 ulong n; 392 393 if(clearesc) 394 typeesc = -1; 395 if(typestart == typeend) { 396 modified = 0; 397 return; 398 } 399 t = which->user1; 400 if(t != &cmd) 401 modified = 1; 402 rload(&t->rasp, typestart, typeend, &n); 403 scratch[n] = 0; 404 if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){ 405 setlock(); 406 outcmd(); 407 } 408 outTslS(Ttype, t->tag, typestart, scratch); 409 typestart = -1; 410 typeend = -1; 411 } 412 413 #define SCROLLKEY 0x80 414 #define ESC 0x1B 415 416 void 417 type(Flayer *l, int res) /* what a bloody mess this is */ 418 { 419 Text *t = (Text *)l->user1; 420 Rune buf[100]; 421 Rune *p = buf; 422 int c, backspacing; 423 long a; 424 int scrollkey; 425 426 scrollkey = 0; 427 if(res == RKeyboard) 428 scrollkey = qpeekc()==SCROLLKEY; /* ICK */ 429 430 if(lock || t->lock){ 431 kbdblock(); 432 return; 433 } 434 a = l->p0; 435 if(a!=l->p1 && !scrollkey){ 436 flushtyping(1); 437 cut(t, t->front, 1, 1); 438 return; /* it may now be locked */ 439 } 440 backspacing = 0; 441 while((c = kbdchar())>0){ 442 if(res == RKeyboard){ 443 if(c==SCROLLKEY || c==ESC) 444 break; 445 /* backspace, ctrl-u, ctrl-w, del */ 446 if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){ 447 backspacing = 1; 448 break; 449 } 450 } 451 *p++ = c; 452 if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0])) 453 break; 454 } 455 if(p > buf){ 456 if(typestart < 0) 457 typestart = a; 458 if(typeesc < 0) 459 typeesc = a; 460 hgrow(t->tag, a, p-buf, 0); 461 t->lock++; /* pretend we Trequest'ed for hdatarune*/ 462 hdatarune(t->tag, a, buf, p-buf); 463 a += p-buf; 464 l->p0 = a; 465 l->p1 = a; 466 typeend = a; 467 if(c=='\n' || typeend-typestart>100) 468 flushtyping(0); 469 onethird(l, a); 470 } 471 if(c == SCROLLKEY){ 472 flushtyping(0); 473 center(l, l->origin+l->f.nchars+1); 474 /* backspacing immediately after outcmd(): sorry */ 475 }else if(backspacing && !lock){ 476 if(l->f.p0>0 && a>0){ 477 switch(c){ 478 case '\b': 479 case 0x7F: /* del */ 480 l->p0 = a-1; 481 break; 482 case 0x15: /* ctrl-u */ 483 l->p0 = ctlu(&t->rasp, l->origin, a); 484 break; 485 case 0x17: /* ctrl-w */ 486 l->p0 = ctlw(&t->rasp, l->origin, a); 487 break; 488 } 489 l->p1 = a; 490 if(l->p1 != l->p0){ 491 /* cut locally if possible */ 492 if(typestart<=l->p0 && l->p1<=typeend){ 493 t->lock++; /* to call hcut */ 494 hcut(t->tag, l->p0, l->p1-l->p0); 495 /* hcheck is local because we know rasp is contiguous */ 496 hcheck(t->tag); 497 }else{ 498 flushtyping(0); 499 cut(t, t->front, 0, 1); 500 } 501 } 502 if(typeesc >= l->p0) 503 typeesc = l->p0; 504 if(typestart >= 0){ 505 if(typestart >= l->p0) 506 typestart = l->p0; 507 typeend = l->p0; 508 if(typestart == typeend){ 509 typestart = -1; 510 typeend = -1; 511 modified = 0; 512 } 513 } 514 } 515 }else{ 516 if(c==ESC && typeesc>=0){ 517 l->p0 = typeesc; 518 l->p1 = a; 519 flushtyping(1); 520 } 521 for(l=t->l; l<&t->l[NL]; l++) 522 if(l->textfn) 523 flsetselect(l, l->p0, l->p1); 524 } 525 } 526 527 528 void 529 outcmd(void){ 530 if(work) 531 outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1); 532 } 533 534 void 535 panic(char *s) 536 { 537 fprint(2, "samterm:panic: "); 538 perror(s); 539 abort(); 540 } 541 542 Rune* 543 gettext(Flayer *l, long n, ulong *np) 544 { 545 Text *t; 546 547 t = l->user1; 548 rload(&t->rasp, l->origin, l->origin+n, np); 549 return scratch; 550 } 551 552 long 553 scrtotal(Flayer *l) 554 { 555 return ((Text *)l->user1)->rasp.nrunes; 556 } 557 558 void* 559 alloc(ulong n) 560 { 561 void *p; 562 563 p = malloc(n); 564 if(p == 0) 565 panic("alloc"); 566 memset(p, 0, n); 567 return p; 568 } 569