Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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