📄 util.c
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "fns.h"static Point prevmouse;static Window *mousew;voidcvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls){ uchar *q; Rune *s; int j, w; /* * Always guaranteed that n bytes may be interpreted * without worrying about partial runes. This may mean * reading up to UTFmax-1 more bytes than n; the caller * knows this. If n is a firm limit, the caller should * set p[n] = 0. */ q = (uchar*)p; s = r; for(j=0; j<n; j+=w){ if(*q < Runeself){ w = 1; *s = *q++; }else{ w = chartorune(s, (char*)q); q += w; } if(*s) s++; else if(nulls) *nulls = TRUE; } *nb = (char*)q-p; *nr = s-r;}voiderror(char *s){ fprint(2, "acme: %s: %r\n", s); remove(acmeerrorfile); abort();}Window*errorwin1(Rune *dir, int ndir, Rune **incl, int nincl){ Window *w; Rune *r; int i, n; r = runemalloc(ndir+8); if(n = ndir){ /* assign = */ runemove(r, dir, ndir); r[n++] = L'/'; } runemove(r+n, L"+Errors", 7); n += 7; w = lookfile(r, n); if(w == nil){ if(row.ncol == 0) if(rowadd(&row, nil, -1) == nil) error("can't create column to make error window"); w = coladd(row.col[row.ncol-1], nil, nil, -1); w->filemenu = FALSE; winsetname(w, r, n); } free(r); for(i=nincl; --i>=0; ){ n = runestrlen(incl[i]); r = runemalloc(n); runemove(r, incl[i], n); winaddincl(w, r, n); } w->autoindent = globalautoindent; return w;}/* make new window, if necessary; return with it locked */Window*errorwin(Mntdir *md, int owner){ Window *w; for(;;){ if(md == nil) w = errorwin1(nil, 0, nil, 0); else w = errorwin1(md->dir, md->ndir, md->incl, md->nincl); winlock(w, owner); if(w->col != nil) break; /* window was deleted too fast */ winunlock(w); } return w;}/* * Incoming window should be locked. * It will be unlocked and returned window * will be locked in its place. */Window*errorwinforwin(Window *w){ int i, n, nincl, owner; Rune **incl; Runestr dir; Text *t; t = &w->body; dir = dirname(t, nil, 0); if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ free(dir.r); dir.r = nil; dir.nr = 0; } incl = nil; nincl = w->nincl; if(nincl > 0){ incl = emalloc(nincl*sizeof(Rune*)); for(i=0; i<nincl; i++){ n = runestrlen(w->incl[i]); incl[i] = runemalloc(n+1); runemove(incl[i], w->incl[i], n); } } owner = w->owner; winunlock(w); for(;;){ w = errorwin1(dir.r, dir.nr, incl, nincl); winlock(w, owner); if(w->col != nil) break; /* window deleted too fast */ winunlock(w); } return w;}typedef struct Warning Warning;struct Warning{ Mntdir *md; Buffer buf; Warning *next;};static Warning *warnings;staticvoidaddwarningtext(Mntdir *md, Rune *r, int nr){ Warning *warn; for(warn = warnings; warn; warn=warn->next){ if(warn->md == md){ bufinsert(&warn->buf, warn->buf.nc, r, nr); return; } } warn = emalloc(sizeof(Warning)); warn->next = warnings; warn->md = md; if(md) fsysincid(md); warnings = warn; bufinsert(&warn->buf, 0, r, nr); nbsendp(cwarn, 0);}/* called while row is locked */voidflushwarnings(void){ Warning *warn, *next; Window *w; Text *t; int owner, nr, q0, n; Rune *r; for(warn=warnings; warn; warn=next) { w = errorwin(warn->md, 'E'); t = &w->body; owner = w->owner; if(owner == 0) w->owner = 'E'; wincommit(w, t); /* * Most commands don't generate much output. For instance, * Edit ,>cat goes through /dev/cons and is already in blocks * because of the i/o system, but a few can. Edit ,p will * put the entire result into a single hunk. So it's worth doing * this in blocks (and putting the text in a buffer in the first * place), to avoid a big memory footprint. */ r = fbufalloc(); q0 = t->file->nc; for(n = 0; n < warn->buf.nc; n += nr){ nr = warn->buf.nc - n; if(nr > RBUFSIZE) nr = RBUFSIZE; bufread(&warn->buf, n, r, nr); textbsinsert(t, t->file->nc, r, nr, TRUE, &nr); } textshow(t, q0, t->file->nc, 1); free(r); winsettag(t->w); textscrdraw(t); w->owner = owner; w->dirty = FALSE; winunlock(w); bufclose(&warn->buf); next = warn->next; if(warn->md) fsysdelid(warn->md); free(warn); } warnings = nil;}voidwarning(Mntdir *md, char *s, ...){ Rune *r; va_list arg; va_start(arg, s); r = runevsmprint(s, arg); va_end(arg); if(r == nil) error("runevsmprint failed"); addwarningtext(md, r, runestrlen(r));}intruneeq(Rune *s1, uint n1, Rune *s2, uint n2){ if(n1 != n2) return FALSE; return memcmp(s1, s2, n1*sizeof(Rune)) == 0;}uintmin(uint a, uint b){ if(a < b) return a; return b;}uintmax(uint a, uint b){ if(a > b) return a; return b;}char*runetobyte(Rune *r, int n){ char *s; if(r == nil) return nil; s = emalloc(n*UTFmax+1); setmalloctag(s, getcallerpc(&r)); snprint(s, n*UTFmax+1, "%.*S", n, r); return s;}Rune*bytetorune(char *s, int *ip){ Rune *r; int nb, nr; nb = strlen(s); r = runemalloc(nb+1); cvttorunes(s, nb, r, &nb, &nr, nil); r[nr] = '\0'; *ip = nr; return r;}intisalnum(Rune c){ /* * Hard to get absolutely right. Use what we know about ASCII * and assume anything above the Latin control characters is * potentially an alphanumeric. */ if(c <= ' ') return FALSE; if(0x7F<=c && c<=0xA0) return FALSE; if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c)) return FALSE; return TRUE;}intrgetc(void *v, uint n){ return ((Rune*)v)[n];}inttgetc(void *a, uint n){ Text *t; t = a; if(n >= t->file->nc) return 0; return textreadc(t, n);}Rune*skipbl(Rune *r, int n, int *np){ while(n>0 && (*r==' ' || *r=='\t' || *r=='\n')){ --n; r++; } *np = n; return r;}Rune*findbl(Rune *r, int n, int *np){ while(n>0 && *r!=' ' && *r!='\t' && *r!='\n'){ --n; r++; } *np = n; return r;}voidsavemouse(Window *w){ prevmouse = mouse->xy; mousew = w;}voidrestoremouse(Window *w){ if(mousew!=nil && mousew==w) moveto(mousectl, prevmouse); mousew = nil;}voidclearmouse(){ mousew = nil;}char*estrdup(char *s){ char *t; t = strdup(s); if(t == nil) error("strdup failed"); setmalloctag(t, getcallerpc(&s)); return t;}void*emalloc(uint n){ void *p; p = malloc(n); if(p == nil) error("malloc failed"); setmalloctag(p, getcallerpc(&n)); memset(p, 0, n); return p;}void*erealloc(void *p, uint n){ p = realloc(p, n); if(p == nil) error("realloc failed"); setmalloctag(p, getcallerpc(&n)); return p;}/* * Heuristic city. */Window*makenewwindow(Text *t){ Column *c; Window *w, *bigw, *emptyw; Text *emptyb; int i, y, el; if(activecol) c = activecol; else if(seltext && seltext->col) c = seltext->col; else if(t && t->col) c = t->col; else{ if(row.ncol==0 && rowadd(&row, nil, -1)==nil) error("can't make column"); c = row.col[row.ncol-1]; } activecol = c; if(t==nil || t->w==nil || c->nw==0) return coladd(c, nil, nil, -1); /* find biggest window and biggest blank spot */ emptyw = c->w[0]; bigw = emptyw; for(i=1; i<c->nw; i++){ w = c->w[i]; /* use >= to choose one near bottom of screen */ if(w->body.maxlines >= bigw->body.maxlines) bigw = w; if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines) emptyw = w; } emptyb = &emptyw->body; el = emptyb->maxlines-emptyb->nlines; /* if empty space is big, use it */ if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2)) y = emptyb->r.min.y+emptyb->nlines*font->height; else{ /* if this window is in column and isn't much smaller, split it */ if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) bigw = t->w; y = (bigw->r.min.y + bigw->r.max.y)/2; } w = coladd(c, nil, nil, y); if(w->body.maxlines < 2) colgrow(w->col, w, 1); return w;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -