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 for(warn=warnings; warn; warn=next) {
175 w = errorwin(warn->md, 'E');
182 * Most commands don't generate much output. For instance,
183 * Edit ,>cat goes through /dev/cons and is already in blocks
184 * because of the i/o system, but a few can. Edit ,p will
185 * put the entire result into a single hunk. So it's worth doing
186 * this in blocks (and putting the text in a buffer in the first
187 * place), to avoid a big memory footprint.
191 for(n = 0; n < warn->buf.nc; n += nr){
192 nr = warn->buf.nc - n;
195 bufread(&warn->buf, n, r, nr);
196 textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
198 textshow(t, q0, t->file->b.nc, 1);
205 bufclose(&warn->buf);
215 warning(Mntdir *md, char *s, ...)
221 r = runevsmprint(s, arg);
224 error("runevsmprint failed");
225 addwarningtext(md, r, runestrlen(r));
229 runeeq(Rune *s1, uint n1, Rune *s2, uint n2)
233 return memcmp(s1, s2, n1*sizeof(Rune)) == 0;
253 runetobyte(Rune *r, int n)
259 s = emalloc(n*UTFmax+1);
260 setmalloctag(s, getcallerpc(&r));
261 snprint(s, n*UTFmax+1, "%.*S", n, r);
266 bytetorune(char *s, int *ip)
272 r = runemalloc(nb+1);
273 cvttorunes(s, nb, r, &nb, &nr, nil);
283 * Hard to get absolutely right. Use what we know about ASCII
284 * and assume anything above the Latin control characters is
285 * potentially an alphanumeric.
289 if(0x7F<=c && c<=0xA0)
291 if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
297 rgetc(void *v, uint n)
299 return ((Rune*)v)[n];
303 tgetc(void *a, uint n)
308 if(n >= t->file->b.nc)
310 return textreadc(t, n);
314 skipbl(Rune *r, int n, int *np)
316 while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){
325 findbl(Rune *r, int n, int *np)
327 while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){
338 prevmouse = mouse->xy;
343 restoremouse(Window *w)
345 if(mousew!=nil && mousew==w)
346 moveto(mousectl, prevmouse);
363 error("strdup failed");
364 setmalloctag(t, getcallerpc(&s));
375 fprint(2, "allocating %d from %lux: %r\n", n, getcallerpc(&n));
377 error("malloc failed");
379 setmalloctag(p, getcallerpc(&n));
385 erealloc(void *p, uint n)
389 fprint(2, "reallocating %d: %r\n", n);
390 error("realloc failed");
392 setmalloctag(p, getcallerpc(&n));
400 makenewwindow(Text *t)
403 Window *w, *bigw, *emptyw;
409 else if(seltext && seltext->col)
414 if(row.ncol==0 && rowadd(&row, nil, -1)==nil)
415 error("can't make column");
416 c = row.col[row.ncol-1];
419 if(t==nil || t->w==nil || c->nw==0)
420 return coladd(c, nil, nil, -1);
422 /* find biggest window and biggest blank spot */
425 for(i=1; i<c->nw; i++){
427 /* use >= to choose one near bottom of screen */
428 if(w->body.fr.maxlines >= bigw->body.fr.maxlines)
430 if(w->body.fr.maxlines-w->body.fr.nlines >= emptyw->body.fr.maxlines-emptyw->body.fr.nlines)
433 emptyb = &emptyw->body;
434 el = emptyb->fr.maxlines-emptyb->fr.nlines;
435 /* if empty space is big, use it */
436 if(el>15 || (el>3 && el>(bigw->body.fr.maxlines-1)/2))
437 y = emptyb->fr.r.min.y+emptyb->fr.nlines*font->height;
439 /* if this window is in column and isn't much smaller, split it */
440 if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3)
442 y = (bigw->r.min.y + bigw->r.max.y)/2;
444 w = coladd(c, nil, nil, y);
445 if(w->body.fr.maxlines < 2)
446 colgrow(w->col, w, 1);