main.c 11 KB

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