xref: /plan9/sys/src/cmd/acme/text.c (revision 43f160e5eef85e570b25ad1229041bef935f2e87)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <plumb.h>
11fe853e23SDavid du Colombier #include <complete.h>
127dd7cddfSDavid du Colombier #include "dat.h"
137dd7cddfSDavid du Colombier #include "fns.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier Image	*tagcols[NCOL];
167dd7cddfSDavid du Colombier Image	*textcols[NCOL];
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier enum{
197dd7cddfSDavid du Colombier 	TABDIR = 3	/* width of tabs in directory windows */
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier void
textinit(Text * t,File * f,Rectangle r,Reffont * rf,Image * cols[NCOL])237dd7cddfSDavid du Colombier textinit(Text *t, File *f, Rectangle r, Reffont *rf, Image *cols[NCOL])
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier 	t->file = f;
267dd7cddfSDavid du Colombier 	t->all = r;
277dd7cddfSDavid du Colombier 	t->scrollr = r;
287dd7cddfSDavid du Colombier 	t->scrollr.max.x = r.min.x+Scrollwid;
297dd7cddfSDavid du Colombier 	t->lastsr = nullrect;
307dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
317dd7cddfSDavid du Colombier 	t->eq0 = ~0;
327dd7cddfSDavid du Colombier 	t->ncache = 0;
337dd7cddfSDavid du Colombier 	t->reffont = rf;
347dd7cddfSDavid du Colombier 	t->tabstop = maxtab;
357dd7cddfSDavid du Colombier 	memmove(t->Frame.cols, cols, sizeof t->Frame.cols);
367dd7cddfSDavid du Colombier 	textredraw(t, r, rf->f, screen, -1);
377dd7cddfSDavid du Colombier }
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier void
textredraw(Text * t,Rectangle r,Font * f,Image * b,int odx)407dd7cddfSDavid du Colombier textredraw(Text *t, Rectangle r, Font *f, Image *b, int odx)
417dd7cddfSDavid du Colombier {
427dd7cddfSDavid du Colombier 	int maxt;
437dd7cddfSDavid du Colombier 	Rectangle rr;
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier 	frinit(t, r, f, b, t->Frame.cols);
467dd7cddfSDavid du Colombier 	rr = t->r;
479d4e827aSDavid du Colombier 	rr.min.x -= Scrollwid+Scrollgap;	/* back fill to scroll bar */
487dd7cddfSDavid du Colombier 	draw(t->b, rr, t->cols[BACK], nil, ZP);
497dd7cddfSDavid du Colombier 	/* use no wider than 3-space tabs in a directory */
507dd7cddfSDavid du Colombier 	maxt = maxtab;
517dd7cddfSDavid du Colombier 	if(t->what == Body){
527dd7cddfSDavid du Colombier 		if(t->w->isdir)
537dd7cddfSDavid du Colombier 			maxt = min(TABDIR, maxtab);
547dd7cddfSDavid du Colombier 		else
557dd7cddfSDavid du Colombier 			maxt = t->tabstop;
567dd7cddfSDavid du Colombier 	}
577dd7cddfSDavid du Colombier 	t->maxtab = maxt*stringwidth(f, "0");
587dd7cddfSDavid du Colombier 	if(t->what==Body && t->w->isdir && odx!=Dx(t->all)){
597dd7cddfSDavid du Colombier 		if(t->maxlines > 0){
607dd7cddfSDavid du Colombier 			textreset(t);
617dd7cddfSDavid du Colombier 			textcolumnate(t, t->w->dlp,  t->w->ndl);
629a747e4fSDavid du Colombier 			textshow(t, 0, 0, 1);
637dd7cddfSDavid du Colombier 		}
647dd7cddfSDavid du Colombier 	}else{
657dd7cddfSDavid du Colombier 		textfill(t);
667dd7cddfSDavid du Colombier 		textsetselect(t, t->q0, t->q1);
677dd7cddfSDavid du Colombier 	}
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier int
textresize(Text * t,Rectangle r)717dd7cddfSDavid du Colombier textresize(Text *t, Rectangle r)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier 	int odx;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	if(Dy(r) > 0)
767dd7cddfSDavid du Colombier 		r.max.y -= Dy(r)%t->font->height;
777dd7cddfSDavid du Colombier 	else
787dd7cddfSDavid du Colombier 		r.max.y = r.min.y;
797dd7cddfSDavid du Colombier 	odx = Dx(t->all);
807dd7cddfSDavid du Colombier 	t->all = r;
817dd7cddfSDavid du Colombier 	t->scrollr = r;
827dd7cddfSDavid du Colombier 	t->scrollr.max.x = r.min.x+Scrollwid;
837dd7cddfSDavid du Colombier 	t->lastsr = nullrect;
847dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
857dd7cddfSDavid du Colombier 	frclear(t, 0);
867dd7cddfSDavid du Colombier 	textredraw(t, r, t->font, t->b, odx);
877dd7cddfSDavid du Colombier 	return r.max.y;
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier void
textclose(Text * t)917dd7cddfSDavid du Colombier textclose(Text *t)
927dd7cddfSDavid du Colombier {
937dd7cddfSDavid du Colombier 	free(t->cache);
947dd7cddfSDavid du Colombier 	frclear(t, 1);
957dd7cddfSDavid du Colombier 	filedeltext(t->file, t);
967dd7cddfSDavid du Colombier 	t->file = nil;
977dd7cddfSDavid du Colombier 	rfclose(t->reffont);
987dd7cddfSDavid du Colombier 	if(argtext == t)
997dd7cddfSDavid du Colombier 		argtext = nil;
1007dd7cddfSDavid du Colombier 	if(typetext == t)
1017dd7cddfSDavid du Colombier 		typetext = nil;
1027dd7cddfSDavid du Colombier 	if(seltext == t)
1037dd7cddfSDavid du Colombier 		seltext = nil;
1047dd7cddfSDavid du Colombier 	if(mousetext == t)
1057dd7cddfSDavid du Colombier 		mousetext = nil;
1067dd7cddfSDavid du Colombier 	if(barttext == t)
1077dd7cddfSDavid du Colombier 		barttext = nil;
1087dd7cddfSDavid du Colombier }
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier int
dircmp(void * a,void * b)1117dd7cddfSDavid du Colombier dircmp(void *a, void *b)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier 	Dirlist *da, *db;
1147dd7cddfSDavid du Colombier 	int i, n;
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	da = *(Dirlist**)a;
1177dd7cddfSDavid du Colombier 	db = *(Dirlist**)b;
1187dd7cddfSDavid du Colombier 	n = min(da->nr, db->nr);
1197dd7cddfSDavid du Colombier 	i = memcmp(da->r, db->r, n*sizeof(Rune));
1207dd7cddfSDavid du Colombier 	if(i)
1217dd7cddfSDavid du Colombier 		return i;
1227dd7cddfSDavid du Colombier 	return da->nr - db->nr;
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier void
textcolumnate(Text * t,Dirlist ** dlp,int ndl)1267dd7cddfSDavid du Colombier textcolumnate(Text *t, Dirlist **dlp, int ndl)
1277dd7cddfSDavid du Colombier {
1287dd7cddfSDavid du Colombier 	int i, j, w, colw, mint, maxt, ncol, nrow;
1297dd7cddfSDavid du Colombier 	Dirlist *dl;
1307dd7cddfSDavid du Colombier 	uint q1;
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 	if(t->file->ntext > 1)
1337dd7cddfSDavid du Colombier 		return;
1347dd7cddfSDavid du Colombier 	mint = stringwidth(t->font, "0");
1357dd7cddfSDavid du Colombier 	/* go for narrower tabs if set more than 3 wide */
1367dd7cddfSDavid du Colombier 	t->maxtab = min(maxtab, TABDIR)*mint;
1377dd7cddfSDavid du Colombier 	maxt = t->maxtab;
1387dd7cddfSDavid du Colombier 	colw = 0;
1397dd7cddfSDavid du Colombier 	for(i=0; i<ndl; i++){
1407dd7cddfSDavid du Colombier 		dl = dlp[i];
1417dd7cddfSDavid du Colombier 		w = dl->wid;
1429a747e4fSDavid du Colombier 		if(maxt-w%maxt < mint || w%maxt==0)
1437dd7cddfSDavid du Colombier 			w += mint;
1447dd7cddfSDavid du Colombier 		if(w % maxt)
1457dd7cddfSDavid du Colombier 			w += maxt-(w%maxt);
1467dd7cddfSDavid du Colombier 		if(w > colw)
1477dd7cddfSDavid du Colombier 			colw = w;
1487dd7cddfSDavid du Colombier 	}
1497dd7cddfSDavid du Colombier 	if(colw == 0)
1507dd7cddfSDavid du Colombier 		ncol = 1;
1517dd7cddfSDavid du Colombier 	else
1527dd7cddfSDavid du Colombier 		ncol = max(1, Dx(t->r)/colw);
1537dd7cddfSDavid du Colombier 	nrow = (ndl+ncol-1)/ncol;
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	q1 = 0;
1567dd7cddfSDavid du Colombier 	for(i=0; i<nrow; i++){
1577dd7cddfSDavid du Colombier 		for(j=i; j<ndl; j+=nrow){
1587dd7cddfSDavid du Colombier 			dl = dlp[j];
1597dd7cddfSDavid du Colombier 			fileinsert(t->file, q1, dl->r, dl->nr);
1607dd7cddfSDavid du Colombier 			q1 += dl->nr;
1617dd7cddfSDavid du Colombier 			if(j+nrow >= ndl)
1627dd7cddfSDavid du Colombier 				break;
1637dd7cddfSDavid du Colombier 			w = dl->wid;
1647dd7cddfSDavid du Colombier 			if(maxt-w%maxt < mint){
1657dd7cddfSDavid du Colombier 				fileinsert(t->file, q1, L"\t", 1);
1667dd7cddfSDavid du Colombier 				q1++;
1677dd7cddfSDavid du Colombier 				w += mint;
1687dd7cddfSDavid du Colombier 			}
1697dd7cddfSDavid du Colombier 			do{
1707dd7cddfSDavid du Colombier 				fileinsert(t->file, q1, L"\t", 1);
1717dd7cddfSDavid du Colombier 				q1++;
1727dd7cddfSDavid du Colombier 				w += maxt-(w%maxt);
1737dd7cddfSDavid du Colombier 			}while(w < colw);
1747dd7cddfSDavid du Colombier 		}
1757dd7cddfSDavid du Colombier 		fileinsert(t->file, q1, L"\n", 1);
1767dd7cddfSDavid du Colombier 		q1++;
1777dd7cddfSDavid du Colombier 	}
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier uint
textload(Text * t,uint q0,char * file,int setqid)1817dd7cddfSDavid du Colombier textload(Text *t, uint q0, char *file, int setqid)
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier 	Rune *rp;
1847dd7cddfSDavid du Colombier 	Dirlist *dl, **dlp;
1859a747e4fSDavid du Colombier 	int fd, i, j, n, ndl, nulls;
1867dd7cddfSDavid du Colombier 	uint q, q1;
1879a747e4fSDavid du Colombier 	Dir *d, *dbuf;
1889a747e4fSDavid du Colombier 	char *tmp;
1897dd7cddfSDavid du Colombier 	Text *u;
1907dd7cddfSDavid du Colombier 
1913df12bc6SDavid du Colombier 	if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body)
1927dd7cddfSDavid du Colombier 		error("text.load");
1933df12bc6SDavid du Colombier 	if(t->w->isdir && t->file->nname==0){
1943df12bc6SDavid du Colombier 		warning(nil, "empty directory name\n");
1953df12bc6SDavid du Colombier 		return 0;
1963df12bc6SDavid du Colombier 	}
1977dd7cddfSDavid du Colombier 	fd = open(file, OREAD);
1987dd7cddfSDavid du Colombier 	if(fd < 0){
1997dd7cddfSDavid du Colombier 		warning(nil, "can't open %s: %r\n", file);
2007dd7cddfSDavid du Colombier 		return 0;
2017dd7cddfSDavid du Colombier 	}
2029a747e4fSDavid du Colombier 	d = dirfstat(fd);
2039a747e4fSDavid du Colombier 	if(d == nil){
2047dd7cddfSDavid du Colombier 		warning(nil, "can't fstat %s: %r\n", file);
2057dd7cddfSDavid du Colombier 		goto Rescue;
2067dd7cddfSDavid du Colombier 	}
2077dd7cddfSDavid du Colombier 	nulls = FALSE;
2089a747e4fSDavid du Colombier 	if(d->qid.type & QTDIR){
2097dd7cddfSDavid du Colombier 		/* this is checked in get() but it's possible the file changed underfoot */
2107dd7cddfSDavid du Colombier 		if(t->file->ntext > 1){
2117dd7cddfSDavid du Colombier 			warning(nil, "%s is a directory; can't read with multiple windows on it\n", file);
2127dd7cddfSDavid du Colombier 			goto Rescue;
2137dd7cddfSDavid du Colombier 		}
2147dd7cddfSDavid du Colombier 		t->w->isdir = TRUE;
2157dd7cddfSDavid du Colombier 		t->w->filemenu = FALSE;
2167dd7cddfSDavid du Colombier 		if(t->file->name[t->file->nname-1] != '/'){
2177dd7cddfSDavid du Colombier 			rp = runemalloc(t->file->nname+1);
2187dd7cddfSDavid du Colombier 			runemove(rp, t->file->name, t->file->nname);
2197dd7cddfSDavid du Colombier 			rp[t->file->nname] = '/';
2207dd7cddfSDavid du Colombier 			winsetname(t->w, rp, t->file->nname+1);
22159cc4ca5SDavid du Colombier 			free(rp);
2227dd7cddfSDavid du Colombier 		}
2237dd7cddfSDavid du Colombier 		dlp = nil;
2247dd7cddfSDavid du Colombier 		ndl = 0;
2259a747e4fSDavid du Colombier 		dbuf = nil;
2269a747e4fSDavid du Colombier 		while((n=dirread(fd, &dbuf)) > 0){
2277dd7cddfSDavid du Colombier 			for(i=0; i<n; i++){
2287dd7cddfSDavid du Colombier 				dl = emalloc(sizeof(Dirlist));
2299a747e4fSDavid du Colombier 				j = strlen(dbuf[i].name);
2309a747e4fSDavid du Colombier 				tmp = emalloc(j+1+1);
2319a747e4fSDavid du Colombier 				memmove(tmp, dbuf[i].name, j);
2329a747e4fSDavid du Colombier 				if(dbuf[i].qid.type & QTDIR)
2339a747e4fSDavid du Colombier 					tmp[j++] = '/';
2349a747e4fSDavid du Colombier 				tmp[j] = '\0';
2357dd7cddfSDavid du Colombier 				dl->r = bytetorune(tmp, &dl->nr);
2367dd7cddfSDavid du Colombier 				dl->wid = stringwidth(t->font, tmp);
2379a747e4fSDavid du Colombier 				free(tmp);
2387dd7cddfSDavid du Colombier 				ndl++;
2397dd7cddfSDavid du Colombier 				dlp = realloc(dlp, ndl*sizeof(Dirlist*));
2407dd7cddfSDavid du Colombier 				dlp[ndl-1] = dl;
2417dd7cddfSDavid du Colombier 			}
2429a747e4fSDavid du Colombier 			free(dbuf);
2437dd7cddfSDavid du Colombier 		}
2447dd7cddfSDavid du Colombier 		qsort(dlp, ndl, sizeof(Dirlist*), dircmp);
2457dd7cddfSDavid du Colombier 		t->w->dlp = dlp;
2467dd7cddfSDavid du Colombier 		t->w->ndl = ndl;
2477dd7cddfSDavid du Colombier 		textcolumnate(t, dlp, ndl);
2487dd7cddfSDavid du Colombier 		q1 = t->file->nc;
2497dd7cddfSDavid du Colombier 	}else{
2507dd7cddfSDavid du Colombier 		t->w->isdir = FALSE;
2517dd7cddfSDavid du Colombier 		t->w->filemenu = TRUE;
2527dd7cddfSDavid du Colombier 		q1 = q0 + fileload(t->file, q0, fd, &nulls);
2537dd7cddfSDavid du Colombier 	}
2547dd7cddfSDavid du Colombier 	if(setqid){
2559a747e4fSDavid du Colombier 		t->file->dev = d->dev;
2569a747e4fSDavid du Colombier 		t->file->mtime = d->mtime;
2579a747e4fSDavid du Colombier 		t->file->qidpath = d->qid.path;
2587dd7cddfSDavid du Colombier 	}
2597dd7cddfSDavid du Colombier 	close(fd);
2607dd7cddfSDavid du Colombier 	rp = fbufalloc();
2617dd7cddfSDavid du Colombier 	for(q=q0; q<q1; q+=n){
2627dd7cddfSDavid du Colombier 		n = q1-q;
2637dd7cddfSDavid du Colombier 		if(n > RBUFSIZE)
2647dd7cddfSDavid du Colombier 			n = RBUFSIZE;
2657dd7cddfSDavid du Colombier 		bufread(t->file, q, rp, n);
2667dd7cddfSDavid du Colombier 		if(q < t->org)
2677dd7cddfSDavid du Colombier 			t->org += n;
2687dd7cddfSDavid du Colombier 		else if(q <= t->org+t->nchars)
2697dd7cddfSDavid du Colombier 			frinsert(t, rp, rp+n, q-t->org);
2707dd7cddfSDavid du Colombier 		if(t->lastlinefull)
2717dd7cddfSDavid du Colombier 			break;
2727dd7cddfSDavid du Colombier 	}
2737dd7cddfSDavid du Colombier 	fbuffree(rp);
2747dd7cddfSDavid du Colombier 	for(i=0; i<t->file->ntext; i++){
2757dd7cddfSDavid du Colombier 		u = t->file->text[i];
2767dd7cddfSDavid du Colombier 		if(u != t){
2777dd7cddfSDavid du Colombier 			if(u->org > u->file->nc)	/* will be 0 because of reset(), but safety first */
2787dd7cddfSDavid du Colombier 				u->org = 0;
2797dd7cddfSDavid du Colombier 			textresize(u, u->all);
2807dd7cddfSDavid du Colombier 			textbacknl(u, u->org, 0);	/* go to beginning of line */
2817dd7cddfSDavid du Colombier 		}
2827dd7cddfSDavid du Colombier 		textsetselect(u, q0, q0);
2837dd7cddfSDavid du Colombier 	}
2847dd7cddfSDavid du Colombier 	if(nulls)
2857dd7cddfSDavid du Colombier 		warning(nil, "%s: NUL bytes elided\n", file);
2869a747e4fSDavid du Colombier 	free(d);
2877dd7cddfSDavid du Colombier 	return q1-q0;
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier     Rescue:
2907dd7cddfSDavid du Colombier 	close(fd);
2917dd7cddfSDavid du Colombier 	return 0;
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier uint
textbsinsert(Text * t,uint q0,Rune * r,uint n,int tofile,int * nrp)2957dd7cddfSDavid du Colombier textbsinsert(Text *t, uint q0, Rune *r, uint n, int tofile, int *nrp)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier 	Rune *bp, *tp, *up;
2987dd7cddfSDavid du Colombier 	int i, initial;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	if(t->what == Tag){	/* can't happen but safety first: mustn't backspace over file name */
3017dd7cddfSDavid du Colombier     Err:
3027dd7cddfSDavid du Colombier 		textinsert(t, q0, r, n, tofile);
3037dd7cddfSDavid du Colombier 		*nrp = n;
3047dd7cddfSDavid du Colombier 		return q0;
3057dd7cddfSDavid du Colombier 	}
3067dd7cddfSDavid du Colombier 	bp = r;
3077dd7cddfSDavid du Colombier 	for(i=0; i<n; i++)
3087dd7cddfSDavid du Colombier 		if(*bp++ == '\b'){
3097dd7cddfSDavid du Colombier 			--bp;
3107dd7cddfSDavid du Colombier 			initial = 0;
3117dd7cddfSDavid du Colombier 			tp = runemalloc(n);
3127dd7cddfSDavid du Colombier 			runemove(tp, r, i);
3137dd7cddfSDavid du Colombier 			up = tp+i;
3147dd7cddfSDavid du Colombier 			for(; i<n; i++){
3157dd7cddfSDavid du Colombier 				*up = *bp++;
3167dd7cddfSDavid du Colombier 				if(*up == '\b')
3177dd7cddfSDavid du Colombier 					if(up == tp)
3187dd7cddfSDavid du Colombier 						initial++;
3197dd7cddfSDavid du Colombier 					else
3207dd7cddfSDavid du Colombier 						--up;
3217dd7cddfSDavid du Colombier 				else
3227dd7cddfSDavid du Colombier 					up++;
3237dd7cddfSDavid du Colombier 			}
3247dd7cddfSDavid du Colombier 			if(initial){
3257dd7cddfSDavid du Colombier 				if(initial > q0)
3267dd7cddfSDavid du Colombier 					initial = q0;
3277dd7cddfSDavid du Colombier 				q0 -= initial;
3287dd7cddfSDavid du Colombier 				textdelete(t, q0, q0+initial, tofile);
3297dd7cddfSDavid du Colombier 			}
3307dd7cddfSDavid du Colombier 			n = up-tp;
3317dd7cddfSDavid du Colombier 			textinsert(t, q0, tp, n, tofile);
3327dd7cddfSDavid du Colombier 			free(tp);
3337dd7cddfSDavid du Colombier 			*nrp = n;
3347dd7cddfSDavid du Colombier 			return q0;
3357dd7cddfSDavid du Colombier 		}
3367dd7cddfSDavid du Colombier 	goto Err;
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier void
textinsert(Text * t,uint q0,Rune * r,uint n,int tofile)3407dd7cddfSDavid du Colombier textinsert(Text *t, uint q0, Rune *r, uint n, int tofile)
3417dd7cddfSDavid du Colombier {
3427dd7cddfSDavid du Colombier 	int c, i;
3437dd7cddfSDavid du Colombier 	Text *u;
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier 	if(tofile && t->ncache != 0)
3467dd7cddfSDavid du Colombier 		error("text.insert");
3477dd7cddfSDavid du Colombier 	if(n == 0)
3487dd7cddfSDavid du Colombier 		return;
3497dd7cddfSDavid du Colombier 	if(tofile){
3507dd7cddfSDavid du Colombier 		fileinsert(t->file, q0, r, n);
3517dd7cddfSDavid du Colombier 		if(t->what == Body){
3527dd7cddfSDavid du Colombier 			t->w->dirty = TRUE;
3537dd7cddfSDavid du Colombier 			t->w->utflastqid = -1;
3547dd7cddfSDavid du Colombier 		}
3557dd7cddfSDavid du Colombier 		if(t->file->ntext > 1)
3567dd7cddfSDavid du Colombier 			for(i=0; i<t->file->ntext; i++){
3577dd7cddfSDavid du Colombier 				u = t->file->text[i];
3587dd7cddfSDavid du Colombier 				if(u != t){
3597dd7cddfSDavid du Colombier 					u->w->dirty = TRUE;	/* always a body */
3607dd7cddfSDavid du Colombier 					textinsert(u, q0, r, n, FALSE);
3617dd7cddfSDavid du Colombier 					textsetselect(u, u->q0, u->q1);
3627dd7cddfSDavid du Colombier 					textscrdraw(u);
3637dd7cddfSDavid du Colombier 				}
3647dd7cddfSDavid du Colombier 			}
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier 	}
3677dd7cddfSDavid du Colombier 	if(q0 < t->q1)
3687dd7cddfSDavid du Colombier 		t->q1 += n;
3697dd7cddfSDavid du Colombier 	if(q0 < t->q0)
3707dd7cddfSDavid du Colombier 		t->q0 += n;
3717dd7cddfSDavid du Colombier 	if(q0 < t->org)
3727dd7cddfSDavid du Colombier 		t->org += n;
3737dd7cddfSDavid du Colombier 	else if(q0 <= t->org+t->nchars)
3747dd7cddfSDavid du Colombier 		frinsert(t, r, r+n, q0-t->org);
3757dd7cddfSDavid du Colombier 	if(t->w){
3767dd7cddfSDavid du Colombier 		c = 'i';
3777dd7cddfSDavid du Colombier 		if(t->what == Body)
3787dd7cddfSDavid du Colombier 			c = 'I';
3797dd7cddfSDavid du Colombier 		if(n <= EVENTSIZE)
3807dd7cddfSDavid du Colombier 			winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q0+n, n, n, r);
3817dd7cddfSDavid du Colombier 		else
3827dd7cddfSDavid du Colombier 			winevent(t->w, "%c%d %d 0 0 \n", c, q0, q0+n, n);
3837dd7cddfSDavid du Colombier 	}
3847dd7cddfSDavid du Colombier }
3857dd7cddfSDavid du Colombier 
386e7d29567SDavid du Colombier void
typecommit(Text * t)387e7d29567SDavid du Colombier typecommit(Text *t)
388e7d29567SDavid du Colombier {
389e7d29567SDavid du Colombier 	if(t->w != nil)
390e7d29567SDavid du Colombier 		wincommit(t->w, t);
391e7d29567SDavid du Colombier 	else
392e7d29567SDavid du Colombier 		textcommit(t, TRUE);
393e7d29567SDavid du Colombier }
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier void
textfill(Text * t)3967dd7cddfSDavid du Colombier textfill(Text *t)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier 	Rune *rp;
3997dd7cddfSDavid du Colombier 	int i, n, m, nl;
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	if(t->lastlinefull || t->nofill)
4027dd7cddfSDavid du Colombier 		return;
403e7d29567SDavid du Colombier 	if(t->ncache > 0)
404e7d29567SDavid du Colombier 		typecommit(t);
4057dd7cddfSDavid du Colombier 	rp = fbufalloc();
4067dd7cddfSDavid du Colombier 	do{
4077dd7cddfSDavid du Colombier 		n = t->file->nc-(t->org+t->nchars);
4087dd7cddfSDavid du Colombier 		if(n == 0)
4097dd7cddfSDavid du Colombier 			break;
4107dd7cddfSDavid du Colombier 		if(n > 2000)	/* educated guess at reasonable amount */
4117dd7cddfSDavid du Colombier 			n = 2000;
4127dd7cddfSDavid du Colombier 		bufread(t->file, t->org+t->nchars, rp, n);
4137dd7cddfSDavid du Colombier 		/*
4147dd7cddfSDavid du Colombier 		 * it's expensive to frinsert more than we need, so
4157dd7cddfSDavid du Colombier 		 * count newlines.
4167dd7cddfSDavid du Colombier 		 */
4177dd7cddfSDavid du Colombier 		nl = t->maxlines-t->nlines;
4187dd7cddfSDavid du Colombier 		m = 0;
4197dd7cddfSDavid du Colombier 		for(i=0; i<n; ){
4207dd7cddfSDavid du Colombier 			if(rp[i++] == '\n'){
4217dd7cddfSDavid du Colombier 				m++;
4227dd7cddfSDavid du Colombier 				if(m >= nl)
4237dd7cddfSDavid du Colombier 					break;
4247dd7cddfSDavid du Colombier 			}
4257dd7cddfSDavid du Colombier 		}
4267dd7cddfSDavid du Colombier 		frinsert(t, rp, rp+i, t->nchars);
4277dd7cddfSDavid du Colombier 	}while(t->lastlinefull == FALSE);
4287dd7cddfSDavid du Colombier 	fbuffree(rp);
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier void
textdelete(Text * t,uint q0,uint q1,int tofile)4327dd7cddfSDavid du Colombier textdelete(Text *t, uint q0, uint q1, int tofile)
4337dd7cddfSDavid du Colombier {
4347dd7cddfSDavid du Colombier 	uint n, p0, p1;
4357dd7cddfSDavid du Colombier 	int i, c;
4367dd7cddfSDavid du Colombier 	Text *u;
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 	if(tofile && t->ncache != 0)
4397dd7cddfSDavid du Colombier 		error("text.delete");
4407dd7cddfSDavid du Colombier 	n = q1-q0;
4417dd7cddfSDavid du Colombier 	if(n == 0)
4427dd7cddfSDavid du Colombier 		return;
4437dd7cddfSDavid du Colombier 	if(tofile){
4447dd7cddfSDavid du Colombier 		filedelete(t->file, q0, q1);
4457dd7cddfSDavid du Colombier 		if(t->what == Body){
4467dd7cddfSDavid du Colombier 			t->w->dirty = TRUE;
4477dd7cddfSDavid du Colombier 			t->w->utflastqid = -1;
4487dd7cddfSDavid du Colombier 		}
4497dd7cddfSDavid du Colombier 		if(t->file->ntext > 1)
4507dd7cddfSDavid du Colombier 			for(i=0; i<t->file->ntext; i++){
4517dd7cddfSDavid du Colombier 				u = t->file->text[i];
4527dd7cddfSDavid du Colombier 				if(u != t){
4537dd7cddfSDavid du Colombier 					u->w->dirty = TRUE;	/* always a body */
4547dd7cddfSDavid du Colombier 					textdelete(u, q0, q1, FALSE);
4557dd7cddfSDavid du Colombier 					textsetselect(u, u->q0, u->q1);
4567dd7cddfSDavid du Colombier 					textscrdraw(u);
4577dd7cddfSDavid du Colombier 				}
4587dd7cddfSDavid du Colombier 			}
4597dd7cddfSDavid du Colombier 	}
4607dd7cddfSDavid du Colombier 	if(q0 < t->q0)
4617dd7cddfSDavid du Colombier 		t->q0 -= min(n, t->q0-q0);
4627dd7cddfSDavid du Colombier 	if(q0 < t->q1)
4637dd7cddfSDavid du Colombier 		t->q1 -= min(n, t->q1-q0);
4647dd7cddfSDavid du Colombier 	if(q1 <= t->org)
4657dd7cddfSDavid du Colombier 		t->org -= n;
4667dd7cddfSDavid du Colombier 	else if(q0 < t->org+t->nchars){
4677dd7cddfSDavid du Colombier 		p1 = q1 - t->org;
4687dd7cddfSDavid du Colombier 		if(p1 > t->nchars)
4697dd7cddfSDavid du Colombier 			p1 = t->nchars;
4707dd7cddfSDavid du Colombier 		if(q0 < t->org){
4717dd7cddfSDavid du Colombier 			t->org = q0;
4727dd7cddfSDavid du Colombier 			p0 = 0;
4737dd7cddfSDavid du Colombier 		}else
4747dd7cddfSDavid du Colombier 			p0 = q0 - t->org;
4757dd7cddfSDavid du Colombier 		frdelete(t, p0, p1);
4767dd7cddfSDavid du Colombier 		textfill(t);
4777dd7cddfSDavid du Colombier 	}
4787dd7cddfSDavid du Colombier 	if(t->w){
4797dd7cddfSDavid du Colombier 		c = 'd';
4807dd7cddfSDavid du Colombier 		if(t->what == Body)
4817dd7cddfSDavid du Colombier 			c = 'D';
4827dd7cddfSDavid du Colombier 		winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1);
4837dd7cddfSDavid du Colombier 	}
4847dd7cddfSDavid du Colombier }
4857dd7cddfSDavid du Colombier 
4866b6b9ac8SDavid du Colombier void
textconstrain(Text * t,uint q0,uint q1,uint * p0,uint * p1)4876b6b9ac8SDavid du Colombier textconstrain(Text *t, uint q0, uint q1, uint *p0, uint *p1)
4886b6b9ac8SDavid du Colombier {
4896b6b9ac8SDavid du Colombier 	*p0 = min(q0, t->file->nc);
4906b6b9ac8SDavid du Colombier 	*p1 = min(q1, t->file->nc);
4916b6b9ac8SDavid du Colombier }
4926b6b9ac8SDavid du Colombier 
4937dd7cddfSDavid du Colombier Rune
textreadc(Text * t,uint q)4947dd7cddfSDavid du Colombier textreadc(Text *t, uint q)
4957dd7cddfSDavid du Colombier {
4967dd7cddfSDavid du Colombier 	Rune r;
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier 	if(t->cq0<=q && q<t->cq0+t->ncache)
4997dd7cddfSDavid du Colombier 		r = t->cache[q-t->cq0];
5007dd7cddfSDavid du Colombier 	else
5017dd7cddfSDavid du Colombier 		bufread(t->file, q, &r, 1);
5027dd7cddfSDavid du Colombier 	return r;
5037dd7cddfSDavid du Colombier }
5047dd7cddfSDavid du Colombier 
5057dd7cddfSDavid du Colombier int
textbswidth(Text * t,Rune c)5067dd7cddfSDavid du Colombier textbswidth(Text *t, Rune c)
5077dd7cddfSDavid du Colombier {
5087dd7cddfSDavid du Colombier 	uint q, eq;
5097dd7cddfSDavid du Colombier 	Rune r;
5107dd7cddfSDavid du Colombier 	int skipping;
5117dd7cddfSDavid du Colombier 
5127dd7cddfSDavid du Colombier 	/* there is known to be at least one character to erase */
5137dd7cddfSDavid du Colombier 	if(c == 0x08)	/* ^H: erase character */
5147dd7cddfSDavid du Colombier 		return 1;
5157dd7cddfSDavid du Colombier 	q = t->q0;
5167dd7cddfSDavid du Colombier 	skipping = TRUE;
5177dd7cddfSDavid du Colombier 	while(q > 0){
5187dd7cddfSDavid du Colombier 		r = textreadc(t, q-1);
5197dd7cddfSDavid du Colombier 		if(r == '\n'){		/* eat at most one more character */
5207dd7cddfSDavid du Colombier 			if(q == t->q0)	/* eat the newline */
5217dd7cddfSDavid du Colombier 				--q;
5227dd7cddfSDavid du Colombier 			break;
5237dd7cddfSDavid du Colombier 		}
5247dd7cddfSDavid du Colombier 		if(c == 0x17){
5257dd7cddfSDavid du Colombier 			eq = isalnum(r);
5267dd7cddfSDavid du Colombier 			if(eq && skipping)	/* found one; stop skipping */
5277dd7cddfSDavid du Colombier 				skipping = FALSE;
5287dd7cddfSDavid du Colombier 			else if(!eq && !skipping)
5297dd7cddfSDavid du Colombier 				break;
5307dd7cddfSDavid du Colombier 		}
5317dd7cddfSDavid du Colombier 		--q;
5327dd7cddfSDavid du Colombier 	}
5337dd7cddfSDavid du Colombier 	return t->q0-q;
5347dd7cddfSDavid du Colombier }
5357dd7cddfSDavid du Colombier 
536fe853e23SDavid du Colombier int
textfilewidth(Text * t,uint q0,int oneelement)537fe853e23SDavid du Colombier textfilewidth(Text *t, uint q0, int oneelement)
538fe853e23SDavid du Colombier {
539fe853e23SDavid du Colombier 	uint q;
540fe853e23SDavid du Colombier 	Rune r;
541fe853e23SDavid du Colombier 
542fe853e23SDavid du Colombier 	q = q0;
543fe853e23SDavid du Colombier 	while(q > 0){
544fe853e23SDavid du Colombier 		r = textreadc(t, q-1);
545fe853e23SDavid du Colombier 		if(r <= ' ')
546fe853e23SDavid du Colombier 			break;
547fe853e23SDavid du Colombier 		if(oneelement && r=='/')
548fe853e23SDavid du Colombier 			break;
549fe853e23SDavid du Colombier 		--q;
550fe853e23SDavid du Colombier 	}
551fe853e23SDavid du Colombier 	return q0-q;
552fe853e23SDavid du Colombier }
553fe853e23SDavid du Colombier 
554fe853e23SDavid du Colombier Rune*
textcomplete(Text * t)555fe853e23SDavid du Colombier textcomplete(Text *t)
556fe853e23SDavid du Colombier {
557fe853e23SDavid du Colombier 	int i, nstr, npath;
558fe853e23SDavid du Colombier 	uint q;
559fe853e23SDavid du Colombier 	Rune tmp[200];
560fe853e23SDavid du Colombier 	Rune *str, *path;
561fe853e23SDavid du Colombier 	Rune *rp;
562fe853e23SDavid du Colombier 	Completion *c;
563fe853e23SDavid du Colombier 	char *s, *dirs;
564fe853e23SDavid du Colombier 	Runestr dir;
565fe853e23SDavid du Colombier 
566fe853e23SDavid du Colombier 	/* control-f: filename completion; works back to white space or / */
567fe853e23SDavid du Colombier 	if(t->q0<t->file->nc && textreadc(t, t->q0)>' ')	/* must be at end of word */
568fe853e23SDavid du Colombier 		return nil;
569fe853e23SDavid du Colombier 	nstr = textfilewidth(t, t->q0, TRUE);
570fe853e23SDavid du Colombier 	str = runemalloc(nstr);
571fe853e23SDavid du Colombier 	npath = textfilewidth(t, t->q0-nstr, FALSE);
572fe853e23SDavid du Colombier 	path = runemalloc(npath);
573fe853e23SDavid du Colombier 
574fe853e23SDavid du Colombier 	c = nil;
575fe853e23SDavid du Colombier 	rp = nil;
576fe853e23SDavid du Colombier 	dirs = nil;
577fe853e23SDavid du Colombier 
578fe853e23SDavid du Colombier 	q = t->q0-nstr;
579fe853e23SDavid du Colombier 	for(i=0; i<nstr; i++)
580fe853e23SDavid du Colombier 		str[i] = textreadc(t, q++);
581fe853e23SDavid du Colombier 	q = t->q0-nstr-npath;
582fe853e23SDavid du Colombier 	for(i=0; i<npath; i++)
583fe853e23SDavid du Colombier 		path[i] = textreadc(t, q++);
584fe853e23SDavid du Colombier 	/* is path rooted? if not, we need to make it relative to window path */
585fe853e23SDavid du Colombier 	if(npath>0 && path[0]=='/')
586fe853e23SDavid du Colombier 		dir = (Runestr){path, npath};
587fe853e23SDavid du Colombier 	else{
588fe853e23SDavid du Colombier 		dir = dirname(t, nil, 0);
589fe853e23SDavid du Colombier 		if(dir.nr + 1 + npath > nelem(tmp)){
590fe853e23SDavid du Colombier 			free(dir.r);
591fe853e23SDavid du Colombier 			goto Return;
592fe853e23SDavid du Colombier 		}
593fe853e23SDavid du Colombier 		if(dir.nr == 0){
594fe853e23SDavid du Colombier 			dir.nr = 1;
595fe853e23SDavid du Colombier 			dir.r = runestrdup(L".");
596fe853e23SDavid du Colombier 		}
597fe853e23SDavid du Colombier 		runemove(tmp, dir.r, dir.nr);
598fe853e23SDavid du Colombier 		tmp[dir.nr] = '/';
599fe853e23SDavid du Colombier 		runemove(tmp+dir.nr+1, path, npath);
600fe853e23SDavid du Colombier 		free(dir.r);
601fe853e23SDavid du Colombier 		dir.r = tmp;
602fe853e23SDavid du Colombier 		dir.nr += 1+npath;
603fe853e23SDavid du Colombier 		dir = cleanrname(dir);
604fe853e23SDavid du Colombier 	}
605fe853e23SDavid du Colombier 
606fe853e23SDavid du Colombier 	s = smprint("%.*S", nstr, str);
607fe853e23SDavid du Colombier 	dirs = smprint("%.*S", dir.nr, dir.r);
608fe853e23SDavid du Colombier 	c = complete(dirs, s);
609fe853e23SDavid du Colombier 	free(s);
610fe853e23SDavid du Colombier 	if(c == nil){
611fe853e23SDavid du Colombier 		warning(nil, "error attempting completion: %r\n");
612fe853e23SDavid du Colombier 		goto Return;
613fe853e23SDavid du Colombier 	}
614fe853e23SDavid du Colombier 
615fe853e23SDavid du Colombier 	if(!c->advance){
6164fec87e5SDavid du Colombier 		warning(nil, "%.*S%s%.*S*%s\n",
617fe853e23SDavid du Colombier 			dir.nr, dir.r,
618fe853e23SDavid du Colombier 			dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
6194fec87e5SDavid du Colombier 			nstr, str,
6204fec87e5SDavid du Colombier 			c->nmatch? "" : ": no matches in:");
621fe853e23SDavid du Colombier 		for(i=0; i<c->nfile; i++)
622fe853e23SDavid du Colombier 			warning(nil, " %s\n", c->filename[i]);
623fe853e23SDavid du Colombier 	}
624fe853e23SDavid du Colombier 
625fe853e23SDavid du Colombier 	if(c->advance)
626fe853e23SDavid du Colombier 		rp = runesmprint("%s", c->string);
627fe853e23SDavid du Colombier 	else
628fe853e23SDavid du Colombier 		rp = nil;
629fe853e23SDavid du Colombier   Return:
630fe853e23SDavid du Colombier 	freecompletion(c);
631fe853e23SDavid du Colombier 	free(dirs);
632fe853e23SDavid du Colombier 	free(str);
633fe853e23SDavid du Colombier 	free(path);
634fe853e23SDavid du Colombier 	return rp;
635fe853e23SDavid du Colombier }
636fe853e23SDavid du Colombier 
6377dd7cddfSDavid du Colombier void
texttype(Text * t,Rune r)6387dd7cddfSDavid du Colombier texttype(Text *t, Rune r)
6397dd7cddfSDavid du Colombier {
6407dd7cddfSDavid du Colombier 	uint q0, q1;
6417dd7cddfSDavid du Colombier 	int nnb, nb, n, i;
642fe853e23SDavid du Colombier 	int nr;
643fe853e23SDavid du Colombier 	Rune *rp;
6447dd7cddfSDavid du Colombier 	Text *u;
6457dd7cddfSDavid du Colombier 
6467dd7cddfSDavid du Colombier 	if(t->what!=Body && r=='\n')
6477dd7cddfSDavid du Colombier 		return;
648fe853e23SDavid du Colombier 	nr = 1;
649fe853e23SDavid du Colombier 	rp = &r;
6507dd7cddfSDavid du Colombier 	switch(r){
6517dd7cddfSDavid du Colombier 	case Kleft:
652fe853e23SDavid du Colombier 		if(t->q0 > 0){
653e7d29567SDavid du Colombier 			typecommit(t);
654fe853e23SDavid du Colombier 			textshow(t, t->q0-1, t->q0-1, TRUE);
655fe853e23SDavid du Colombier 		}
656fe853e23SDavid du Colombier 		return;
6577dd7cddfSDavid du Colombier 	case Kright:
658fe853e23SDavid du Colombier 		if(t->q1 < t->file->nc){
659e7d29567SDavid du Colombier 			typecommit(t);
660fe853e23SDavid du Colombier 			textshow(t, t->q1+1, t->q1+1, TRUE);
661fe853e23SDavid du Colombier 		}
662fe853e23SDavid du Colombier 		return;
663fe853e23SDavid du Colombier 	case Kdown:
664fe853e23SDavid du Colombier 		n = t->maxlines/3;
665fe853e23SDavid du Colombier 		goto case_Down;
666a8453668SDavid du Colombier 	case Kscrollonedown:
667a8453668SDavid du Colombier 		n = mousescrollsize(t->maxlines);
668a8453668SDavid du Colombier 		if(n <= 0)
669a8453668SDavid du Colombier 			n = 1;
670a8453668SDavid du Colombier 		goto case_Down;
671fe853e23SDavid du Colombier 	case Kpgdown:
672fe853e23SDavid du Colombier 		n = 2*t->maxlines/3;
673fe853e23SDavid du Colombier 	case_Down:
6747dd7cddfSDavid du Colombier 		q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height));
6759847521cSDavid du Colombier 		textsetorigin(t, q0, TRUE);
6767dd7cddfSDavid du Colombier 		return;
6777dd7cddfSDavid du Colombier 	case Kup:
678fe853e23SDavid du Colombier 		n = t->maxlines/3;
679fe853e23SDavid du Colombier 		goto case_Up;
680a8453668SDavid du Colombier 	case Kscrolloneup:
681a8453668SDavid du Colombier 		n = mousescrollsize(t->maxlines);
682a8453668SDavid du Colombier 		goto case_Up;
683fe853e23SDavid du Colombier 	case Kpgup:
684fe853e23SDavid du Colombier 		n = 2*t->maxlines/3;
685fe853e23SDavid du Colombier 	case_Up:
6867dd7cddfSDavid du Colombier 		q0 = textbacknl(t, t->org, n);
6879847521cSDavid du Colombier 		textsetorigin(t, q0, TRUE);
6887dd7cddfSDavid du Colombier 		return;
689fe853e23SDavid du Colombier 	case Khome:
690e7d29567SDavid du Colombier 		typecommit(t);
691fe853e23SDavid du Colombier 		textshow(t, 0, 0, FALSE);
692fe853e23SDavid du Colombier 		return;
693fe853e23SDavid du Colombier 	case Kend:
694e7d29567SDavid du Colombier 		typecommit(t);
695fe853e23SDavid du Colombier 		textshow(t, t->file->nc, t->file->nc, FALSE);
696fe853e23SDavid du Colombier 		return;
697e7d29567SDavid du Colombier 	case 0x01:	/* ^A: beginning of line */
698e7d29567SDavid du Colombier 		typecommit(t);
699e7d29567SDavid du Colombier 		/* go to where ^U would erase, if not already at BOL */
700e7d29567SDavid du Colombier 		nnb = 0;
701e7d29567SDavid du Colombier 		if(t->q0>0 && textreadc(t, t->q0-1)!='\n')
702e7d29567SDavid du Colombier 			nnb = textbswidth(t, 0x15);
703e7d29567SDavid du Colombier 		textshow(t, t->q0-nnb, t->q0-nnb, TRUE);
704e7d29567SDavid du Colombier 		return;
705e7d29567SDavid du Colombier 	case 0x05:	/* ^E: end of line */
706e7d29567SDavid du Colombier 		typecommit(t);
707e7d29567SDavid du Colombier 		q0 = t->q0;
708e7d29567SDavid du Colombier 		while(q0<t->file->nc && textreadc(t, q0)!='\n')
709e7d29567SDavid du Colombier 			q0++;
710e7d29567SDavid du Colombier 		textshow(t, q0, q0, TRUE);
711e7d29567SDavid du Colombier 		return;
7127dd7cddfSDavid du Colombier 	}
7137dd7cddfSDavid du Colombier 	if(t->what == Body){
7147dd7cddfSDavid du Colombier 		seq++;
7157dd7cddfSDavid du Colombier 		filemark(t->file);
7167dd7cddfSDavid du Colombier 	}
7177dd7cddfSDavid du Colombier 	if(t->q1 > t->q0){
7187dd7cddfSDavid du Colombier 		if(t->ncache != 0)
7197dd7cddfSDavid du Colombier 			error("text.type");
7207dd7cddfSDavid du Colombier 		cut(t, t, nil, TRUE, TRUE, nil, 0);
7217dd7cddfSDavid du Colombier 		t->eq0 = ~0;
7227dd7cddfSDavid du Colombier 	}
7239a747e4fSDavid du Colombier 	textshow(t, t->q0, t->q0, 1);
7247dd7cddfSDavid du Colombier 	switch(r){
725fe853e23SDavid du Colombier 	case 0x06:
726fe853e23SDavid du Colombier 	case Kins:
727fe853e23SDavid du Colombier 		rp = textcomplete(t);
728fe853e23SDavid du Colombier 		if(rp == nil)
729fe853e23SDavid du Colombier 			return;
730fe853e23SDavid du Colombier 		nr = runestrlen(rp);
731fe853e23SDavid du Colombier 		break;	/* fall through to normal insertion case */
7327dd7cddfSDavid du Colombier 	case 0x1B:
7337dd7cddfSDavid du Colombier 		if(t->eq0 != ~0)
7347dd7cddfSDavid du Colombier 			textsetselect(t, t->eq0, t->q0);
735e7d29567SDavid du Colombier 		if(t->ncache > 0)
736e7d29567SDavid du Colombier 			typecommit(t);
7377dd7cddfSDavid du Colombier 		return;
7387dd7cddfSDavid du Colombier 	case 0x08:	/* ^H: erase character */
7397dd7cddfSDavid du Colombier 	case 0x15:	/* ^U: erase line */
7407dd7cddfSDavid du Colombier 	case 0x17:	/* ^W: erase word */
74180ee5cbfSDavid du Colombier 		if(t->q0 == 0)	/* nothing to erase */
7427dd7cddfSDavid du Colombier 			return;
7437dd7cddfSDavid du Colombier 		nnb = textbswidth(t, r);
7447dd7cddfSDavid du Colombier 		q1 = t->q0;
7457dd7cddfSDavid du Colombier 		q0 = q1-nnb;
74680ee5cbfSDavid du Colombier 		/* if selection is at beginning of window, avoid deleting invisible text */
74780ee5cbfSDavid du Colombier 		if(q0 < t->org){
74880ee5cbfSDavid du Colombier 			q0 = t->org;
74980ee5cbfSDavid du Colombier 			nnb = q1-q0;
75080ee5cbfSDavid du Colombier 		}
75180ee5cbfSDavid du Colombier 		if(nnb <= 0)
75280ee5cbfSDavid du Colombier 			return;
7537dd7cddfSDavid du Colombier 		for(i=0; i<t->file->ntext; i++){
7547dd7cddfSDavid du Colombier 			u = t->file->text[i];
7557dd7cddfSDavid du Colombier 			u->nofill = TRUE;
7567dd7cddfSDavid du Colombier 			nb = nnb;
7577dd7cddfSDavid du Colombier 			n = u->ncache;
7587dd7cddfSDavid du Colombier 			if(n > 0){
7597dd7cddfSDavid du Colombier 				if(q1 != u->cq0+n)
7607dd7cddfSDavid du Colombier 					error("text.type backspace");
7617dd7cddfSDavid du Colombier 				if(n > nb)
7627dd7cddfSDavid du Colombier 					n = nb;
7637dd7cddfSDavid du Colombier 				u->ncache -= n;
7647dd7cddfSDavid du Colombier 				textdelete(u, q1-n, q1, FALSE);
7657dd7cddfSDavid du Colombier 				nb -= n;
7667dd7cddfSDavid du Colombier 			}
7677dd7cddfSDavid du Colombier 			if(u->eq0==q1 || u->eq0==~0)
7687dd7cddfSDavid du Colombier 				u->eq0 = q0;
7697dd7cddfSDavid du Colombier 			if(nb && u==t)
7707dd7cddfSDavid du Colombier 				textdelete(u, q0, q0+nb, TRUE);
7717dd7cddfSDavid du Colombier 			if(u != t)
7727dd7cddfSDavid du Colombier 				textsetselect(u, u->q0, u->q1);
7737dd7cddfSDavid du Colombier 			else
7747dd7cddfSDavid du Colombier 				textsetselect(t, q0, q0);
7757dd7cddfSDavid du Colombier 			u->nofill = FALSE;
7767dd7cddfSDavid du Colombier 		}
7777dd7cddfSDavid du Colombier 		for(i=0; i<t->file->ntext; i++)
7787dd7cddfSDavid du Colombier 			textfill(t->file->text[i]);
7797dd7cddfSDavid du Colombier 		return;
7804fec87e5SDavid du Colombier 	case '\n':
7814fec87e5SDavid du Colombier 		if(t->w->autoindent){
7824fec87e5SDavid du Colombier 			/* find beginning of previous line using backspace code */
7834fec87e5SDavid du Colombier 			nnb = textbswidth(t, 0x15); /* ^U case */
7844fec87e5SDavid du Colombier 			rp = runemalloc(nnb + 1);
7854fec87e5SDavid du Colombier 			nr = 0;
7864fec87e5SDavid du Colombier 			rp[nr++] = r;
7874fec87e5SDavid du Colombier 			for(i=0; i<nnb; i++){
7884fec87e5SDavid du Colombier 				r = textreadc(t, t->q0-nnb+i);
7894fec87e5SDavid du Colombier 				if(r != ' ' && r != '\t')
7904fec87e5SDavid du Colombier 					break;
7914fec87e5SDavid du Colombier 				rp[nr++] = r;
7924fec87e5SDavid du Colombier 			}
7934fec87e5SDavid du Colombier 		}
7944fec87e5SDavid du Colombier 		break; /* fall through to normal code */
7957dd7cddfSDavid du Colombier 	}
7967dd7cddfSDavid du Colombier 	/* otherwise ordinary character; just insert, typically in caches of all texts */
7977dd7cddfSDavid du Colombier 	for(i=0; i<t->file->ntext; i++){
7987dd7cddfSDavid du Colombier 		u = t->file->text[i];
7997dd7cddfSDavid du Colombier 		if(u->eq0 == ~0)
8007dd7cddfSDavid du Colombier 			u->eq0 = t->q0;
8017dd7cddfSDavid du Colombier 		if(u->ncache == 0)
8027dd7cddfSDavid du Colombier 			u->cq0 = t->q0;
8037dd7cddfSDavid du Colombier 		else if(t->q0 != u->cq0+u->ncache)
8047dd7cddfSDavid du Colombier 			error("text.type cq1");
805fe853e23SDavid du Colombier 		textinsert(u, t->q0, rp, nr, FALSE);
8067dd7cddfSDavid du Colombier 		if(u != t)
8077dd7cddfSDavid du Colombier 			textsetselect(u, u->q0, u->q1);
808fe853e23SDavid du Colombier 		if(u->ncache+nr > u->ncachealloc){
809fe853e23SDavid du Colombier 			u->ncachealloc += 10 + nr;
8107dd7cddfSDavid du Colombier 			u->cache = runerealloc(u->cache, u->ncachealloc);
8117dd7cddfSDavid du Colombier 		}
812fe853e23SDavid du Colombier 		runemove(u->cache+u->ncache, rp, nr);
813fe853e23SDavid du Colombier 		u->ncache += nr;
8147dd7cddfSDavid du Colombier 	}
815fe853e23SDavid du Colombier 	if(rp != &r)
816fe853e23SDavid du Colombier 		free(rp);
817fe853e23SDavid du Colombier 	textsetselect(t, t->q0+nr, t->q0+nr);
8187dd7cddfSDavid du Colombier 	if(r=='\n' && t->w!=nil)
8197dd7cddfSDavid du Colombier 		wincommit(t->w, t);
8207dd7cddfSDavid du Colombier }
8217dd7cddfSDavid du Colombier 
8227dd7cddfSDavid du Colombier void
textcommit(Text * t,int tofile)8237dd7cddfSDavid du Colombier textcommit(Text *t, int tofile)
8247dd7cddfSDavid du Colombier {
8257dd7cddfSDavid du Colombier 	if(t->ncache == 0)
8267dd7cddfSDavid du Colombier 		return;
8277dd7cddfSDavid du Colombier 	if(tofile)
8287dd7cddfSDavid du Colombier 		fileinsert(t->file, t->cq0, t->cache, t->ncache);
8297dd7cddfSDavid du Colombier 	if(t->what == Body){
8307dd7cddfSDavid du Colombier 		t->w->dirty = TRUE;
8317dd7cddfSDavid du Colombier 		t->w->utflastqid = -1;
8327dd7cddfSDavid du Colombier 	}
8337dd7cddfSDavid du Colombier 	t->ncache = 0;
8347dd7cddfSDavid du Colombier }
8357dd7cddfSDavid du Colombier 
8367dd7cddfSDavid du Colombier static	Text	*clicktext;
8377dd7cddfSDavid du Colombier static	uint	clickmsec;
8387dd7cddfSDavid du Colombier static	Text	*selecttext;
8397dd7cddfSDavid du Colombier static	uint	selectq;
8407dd7cddfSDavid du Colombier 
8417dd7cddfSDavid du Colombier /*
8427dd7cddfSDavid du Colombier  * called from frame library
8437dd7cddfSDavid du Colombier  */
8447dd7cddfSDavid du Colombier void
framescroll(Frame * f,int dl)8457dd7cddfSDavid du Colombier framescroll(Frame *f, int dl)
8467dd7cddfSDavid du Colombier {
8477dd7cddfSDavid du Colombier 	if(f != &selecttext->Frame)
8487dd7cddfSDavid du Colombier 		error("frameselect not right frame");
8497dd7cddfSDavid du Colombier 	textframescroll(selecttext, dl);
8507dd7cddfSDavid du Colombier }
8517dd7cddfSDavid du Colombier 
8527dd7cddfSDavid du Colombier void
textframescroll(Text * t,int dl)8537dd7cddfSDavid du Colombier textframescroll(Text *t, int dl)
8547dd7cddfSDavid du Colombier {
8557dd7cddfSDavid du Colombier 	uint q0;
8567dd7cddfSDavid du Colombier 
8577dd7cddfSDavid du Colombier 	if(dl == 0){
8587dd7cddfSDavid du Colombier 		scrsleep(100);
8597dd7cddfSDavid du Colombier 		return;
8607dd7cddfSDavid du Colombier 	}
8617dd7cddfSDavid du Colombier 	if(dl < 0){
8627dd7cddfSDavid du Colombier 		q0 = textbacknl(t, t->org, -dl);
8637dd7cddfSDavid du Colombier 		if(selectq > t->org+t->p0)
8647dd7cddfSDavid du Colombier 			textsetselect(t, t->org+t->p0, selectq);
8657dd7cddfSDavid du Colombier 		else
8667dd7cddfSDavid du Colombier 			textsetselect(t, selectq, t->org+t->p0);
8677dd7cddfSDavid du Colombier 	}else{
8687dd7cddfSDavid du Colombier 		if(t->org+t->nchars == t->file->nc)
8697dd7cddfSDavid du Colombier 			return;
8707dd7cddfSDavid du Colombier 		q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height));
8717dd7cddfSDavid du Colombier 		if(selectq > t->org+t->p1)
8727dd7cddfSDavid du Colombier 			textsetselect(t, t->org+t->p1, selectq);
8737dd7cddfSDavid du Colombier 		else
8747dd7cddfSDavid du Colombier 			textsetselect(t, selectq, t->org+t->p1);
8757dd7cddfSDavid du Colombier 	}
8767dd7cddfSDavid du Colombier 	textsetorigin(t, q0, TRUE);
8777dd7cddfSDavid du Colombier }
8787dd7cddfSDavid du Colombier 
8797dd7cddfSDavid du Colombier 
8807dd7cddfSDavid du Colombier void
textselect(Text * t)8817dd7cddfSDavid du Colombier textselect(Text *t)
8827dd7cddfSDavid du Colombier {
8837dd7cddfSDavid du Colombier 	uint q0, q1;
8847dd7cddfSDavid du Colombier 	int b, x, y;
885*43f160e5SDavid du Colombier 	int state;
8867dd7cddfSDavid du Colombier 
8877dd7cddfSDavid du Colombier 	selecttext = t;
8887dd7cddfSDavid du Colombier 	/*
8897dd7cddfSDavid du Colombier 	 * To have double-clicking and chording, we double-click
8907dd7cddfSDavid du Colombier 	 * immediately if it might make sense.
8917dd7cddfSDavid du Colombier 	 */
8927dd7cddfSDavid du Colombier 	b = mouse->buttons;
8937dd7cddfSDavid du Colombier 	q0 = t->q0;
8947dd7cddfSDavid du Colombier 	q1 = t->q1;
8957dd7cddfSDavid du Colombier 	selectq = t->org+frcharofpt(t, mouse->xy);
8967dd7cddfSDavid du Colombier 	if(clicktext==t && mouse->msec-clickmsec<500)
8977dd7cddfSDavid du Colombier 	if(q0==q1 && selectq==q0){
8987dd7cddfSDavid du Colombier 		textdoubleclick(t, &q0, &q1);
8997dd7cddfSDavid du Colombier 		textsetselect(t, q0, q1);
9007dd7cddfSDavid du Colombier 		flushimage(display, 1);
9017dd7cddfSDavid du Colombier 		x = mouse->xy.x;
9027dd7cddfSDavid du Colombier 		y = mouse->xy.y;
9037dd7cddfSDavid du Colombier 		/* stay here until something interesting happens */
9047dd7cddfSDavid du Colombier 		do
9057dd7cddfSDavid du Colombier 			readmouse(mousectl);
9067dd7cddfSDavid du Colombier 		while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3);
9077dd7cddfSDavid du Colombier 		mouse->xy.x = x;	/* in case we're calling frselect */
9087dd7cddfSDavid du Colombier 		mouse->xy.y = y;
9097dd7cddfSDavid du Colombier 		q0 = t->q0;	/* may have changed */
9107dd7cddfSDavid du Colombier 		q1 = t->q1;
9117dd7cddfSDavid du Colombier 		selectq = q0;
9127dd7cddfSDavid du Colombier 	}
9137dd7cddfSDavid du Colombier 	if(mouse->buttons == b){
9147dd7cddfSDavid du Colombier 		t->Frame.scroll = framescroll;
9157dd7cddfSDavid du Colombier 		frselect(t, mousectl);
9167dd7cddfSDavid du Colombier 		/* horrible botch: while asleep, may have lost selection altogether */
9177dd7cddfSDavid du Colombier 		if(selectq > t->file->nc)
9187dd7cddfSDavid du Colombier 			selectq = t->org + t->p0;
9197dd7cddfSDavid du Colombier 		t->Frame.scroll = nil;
9207dd7cddfSDavid du Colombier 		if(selectq < t->org)
9217dd7cddfSDavid du Colombier 			q0 = selectq;
9227dd7cddfSDavid du Colombier 		else
9237dd7cddfSDavid du Colombier 			q0 = t->org + t->p0;
9247dd7cddfSDavid du Colombier 		if(selectq > t->org+t->nchars)
9257dd7cddfSDavid du Colombier 			q1 = selectq;
9267dd7cddfSDavid du Colombier 		else
9277dd7cddfSDavid du Colombier 			q1 = t->org+t->p1;
9287dd7cddfSDavid du Colombier 	}
9297dd7cddfSDavid du Colombier 	if(q0 == q1){
9307dd7cddfSDavid du Colombier 		if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){
9317dd7cddfSDavid du Colombier 			textdoubleclick(t, &q0, &q1);
9327dd7cddfSDavid du Colombier 			clicktext = nil;
9337dd7cddfSDavid du Colombier 		}else{
9347dd7cddfSDavid du Colombier 			clicktext = t;
9357dd7cddfSDavid du Colombier 			clickmsec = mouse->msec;
9367dd7cddfSDavid du Colombier 		}
9377dd7cddfSDavid du Colombier 	}else
9387dd7cddfSDavid du Colombier 		clicktext = nil;
9397dd7cddfSDavid du Colombier 	textsetselect(t, q0, q1);
9407dd7cddfSDavid du Colombier 	flushimage(display, 1);
941*43f160e5SDavid du Colombier 	state = 0;	/* undo when possible; +1 for cut, -1 for paste */
9427dd7cddfSDavid du Colombier 	while(mouse->buttons){
9437dd7cddfSDavid du Colombier 		mouse->msec = 0;
9447dd7cddfSDavid du Colombier 		b = mouse->buttons;
945*43f160e5SDavid du Colombier 		if((b&1) && (b&6)){
946*43f160e5SDavid du Colombier 			if(state==0 && t->what==Body){
9477dd7cddfSDavid du Colombier 				seq++;
9487dd7cddfSDavid du Colombier 				filemark(t->w->body.file);
9497dd7cddfSDavid du Colombier 			}
9507dd7cddfSDavid du Colombier 			if(b & 2){
9517dd7cddfSDavid du Colombier 				if(state==-1 && t->what==Body){
9527dd7cddfSDavid du Colombier 					winundo(t->w, TRUE);
9537dd7cddfSDavid du Colombier 					textsetselect(t, q0, t->q0);
9547dd7cddfSDavid du Colombier 					state = 0;
955*43f160e5SDavid du Colombier 				}else if(state != 1){
9567dd7cddfSDavid du Colombier 					cut(t, t, nil, TRUE, TRUE, nil, 0);
957*43f160e5SDavid du Colombier 					state = 1;
9587dd7cddfSDavid du Colombier 				}
9597dd7cddfSDavid du Colombier 			}else{
9607dd7cddfSDavid du Colombier 				if(state==1 && t->what==Body){
9617dd7cddfSDavid du Colombier 					winundo(t->w, TRUE);
9627dd7cddfSDavid du Colombier 					textsetselect(t, q0, t->q1);
9637dd7cddfSDavid du Colombier 					state = 0;
964*43f160e5SDavid du Colombier 				}else if(state != -1){
96559cc4ca5SDavid du Colombier 					paste(t, t, nil, TRUE, FALSE, nil, 0);
966*43f160e5SDavid du Colombier 					state = -1;
9677dd7cddfSDavid du Colombier 				}
9687dd7cddfSDavid du Colombier 			}
9697dd7cddfSDavid du Colombier 			textscrdraw(t);
9707dd7cddfSDavid du Colombier 			clearmouse();
9717dd7cddfSDavid du Colombier 		}
9727dd7cddfSDavid du Colombier 		flushimage(display, 1);
9737dd7cddfSDavid du Colombier 		while(mouse->buttons == b)
9747dd7cddfSDavid du Colombier 			readmouse(mousectl);
9757dd7cddfSDavid du Colombier 		clicktext = nil;
9767dd7cddfSDavid du Colombier 	}
9777dd7cddfSDavid du Colombier }
9787dd7cddfSDavid du Colombier 
9797dd7cddfSDavid du Colombier void
textshow(Text * t,uint q0,uint q1,int doselect)9809a747e4fSDavid du Colombier textshow(Text *t, uint q0, uint q1, int doselect)
9817dd7cddfSDavid du Colombier {
9827dd7cddfSDavid du Colombier 	int qe;
9837dd7cddfSDavid du Colombier 	int nl;
9847dd7cddfSDavid du Colombier 	uint q;
9857dd7cddfSDavid du Colombier 
9862af003dfSDavid du Colombier 	if(t->what != Body){
9872af003dfSDavid du Colombier 		if(doselect)
9882af003dfSDavid du Colombier 			textsetselect(t, q0, q1);
9897dd7cddfSDavid du Colombier 		return;
9902af003dfSDavid du Colombier 	}
9917dd7cddfSDavid du Colombier 	if(t->w!=nil && t->maxlines==0)
9927dd7cddfSDavid du Colombier 		colgrow(t->col, t->w, 1);
9939a747e4fSDavid du Colombier 	if(doselect)
9947dd7cddfSDavid du Colombier 		textsetselect(t, q0, q1);
9957dd7cddfSDavid du Colombier 	qe = t->org+t->nchars;
9967dd7cddfSDavid du Colombier 	if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->file->nc+t->ncache)))
9977dd7cddfSDavid du Colombier 		textscrdraw(t);
9987dd7cddfSDavid du Colombier 	else{
9997dd7cddfSDavid du Colombier 		if(t->w->nopen[QWevent] > 0)
10007dd7cddfSDavid du Colombier 			nl = 3*t->maxlines/4;
10017dd7cddfSDavid du Colombier 		else
10027dd7cddfSDavid du Colombier 			nl = t->maxlines/4;
10037dd7cddfSDavid du Colombier 		q = textbacknl(t, q0, nl);
10047dd7cddfSDavid du Colombier 		/* avoid going backwards if trying to go forwards - long lines! */
10057dd7cddfSDavid du Colombier 		if(!(q0>t->org && q<t->org))
10067dd7cddfSDavid du Colombier 			textsetorigin(t, q, TRUE);
10077dd7cddfSDavid du Colombier 		while(q0 > t->org+t->nchars)
10087dd7cddfSDavid du Colombier 			textsetorigin(t, t->org+1, FALSE);
10097dd7cddfSDavid du Colombier 	}
10107dd7cddfSDavid du Colombier }
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier static
10137dd7cddfSDavid du Colombier int
region(int a,int b)10147dd7cddfSDavid du Colombier region(int a, int b)
10157dd7cddfSDavid du Colombier {
10167dd7cddfSDavid du Colombier 	if(a < b)
10177dd7cddfSDavid du Colombier 		return -1;
10187dd7cddfSDavid du Colombier 	if(a == b)
10197dd7cddfSDavid du Colombier 		return 0;
10207dd7cddfSDavid du Colombier 	return 1;
10217dd7cddfSDavid du Colombier }
10227dd7cddfSDavid du Colombier 
10237dd7cddfSDavid du Colombier void
selrestore(Frame * f,Point pt0,uint p0,uint p1)10247dd7cddfSDavid du Colombier selrestore(Frame *f, Point pt0, uint p0, uint p1)
10257dd7cddfSDavid du Colombier {
10267dd7cddfSDavid du Colombier 	if(p1<=f->p0 || p0>=f->p1){
10277dd7cddfSDavid du Colombier 		/* no overlap */
10287dd7cddfSDavid du Colombier 		frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]);
10297dd7cddfSDavid du Colombier 		return;
10307dd7cddfSDavid du Colombier 	}
10317dd7cddfSDavid du Colombier 	if(p0>=f->p0 && p1<=f->p1){
10327dd7cddfSDavid du Colombier 		/* entirely inside */
10337dd7cddfSDavid du Colombier 		frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
10347dd7cddfSDavid du Colombier 		return;
10357dd7cddfSDavid du Colombier 	}
10367dd7cddfSDavid du Colombier 
10377dd7cddfSDavid du Colombier 	/* they now are known to overlap */
10387dd7cddfSDavid du Colombier 
10397dd7cddfSDavid du Colombier 	/* before selection */
10407dd7cddfSDavid du Colombier 	if(p0 < f->p0){
10417dd7cddfSDavid du Colombier 		frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]);
10427dd7cddfSDavid du Colombier 		p0 = f->p0;
10437dd7cddfSDavid du Colombier 		pt0 = frptofchar(f, p0);
10447dd7cddfSDavid du Colombier 	}
10457dd7cddfSDavid du Colombier 	/* after selection */
10467dd7cddfSDavid du Colombier 	if(p1 > f->p1){
10477dd7cddfSDavid du Colombier 		frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]);
10487dd7cddfSDavid du Colombier 		p1 = f->p1;
10497dd7cddfSDavid du Colombier 	}
10507dd7cddfSDavid du Colombier 	/* inside selection */
10517dd7cddfSDavid du Colombier 	frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
10527dd7cddfSDavid du Colombier }
10537dd7cddfSDavid du Colombier 
10547dd7cddfSDavid du Colombier void
textsetselect(Text * t,uint q0,uint q1)10557dd7cddfSDavid du Colombier textsetselect(Text *t, uint q0, uint q1)
10567dd7cddfSDavid du Colombier {
10577dd7cddfSDavid du Colombier 	int p0, p1;
10587dd7cddfSDavid du Colombier 
10597dd7cddfSDavid du Colombier 	/* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */
10607dd7cddfSDavid du Colombier 	t->q0 = q0;
10617dd7cddfSDavid du Colombier 	t->q1 = q1;
10627dd7cddfSDavid du Colombier 	/* compute desired p0,p1 from q0,q1 */
10637dd7cddfSDavid du Colombier 	p0 = q0-t->org;
10647dd7cddfSDavid du Colombier 	p1 = q1-t->org;
10657dd7cddfSDavid du Colombier 	if(p0 < 0)
10667dd7cddfSDavid du Colombier 		p0 = 0;
10677dd7cddfSDavid du Colombier 	if(p1 < 0)
10687dd7cddfSDavid du Colombier 		p1 = 0;
10697dd7cddfSDavid du Colombier 	if(p0 > t->nchars)
10707dd7cddfSDavid du Colombier 		p0 = t->nchars;
10717dd7cddfSDavid du Colombier 	if(p1 > t->nchars)
10727dd7cddfSDavid du Colombier 		p1 = t->nchars;
10737dd7cddfSDavid du Colombier 	if(p0==t->p0 && p1==t->p1)
10747dd7cddfSDavid du Colombier 		return;
10757dd7cddfSDavid du Colombier 	/* screen disagrees with desired selection */
10767dd7cddfSDavid du Colombier 	if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){
10777dd7cddfSDavid du Colombier 		/* no overlap or too easy to bother trying */
10787dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0);
10797dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, p0), p0, p1, 1);
10807dd7cddfSDavid du Colombier 		goto Return;
10817dd7cddfSDavid du Colombier 	}
10827dd7cddfSDavid du Colombier 	/* overlap; avoid unnecessary painting */
10837dd7cddfSDavid du Colombier 	if(p0 < t->p0){
10847dd7cddfSDavid du Colombier 		/* extend selection backwards */
10857dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1);
10867dd7cddfSDavid du Colombier 	}else if(p0 > t->p0){
10877dd7cddfSDavid du Colombier 		/* trim first part of selection */
10887dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0);
10897dd7cddfSDavid du Colombier 	}
10907dd7cddfSDavid du Colombier 	if(p1 > t->p1){
10917dd7cddfSDavid du Colombier 		/* extend selection forwards */
10927dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1);
10937dd7cddfSDavid du Colombier 	}else if(p1 < t->p1){
10947dd7cddfSDavid du Colombier 		/* trim last part of selection */
10957dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0);
10967dd7cddfSDavid du Colombier 	}
10977dd7cddfSDavid du Colombier 
10987dd7cddfSDavid du Colombier     Return:
10997dd7cddfSDavid du Colombier 	t->p0 = p0;
11007dd7cddfSDavid du Colombier 	t->p1 = p1;
11017dd7cddfSDavid du Colombier }
11027dd7cddfSDavid du Colombier 
11039a747e4fSDavid du Colombier /*
11049a747e4fSDavid du Colombier  * Release the button in less than DELAY ms and it's considered a null selection
11059a747e4fSDavid du Colombier  * if the mouse hardly moved, regardless of whether it crossed a char boundary.
11069a747e4fSDavid du Colombier  */
11079a747e4fSDavid du Colombier enum {
11089a747e4fSDavid du Colombier 	DELAY = 2,
11099a747e4fSDavid du Colombier 	MINMOVE = 4,
11109a747e4fSDavid du Colombier };
11119a747e4fSDavid du Colombier 
11129a747e4fSDavid du Colombier uint
xselect(Frame * f,Mousectl * mc,Image * col,uint * p1p)11137dd7cddfSDavid du Colombier xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p)	/* when called, button is down */
11147dd7cddfSDavid du Colombier {
11157dd7cddfSDavid du Colombier 	uint p0, p1, q, tmp;
11169a747e4fSDavid du Colombier 	ulong msec;
11177dd7cddfSDavid du Colombier 	Point mp, pt0, pt1, qt;
11187dd7cddfSDavid du Colombier 	int reg, b;
11197dd7cddfSDavid du Colombier 
11207dd7cddfSDavid du Colombier 	mp = mc->xy;
11217dd7cddfSDavid du Colombier 	b = mc->buttons;
11229a747e4fSDavid du Colombier 	msec = mc->msec;
11237dd7cddfSDavid du Colombier 
11247dd7cddfSDavid du Colombier 	/* remove tick */
11257dd7cddfSDavid du Colombier 	if(f->p0 == f->p1)
11267dd7cddfSDavid du Colombier 		frtick(f, frptofchar(f, f->p0), 0);
11277dd7cddfSDavid du Colombier 	p0 = p1 = frcharofpt(f, mp);
11287dd7cddfSDavid du Colombier 	pt0 = frptofchar(f, p0);
11297dd7cddfSDavid du Colombier 	pt1 = frptofchar(f, p1);
11307dd7cddfSDavid du Colombier 	reg = 0;
11317dd7cddfSDavid du Colombier 	frtick(f, pt0, 1);
11327dd7cddfSDavid du Colombier 	do{
11337dd7cddfSDavid du Colombier 		q = frcharofpt(f, mc->xy);
11347dd7cddfSDavid du Colombier 		if(p1 != q){
11357dd7cddfSDavid du Colombier 			if(p0 == p1)
11367dd7cddfSDavid du Colombier 				frtick(f, pt0, 0);
11377dd7cddfSDavid du Colombier 			if(reg != region(q, p0)){	/* crossed starting point; reset */
11387dd7cddfSDavid du Colombier 				if(reg > 0)
11397dd7cddfSDavid du Colombier 					selrestore(f, pt0, p0, p1);
11407dd7cddfSDavid du Colombier 				else if(reg < 0)
11417dd7cddfSDavid du Colombier 					selrestore(f, pt1, p1, p0);
11427dd7cddfSDavid du Colombier 				p1 = p0;
11437dd7cddfSDavid du Colombier 				pt1 = pt0;
11447dd7cddfSDavid du Colombier 				reg = region(q, p0);
11457dd7cddfSDavid du Colombier 				if(reg == 0)
11467dd7cddfSDavid du Colombier 					frdrawsel0(f, pt0, p0, p1, col, display->white);
11477dd7cddfSDavid du Colombier 			}
11487dd7cddfSDavid du Colombier 			qt = frptofchar(f, q);
11497dd7cddfSDavid du Colombier 			if(reg > 0){
11507dd7cddfSDavid du Colombier 				if(q > p1)
11517dd7cddfSDavid du Colombier 					frdrawsel0(f, pt1, p1, q, col, display->white);
11527dd7cddfSDavid du Colombier 
11537dd7cddfSDavid du Colombier 				else if(q < p1)
11547dd7cddfSDavid du Colombier 					selrestore(f, qt, q, p1);
11557dd7cddfSDavid du Colombier 			}else if(reg < 0){
11567dd7cddfSDavid du Colombier 				if(q > p1)
11577dd7cddfSDavid du Colombier 					selrestore(f, pt1, p1, q);
11587dd7cddfSDavid du Colombier 				else
11597dd7cddfSDavid du Colombier 					frdrawsel0(f, qt, q, p1, col, display->white);
11607dd7cddfSDavid du Colombier 			}
11617dd7cddfSDavid du Colombier 			p1 = q;
11627dd7cddfSDavid du Colombier 			pt1 = qt;
11637dd7cddfSDavid du Colombier 		}
11647dd7cddfSDavid du Colombier 		if(p0 == p1)
11657dd7cddfSDavid du Colombier 			frtick(f, pt0, 1);
11667dd7cddfSDavid du Colombier 		flushimage(f->display, 1);
11677dd7cddfSDavid du Colombier 		readmouse(mc);
11687dd7cddfSDavid du Colombier 	}while(mc->buttons == b);
11699a747e4fSDavid du Colombier 	if(mc->msec-msec < DELAY && p0!=p1
11709a747e4fSDavid du Colombier 	&& abs(mp.x-mc->xy.x)<MINMOVE
11719a747e4fSDavid du Colombier 	&& abs(mp.y-mc->xy.y)<MINMOVE) {
11729a747e4fSDavid du Colombier 		if(reg > 0)
11739a747e4fSDavid du Colombier 			selrestore(f, pt0, p0, p1);
11749a747e4fSDavid du Colombier 		else if(reg < 0)
11759a747e4fSDavid du Colombier 			selrestore(f, pt1, p1, p0);
11769a747e4fSDavid du Colombier 		p1 = p0;
11779a747e4fSDavid du Colombier 	}
11787dd7cddfSDavid du Colombier 	if(p1 < p0){
11797dd7cddfSDavid du Colombier 		tmp = p0;
11807dd7cddfSDavid du Colombier 		p0 = p1;
11817dd7cddfSDavid du Colombier 		p1 = tmp;
11827dd7cddfSDavid du Colombier 	}
11837dd7cddfSDavid du Colombier 	pt0 = frptofchar(f, p0);
11847dd7cddfSDavid du Colombier 	if(p0 == p1)
11857dd7cddfSDavid du Colombier 		frtick(f, pt0, 0);
11867dd7cddfSDavid du Colombier 	selrestore(f, pt0, p0, p1);
11877dd7cddfSDavid du Colombier 	/* restore tick */
11887dd7cddfSDavid du Colombier 	if(f->p0 == f->p1)
11897dd7cddfSDavid du Colombier 		frtick(f, frptofchar(f, f->p0), 1);
11907dd7cddfSDavid du Colombier 	flushimage(f->display, 1);
11917dd7cddfSDavid du Colombier 	*p1p = p1;
11927dd7cddfSDavid du Colombier 	return p0;
11937dd7cddfSDavid du Colombier }
11947dd7cddfSDavid du Colombier 
11957dd7cddfSDavid du Colombier int
textselect23(Text * t,uint * q0,uint * q1,Image * high,int mask)11967dd7cddfSDavid du Colombier textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask)
11977dd7cddfSDavid du Colombier {
11987dd7cddfSDavid du Colombier 	uint p0, p1;
11997dd7cddfSDavid du Colombier 	int buts;
12007dd7cddfSDavid du Colombier 
12017dd7cddfSDavid du Colombier 	p0 = xselect(t, mousectl, high, &p1);
12027dd7cddfSDavid du Colombier 	buts = mousectl->buttons;
12037dd7cddfSDavid du Colombier 	if((buts & mask) == 0){
12047dd7cddfSDavid du Colombier 		*q0 = p0+t->org;
12057dd7cddfSDavid du Colombier 		*q1 = p1+t->org;
12067dd7cddfSDavid du Colombier 	}
12077dd7cddfSDavid du Colombier 
12087dd7cddfSDavid du Colombier 	while(mousectl->buttons)
12097dd7cddfSDavid du Colombier 		readmouse(mousectl);
12107dd7cddfSDavid du Colombier 	return buts;
12117dd7cddfSDavid du Colombier }
12127dd7cddfSDavid du Colombier 
12137dd7cddfSDavid du Colombier int
textselect2(Text * t,uint * q0,uint * q1,Text ** tp)12147dd7cddfSDavid du Colombier textselect2(Text *t, uint *q0, uint *q1, Text **tp)
12157dd7cddfSDavid du Colombier {
12167dd7cddfSDavid du Colombier 	int buts;
12177dd7cddfSDavid du Colombier 
12187dd7cddfSDavid du Colombier 	*tp = nil;
12197dd7cddfSDavid du Colombier 	buts = textselect23(t, q0, q1, but2col, 4);
12207dd7cddfSDavid du Colombier 	if(buts & 4)
12217dd7cddfSDavid du Colombier 		return 0;
12227dd7cddfSDavid du Colombier 	if(buts & 1){	/* pick up argument */
12237dd7cddfSDavid du Colombier 		*tp = argtext;
12247dd7cddfSDavid du Colombier 		return 1;
12257dd7cddfSDavid du Colombier 	}
12267dd7cddfSDavid du Colombier 	return 1;
12277dd7cddfSDavid du Colombier }
12287dd7cddfSDavid du Colombier 
12297dd7cddfSDavid du Colombier int
textselect3(Text * t,uint * q0,uint * q1)12307dd7cddfSDavid du Colombier textselect3(Text *t, uint *q0, uint *q1)
12317dd7cddfSDavid du Colombier {
12327dd7cddfSDavid du Colombier 	int h;
12337dd7cddfSDavid du Colombier 
12347dd7cddfSDavid du Colombier 	h = (textselect23(t, q0, q1, but3col, 1|2) == 0);
12357dd7cddfSDavid du Colombier 	return h;
12367dd7cddfSDavid du Colombier }
12377dd7cddfSDavid du Colombier 
12387dd7cddfSDavid du Colombier static Rune left1[] =  { L'{', L'[', L'(', L'<', L'«', 0 };
12397dd7cddfSDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
12407dd7cddfSDavid du Colombier static Rune left2[] =  { L'\n', 0 };
12417dd7cddfSDavid du Colombier static Rune left3[] =  { L'\'', L'"', L'`', 0 };
12427dd7cddfSDavid du Colombier 
12437dd7cddfSDavid du Colombier static
12447dd7cddfSDavid du Colombier Rune *left[] = {
12457dd7cddfSDavid du Colombier 	left1,
12467dd7cddfSDavid du Colombier 	left2,
12477dd7cddfSDavid du Colombier 	left3,
12487dd7cddfSDavid du Colombier 	nil
12497dd7cddfSDavid du Colombier };
12507dd7cddfSDavid du Colombier static
12517dd7cddfSDavid du Colombier Rune *right[] = {
12527dd7cddfSDavid du Colombier 	right1,
12537dd7cddfSDavid du Colombier 	left2,
12547dd7cddfSDavid du Colombier 	left3,
12557dd7cddfSDavid du Colombier 	nil
12567dd7cddfSDavid du Colombier };
12577dd7cddfSDavid du Colombier 
12587dd7cddfSDavid du Colombier void
textdoubleclick(Text * t,uint * q0,uint * q1)12597dd7cddfSDavid du Colombier textdoubleclick(Text *t, uint *q0, uint *q1)
12607dd7cddfSDavid du Colombier {
12617dd7cddfSDavid du Colombier 	int c, i;
12627dd7cddfSDavid du Colombier 	Rune *r, *l, *p;
12637dd7cddfSDavid du Colombier 	uint q;
12647dd7cddfSDavid du Colombier 
12657dd7cddfSDavid du Colombier 	for(i=0; left[i]!=nil; i++){
12667dd7cddfSDavid du Colombier 		q = *q0;
12677dd7cddfSDavid du Colombier 		l = left[i];
12687dd7cddfSDavid du Colombier 		r = right[i];
12697dd7cddfSDavid du Colombier 		/* try matching character to left, looking right */
12707dd7cddfSDavid du Colombier 		if(q == 0)
12717dd7cddfSDavid du Colombier 			c = '\n';
12727dd7cddfSDavid du Colombier 		else
12737dd7cddfSDavid du Colombier 			c = textreadc(t, q-1);
127459cc4ca5SDavid du Colombier 		p = runestrchr(l, c);
12757dd7cddfSDavid du Colombier 		if(p != nil){
12767dd7cddfSDavid du Colombier 			if(textclickmatch(t, c, r[p-l], 1, &q))
12777dd7cddfSDavid du Colombier 				*q1 = q-(c!='\n');
12787dd7cddfSDavid du Colombier 			return;
12797dd7cddfSDavid du Colombier 		}
12807dd7cddfSDavid du Colombier 		/* try matching character to right, looking left */
12817dd7cddfSDavid du Colombier 		if(q == t->file->nc)
12827dd7cddfSDavid du Colombier 			c = '\n';
12837dd7cddfSDavid du Colombier 		else
12847dd7cddfSDavid du Colombier 			c = textreadc(t, q);
128559cc4ca5SDavid du Colombier 		p = runestrchr(r, c);
12867dd7cddfSDavid du Colombier 		if(p != nil){
12877dd7cddfSDavid du Colombier 			if(textclickmatch(t, c, l[p-r], -1, &q)){
12887dd7cddfSDavid du Colombier 				*q1 = *q0+(*q0<t->file->nc && c=='\n');
12897dd7cddfSDavid du Colombier 				*q0 = q;
12907dd7cddfSDavid du Colombier 				if(c!='\n' || q!=0 || textreadc(t, 0)=='\n')
12917dd7cddfSDavid du Colombier 					(*q0)++;
12927dd7cddfSDavid du Colombier 			}
12937dd7cddfSDavid du Colombier 			return;
12947dd7cddfSDavid du Colombier 		}
12957dd7cddfSDavid du Colombier 	}
12967dd7cddfSDavid du Colombier 	/* try filling out word to right */
12977dd7cddfSDavid du Colombier 	while(*q1<t->file->nc && isalnum(textreadc(t, *q1)))
12987dd7cddfSDavid du Colombier 		(*q1)++;
12997dd7cddfSDavid du Colombier 	/* try filling out word to left */
13007dd7cddfSDavid du Colombier 	while(*q0>0 && isalnum(textreadc(t, *q0-1)))
13017dd7cddfSDavid du Colombier 		(*q0)--;
13027dd7cddfSDavid du Colombier }
13037dd7cddfSDavid du Colombier 
13047dd7cddfSDavid du Colombier int
textclickmatch(Text * t,int cl,int cr,int dir,uint * q)13057dd7cddfSDavid du Colombier textclickmatch(Text *t, int cl, int cr, int dir, uint *q)
13067dd7cddfSDavid du Colombier {
13077dd7cddfSDavid du Colombier 	Rune c;
13087dd7cddfSDavid du Colombier 	int nest;
13097dd7cddfSDavid du Colombier 
13107dd7cddfSDavid du Colombier 	nest = 1;
13117dd7cddfSDavid du Colombier 	for(;;){
13127dd7cddfSDavid du Colombier 		if(dir > 0){
13137dd7cddfSDavid du Colombier 			if(*q == t->file->nc)
13147dd7cddfSDavid du Colombier 				break;
13157dd7cddfSDavid du Colombier 			c = textreadc(t, *q);
13167dd7cddfSDavid du Colombier 			(*q)++;
13177dd7cddfSDavid du Colombier 		}else{
13187dd7cddfSDavid du Colombier 			if(*q == 0)
13197dd7cddfSDavid du Colombier 				break;
13207dd7cddfSDavid du Colombier 			(*q)--;
13217dd7cddfSDavid du Colombier 			c = textreadc(t, *q);
13227dd7cddfSDavid du Colombier 		}
13237dd7cddfSDavid du Colombier 		if(c == cr){
13247dd7cddfSDavid du Colombier 			if(--nest==0)
13257dd7cddfSDavid du Colombier 				return 1;
13267dd7cddfSDavid du Colombier 		}else if(c == cl)
13277dd7cddfSDavid du Colombier 			nest++;
13287dd7cddfSDavid du Colombier 	}
13297dd7cddfSDavid du Colombier 	return cl=='\n' && nest==1;
13307dd7cddfSDavid du Colombier }
13317dd7cddfSDavid du Colombier 
13327dd7cddfSDavid du Colombier uint
textbacknl(Text * t,uint p,uint n)13337dd7cddfSDavid du Colombier textbacknl(Text *t, uint p, uint n)
13347dd7cddfSDavid du Colombier {
13357dd7cddfSDavid du Colombier 	int i, j;
13367dd7cddfSDavid du Colombier 
13377dd7cddfSDavid du Colombier 	/* look for start of this line if n==0 */
13387dd7cddfSDavid du Colombier 	if(n==0 && p>0 && textreadc(t, p-1)!='\n')
13397dd7cddfSDavid du Colombier 		n = 1;
13407dd7cddfSDavid du Colombier 	i = n;
13417dd7cddfSDavid du Colombier 	while(i-->0 && p>0){
13427dd7cddfSDavid du Colombier 		--p;	/* it's at a newline now; back over it */
13437dd7cddfSDavid du Colombier 		if(p == 0)
13447dd7cddfSDavid du Colombier 			break;
13457dd7cddfSDavid du Colombier 		/* at 128 chars, call it a line anyway */
13467dd7cddfSDavid du Colombier 		for(j=128; --j>0 && p>0; p--)
13477dd7cddfSDavid du Colombier 			if(textreadc(t, p-1)=='\n')
13487dd7cddfSDavid du Colombier 				break;
13497dd7cddfSDavid du Colombier 	}
13507dd7cddfSDavid du Colombier 	return p;
13517dd7cddfSDavid du Colombier }
13527dd7cddfSDavid du Colombier 
13537dd7cddfSDavid du Colombier void
textsetorigin(Text * t,uint org,int exact)13547dd7cddfSDavid du Colombier textsetorigin(Text *t, uint org, int exact)
13557dd7cddfSDavid du Colombier {
13567dd7cddfSDavid du Colombier 	int i, a, fixup;
13577dd7cddfSDavid du Colombier 	Rune *r;
13587dd7cddfSDavid du Colombier 	uint n;
13597dd7cddfSDavid du Colombier 
13607dd7cddfSDavid du Colombier 	if(org>0 && !exact){
13617dd7cddfSDavid du Colombier 		/* org is an estimate of the char posn; find a newline */
13627dd7cddfSDavid du Colombier 		/* don't try harder than 256 chars */
13637dd7cddfSDavid du Colombier 		for(i=0; i<256 && org<t->file->nc; i++){
13647dd7cddfSDavid du Colombier 			if(textreadc(t, org) == '\n'){
13657dd7cddfSDavid du Colombier 				org++;
13667dd7cddfSDavid du Colombier 				break;
13677dd7cddfSDavid du Colombier 			}
13687dd7cddfSDavid du Colombier 			org++;
13697dd7cddfSDavid du Colombier 		}
13707dd7cddfSDavid du Colombier 	}
13717dd7cddfSDavid du Colombier 	a = org-t->org;
13727dd7cddfSDavid du Colombier 	fixup = 0;
13737dd7cddfSDavid du Colombier 	if(a>=0 && a<t->nchars){
13747dd7cddfSDavid du Colombier 		frdelete(t, 0, a);
13757dd7cddfSDavid du Colombier 		fixup = 1;	/* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
13767dd7cddfSDavid du Colombier 	}
13777dd7cddfSDavid du Colombier 	else if(a<0 && -a<t->nchars){
13787dd7cddfSDavid du Colombier 		n = t->org - org;
13797dd7cddfSDavid du Colombier 		r = runemalloc(n);
13807dd7cddfSDavid du Colombier 		bufread(t->file, org, r, n);
13817dd7cddfSDavid du Colombier 		frinsert(t, r, r+n, 0);
13827dd7cddfSDavid du Colombier 		free(r);
13837dd7cddfSDavid du Colombier 	}else
13847dd7cddfSDavid du Colombier 		frdelete(t, 0, t->nchars);
13857dd7cddfSDavid du Colombier 	t->org = org;
13867dd7cddfSDavid du Colombier 	textfill(t);
13877dd7cddfSDavid du Colombier 	textscrdraw(t);
13887dd7cddfSDavid du Colombier 	textsetselect(t, t->q0, t->q1);
13897dd7cddfSDavid du Colombier 	if(fixup && t->p1 > t->p0)
13907dd7cddfSDavid du Colombier 		frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1);
13917dd7cddfSDavid du Colombier }
13927dd7cddfSDavid du Colombier 
13937dd7cddfSDavid du Colombier void
textreset(Text * t)13947dd7cddfSDavid du Colombier textreset(Text *t)
13957dd7cddfSDavid du Colombier {
13967dd7cddfSDavid du Colombier 	t->file->seq = 0;
13977dd7cddfSDavid du Colombier 	t->eq0 = ~0;
13987dd7cddfSDavid du Colombier 	/* do t->delete(0, t->nc, TRUE) without building backup stuff */
13997dd7cddfSDavid du Colombier 	textsetselect(t, t->org, t->org);
14007dd7cddfSDavid du Colombier 	frdelete(t, 0, t->nchars);
14017dd7cddfSDavid du Colombier 	t->org = 0;
14027dd7cddfSDavid du Colombier 	t->q0 = 0;
14037dd7cddfSDavid du Colombier 	t->q1 = 0;
14047dd7cddfSDavid du Colombier 	filereset(t->file);
14057dd7cddfSDavid du Colombier 	bufreset(t->file);
14067dd7cddfSDavid du Colombier }
1407