ref: b281eb93bd34cca00bfe31f0bb5fb4a7b4eb8c76
dir: /main.c/
#include "inc.h" #include <cursor.h> RKeyboardctl *kbctl; Keyboardctl *fwdkc, kbdctl2; Mousectl *mctl; int shiftdown; // TODO: needed? int ctldown; 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 xgetsel(Text *x, uint *q0, uint *q) { if(x->selflip){ *q0 = x->q1; *q = x->q0; }else{ *q0 = x->q0; *q = x->q1; } } void xleftright(Text *x, int dir, int extend) { uint q0, q; xgetsel(x, &q0, &q); if(dir < 0 && -dir > q) q = 0; else q = min(q+dir, x->nr); xsetselect(x, extend ? q0 : q, q); xshow(x, q); } void xupdown(Text *x, int dir, int extend) { Point p; int py; uint q0, q; xgetsel(x, &q0, &q); xshow(x, q); p = frptofchar(x, q-x->org); if(x->posx >= 0) p.x = x->posx; py = p.y; p.y += dir*x->font->height; if(p.y < x->Frame.r.min.y || p.y > x->Frame.r.max.y-x->font->height){ xscrolln(x, dir); p.y = py; } q = x->org+frcharofpt(x, p); xsetselect(x, extend ? q0 : q, q); xshow(x, q); x->posx = p.x; } void xline(Text *x, int dir, int extend) { uint q0, q; xgetsel(x, &q0, &q); if(dir < 0){ while(q > 0 && x->r[q-1] != '\n' && q != x->qh) q--; }else{ while(q < x->nr && x->r[q] != '\n') q++; } xsetselect(x, extend ? q0 : q, q); xshow(x, q); } void xbegend(Text *x, int dir, int extend) { uint q0, q; xgetsel(x, &q0, &q); if(dir < 0) q = 0; else q = x->nr; xsetselect(x, extend ? q0 : q, q); xshow(x, q); } 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 Kpgdown: if(ctldown) xscrolln(x, nlines*2/3); else xscrolln(x, nlines*1/3); break; case Kscrolloneup: n = mousescrollsize(x->maxlines); xscrolln(x, -max(n, 1)); break; case Kpgup: if(ctldown) xscrolln(x, -nlines*2/3); else xscrolln(x, -nlines*1/3); break; /* Cursor movement */ case Kdown: xupdown(x, 1, shiftdown); break; case Kup: xupdown(x, -1, shiftdown); break; case Kleft: xleftright(x, -1, shiftdown); break; case Kright: xleftright(x, 1, shiftdown); break; case Khome: if(ctldown) xbegend(x, -1, shiftdown); else xline(x, -1, shiftdown); break; case Kend: if(ctldown) xbegend(x, 1, shiftdown); else xline(x, 1, shiftdown); break; case CTRL('A'): xline(x, -1, shiftdown); break; case CTRL('E'): xline(x, 1, shiftdown); 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 dumpkbd(char *s) { Rune *rs; int i; rs = runesmprint("%s", s); for(i = 0; rs[i]; i++) print("%C %X\n", rs[i], rs[i]); print("\n"); free(rs); } void kbthread(void*) { char *s; Rune r; for(;;){ s = recvp(kbctl->c); //dumpkbd(s); if(*s == 'k' || *s == 'K'){ shiftdown = utfrune(s+1, Kshift) != nil; ctldown = utfrune(s+1, Kctl) != nil; } if(*s == 'c'){ chartorune(&r, s+1); if(r){ if(fwdkc) send(fwdkc->c, &r); else keyctl(&text, r); flushimage(display, 1); } } free(s); } } 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 = initkbd(nil, nil); if(kbctl == nil) sysfatal("inikeyboard: %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); } }