main.c - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
main.c (23368B)
---
1
2 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
3 #include <u.h>
4 #include <libg.h>
5 #include <frame.h>
6 #include <unistd.h>
7 #include "flayer.h"
8 #include "samterm.h"
9
10 extern uint64_t _bgpixel;
11 extern void hmoveto(int, int64_t, Flayer *);
12
13 Text cmd;
14 wchar_t *scratch;
15 int64_t nscralloc;
16 extern Bitmap screen;
17 unsigned int cursor;
18 Mouse mouse;
19 Flayer *which = NULL;
20 Flayer *flast = NULL;
21 Flayer *work = NULL;
22 int64_t snarflen;
23 int64_t typestart = -1;
24 int64_t typeend = -1;
25 int64_t typeesc = -1;
26 bool modified = false; /* strange lookahead for menus */
27 char lock = 1;
28 bool hasunlocked = false;
29 bool expandtabs = false;
30 bool autoindent = false;
31 char *machine = "localhost";
32 int exfd = -1;
33 const char *exname;
34 bool followfocus = false;
35
36 void
37 removeext(void)
38 {
39 if (exname)
40 unlink(exname);
41 }
42
43 int
44 main(int argc, char *argv[])
45 {
46 int i, got, scr, opt;
47 Text *t;
48 Rectangle r;
49 Flayer *nwhich;
50 char rcpath[PATH_MAX + 1] = {0};
51 FILE *rc = NULL;
52
53 setlocale(LC_ALL, "");
54 installdefaultbindings();
55 installdefaultchords();
56
57 if (getenv("SAMRC"))
58 strncpy(rcpath, getenv("SAMRC"), PATH_MAX);
59 else
60 snprintf(rcpath, PATH_MAX, "%s/.samrc", getenv("HOME") ? getenv("HOME") : ".");
61
62 while ((opt = getopt(argc, argv, "ef:n:r:")) != -1){
63 switch (opt){
64 case 'r':
65 machine = optarg;
66 break;
67
68 case 'f':
69 exfd = atoi(optarg);
70 break;
71
72 case 'n':
73 exname = optarg;
74 atexit(removeext);
75 break;
76 }
77 }
78
79 rc = fopen(rcpath, "r");
80 if (rc){
81 loadrcfile(rc);
82 fclose(rc);
83 }
84
85 getscreen(argc, argv);
86 initio();
87 scratch = alloc(100*RUNESIZE);
88 nscralloc = 100;
89 r = screen.r;
90 r.max.y = r.min.y+Dy(r)/5;
91 flstart(screen.clipr);
92 rinit(&cmd.rasp);
93 flnew(&cmd.l[0], stgettext, 1, &cmd);
94 cmd.l[0].bg = getbg();
95 flinit(&cmd.l[0], r, font, cmd.l[0].bg);
96 cmd.nwin = 1;
97 which = &cmd.l[0];
98 cmd.tag = Untagged;
99 outTs(Tversion, VERSION);
100 startnewfile(Tstartcmdfile, &cmd);
101
102 got = 0;
103 for(;;got = waitforio()){
104 if(hasunlocked && RESHAPED())
105 reshape();
106 if(got&RHost)
107 rcv();
108 if(got&RExtern){
109 for(i=0; cmd.l[i].textfn==0; i++)
110 ;
111 current(&cmd.l[i]);
112 flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes);
113 type(which);
114 }
115 if(got&RKeyboard){
116 if(which)
117 type(which);
118 else
119 kbdblock();
120 }
121 if(got&RMouse){
122 if(lock==2 || !ptinrect(mouse.xy, screen.r)){
123 mouseunblock();
124 continue;
125 }
126 nwhich = flwhich(mouse.xy);
127 scr = which && ptinrect(mouse.xy, which->scroll);
128 if(mouse.buttons)
129 flushtyping(true);
130 if(mouse.buttons&1){
131 if(nwhich){
132 if(nwhich!=which)
133 current(nwhich);
134 else if(scr)
135 scroll(which, 1, 1);
136 else{
137 t=(Text *)which->user1;
138 if(flselect(which)){
139 outTsl(Tdclick, t->tag, which->p0);
140 t->lock++;
141 }else if(t!=&cmd)
142 outcmd();
143 }
144 }
145 }else if((mouse.buttons&2) && which){
146 if(scr)
147 scroll(which, 2, 2);
148 else
149 menu2hit();
150 }else if((mouse.buttons&4)){
151 if(scr)
152 scroll(which, 3, 3);
153 else
154 menu3hit();
155 }else if(followfocus && nwhich && nwhich!=which){
156 current(nwhich);
157 }
158 mouseunblock();
159 }
160 }
161
162 return EXIT_SUCCESS;
163 }
164
165
166 void
167 reshape(void)
168 {
169 int i;
170
171 flreshape(screen.clipr);
172 for(i = 0; i<nname; i++)
173 if(text[i])
174 hcheck(text[i]->tag);
175 }
176
177 void
178 current(Flayer *nw)
179 {
180 Text *t;
181
182 if(which)
183 flborder(which, false);
184 if(nw){
185 flushtyping(true);
186 if (!followfocus)
187 flupfront(nw);
188 flborder(nw, true);
189 buttons(Up);
190 t = (Text *)nw->user1;
191 t->front = nw-&t->l[0];
192 if(t != &cmd)
193 work = nw;
194 }
195 which = nw;
196 }
197
198 void
199 closeup(Flayer *l)
200 {
201 Text *t=(Text *)l->user1;
202 int m;
203
204 m = whichmenu(t->tag);
205 if(m < 0)
206 return;
207 flclose(l);
208 if(l == which){
209 which = 0;
210 current(flwhich(Pt(0, 0)));
211 }
212 if(l == flast)
213 flast = 0;
214 if(l == work)
215 work = 0;
216 if(--t->nwin == 0){
217 rclear(&t->rasp);
218 free(t);
219 text[m] = 0;
220 }else if(l == &t->l[t->front]){
221 for(m=0; m<NL; m++) /* find one; any one will do */
222 if(t->l[m].textfn){
223 t->front = m;
224 return;
225 }
226 panic("close");
227 }
228 }
229
230 Flayer *
231 findl(Text *t)
232 {
233 int i;
234 for(i = 0; i<NL; i++)
235 if(t->l[i].textfn==0)
236 return &t->l[i];
237 return 0;
238 }
239
240 void
241 duplicate(Flayer *l, Rectangle r, XftFont *f, int close)
242 {
243 Text *t=(Text *)l->user1;
244 Flayer *nl = findl(t);
245 wchar_t *rp;
246 uint64_t n;
247
248 if(nl){
249 flnew(nl, stgettext, l->user0, (char *)t);
250 flinit(nl, r, f, l->bg);
251 nl->origin = l->origin;
252 rp = (*l->textfn)(l, l->f.nchars, &n);
253 flinsert(nl, rp, rp+n, l->origin);
254 flsetselect(nl, l->p0, l->p1);
255 if(close){
256 flclose(l);
257 if(l==which)
258 which = 0;
259 }else
260 t->nwin++;
261 current(nl);
262 hcheck(t->tag);
263 }
264 cursorswitch(cursor);
265 }
266
267 void
268 buttons(int updown)
269 {
270 while(((mouse.buttons&7)!=0) != updown)
271 frgetmouse();
272 }
273
274 int
275 getr(Rectangle *rp)
276 {
277 Point p;
278 Rectangle r;
279
280 *rp = getrect(3, &mouse);
281 if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){
282 p = rp->min;
283 r = cmd.l[cmd.front].entire;
284 *rp = screen.r;
285 if(cmd.nwin==1){
286 if (p.y <= r.min.y)
287 rp->max.y = r.min.y;
288 else if (p.y >= r.max.y)
289 rp->min.y = r.max.y;
290 if (p.x <= r.min.x)
291 rp->max.x = r.min.x;
292 else if (p.x >= r.max.x)
293 rp->min.x = r.max.x;
294 }
295 }
296 return rectclip(rp, screen.r) &&
297 rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40;
298 }
299
300 void
301 snarf(Text *t, int w)
302 {
303 Flayer *l = &t->l[w];
304
305 if(l->p1>l->p0){
306 snarflen = l->p1-l->p0;
307 outTsll(Tsnarf, t->tag, l->p0, l->p1);
308 }
309 }
310
311 void
312 cut(Text *t, int w, bool save, bool check)
313 {
314 int64_t p0, p1;
315 Flayer *l;
316
317 l = &t->l[w];
318 p0 = l->p0;
319 p1 = l->p1;
320 if(p0 == p1)
321 return;
322 if(p0 < 0)
323 panic("cut");
324 if(save)
325 snarf(t, w);
326 outTsll(Tcut, t->tag, p0, p1);
327 flsetselect(l, p0, p0);
328 t->lock++;
329 hcut(t->tag, p0, p1-p0);
330 if(check)
331 hcheck(t->tag);
332 }
333
334 void
335 paste(Text *t, int w)
336 {
337 if(snarflen){
338 cut(t, w, false, false);
339 t->lock++;
340 outTsl(Tpaste, t->tag, t->l[w].p0);
341 }
342 }
343
344 void
345 scrorigin(Flayer *l, int but, int64_t p0)
346 {
347 Text *t=(Text *)l->user1;
348
349 switch(but){
350 case 1:
351 outTslll(Torigin, t->tag, l->origin, p0, getlayer(l, t));
352 break;
353 case 2:
354 outTslll(Torigin, t->tag, p0, 1L, getlayer(l, t));
355 break;
356 case 3:
357 horigin(t->tag, p0, NULL);
358 }
359 }
360
361 int
362 raspc(Rasp *r, int64_t p)
363 {
364 uint64_t n;
365 rload(r, p, p+1, &n);
366 if(n)
367 return scratch[0];
368 return 0;
369 }
370
371 int64_t
372 ctlw(Rasp *r, int64_t o, int64_t p)
373 {
374 int c;
375
376 if(--p < o)
377 return o;
378 if(raspc(r, p)=='\n')
379 return p;
380 for(; p>=o && !iswalnum(c=raspc(r, p)); --p)
381 if(c=='\n')
382 return p+1;
383 for(; p>o && iswalnum(raspc(r, p-1)); --p)
384 ;
385 return p>=o? p : o;
386 }
387
388 int64_t
389 ctlu(Rasp *r, int64_t o, int64_t p)
390 {
391 for(; p-1>=o && raspc(r, p-1)!='\n'; --p)
392 ;
393 return p>=o? p : o;
394 }
395
396 int64_t
397 indent(Flayer *l, long p)
398 {
399 Text *t = (Text *)l->user1;
400 static wchar_t sbuf[7] = {' ',' ',' ',' ',' ',' ',' '};
401 static wchar_t tbuf[7] = {'\t','\t','\t','\t','\t','\t','\t'};
402 int i, is, it, q, c, space;
403
404 q = p - 1; is = 0; it = 0; space = true;
405 while(--q >= l->origin) {
406 c = raspc(&t->rasp, q);
407 if(c == '\n') {
408 break;
409 } else if(c == '\t') {
410 ++it;
411 } else if(c == ' ') {
412 ++is;
413 } else {
414 it = is = 0;
415 space = false;
416 }
417 }
418 if(space)
419 it = is = 0;
420
421 while(it != 0) {
422 i = it>7?7:it;
423 hgrow(t->tag, p, i, 0);
424 t->lock++;
425 hdatarune(t->tag, p, tbuf, i);
426 it -= i; p += i;
427 }
428 while(is != 0) {
429 i = is > 7? 7 : is;
430 hgrow(t->tag, p, i, 0);
431 t->lock++;
432 hdatarune(t->tag, p, sbuf, i);
433 is -= i; p += i;
434 }
435
436 return typeend = l->p0 = l->p1 = p;
437 }
438
439 int
440 center(Flayer *l, int64_t a)
441 {
442 Text *t = l->user1;
443
444 if (!t->lock && (a < l->origin || l->origin + l->f.nchars < a)){
445 a = (a > t->rasp.nrunes) ? t->rasp.nrunes : a;
446 outTslll(Torigin, t->tag, a, 2L, getlayer(l, t));
447 return 1;
448 }
449
450 return 0;
451 }
452
453 int
454 onethird(Flayer *l, int64_t a)
455 {
456 Text *t;
457 Rectangle s;
458 int64_t lines;
459
460 t = l->user1;
461 if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
462 if(a > t->rasp.nrunes)
463 a = t->rasp.nrunes;
464 s = inset(l->scroll, 1);
465 lines = ((s.max.y-s.min.y)/l->f.fheight+1)/3;
466 if (lines < 2)
467 lines = 2;
468 outTslll(Torigin, t->tag, a, lines, getlayer(l, t));
469 return 1;
470 }
471 return 0;
472 }
473
474
475 int
476 XDisplay(Display *);
477
478 extern Display * _dpy;
479
480 void
481 flushtyping(bool clearesc)
482 {
483 Text *t;
484 uint64_t n;
485
486 if (clearesc)
487 typeesc = -1;
488 if (typestart == typeend){
489 modified = false;
490 return;
491 }
492 t = which->user1;
493 if(t != &cmd)
494 modified = true;
495 rload(&t->rasp, typestart, typeend, &n);
496 scratch[n] = 0;
497 if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){
498 setlock();
499 outcmd();
500 }
501 outTslS(Ttype, t->tag, typestart, scratch);
502 typestart = -1;
503 typeend = -1;
504 XFlush(_dpy);
505 }
506
507 static int64_t
508 cmdscrolldown(Flayer *l, int64_t a, Text *t, const char *arg)
509 {
510 flushtyping(false);
511 center(l, l->origin + l->f.nchars + 1);
512 return a;
513 }
514
515 static int64_t
516 cmdscrollup(Flayer *l, int64_t a, Text *t, const char *arg)
517 {
518 flushtyping(false);
519 outTslll(Torigin, t->tag, l->origin, l->f.maxlines + 1, getlayer(l, t));
520 return a;
521 }
522
523 static int64_t
524 cmdcharleft(Flayer *l, int64_t a, Text *t, const char *arg)
525 {
526 flsetselect(l, a, a);
527 flushtyping(false);
528 if (a > 0)
529 a--;
530 flsetselect(l, a, a);
531 center(l, a);
532
533 return a;
534 }
535
536 static int64_t
537 cmdcharright(Flayer *l, int64_t a, Text *t, const char *arg)
538 {
539 flsetselect(l, a, a);
540 flushtyping(false);
541 if (a < t->rasp.nrunes)
542 a++;
543 flsetselect(l, a, a);
544 center(l, a);
545
546 return a;
547 }
548
549 static int64_t
550 cmdeol(Flayer *l, int64_t a, Text *t, const char *arg)
551 {
552 flsetselect(l, a, a);
553 flushtyping(true);
554 while(a < t->rasp.nrunes)
555 if(raspc(&t->rasp, a++) == '\n') {
556 a--;
557 break;
558 }
559
560 flsetselect(l, a, a);
561 center(l, a);
562
563 return a;
564 }
565
566 static int64_t
567 cmdbol(Flayer *l, int64_t a, Text *t, const char *arg)
568 {
569 flsetselect(l, a, a);
570 flushtyping(true);
571 while (a > 0){
572 if (raspc(&t->rasp, --a) == '\n'){
573 a++;
574 break;
575 }
576 }
577
578 flsetselect(l, a, a);
579 center(l, a);
580
581 return a;
582 }
583
584 static int64_t
585 cmdscrollupline(Flayer *l, int64_t a, Text *t, const char *arg)
586 {
587 if (l->origin > 0)
588 hmoveto(t->tag, l->origin - 1, l);
589 return a;
590 }
591
592 static int64_t
593 cmdscrolldownline(Flayer *l, int64_t a, Text *t, const char *arg)
594 {
595 int64_t e = t->rasp.nrunes;
596
597 horigin(t->tag,
598 l->origin + frcharofpt(&l->f,Pt(l->f.r.min.x, l->f.r.min.y + l->f.fheight)),
599 l);
600
601 return a;
602 }
603
604 static int64_t
605 cmdlineup(Flayer *l, int64_t a, Text *t, const char *arg)
606 {
607 flsetselect(l, a, a);
608 flushtyping(true);
609 if (a > 0){
610 int64_t n0, n1, count = 0;
611 while (a > 0 && raspc(&t->rasp, a - 1) != '\n'){
612 a--;
613 count++;
614 }
615 if (a > 0){
616 n1 = a;
617 a--;
618 while (a > 0 && raspc(&t->rasp, a - 1) != '\n')
619 a--;
620
621 n0 = a;
622 a = (n0 + count >= n1) ? n1 - 1 : n0 + count;
623 flsetselect(l, a, a);
624 center(l, a);
625 }
626 }
627
628 return a;
629 }
630
631 static int64_t
632 cmdlinedown(Flayer *l, int64_t a, Text *t, const char *arg)
633 {
634 flsetselect(l, a, a);
635 flushtyping(true);
636 if (a < t->rasp.nrunes){
637 int64_t p0, count = 0;
638
639 p0 = a;
640 while (a > 0 && raspc(&t->rasp, a - 1) != '\n'){
641 a--;
642 count++;
643 }
644
645 a = p0;
646 while (a < t->rasp.nrunes && raspc(&t->rasp, a) != '\n')
647 a++;
648
649 if (a < t->rasp.nrunes){
650 a++;
651 while (a < t->rasp.nrunes && count > 0 && raspc(&t->rasp, a) != '\n'){
652 a++;
653 count--;
654 }
655 if (a != p0){
656 flsetselect(l, a, a);
657 center(l, a);
658 }
659 }
660 }
661
662 return a;
663 }
664
665 static int64_t
666 cmdjump(Flayer *l, int64_t a, Text *u, const char *arg)
667 {
668 Text *t = NULL;
669
670 if (which == &cmd.l[cmd.front] && flast)
671 current(flast);
672 else{
673 l = &cmd.l[cmd.front];
674 t = (Text *)l->user1;
675 flast = which;
676 current(l);
677 flushtyping(false);
678 flsetselect(l, t->rasp.nrunes, t->rasp.nrunes);
679 center(l, a);
680 }
681
682 return a;
683 }
684
685 static int64_t
686 cmdlook(Flayer *l, int64_t a, Text *t, const char *arg)
687 {
688 outTsll(Tlook, t->tag, which->p0, which->p1);
689 setlock();
690 return a;
691 }
692
693 static int64_t
694 cmdsearch(Flayer *l, int64_t a, Text *t, const char *arg)
695 {
696 if (t != &cmd && haspat()){
697 outcmd();
698 outT0(Tsearch);
699 setlock();
700 }
701 return a;
702 }
703
704 static int64_t
705 cmdwrite(Flayer *l, int64_t a, Text *t, const char *arg)
706 {
707 cursorswitch(BullseyeCursor);
708 if (t != &cmd){
709 outTs(Twrite, t->tag);
710 setlock();
711 }
712 cursorswitch(cursor);
713 return a;
714 }
715
716 static int64_t
717 cmdescape(Flayer *l, int64_t a, Text *t, const char *arg)
718 {
719 if (typeesc >= 0){
720 l->p0 = typeesc;
721 l->p1 = a;
722 flushtyping(true);
723 }
724
725 for (l = t->l; l < &t->l[NL]; l++)
726 if (l->textfn)
727 flsetselect(l, l->p0, l->p1);
728
729 return a;
730 }
731
732 static int64_t
733 cmddelword(Flayer *l, int64_t a, Text *t, const char *arg)
734 {
735 if (l->f.p0 > 0 && a > 0)
736 l->p0 = ctlw(&t->rasp, l->origin, a);
737
738 l->p1 = a;
739 if (l->p1 != l->p0){
740 if(typestart<=l->p0 && l->p1<=typeend){
741 t->lock++; /* to call hcut */
742 hcut(t->tag, l->p0, l->p1-l->p0);
743 /* hcheck is local because we know rasp is contiguous */
744 hcheck(t->tag);
745 }else{
746 flushtyping(false);
747 cut(t, t->front, false, true);
748 }
749 }
750
751 return a;
752 }
753
754 static int64_t
755 cmddelbol(Flayer *l, int64_t a, Text *t, const char *arg)
756 {
757 if (l->f.p0 > 0 && a > 0)
758 l->p0 = ctlu(&t->rasp, l->origin, a);
759
760 l->p1 = a;
761 if (l->p1 != l->p0){
762 if(typestart<=l->p0 && l->p1<=typeend){
763 t->lock++; /* to call hcut */
764 hcut(t->tag, l->p0, l->p1-l->p0);
765 /* hcheck is local because we know rasp is contiguous */
766 hcheck(t->tag);
767 }else{
768 flushtyping(false);
769 cut(t, t->front, false, true);
770 }
771 }
772
773 return a;
774 }
775
776 static int64_t
777 cmddelbs(Flayer *l, int64_t a, Text *t, const char *arg)
778 {
779 if (l->f.p0 > 0 && a > 0)
780 l->p0 = a - 1;
781
782 l->p1 = a;
783 if (l->p1 != l->p0){
784 if(typestart <= l->p0 && l->p1 <= typeend){
785 t->lock++; /* to call hcut */
786 hcut(t->tag, l->p0, l->p1 - l->p0);
787 /* hcheck is local because we know rasp is contiguous */
788 hcheck(t->tag);
789 }else{
790 flushtyping(false);
791 cut(t, t->front, false, true);
792 }
793 }
794
795 return a;
796 }
797
798 static int64_t
799 cmddel(Flayer *l, int64_t a, Text *t, const char *arg)
800 {
801 l->p0 = a;
802 if (a < t->rasp.nrunes)
803 l->p1 = a + 1;
804 if (l->p1 != l->p0){
805 if(typestart <= l->p0 && l->p1 <= typeend){
806 t->lock++; /* to call hcut */
807 hcut(t->tag, l->p0, l->p1 - l->p0);
808 /* hcheck is local because we know rasp is contiguous */
809 hcheck(t->tag);
810 }else{
811 flushtyping(false);
812 cut(t, t->front, false, true);
813 }
814 }
815
816 return a;
817 }
818
819 int
820 getlayer(const Flayer *l, const Text *t)
821 {
822 int i;
823 for (i = 0; i < NL; i++){
824 if (&t->l[i] == l)
825 return i;
826 }
827
828 return -1;
829 }
830
831 static int64_t
832 cmdexchange(Flayer *l, int64_t a, Text *t, const char *arg)
833 {
834 int w = getlayer(l, t);
835 if (w >= 0){
836 snarf(t, w);
837 outT0(Tstartsnarf);
838 setlock();
839 }
840
841 return a;
842 }
843
844 static int64_t
845 cmdsnarf(Flayer *l, int64_t a, Text *t, const char *arg)
846 {
847 flushtyping(false);
848
849 int w = getlayer(l, t);
850 if (w >= 0)
851 snarf(t, w);
852
853 return a;
854 }
855
856 static int64_t
857 cmdcut(Flayer *l, int64_t a, Text *t, const char *arg)
858 {
859 flushtyping(false);
860
861 int w = getlayer(l, t);
862 if (w >= 0)
863 cut(t, w, true, true);
864
865 return a;
866 }
867
868 static int64_t
869 cmdpaste(Flayer *l, int64_t a, Text *t, const char *arg)
870 {
871 flushtyping(false);
872
873 int w = getlayer(l, t);
874 if (w >= 0)
875 paste(t, w);
876
877 return a;
878 }
879
880 static int64_t
881 cmdtab(Flayer *l, int64_t a, Text *t, const char *arg)
882 {
883 flushtyping(false);
884
885 if (!expandtabs)
886 pushkbd('\t');
887 else{
888 int col = 0, nspaces = 8, off = a;
889 int i;
890 while (off > 0 && raspc(&t->rasp, off - 1) != '\n')
891 off--, col++;
892
893 nspaces = tabwidth - col % tabwidth;
894 for (i = 0; i < nspaces; i++)
895 pushkbd(' ');
896 }
897
898 return a;
899 }
900
901 static int64_t
902 cmdsend(Flayer *l, int64_t a, Text *t, const char *arg)
903 {
904 bool dojump = (t != &cmd);
905
906 flushtyping(false);
907 if (dojump)
908 cmdjump(l, a, t, NULL);
909
910 for (const char *c = arg; *c; c++){
911 pushkbd(*c);
912 type(&cmd.l[cmd.front]);
913 flushtyping(false);
914 }
915 pushkbd('\n');
916 type(&cmd.l[cmd.front]);
917 flushtyping(false);
918
919 if (dojump)
920 cmdjump(l, a, t, NULL);
921
922 return a;
923 }
924
925 static int64_t
926 cmdnone(Flayer *l, int64_t a, Text *t, const char *arg)
927 {
928 return a;
929 }
930
931 typedef int64_t (*Commandfunc)(Flayer *, int64_t, Text *, const char *);
932 typedef struct CommandEntry CommandEntry;
933 struct CommandEntry{
934 Commandfunc f;
935 bool unlocked;
936 bool docut;
937 };
938
939 CommandEntry commands[Cmax] ={
940 [Cnone] = {cmdnone, false, false},
941 [Cscrolldown] = {cmdscrolldown, false, false},
942 [Cscrollup] = {cmdscrollup, false, false},
943 [Cscrolldownline] = {cmdscrolldownline, false, false},
944 [Cscrollupline] = {cmdscrollupline, false, false},
945 [Ccharleft] = {cmdcharleft, false, false},
946 [Ccharright] = {cmdcharright, false, false},
947 [Clineup] = {cmdlineup, false, false},
948 [Clinedown] = {cmdlinedown, false, false},
949 [Cjump] = {cmdjump, false, false},
950 [Cescape] = {cmdescape, false, false},
951 [Csnarf] = {cmdsnarf, false, false},
952 [Ccut] = {cmdcut, false, false},
953 [Cpaste] = {cmdpaste, false, false},
954 [Cexchange] = {cmdexchange, false, false},
955 [Cdelword] = {cmddelword, true, false},
956 [Cdelbol] = {cmddelbol, true, false},
957 [Cdelbs] = {cmddelbs, true, true},
958 [Cdel] = {cmddel, true, true},
959 [Ceol] = {cmdeol, false, false},
960 [Cbol] = {cmdbol, false, false},
961 [Ctab] = {cmdtab, false, false},
962 [Csend] = {cmdsend, false, false},
963 [Clook] = {cmdlook, false, false},
964 [Csearch] = {cmdsearch, false, false},
965 [Cwrite] = {cmdwrite, false, false}
966 };
967
968
969 void
970 type(Flayer *l) /* what a bloody mess this is -- but it's getting better! */
971 {
972 Text *t = (Text *)l->user1;
973 wchar_t buf[100];
974 Keystroke k = {0};
975 wchar_t *p = buf;
976 int64_t a;
977
978 if(lock || t->lock){
979 kbdblock();
980 return;
981 }
982
983 k = qpeekc();
984 a = l->p0;
985 if (a != l->p1 && (k.k != Kcommand || commands[k.c].docut)){
986 flushtyping(true);
987 cut(t, t->front, true, true);
988 return; /* it may now be locked */
989 }
990
991 while (((k = kbdchar()), k.c) > 0) {
992 if (k.k == Kcommand)
993 break;
994
995 *p++ = k.c;
996 if (k.c == '\n' || p >= buf + sizeof(buf) / sizeof(buf[0]))
997 break;
998 }
999
1000 if (k.k == Kcommand){
1001 flushtyping(false);
1002 if (k.c < 0 || k.c >= Cmax || commands[k.c].f == NULL)
1003 panic("command table miss");
1004
1005 CommandEntry *e = &commands[k.c];
1006 if (!e->unlocked || !lock){
1007 if (k.t == Tcurrent)
1008 a = e->f(l, a, t, k.a);
1009 else{
1010 Flayer *lt = flwhich(k.p);
1011 if (lt)
1012 lt->p0 = e->f(lt, lt->p0, (Text *)lt->user1, k.a);
1013 }
1014 }
1015 }
1016
1017 if (p > buf){
1018 if (typestart < 0)
1019 typestart = a;
1020
1021 if (typeesc < 0)
1022 typeesc = a;
1023
1024 hgrow(t->tag, a, p-buf, 0);
1025 t->lock++; /* pretend we Trequest'ed for hdatarune*/
1026 hdatarune(t->tag, a, buf, p-buf);
1027 a += p-buf;
1028 l->p0 = a;
1029 l->p1 = a;
1030 typeend = a;
1031 if (autoindent && k.c == '\n' && t!=&cmd)
1032 a = indent(l, a);
1033 if (k.c == '\n' || typeend - typestart > 100)
1034 flushtyping(false);
1035 onethird(l, a);
1036 }
1037
1038 if (typeesc >= l->p0)
1039 typeesc = l->p0;
1040
1041 if (typestart >= 0){
1042 if(typestart >= l->p0)
1043 typestart = l->p0;
1044 typeend = l->p0;
1045 if (typestart == typeend){
1046 typestart = -1;
1047 typeend = -1;
1048 modified = false;
1049 }
1050 }
1051 }
1052
1053 void
1054 outcmd(void)
1055 {
1056 if(work)
1057 outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1);
1058 }
1059
1060 void
1061 panic(char *s)
1062 {
1063 fprintf(stderr, "samterm:panic: ");
1064 perror(s);
1065 abort();
1066 }
1067
1068 wchar_t*
1069 stgettext(Flayer *l, int64_t n, uint64_t *np)
1070 {
1071 Text *t;
1072
1073 t = l->user1;
1074 rload(&t->rasp, l->origin, l->origin+n, np);
1075 return scratch;
1076 }
1077
1078 int64_t
1079 scrtotal(Flayer *l)
1080 {
1081 return ((Text *)l->user1)->rasp.nrunes;
1082 }
1083
1084 void*
1085 alloc(uint64_t n)
1086 {
1087 void *p;
1088
1089 p = malloc(n);
1090 if(p == 0)
1091 panic("alloc");
1092 memset(p, 0, n);
1093 return p;
1094 }