📄 xfid.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"enum{ Ctlsize = 5*12};char Edel[] = "deleted window";char Ebadctl[] = "ill-formed control message";char Ebadaddr[] = "bad address syntax";char Eaddr[] = "address out of range";char Einuse[] = "already in use";char Ebadevent[] = "bad event syntax";extern char Eperm[];staticvoidclampaddr(Window *w){ if(w->addr.q0 < 0) w->addr.q0 = 0; if(w->addr.q1 < 0) w->addr.q1 = 0; if(w->addr.q0 > w->body.file->nc) w->addr.q0 = w->body.file->nc; if(w->addr.q1 > w->body.file->nc) w->addr.q1 = w->body.file->nc;}voidxfidctl(void *arg){ Xfid *x; void (*f)(Xfid*); threadsetname("xfidctlthread"); x = arg; for(;;){ f = recvp(x->c); (*f)(x); flushimage(display, 1); sendp(cxfidfree, x); }}voidxfidflush(Xfid *x){ Fcall fc; int i, j; Window *w; Column *c; Xfid *wx; /* search windows for matching tag */ qlock(&row); for(j=0; j<row.ncol; j++){ c = row.col[j]; for(i=0; i<c->nw; i++){ w = c->w[i]; winlock(w, 'E'); wx = w->eventx; if(wx!=nil && wx->tag==x->oldtag){ w->eventx = nil; wx->flushed = TRUE; sendp(wx->c, nil); winunlock(w); goto out; } winunlock(w); } }out: qunlock(&row); respond(x, &fc, nil);}voidxfidopen(Xfid *x){ Fcall fc; Window *w; Text *t; char *s; Rune *r; int m, n, q, q0, q1; w = x->f->w; t = &w->body; if(w){ winlock(w, 'E'); q = FILE(x->f->qid); switch(q){ case QWaddr: if(w->nopen[q]++ == 0){ w->addr = (Range){0,0}; w->limit = (Range){-1,-1}; } break; case QWdata: case QWxdata: w->nopen[q]++; break; case QWevent: if(w->nopen[q]++ == 0){ if(!w->isdir && w->col!=nil){ w->filemenu = FALSE; winsettag(w); } } break; case QWrdsel: /* * Use a temporary file. * A pipe would be the obvious, but we can't afford the * broken pipe notification. Using the code to read QWbody * is n², which should probably also be fixed. Even then, * though, we'd need to squirrel away the data in case it's * modified during the operation, e.g. by |sort */ if(w->rdselfd > 0){ winunlock(w); respond(x, &fc, Einuse); return; } w->rdselfd = tempfile(); if(w->rdselfd < 0){ winunlock(w); respond(x, &fc, "can't create temp file"); return; } w->nopen[q]++; q0 = t->q0; q1 = t->q1; r = fbufalloc(); s = fbufalloc(); while(q0 < q1){ n = q1 - q0; if(n > BUFSIZE/UTFmax) n = BUFSIZE/UTFmax; bufread(t->file, q0, r, n); m = snprint(s, BUFSIZE+1, "%.*S", n, r); if(write(w->rdselfd, s, m) != m){ warning(nil, "can't write temp file for pipe command %r\n"); break; } q0 += n; } fbuffree(s); fbuffree(r); break; case QWwrsel: w->nopen[q]++; seq++; filemark(t->file); cut(t, t, nil, FALSE, TRUE, nil, 0); w->wrselrange = (Range){t->q1, t->q1}; w->nomark = TRUE; break; case QWeditout: if(editing == FALSE){ winunlock(w); respond(x, &fc, Eperm); return; } w->wrselrange = (Range){t->q1, t->q1}; break; } winunlock(w); } fc.qid = x->f->qid; fc.iounit = messagesize-IOHDRSZ; x->f->open = TRUE; respond(x, &fc, nil);}voidxfidclose(Xfid *x){ Fcall fc; Window *w; int q; Text *t; w = x->f->w; x->f->busy = FALSE; if(x->f->open == FALSE){ if(w != nil) winclose(w); respond(x, &fc, nil); return; } x->f->open = FALSE; if(w){ winlock(w, 'E'); q = FILE(x->f->qid); switch(q){ case QWctl: if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){ w->ctlfid = ~0; qunlock(&w->ctllock); } break; case QWdata: case QWxdata: w->nomark = FALSE; /* fall through */ case QWaddr: case QWevent: /* BUG: do we need to shut down Xfid? */ if(--w->nopen[q] == 0){ if(q == QWdata || q == QWxdata) w->nomark = FALSE; if(q==QWevent && !w->isdir && w->col!=nil){ w->filemenu = TRUE; winsettag(w); } if(q == QWevent){ free(w->dumpstr); free(w->dumpdir); w->dumpstr = nil; w->dumpdir = nil; } } break; case QWrdsel: close(w->rdselfd); w->rdselfd = 0; break; case QWwrsel: w->nomark = FALSE; t = &w->body; /* before: only did this if !w->noscroll, but that didn't seem right in practice */ textshow(t, min(w->wrselrange.q0, t->file->nc), min(w->wrselrange.q1, t->file->nc), 1); textscrdraw(t); break; } winunlock(w); winclose(w); } respond(x, &fc, nil);}voidxfidread(Xfid *x){ Fcall fc; int n, q; uint off; char *b; char buf[128]; Window *w; q = FILE(x->f->qid); w = x->f->w; if(w == nil){ fc.count = 0; switch(q){ case Qcons: case Qlabel: break; case Qindex: xfidindexread(x); return; default: warning(nil, "unknown qid %d\n", q); break; } respond(x, &fc, nil); return; } winlock(w, 'F'); if(w->col == nil){ winunlock(w); respond(x, &fc, Edel); return; } off = x->offset; switch(q){ case QWaddr: textcommit(&w->body, TRUE); clampaddr(w); sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1); goto Readbuf; case QWbody: xfidutfread(x, &w->body, w->body.file->nc, QWbody); break; case QWctl: b = winctlprint(w, buf, 1); goto Readb; Readbuf: b = buf; Readb: n = strlen(b); if(off > n) off = n; if(off+x->count > n) x->count = n-off; fc.count = x->count; fc.data = b+off; respond(x, &fc, nil); if(b != buf) free(b); break; case QWevent: xfideventread(x, w); break; case QWdata: /* BUG: what should happen if q1 > q0? */ if(w->addr.q0 > w->body.file->nc){ respond(x, &fc, Eaddr); break; } w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->nc); w->addr.q1 = w->addr.q0; break; case QWxdata: /* BUG: what should happen if q1 > q0? */ if(w->addr.q0 > w->body.file->nc){ respond(x, &fc, Eaddr); break; } w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1); break; case QWtag: xfidutfread(x, &w->tag, w->tag.file->nc, QWtag); break; case QWrdsel: seek(w->rdselfd, off, 0); n = x->count; if(n > BUFSIZE) n = BUFSIZE; b = fbufalloc(); n = read(w->rdselfd, b, n); if(n < 0){ respond(x, &fc, "I/O error in temp file"); break; } fc.count = n; fc.data = b; respond(x, &fc, nil); fbuffree(b); break; default: sprint(buf, "unknown qid %d in read", q); respond(x, &fc, nil); } winunlock(w);}voidxfidwrite(Xfid *x){ Fcall fc; int c, cnt, qid, q, nb, nr, eval; char buf[64], *err; Window *w; Rune *r; Range a; Text *t; uint q0, tq0, tq1; qid = FILE(x->f->qid); w = x->f->w; if(w){ c = 'F'; if(qid==QWtag || qid==QWbody) c = 'E'; winlock(w, c); if(w->col == nil){ winunlock(w); respond(x, &fc, Edel); return; } } x->data[x->count] = 0; switch(qid){ case Qcons: w = errorwin(x->f->mntdir, 'X'); t=&w->body; goto BodyTag; case Qlabel: fc.count = x->count; respond(x, &fc, nil); break; case QWaddr: x->data[x->count] = 0; r = bytetorune(x->data, &nr); t = &w->body; wincommit(w, t); eval = TRUE; a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb); free(r); if(nb < nr){ respond(x, &fc, Ebadaddr); break; } if(!eval){ respond(x, &fc, Eaddr); break; } w->addr = a; fc.count = x->count; respond(x, &fc, nil); break; case Qeditout: case QWeditout: r = bytetorune(x->data, &nr); if(w) err = edittext(w, w->wrselrange.q1, r, nr); else err = edittext(nil, 0, r, nr); free(r); if(err != nil){ respond(x, &fc, err); break; } fc.count = x->count; respond(x, &fc, nil); break; case QWerrors: w = errorwinforwin(w); t = &w->body; goto BodyTag; case QWbody: case QWwrsel: t = &w->body; goto BodyTag; case QWctl: xfidctlwrite(x, w); break; case QWdata: a = w->addr; t = &w->body; wincommit(w, t); if(a.q0>t->file->nc || a.q1>t->file->nc){ respond(x, &fc, Eaddr); break; } r = runemalloc(x->count); cvttorunes(x->data, x->count, r, &nb, &nr, nil); if(w->nomark == FALSE){ seq++; filemark(t->file); } q0 = a.q0; if(a.q1 > q0){ textdelete(t, q0, a.q1, TRUE); w->addr.q1 = q0; } tq0 = t->q0; tq1 = t->q1; textinsert(t, q0, r, nr, TRUE); if(tq0 >= q0) tq0 += nr; if(tq1 >= q0) tq1 += nr; textsetselect(t, tq0, tq1); if(!t->w->noscroll) textshow(t, q0, q0+nr, 0); textscrdraw(t); winsettag(w); free(r); w->addr.q0 += nr; w->addr.q1 = w->addr.q0; fc.count = x->count; respond(x, &fc, nil); break; case QWevent: xfideventwrite(x, w); break; case QWtag: t = &w->tag; goto BodyTag; BodyTag: q = x->f->nrpart; cnt = x->count; if(q > 0){ memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */ memmove(x->data, x->f->rpart, q); cnt += q; x->f->nrpart = 0; } r = runemalloc(cnt); cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil); /* approach end of buffer */ while(fullrune(x->data+nb, cnt-nb)){ c = nb; nb += chartorune(&r[nr], x->data+c); if(r[nr]) nr++; } if(nb < cnt){ memmove(x->f->rpart, x->data+nb, cnt-nb); x->f->nrpart = cnt-nb; } if(nr > 0){ wincommit(w, t); if(qid == QWwrsel){ q0 = w->wrselrange.q1; if(q0 > t->file->nc) q0 = t->file->nc; }else q0 = t->file->nc; if(qid == QWtag) textinsert(t, q0, r, nr, TRUE); else{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -