14 static Point prevmouse;
15 static Window *mousew;
28 runestr(Rune *r, uint n)
38 cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
45 * Always guaranteed that n bytes may be interpreted
46 * without worrying about partial runes. This may mean
47 * reading up to UTFmax-1 more bytes than n; the caller
48 * knows this. If n is a firm limit, the caller should
58 w = chartorune(s, (char*)q);
73 fprint(2, "acme: %s: %r\n", s);
78 errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
83 static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
85 r = runemalloc(ndir+8);
86 if(n = ndir){ /* assign = */
87 runemove(r, dir, ndir);
90 runemove(r+n, Lpluserrors, 7);
95 if(rowadd(&row, nil, -1) == nil)
96 error("can't create column to make error window");
97 w = coladd(row.col[row.ncol-1], nil, nil, -1);
102 for(i=nincl; --i>=0; ){
103 n = runestrlen(incl[i]);
105 runemove(r, incl[i], n);
108 w->autoindent = globalautoindent;
112 /* make new window, if necessary; return with it locked */
114 errorwin(Mntdir *md, int owner)
120 w = errorwin1(nil, 0, nil, 0);
122 w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
126 /* window was deleted too fast */
132 typedef struct Warning Warning;
140 static Warning *warnings;
144 addwarningtext(Mntdir *md, Rune *r, int nr)
148 for(warn = warnings; warn; warn=warn->next){
150 bufinsert(&warn->buf, warn->buf.nc, r, nr);
154 warn = emalloc(sizeof(Warning));
155 warn->next = warnings;
160 bufinsert(&warn->buf, 0, r, nr);
164 /* called while row is locked */
168 Warning *warn, *next;
171 int owner, nr, q0, n;
174 if(row.ncol == 0){ /* really early error */
175 rowinit(&row, screen->clipr);
176 rowadd(&row, nil, -1);
177 rowadd(&row, nil, -1);
179 error("initializing columns in flushwarnings()");
182 for(warn=warnings; warn; warn=next) {
183 w = errorwin(warn->md, 'E');
190 * Most commands don't generate much output. For instance,
191 * Edit ,>cat goes through /dev/cons and is already in blocks
192 * because of the i/o system, but a few can. Edit ,p will
193 * put the entire result into a single hunk. So it's worth doing
194 * this in blocks (and putting the text in a buffer in the first
195 * place), to avoid a big memory footprint.
199 for(n = 0; n < warn->buf.nc; n += nr){
200 nr = warn->buf.nc - n;
203 bufread(&warn->buf, n, r, nr);
204 textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
206 textshow(t, q0, t->file->b.nc, 1);
213 bufclose(&warn->buf);
223 warning(Mntdir *md, char *s, ...)
229 r = runevsmprint(s, arg);
232 error("runevsmprint failed");
233 addwarningtext(md, r, runestrlen(r));
237 runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
241 return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
261 runetobyte(Rune *r, int n)
267 s = emalloc(n*UTFmax+1);
268 setmalloctag(s, getcallerpc(&r));
269 snprint(s, n*UTFmax+1, "%.*S", n, r);
274 bytetorune(char *s, int *ip)
280 r = runemalloc(nb+1);
281 cvttorunes(s, nb, r, &nb, &nr, nil);
291 * Hard to get absolutely right. Use what we know about ASCII
292 * and assume anything above the Latin control characters is
293 * potentially an alphanumeric.
297 if(0x7F<=c && c<=0xA0)
299 if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
305 rgetc(void *v, uint n)
307 return ((Rune*)v)[n];
311 tgetc(void *a, uint n)
316 if(n >= t->file->b.nc)
318 return textreadc(t, n);
322 skipbl(Rune *r, int n, int *np)
324 while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
333 findbl(Rune *r, int n, int *np)
335 while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
346 prevmouse = mouse->xy;
351 restoremouse(Window *w)
353 if(mousew!=nil && mousew==w)
354 moveto(mousectl, prevmouse);
371 error("strdup failed");
372 setmalloctag(t, getcallerpc(&s));
383 fprint(2, "allocating %d from %lux: %r\n", n, getcallerpc(&n));
385 error("malloc failed");
387 setmalloctag(p, getcallerpc(&n));
393 erealloc(void *p, uint n)
397 fprint(2, "reallocating %d: %r\n", n);
398 error("realloc failed");
400 setmalloctag(p, getcallerpc(&n));
408 makenewwindow(Text *t)
411 Window *w, *bigw, *emptyw;
417 else if(seltext && seltext->col)
422 if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
423 error("can't make column");
424 c = row.col[row.ncol-1];
427 if(t==nil || t->w==nil || c->nw==0)
428 return coladd(c, nil, nil, -1);
430 /* find biggest window and biggest blank spot */
433 for(i=1; i<c->nw; i++){
435 /* use >= to choose one near bottom of screen */
436 if(w->body.fr.maxlines >= bigw->body.fr.maxlines)
438 if(w->body.fr.maxlines-w->body.fr.nlines >= emptyw->body.fr.maxlines-emptyw->body.fr.nlines)
441 emptyb = &emptyw->body;
442 el = emptyb->fr.maxlines-emptyb->fr.nlines;
443 /* if empty space is big, use it */
444 if(el>15 || (el>3 && el>(bigw->body.fr.maxlines-1)/2))
445 y = emptyb->fr.r.min.y+emptyb->fr.nlines*font->height;
447 /* if this window is in column and isn't much smaller, split it */
448 if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3)
450 y = (bigw->r.min.y + bigw->r.max.y)/2;
452 w = coladd(c, nil, nil, y);
453 if(w->body.fr.maxlines < 2)
454 colgrow(w->col, w, 1);