main.c 12 KB

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