main.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
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(… | |
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… | |
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, … | |
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 +… | |
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)… | |
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 bet… | |
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->p… | |
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 } |