xref: /plan9/sys/src/cmd/acme/util.c (revision a3b78ba5bb0d5cc068598a566c1c400adb4b4783)
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>
117dd7cddfSDavid du Colombier #include "dat.h"
127dd7cddfSDavid du Colombier #include "fns.h"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier static	Point		prevmouse;
157dd7cddfSDavid du Colombier static	Window	*mousew;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier void
187dd7cddfSDavid du Colombier cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
197dd7cddfSDavid du Colombier {
207dd7cddfSDavid du Colombier 	uchar *q;
217dd7cddfSDavid du Colombier 	Rune *s;
227dd7cddfSDavid du Colombier 	int j, w;
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier 	/*
257dd7cddfSDavid du Colombier 	 * Always guaranteed that n bytes may be interpreted
267dd7cddfSDavid du Colombier 	 * without worrying about partial runes.  This may mean
277dd7cddfSDavid du Colombier 	 * reading up to UTFmax-1 more bytes than n; the caller
287dd7cddfSDavid du Colombier 	 * knows this.  If n is a firm limit, the caller should
297dd7cddfSDavid du Colombier 	 * set p[n] = 0.
307dd7cddfSDavid du Colombier 	 */
317dd7cddfSDavid du Colombier 	q = (uchar*)p;
327dd7cddfSDavid du Colombier 	s = r;
337dd7cddfSDavid du Colombier 	for(j=0; j<n; j+=w){
347dd7cddfSDavid du Colombier 		if(*q < Runeself){
357dd7cddfSDavid du Colombier 			w = 1;
367dd7cddfSDavid du Colombier 			*s = *q++;
377dd7cddfSDavid du Colombier 		}else{
387dd7cddfSDavid du Colombier 			w = chartorune(s, (char*)q);
397dd7cddfSDavid du Colombier 			q += w;
407dd7cddfSDavid du Colombier 		}
417dd7cddfSDavid du Colombier 		if(*s)
427dd7cddfSDavid du Colombier 			s++;
437dd7cddfSDavid du Colombier 		else if(nulls)
447dd7cddfSDavid du Colombier 			*nulls = TRUE;
457dd7cddfSDavid du Colombier 	}
467dd7cddfSDavid du Colombier 	*nb = (char*)q-p;
477dd7cddfSDavid du Colombier 	*nr = s-r;
487dd7cddfSDavid du Colombier }
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier void
517dd7cddfSDavid du Colombier error(char *s)
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier 	fprint(2, "acme: %s: %r\n", s);
547dd7cddfSDavid du Colombier 	remove(acmeerrorfile);
557dd7cddfSDavid du Colombier 	abort();
567dd7cddfSDavid du Colombier }
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier Window*
593ff48bf5SDavid du Colombier errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
607dd7cddfSDavid du Colombier {
617dd7cddfSDavid du Colombier 	Window *w;
627dd7cddfSDavid du Colombier 	Rune *r;
637dd7cddfSDavid du Colombier 	int i, n;
647dd7cddfSDavid du Colombier 
65*a3b78ba5SDavid du Colombier 	r = runemalloc(ndir+8);
667dd7cddfSDavid du Colombier 	if(n = ndir)	/* assign = */
677dd7cddfSDavid du Colombier 		runemove(r, dir, ndir);
68*a3b78ba5SDavid du Colombier 	runemove(r+n, L"/+Errors", 8);
69*a3b78ba5SDavid du Colombier 	n += 8;
707dd7cddfSDavid du Colombier 	w = lookfile(r, n);
717dd7cddfSDavid du Colombier 	if(w == nil){
72d9306527SDavid du Colombier 		if(row.ncol == 0)
73d9306527SDavid du Colombier 			if(rowadd(&row, nil, -1) == nil)
74d9306527SDavid du Colombier 				error("can't create column to make error window");
757dd7cddfSDavid du Colombier 		w = coladd(row.col[row.ncol-1], nil, nil, -1);
767dd7cddfSDavid du Colombier 		w->filemenu = FALSE;
777dd7cddfSDavid du Colombier 		winsetname(w, r, n);
787dd7cddfSDavid du Colombier 	}
797dd7cddfSDavid du Colombier 	free(r);
807dd7cddfSDavid du Colombier 	for(i=nincl; --i>=0; ){
817dd7cddfSDavid du Colombier 		n = runestrlen(incl[i]);
827dd7cddfSDavid du Colombier 		r = runemalloc(n);
837dd7cddfSDavid du Colombier 		runemove(r, incl[i], n);
847dd7cddfSDavid du Colombier 		winaddincl(w, r, n);
857dd7cddfSDavid du Colombier 	}
867dd7cddfSDavid du Colombier 	return w;
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
893ff48bf5SDavid du Colombier /* make new window, if necessary; return with it locked */
903ff48bf5SDavid du Colombier Window*
91ef9eff0bSDavid du Colombier errorwin(Mntdir *md, int owner, Window *e)
923ff48bf5SDavid du Colombier {
933ff48bf5SDavid du Colombier 	Window *w;
943ff48bf5SDavid du Colombier 
953ff48bf5SDavid du Colombier 	for(;;){
963ff48bf5SDavid du Colombier 		if(md == nil)
973ff48bf5SDavid du Colombier 			w = errorwin1(nil, 0, nil, 0);
983ff48bf5SDavid du Colombier 		else
993ff48bf5SDavid du Colombier 			w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
100ef9eff0bSDavid du Colombier 		if(w != e)
1013ff48bf5SDavid du Colombier 			winlock(w, owner);
1023ff48bf5SDavid du Colombier 		if(w->col != nil)
1033ff48bf5SDavid du Colombier 			break;
1043ff48bf5SDavid du Colombier 		/* window was deleted too fast */
105ef9eff0bSDavid du Colombier 		if(w != e)
1063ff48bf5SDavid du Colombier 			winunlock(w);
1073ff48bf5SDavid du Colombier 	}
1083ff48bf5SDavid du Colombier 	return w;
1093ff48bf5SDavid du Colombier }
1103ff48bf5SDavid du Colombier 
111ef9eff0bSDavid du Colombier static void
112ef9eff0bSDavid du Colombier printwarning(Window *ew, Mntdir *md, Rune *r)
1137dd7cddfSDavid du Colombier {
1149a747e4fSDavid du Colombier 	int nr, q0, owner;
1157dd7cddfSDavid du Colombier 	Window *w;
1167dd7cddfSDavid du Colombier 	Text *t;
1177dd7cddfSDavid du Colombier 
1189a747e4fSDavid du Colombier 	if(r == nil)
1199a747e4fSDavid du Colombier 		error("runevsmprint failed");
1209a747e4fSDavid du Colombier 	nr = runestrlen(r);
1219a747e4fSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	if(row.ncol == 0){	/* really early error */
1237dd7cddfSDavid du Colombier 		rowinit(&row, screen->clipr);
1247dd7cddfSDavid du Colombier 		rowadd(&row, nil, -1);
1257dd7cddfSDavid du Colombier 		rowadd(&row, nil, -1);
1267dd7cddfSDavid du Colombier 		if(row.ncol == 0)
1277dd7cddfSDavid du Colombier 			error("initializing columns in warning()");
1287dd7cddfSDavid du Colombier 	}
1299a747e4fSDavid du Colombier 
130ef9eff0bSDavid du Colombier 	w = errorwin(md, 'E', ew);
1317dd7cddfSDavid du Colombier 	t = &w->body;
1327dd7cddfSDavid du Colombier 	owner = w->owner;
1337dd7cddfSDavid du Colombier 	if(owner == 0)
1347dd7cddfSDavid du Colombier 		w->owner = 'E';
1357dd7cddfSDavid du Colombier 	wincommit(w, t);
1367dd7cddfSDavid du Colombier 	q0 = textbsinsert(t, t->file->nc, r, nr, TRUE, &nr);
1379a747e4fSDavid du Colombier 	textshow(t, q0, q0+nr, 1);
1387dd7cddfSDavid du Colombier 	winsettag(t->w);
1397dd7cddfSDavid du Colombier 	textscrdraw(t);
1407dd7cddfSDavid du Colombier 	w->owner = owner;
1417dd7cddfSDavid du Colombier 	w->dirty = FALSE;
142ef9eff0bSDavid du Colombier 	if(ew != w)
1437dd7cddfSDavid du Colombier 		winunlock(w);
1447dd7cddfSDavid du Colombier 	free(r);
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
147ef9eff0bSDavid du Colombier void
148ef9eff0bSDavid du Colombier warning(Mntdir *md, char *s, ...)
149ef9eff0bSDavid du Colombier {
150ef9eff0bSDavid du Colombier 	Rune *r;
151ef9eff0bSDavid du Colombier 	va_list arg;
152ef9eff0bSDavid du Colombier 
153ef9eff0bSDavid du Colombier 	va_start(arg, s);
154ef9eff0bSDavid du Colombier 	r = runevsmprint(s, arg);
155ef9eff0bSDavid du Colombier 	va_end(arg);
156ef9eff0bSDavid du Colombier 	printwarning(nil, md, r);
157ef9eff0bSDavid du Colombier }
158ef9eff0bSDavid du Colombier 
159ef9eff0bSDavid du Colombier /*
160ef9eff0bSDavid du Colombier  * Warningew is like warning but avoids locking the error window
161ef9eff0bSDavid du Colombier  * if it's already locked by checking that ew!=error window.
162ef9eff0bSDavid du Colombier  */
163ef9eff0bSDavid du Colombier void
164ef9eff0bSDavid du Colombier warningew(Window *ew, Mntdir *md, char *s, ...)
165ef9eff0bSDavid du Colombier {
166ef9eff0bSDavid du Colombier 	Rune *r;
167ef9eff0bSDavid du Colombier 	va_list arg;
168ef9eff0bSDavid du Colombier 
169ef9eff0bSDavid du Colombier 	va_start(arg, s);
170ef9eff0bSDavid du Colombier 	r = runevsmprint(s, arg);
171ef9eff0bSDavid du Colombier 	va_end(arg);
172ef9eff0bSDavid du Colombier 	printwarning(ew, md, r);
173ef9eff0bSDavid du Colombier }
174ef9eff0bSDavid du Colombier 
1757dd7cddfSDavid du Colombier int
1767dd7cddfSDavid du Colombier runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
1777dd7cddfSDavid du Colombier {
1787dd7cddfSDavid du Colombier 	if(n1 != n2)
1797dd7cddfSDavid du Colombier 		return FALSE;
1807dd7cddfSDavid du Colombier 	return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier uint
1847dd7cddfSDavid du Colombier min(uint a, uint b)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier 	if(a < b)
1877dd7cddfSDavid du Colombier 		return a;
1887dd7cddfSDavid du Colombier 	return b;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier uint
1927dd7cddfSDavid du Colombier max(uint a, uint b)
1937dd7cddfSDavid du Colombier {
1947dd7cddfSDavid du Colombier 	if(a > b)
1957dd7cddfSDavid du Colombier 		return a;
1967dd7cddfSDavid du Colombier 	return b;
1977dd7cddfSDavid du Colombier }
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier char*
2007dd7cddfSDavid du Colombier runetobyte(Rune *r, int n)
2017dd7cddfSDavid du Colombier {
2027dd7cddfSDavid du Colombier 	char *s;
2037dd7cddfSDavid du Colombier 
20434e04225SDavid du Colombier 	if(r == nil)
2057dd7cddfSDavid du Colombier 		return nil;
2067dd7cddfSDavid du Colombier 	s = emalloc(n*UTFmax+1);
20759cc4ca5SDavid du Colombier 	setmalloctag(s, getcallerpc(&r));
2087dd7cddfSDavid du Colombier 	snprint(s, n*UTFmax+1, "%.*S", n, r);
2097dd7cddfSDavid du Colombier 	return s;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier Rune*
2137dd7cddfSDavid du Colombier bytetorune(char *s, int *ip)
2147dd7cddfSDavid du Colombier {
2157dd7cddfSDavid du Colombier 	Rune *r;
2167dd7cddfSDavid du Colombier 	int nb, nr;
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	nb = strlen(s);
2197dd7cddfSDavid du Colombier 	r = runemalloc(nb+1);
2207dd7cddfSDavid du Colombier 	cvttorunes(s, nb, r, &nb, &nr, nil);
2217dd7cddfSDavid du Colombier 	r[nr] = '\0';
2227dd7cddfSDavid du Colombier 	*ip = nr;
2237dd7cddfSDavid du Colombier 	return r;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier int
2277dd7cddfSDavid du Colombier isalnum(Rune c)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier 	/*
2307dd7cddfSDavid du Colombier 	 * Hard to get absolutely right.  Use what we know about ASCII
2317dd7cddfSDavid du Colombier 	 * and assume anything above the Latin control characters is
2327dd7cddfSDavid du Colombier 	 * potentially an alphanumeric.
2337dd7cddfSDavid du Colombier 	 */
2347dd7cddfSDavid du Colombier 	if(c <= ' ')
2357dd7cddfSDavid du Colombier 		return FALSE;
2367dd7cddfSDavid du Colombier 	if(0x7F<=c && c<=0xA0)
2377dd7cddfSDavid du Colombier 		return FALSE;
2387dd7cddfSDavid du Colombier 	if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
2397dd7cddfSDavid du Colombier 		return FALSE;
2407dd7cddfSDavid du Colombier 	return TRUE;
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier int
2447dd7cddfSDavid du Colombier rgetc(void *v, uint n)
2457dd7cddfSDavid du Colombier {
2467dd7cddfSDavid du Colombier 	return ((Rune*)v)[n];
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier int
2507dd7cddfSDavid du Colombier tgetc(void *a, uint n)
2517dd7cddfSDavid du Colombier {
2527dd7cddfSDavid du Colombier 	Text *t;
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 	t = a;
2557dd7cddfSDavid du Colombier 	if(n >= t->file->nc)
2567dd7cddfSDavid du Colombier 		return 0;
2577dd7cddfSDavid du Colombier 	return textreadc(t, n);
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier 
2607dd7cddfSDavid du Colombier Rune*
2617dd7cddfSDavid du Colombier skipbl(Rune *r, int n, int *np)
2627dd7cddfSDavid du Colombier {
2637dd7cddfSDavid du Colombier 	while(n>0 && *r==' ' || *r=='\t' || *r=='\n'){
2647dd7cddfSDavid du Colombier 		--n;
2657dd7cddfSDavid du Colombier 		r++;
2667dd7cddfSDavid du Colombier 	}
2677dd7cddfSDavid du Colombier 	*np = n;
2687dd7cddfSDavid du Colombier 	return r;
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier Rune*
2727dd7cddfSDavid du Colombier findbl(Rune *r, int n, int *np)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier 	while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
2757dd7cddfSDavid du Colombier 		--n;
2767dd7cddfSDavid du Colombier 		r++;
2777dd7cddfSDavid du Colombier 	}
2787dd7cddfSDavid du Colombier 	*np = n;
2797dd7cddfSDavid du Colombier 	return r;
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier void
2837dd7cddfSDavid du Colombier savemouse(Window *w)
2847dd7cddfSDavid du Colombier {
2857dd7cddfSDavid du Colombier 	prevmouse = mouse->xy;
2867dd7cddfSDavid du Colombier 	mousew = w;
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier void
2907dd7cddfSDavid du Colombier restoremouse(Window *w)
2917dd7cddfSDavid du Colombier {
2927dd7cddfSDavid du Colombier 	if(mousew!=nil && mousew==w)
2937dd7cddfSDavid du Colombier 		moveto(mousectl, prevmouse);
2947dd7cddfSDavid du Colombier 	mousew = nil;
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
2987dd7cddfSDavid du Colombier clearmouse()
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier 	mousew = nil;
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier 
30359cc4ca5SDavid du Colombier char*
30459cc4ca5SDavid du Colombier estrdup(char *s)
30559cc4ca5SDavid du Colombier {
30659cc4ca5SDavid du Colombier 	char *t;
30759cc4ca5SDavid du Colombier 
30859cc4ca5SDavid du Colombier 	t = strdup(s);
30959cc4ca5SDavid du Colombier 	if(t == nil)
31059cc4ca5SDavid du Colombier 		error("strdup failed");
31159cc4ca5SDavid du Colombier 	setmalloctag(t, getcallerpc(&s));
31259cc4ca5SDavid du Colombier 	return t;
31359cc4ca5SDavid du Colombier }
31459cc4ca5SDavid du Colombier 
3157dd7cddfSDavid du Colombier void*
3167dd7cddfSDavid du Colombier emalloc(uint n)
3177dd7cddfSDavid du Colombier {
3187dd7cddfSDavid du Colombier 	void *p;
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier 	p = malloc(n);
3217dd7cddfSDavid du Colombier 	if(p == nil)
3227dd7cddfSDavid du Colombier 		error("malloc failed");
32359cc4ca5SDavid du Colombier 	setmalloctag(p, getcallerpc(&n));
3247dd7cddfSDavid du Colombier 	memset(p, 0, n);
3257dd7cddfSDavid du Colombier 	return p;
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier 
32859cc4ca5SDavid du Colombier void*
32959cc4ca5SDavid du Colombier erealloc(void *p, uint n)
33059cc4ca5SDavid du Colombier {
33159cc4ca5SDavid du Colombier 	p = realloc(p, n);
33259cc4ca5SDavid du Colombier 	if(p == nil)
33359cc4ca5SDavid du Colombier 		error("realloc failed");
33459cc4ca5SDavid du Colombier 	setmalloctag(p, getcallerpc(&n));
33559cc4ca5SDavid du Colombier 	return p;
33659cc4ca5SDavid du Colombier }
33759cc4ca5SDavid du Colombier 
3387dd7cddfSDavid du Colombier /*
3397dd7cddfSDavid du Colombier  * Heuristic city.
3407dd7cddfSDavid du Colombier  */
3417dd7cddfSDavid du Colombier Window*
342d9306527SDavid du Colombier makenewwindow(Text *t)
3437dd7cddfSDavid du Colombier {
3447dd7cddfSDavid du Colombier 	Column *c;
3457dd7cddfSDavid du Colombier 	Window *w, *bigw, *emptyw;
3467dd7cddfSDavid du Colombier 	Text *emptyb;
3477dd7cddfSDavid du Colombier 	int i, y, el;
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier 	if(activecol)
3507dd7cddfSDavid du Colombier 		c = activecol;
3517dd7cddfSDavid du Colombier 	else if(seltext && seltext->col)
3527dd7cddfSDavid du Colombier 		c = seltext->col;
3537dd7cddfSDavid du Colombier 	else if(t && t->col)
3547dd7cddfSDavid du Colombier 		c = t->col;
3557dd7cddfSDavid du Colombier 	else{
3567dd7cddfSDavid du Colombier 		if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
3577dd7cddfSDavid du Colombier 			error("can't make column");
3587dd7cddfSDavid du Colombier 		c = row.col[row.ncol-1];
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier 	activecol = c;
3617dd7cddfSDavid du Colombier 	if(t==nil || t->w==nil || c->nw==0)
3627dd7cddfSDavid du Colombier 		return coladd(c, nil, nil, -1);
3637dd7cddfSDavid du Colombier 
3647dd7cddfSDavid du Colombier 	/* find biggest window and biggest blank spot */
3657dd7cddfSDavid du Colombier 	emptyw = c->w[0];
3667dd7cddfSDavid du Colombier 	bigw = emptyw;
3677dd7cddfSDavid du Colombier 	for(i=1; i<c->nw; i++){
3687dd7cddfSDavid du Colombier 		w = c->w[i];
3697dd7cddfSDavid du Colombier 		/* use >= to choose one near bottom of screen */
3707dd7cddfSDavid du Colombier 		if(w->body.maxlines >= bigw->body.maxlines)
3717dd7cddfSDavid du Colombier 			bigw = w;
3727dd7cddfSDavid du Colombier 		if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines)
3737dd7cddfSDavid du Colombier 			emptyw = w;
3747dd7cddfSDavid du Colombier 	}
3757dd7cddfSDavid du Colombier 	emptyb = &emptyw->body;
3767dd7cddfSDavid du Colombier 	el = emptyb->maxlines-emptyb->nlines;
3777dd7cddfSDavid du Colombier 	/* if empty space is big, use it */
3787dd7cddfSDavid du Colombier 	if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2))
3797dd7cddfSDavid du Colombier 		y = emptyb->r.min.y+emptyb->nlines*font->height;
3807dd7cddfSDavid du Colombier 	else{
3817dd7cddfSDavid du Colombier 		/* if this window is in column and isn't much smaller, split it */
3827dd7cddfSDavid du Colombier 		if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3)
3837dd7cddfSDavid du Colombier 			bigw = t->w;
3847dd7cddfSDavid du Colombier 		y = (bigw->r.min.y + bigw->r.max.y)/2;
3857dd7cddfSDavid du Colombier 	}
3867dd7cddfSDavid du Colombier 	w = coladd(c, nil, nil, y);
3877dd7cddfSDavid du Colombier 	if(w->body.maxlines < 2)
3887dd7cddfSDavid du Colombier 		colgrow(w->col, w, 1);
3897dd7cddfSDavid du Colombier 	return w;
3907dd7cddfSDavid du Colombier }
391