ref: 9914a8da911d9fdfefd6b090870bbd385cacae69
dir: /main.c/
#include "inc.h" #include <cursor.h> Keyboardctl *kbctl; Keyboardctl *fwdkc, kbdctl2; Mousectl *mctl; int shiftdown; // TODO: needed? Text text; Image *colors[NCOL]; char filename[1024]; char *startdir; Cursor quest = { {-7,-7}, {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, }, {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } }; void panic(char *s) { fprint(2, "error: %s: %r\n", s); threadexitsall("error"); } void* emalloc(ulong size) { void *p; p = malloc(size); if(p == nil) panic("malloc failed"); memset(p, 0, size); return p; } void* erealloc(void *p, ulong size) { p = realloc(p, size); if(p == nil) panic("realloc failed"); return p; } char* estrdup(char *s) { char *p; p = malloc(strlen(s)+1); if(p == nil) panic("strdup failed"); strcpy(p, s); return p; } /* * /dev/snarf updates when the file is closed, so we must open our own * fd here rather than use snarffd */ void putsnarf(void) { int fd, i, n; if(snarffd<0 || nsnarf==0) return; fd = open("/dev/snarf", OWRITE|OCEXEC); if(fd < 0) return; /* snarf buffer could be huge, so fprint will truncate; do it in blocks */ for(i=0; i<nsnarf; i+=n){ n = nsnarf-i; if(n >= 256) n = 256; if(fprint(fd, "%.*S", n, snarf+i) < 0) break; } close(fd); } void setsnarf(char *s, int ns) { free(snarf); snarf = runesmprint("%.*s", ns, s); nsnarf = runestrlen(snarf); snarfversion++; } void getsnarf(void) { int i, n; char *s, *sn; if(snarffd < 0) return; sn = nil; i = 0; seek(snarffd, 0, 0); for(;;){ if(i > MAXSNARF) break; if((s = realloc(sn, i+1024+1)) == nil) break; sn = s; if((n = read(snarffd, sn+i, 1024)) <= 0) break; i += n; } if(i == 0) return; sn[i] = 0; setsnarf(sn, i); free(sn); } void readfile(char *path) { int fd, n, ns; char *s, buf[1024]; Rune *rs; fd = open(path, OREAD); if(fd < 0) return; s = nil; ns = 0; while(n = read(fd, buf, sizeof(buf)), n > 0) { s = realloc(s, ns+n); memcpy(s+ns, buf, n); ns += n; } close(fd); rs = runesmprint("%.*s", ns, s); free(s); xdelete(&text, 0, text.nr); xinsert(&text, rs, runestrlen(rs), 0); free(rs); } int writefile(char *path) { int fd; char *s; fd = create(path, OWRITE|OTRUNC, 0666); if(fd < 0) return 1; s = smprint("%.*S", text.nr, text.r); write(fd, s, strlen(s)); close(fd); free(s); return 0; } void confused(void) { setcursor(mctl, &quest); sleep(300); setcursor(mctl, nil); } void editmenu(Text *x, Mousectl *mc) { enum { Cut, Paste, Snarf, Plumb, Look }; static char *menu2str[] = { "cut", "paste", "snarf", "plumb", "look", nil }; static Menu menu2 = { menu2str }; switch(menuhit(2, mc, &menu2, nil)){ case Cut: xsnarf(x); xcut(x); break; case Paste: xpaste(x); break; case Snarf: xsnarf(x); break; case Plumb: if(xplumb(x, "jot", startdir, 31*1024)) confused(); break; case Look: xlook(x); break; } } void filemenu(Text *x, Mousectl *mc) { USED(x); enum { Write, Exit }; static char *str[] = { "write", "exit", nil }; static Menu menu = { str }; switch(menuhit(3, mc, &menu, nil)){ case Write: if(filename[0] == '\0'){ fwdkc = &kbdctl2; enter("file", filename, sizeof(filename), mc, fwdkc, nil); fwdkc = nil; } if(writefile(filename)){ memset(filename, 0, sizeof(filename)); confused(); } break; case Exit: threadexitsall(nil); } } void mousectl(Text *x, Mousectl *mc) { int but; for(but = 1; but < 6; but++) if(mc->buttons == 1<<(but-1)) goto found; return; found: /* if(shiftdown && but > 3) wkeyctl(w, but == 4 ? Kscrolloneup : Kscrollonedown); else*/ if(ptinrect(mc->xy, x->scrollr) || but > 3) xscroll(x, mc, but); else if(but == 1) xselect(x, mc); else if(but == 2) editmenu(x, mc); else if(but == 3) filemenu(x, mc); } void keyctl(Text *x, Rune r) { int nlines, n; nlines = x->maxlines; /* need signed */ switch(r){ /* Scrolling */ case Kscrollonedown: n = mousescrollsize(x->maxlines); xscrolln(x, max(n, 1)); break; case Kdown: xscrolln(x, shiftdown ? 1 : nlines/3); break; case Kpgdown: xscrolln(x, nlines*2/3); break; case Kscrolloneup: n = mousescrollsize(x->maxlines); xscrolln(x, -max(n, 1)); break; case Kup: xscrolln(x, -(shiftdown ? 1 : nlines/3)); break; case Kpgup: xscrolln(x, -nlines*2/3); break; case Khome: xshow(x, 0); break; case Kend: xshow(x, x->nr); break; /* Cursor movement */ case Kleft: if(x->q0 > 0) xplacetick(x, x->q0-1); break; case Kright: if(x->q1 < x->nr) xplacetick(x, x->q1+1); break; case CTRL('A'): while(x->q0 > 0 && x->r[x->q0-1] != '\n' && x->q0 != x->qh) x->q0--; xplacetick(x, x->q0); break; case CTRL('E'): while(x->q0 < x->nr && x->r[x->q0] != '\n') x->q0++; xplacetick(x, x->q0); break; case CTRL('B'): xplacetick(x, x->qh); break; case Kesc: xsnarf(x); xcut(x); break; case Kdel: xtype(x, CTRL('H')); break; default: xtype(x, r); break; } } void setsize(Text *x) { Rectangle scrollr, textr; draw(screen, screen->r, colors[BACK], nil, ZP); scrollr = textr = insetrect(screen->r, 1); scrollr.max.x = scrollr.min.x + 12; textr.min.x = scrollr.max.x + 4; xinit(x, textr, scrollr, font, screen, colors); } void mthread(void*) { while(readmouse(mctl) != -1){ mousectl(&text, mctl); } } void kbthread(void*) { Rune r; for(;;){ r = recvul(kbctl->c); if(fwdkc) send(fwdkc->c, &r); else keyctl(&text, r); flushimage(display, 1); } } void resthread(void*) { for(;;){ recvul(mctl->resizec); if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); setsize(&text); } } void threadmain(int argc, char *argv[]) { char buf[1024]; // newwindow(nil); if(initdraw(nil, nil, "jot") < 0) sysfatal("initdraw: %r"); kbctl = initkeyboard("/dev/cons"); if(kbctl == nil) sysfatal("initkeyboard: %r"); kbdctl2.c = chancreate(sizeof(Rune), 20); mctl = initmouse("/dev/mouse", screen); if(mctl == nil) sysfatal("initmouse: %r"); snarffd = open("/dev/snarf", OREAD|OCEXEC); if(getwd(buf, sizeof(buf)) == nil) startdir = estrdup("."); else startdir = estrdup(buf); colors[BACK] = allocimagemix(display, DPaleyellow, DWhite); colors[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); colors[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DYellowgreen); colors[TEXT] = display->black; colors[HTEXT] = display->black; setsize(&text); timerinit(); threadcreate(mthread, nil, mainstacksize); threadcreate(kbthread, nil, mainstacksize); threadcreate(resthread, nil, mainstacksize); if(argc > 1){ strncpy(filename, argv[1], sizeof(filename)); readfile(filename); } }