#include "plan9.h"#include "field.h"#include "gbuffer.h"#include "sim.h"#include <bio.h>#include <draw.h>#include <mouse.h>#include <keyboard.h>#include <thread.h>#include <plumb.h>#include <cursor.h>#include <tos.h>#include "theme.h" #define MIN(x,y) ((x)<=(y)?(x):(y))#define MAX(x,y) ((x)>=(y)?(x):(y))#define is_movement(c) (c == 'W' || c == 'N' || c == 'E' || c == 'S')#define is_send(c) (c == ':' || c == '%' || c == '!' || c == '?' || c == ';' || c == ';' || c == '$') enum { Txtoff = 16, Coloff = 2, Cresize = 0, Ckey, Cmouse, Credraw, Numchan, Sfancy = 0, Splain, Snone, Numstyles, Minsert = 0, Mappend, Mslide, Mselect, Nummodes, Menu3load = 0, Menu3save, Menu3dotstyle, Menu3rulerstyle, Menu3colors, Menu3exit, Nummenu3, /* this might become a bad idea in the future */ Mark_flag_group_highlight = 1<<6, Mark_flag_selected = 1<<7, Midicn = 0<<4, /* cable number. FIXME: write midifs */}; typedef struct Snap Snap; struct Snap { int bpm, apm; vlong tick; Point cur, scroll; Rectangle sel; Field field;}; static int bpm = 120, apm = 120;static Point rulers = {8, 8};static int rulerstyle = Sfancy, dotstyle = Sfancy; static char *ip, *udpport;static int udp = -1; static char *midipath;static int midi = -1;static u8int noteoff[16][128]; /* 16 channels, 128 notes each */ static Help help;static Rune *linebuf;static Rune cursor = '@';static vlong tick;static Point glyphsz;static Point cur, scroll, txtoff, move = { .x = 1, .y = 1 };static Rectangle sel;static Field field;static Mbuf_reusable mbuf, mscr;static char filename[256];static Field fscr, fsel;static bool altdown, shiftdown, ctldown, pause, forward;static int mode = Minsert;static long framedev; /* frame deviation in ms */static char *shellcmd;static bool usensec; static Snap *snaps;static int numsnaps, nextsnap;static int maxsnaps = 100; static Cursor yousure = { {0, 0}, { 0xf7, 0xfe, 0x15, 0x54, 0x1d, 0x54, 0x09, 0x54, 0x09, 0xdc, 0x00, 0x00, 0x75, 0x77, 0x45, 0x54, 0x75, 0x66, 0x15, 0x54, 0x77, 0x57, 0x00, 0x00, 0x00, 0x02, 0x2a, 0x84, 0x11, 0x28, 0x2a, 0x90, }, { 0xea, 0x2b, 0xea, 0xab, 0xe2, 0xab, 0xf6, 0xab, 0xf6, 0x23, 0xff, 0xff, 0x8a, 0x88, 0xba, 0xab, 0x8a, 0x99, 0xea, 0xab, 0x88, 0xa8, 0xff, 0xff, 0xff, 0xfd, 0xd5, 0x7b, 0xee, 0xd7, 0xd5, 0x6f, },}; static struct { struct { char *menu; Rune r; }dot; struct { char *menu; Rune r[9]; }ruler;}styles[Numstyles] = { [Sfancy] = { .dot = {"fancy dots", L'·'}, .ruler = {"fancy rulers", {L'╭', L'┬', L'╮', L'├', L'┼', L'┤', L'╰', L'┴', L'╯'}}, }, [Splain] = { .dot = {"plain dots", '.'}, .ruler = {"plain rulers", {'+', '+', '+', '+', '+', '+', '+', '+', '+'}}, }, [Snone] = { .dot = {"no dots", ' '}, .ruler = {"no rulers", {0}}, },}; static char *modes[Nummodes] = { [Minsert] = "insert", [Mappend] = "append", [Mslide] = "slide ", [Mselect] = "select",}; static char *menu3i[Nummenu3+1] = { [Menu3load] = "load", [Menu3save] = "save", [Menu3colors] = "colors", [Menu3exit] = "exit",}; static Menu menu3 = { .item = menu3i,}; static voidsnapshot(void){ Snap *s; int i; if (maxsnaps < 1) return; if (nextsnap >= maxsnaps) { nextsnap--; field_deinit(&snaps->field); memmove(snaps, snaps+1, sizeof(Snap)*nextsnap); } s = &snaps[nextsnap++]; s->bpm = bpm; s->apm = apm; s->tick = tick; s->cur = cur; s->scroll = scroll; s->sel = sel; for (i = nextsnap; i < numsnaps; i++) field_deinit(&snaps[i].field); field_init(&s->field); field_copy(&field, &s->field); numsnaps = nextsnap;} static voidgotosnapshot(int i){ Snap *s; s = &snaps[i]; bpm = s->bpm; apm = s->apm; tick = s->tick; cur = s->cur; scroll = s->scroll; sel = s->sel; field_copy(&s->field, &field);} static voidundo(void){ if (nextsnap < 1) return; if (nextsnap == numsnaps) { snapshot(); nextsnap--; } gotosnapshot(--nextsnap);} static voidredo(void){ if (nextsnap >= numsnaps-1) return; gotosnapshot(++nextsnap); if (nextsnap == numsnaps) nextsnap--;} Uszorca_round_up_power2(Usz x){ x -= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x + 1;} boolorca_is_valid_glyph(Glyph c){ if (c >= '0' && c <= '9') return true; if (c >= 'A' && c <= 'Z') return true; if (c >= 'a' && c <= 'z') return true; switch (c) { case '!': case '#': case '%': case '*': case '.': case ':': case ';': case '=': case '?': case '$': return true; } return false;} static Glyphfieldget(int x, int y){ if (x < field.width && y < field.height && x >= 0 && y >= 0) return field.buffer[x + field.width*y]; return 0;} static voidfieldset(int x, int y, Glyph c){ if (x < field.width && y < field.height && x >= 0 && y >= 0) field.buffer[x + field.width*y] = c;} static voidfieldsetn(int x, int y, Glyph c, int n){ if (y >= 0 && y < field.height) { for (; n > 0 && x < field.width; n--, x++) field.buffer[x + field.width*y] = c; }} static voidselpasteb(Biobuf *b){ char *s; int cols, rows, i, n, off; Glyph c; for (cols = rows = 0; (s = Brdstr(b, '\n', 1)) != nil;) { if ((n = Blinelen(b)) > cols) cols = MIN(n, field.width-sel.min.x); if (sel.min.y+rows < field.height) { off = sel.min.x + field.width*(sel.min.y+rows); for (i = 0; i < MIN(n, field.width-sel.min.x); i++) { c = orca_is_valid_glyph(s[i]) ? s[i] : '.'; if (c != '.' || !shiftdown) field.buffer[off+i] = c; } rows++; } free(s); } sel.max.x = sel.min.x + MAX(0, cols-1); sel.max.y = sel.min.y + MAX(0, rows-1); if (sel.max.x < cur.x) cur.x = sel.max.x; if (sel.max.y < cur.y) cur.y = sel.max.y;} static voidrunshell(void *x){ int *p; p = x; dup(p[0], 0); close(p[0]); close(p[1]); dup(p[3], 1); close(p[3]); close(p[2]); dup(open("/dev/null", OWRITE), 2); procexecl(nil, "/bin/rc", "rc", "-c", shellcmd, nil); threadexits("exec: %r");} static voidshellpipe(char *s){ Biobuf *in, *out; int x, y, p[4]; Glyph g; shellcmd = s+1; pipe(p); pipe(p+2); procrfork(runshell, p, 4096, RFFDG); close(p[0]); close(p[3]); out = Bfdopen(p[1], OWRITE); in = Bfdopen(p[2], OREAD); for (y = sel.min.y; *s != '<' && y <= sel.max.y; y++) { for (x = sel.min.x; x <= sel.max.x; x++) { if ((g = fieldget(x, y)) == '.') g = ' '; Bputc(out, g); } Bputc(out, '\n'); } Bterm(out); if (*s != '>') selpasteb(in); Bterm(in);} static voidmidiopen(char *path){ if (midi >= 0) { close(midi); midi = -1; } if (path != nil) { free(midipath); midipath = strdup(path); } if (midi < 0 && midipath[0] && (midi = open(midipath, OWRITE)) < 0) { fprint(2, "midi failed: %r\n"); /* FIXME display error */ }} static voidnetdial(char *newip, char *newudpport){ if (udp >= 0) { close(udp); udp = -1; } if (newip != nil) { free(ip); ip = strdup(newip); } if (newudpport != nil) { free(udpport); udpport = strdup(newudpport); } if (udp < 0 && ip[0] && udpport[0]) { if (udpport[0] == '/') udp = open(udpport, OWRITE); else udp = dial(netmkaddr(ip, "udp", udpport), nil, nil, nil); if (udp < 0) /* FIXME display error */ fprint(2, "udp failed: %r\n"); }} static voidselset(Rune key){ int y; bool commented; if (key == '#') { commented = true; for (y = sel.min.y; y <= sel.max.y && commented; y++) commented = fieldget(sel.min.x, y) == key && fieldget(sel.max.x, y) == key; if (commented) key = '.'; } else { commented = false; } for (y = sel.min.y; y <= sel.max.y; y++) { if (key == '#' || commented) { fieldset(sel.min.x, y, key); fieldset(sel.max.x, y, key); } else { fieldsetn(sel.min.x, y, key, Dx(sel)+1); } }} static voidselcopy(void){ Biobuf *b; int y; if ((b = Bopen("/dev/snarf", OWRITE)) != nil) { for (y = sel.min.y; y <= sel.max.y; y++) { Bwrite(b, &field.buffer[sel.min.x + field.width*y], Dx(sel)+1); Bputc(b, '\n'); } Bterm(b); }} static voidinject(char *filename){ Biobuf *b; if ((b = Bopen(filename, OREAD)) != nil) { selpasteb(b); Bterm(b); }} static voidnosnapshot(void){} static Pointptclamp(Point p){ p.x = MAX(0, MIN((int)field.width-1, p.x)); p.y = MAX(0, MIN((int)field.height-1, p.y)); return p;} static voidcurmove(int x, int y){ Point xy; xy = Pt(x, y); cur = ptclamp(addpt(cur, xy)); sel.min = ptclamp(addpt(sel.min, xy)); sel.max = ptclamp(addpt(sel.max, xy));} static voidselext(int xdt, int ydt){ if (sel.max.x > cur.x || (sel.min.x == cur.x && xdt > 0)) sel.max.x = MAX(sel.max.x+xdt, sel.min.x); else sel.min.x = MIN(sel.min.x+xdt, sel.max.x); if (sel.max.y > cur.y || (sel.min.y == cur.y && ydt > 0)) sel.max.y = MAX(sel.max.y+ydt, sel.min.y); else sel.min.y = MIN(sel.min.y+ydt, sel.max.y); rectclip(&sel, Rect(0, 0, (int)field.width-1, (int)field.height-1));} /* * nsec() is wallclock and can be adjusted by timesync * so need to use cycles() instead, but fall back to * nsec() in case we can't */uvlongnanosec(void){ static uvlong fasthz, xstart; uvlong x, div; Lines 1–500 of 1756. Load more
#include "plan9.h" #include "field.h" #include "gbuffer.h" #include "sim.h" #include <bio.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> #include <thread.h> #include <plumb.h> #include <cursor.h> #include <tos.h> #include "theme.h" #define MIN(x,y) ((x)<=(y)?(x):(y)) #define MAX(x,y) ((x)>=(y)?(x):(y)) #define is_movement(c) (c == 'W' || c == 'N' || c == 'E' || c == 'S') #define is_send(c) (c == ':' || c == '%' || c == '!' || c == '?' || c == ';' || c == ';' || c == '$') enum { Txtoff = 16, Coloff = 2, Cresize = 0, Ckey, Cmouse, Credraw, Numchan, Sfancy = 0, Splain, Snone, Numstyles, Minsert = 0, Mappend, Mslide, Mselect, Nummodes, Menu3load = 0, Menu3save, Menu3dotstyle, Menu3rulerstyle, Menu3colors, Menu3exit, Nummenu3, /* this might become a bad idea in the future */ Mark_flag_group_highlight = 1<<6, Mark_flag_selected = 1<<7, Midicn = 0<<4, /* cable number. FIXME: write midifs */ }; typedef struct Snap Snap; struct Snap { int bpm, apm; vlong tick; Point cur, scroll; Rectangle sel; Field field; }; static int bpm = 120, apm = 120; static Point rulers = {8, 8}; static int rulerstyle = Sfancy, dotstyle = Sfancy; static char *ip, *udpport; static int udp = -1; static char *midipath; static int midi = -1; static u8int noteoff[16][128]; /* 16 channels, 128 notes each */ static Help help; static Rune *linebuf; static Rune cursor = '@'; static vlong tick; static Point glyphsz; static Point cur, scroll, txtoff, move = { .x = 1, .y = 1 }; static Rectangle sel; static Field field; static Mbuf_reusable mbuf, mscr; static char filename[256]; static Field fscr, fsel; static bool altdown, shiftdown, ctldown, pause, forward; static int mode = Minsert; static long framedev; /* frame deviation in ms */ static char *shellcmd; static bool usensec; static Snap *snaps; static int numsnaps, nextsnap; static int maxsnaps = 100; static Cursor yousure = { {0, 0}, { 0xf7, 0xfe, 0x15, 0x54, 0x1d, 0x54, 0x09, 0x54, 0x09, 0xdc, 0x00, 0x00, 0x75, 0x77, 0x45, 0x54, 0x75, 0x66, 0x15, 0x54, 0x77, 0x57, 0x00, 0x00, 0x00, 0x02, 0x2a, 0x84, 0x11, 0x28, 0x2a, 0x90, }, { 0xea, 0x2b, 0xea, 0xab, 0xe2, 0xab, 0xf6, 0xab, 0xf6, 0x23, 0xff, 0xff, 0x8a, 0x88, 0xba, 0xab, 0x8a, 0x99, 0xea, 0xab, 0x88, 0xa8, 0xff, 0xff, 0xff, 0xfd, 0xd5, 0x7b, 0xee, 0xd7, 0xd5, 0x6f, }, }; static struct { struct { char *menu; Rune r; }dot; struct { char *menu; Rune r[9]; }ruler; }styles[Numstyles] = { [Sfancy] = { .dot = {"fancy dots", L'·'}, .ruler = {"fancy rulers", {L'╭', L'┬', L'╮', L'├', L'┼', L'┤', L'╰', L'┴', L'╯'}}, }, [Splain] = { .dot = {"plain dots", '.'}, .ruler = {"plain rulers", {'+', '+', '+', '+', '+', '+', '+', '+', '+'}}, }, [Snone] = { .dot = {"no dots", ' '}, .ruler = {"no rulers", {0}}, }, }; static char *modes[Nummodes] = { [Minsert] = "insert", [Mappend] = "append", [Mslide] = "slide ", [Mselect] = "select", }; static char *menu3i[Nummenu3+1] = { [Menu3load] = "load", [Menu3save] = "save", [Menu3colors] = "colors", [Menu3exit] = "exit", }; static Menu menu3 = { .item = menu3i, }; static void snapshot(void) { Snap *s; int i; if (maxsnaps < 1) return; if (nextsnap >= maxsnaps) { nextsnap--; field_deinit(&snaps->field); memmove(snaps, snaps+1, sizeof(Snap)*nextsnap); } s = &snaps[nextsnap++]; s->bpm = bpm; s->apm = apm; s->tick = tick; s->cur = cur; s->scroll = scroll; s->sel = sel; for (i = nextsnap; i < numsnaps; i++) field_deinit(&snaps[i].field); field_init(&s->field); field_copy(&field, &s->field); numsnaps = nextsnap; } static void gotosnapshot(int i) { Snap *s; s = &snaps[i]; bpm = s->bpm; apm = s->apm; tick = s->tick; cur = s->cur; scroll = s->scroll; sel = s->sel; field_copy(&s->field, &field); } static void undo(void) { if (nextsnap < 1) return; if (nextsnap == numsnaps) { snapshot(); nextsnap--; } gotosnapshot(--nextsnap); } static void redo(void) { if (nextsnap >= numsnaps-1) return; gotosnapshot(++nextsnap); if (nextsnap == numsnaps) nextsnap--; } Usz orca_round_up_power2(Usz x) { x -= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x + 1; } bool orca_is_valid_glyph(Glyph c) { if (c >= '0' && c <= '9') return true; if (c >= 'A' && c <= 'Z') return true; if (c >= 'a' && c <= 'z') return true; switch (c) { case '!': case '#': case '%': case '*': case '.': case ':': case ';': case '=': case '?': case '$': return true; } return false; } static Glyph fieldget(int x, int y) { if (x < field.width && y < field.height && x >= 0 && y >= 0) return field.buffer[x + field.width*y]; return 0; } static void fieldset(int x, int y, Glyph c) { if (x < field.width && y < field.height && x >= 0 && y >= 0) field.buffer[x + field.width*y] = c; } static void fieldsetn(int x, int y, Glyph c, int n) { if (y >= 0 && y < field.height) { for (; n > 0 && x < field.width; n--, x++) field.buffer[x + field.width*y] = c; } } static void selpasteb(Biobuf *b) { char *s; int cols, rows, i, n, off; Glyph c; for (cols = rows = 0; (s = Brdstr(b, '\n', 1)) != nil;) { if ((n = Blinelen(b)) > cols) cols = MIN(n, field.width-sel.min.x); if (sel.min.y+rows < field.height) { off = sel.min.x + field.width*(sel.min.y+rows); for (i = 0; i < MIN(n, field.width-sel.min.x); i++) { c = orca_is_valid_glyph(s[i]) ? s[i] : '.'; if (c != '.' || !shiftdown) field.buffer[off+i] = c; } rows++; } free(s); } sel.max.x = sel.min.x + MAX(0, cols-1); sel.max.y = sel.min.y + MAX(0, rows-1); if (sel.max.x < cur.x) cur.x = sel.max.x; if (sel.max.y < cur.y) cur.y = sel.max.y; } static void runshell(void *x) { int *p; p = x; dup(p[0], 0); close(p[0]); close(p[1]); dup(p[3], 1); close(p[3]); close(p[2]); dup(open("/dev/null", OWRITE), 2); procexecl(nil, "/bin/rc", "rc", "-c", shellcmd, nil); threadexits("exec: %r"); } static void shellpipe(char *s) { Biobuf *in, *out; int x, y, p[4]; Glyph g; shellcmd = s+1; pipe(p); pipe(p+2); procrfork(runshell, p, 4096, RFFDG); close(p[0]); close(p[3]); out = Bfdopen(p[1], OWRITE); in = Bfdopen(p[2], OREAD); for (y = sel.min.y; *s != '<' && y <= sel.max.y; y++) { for (x = sel.min.x; x <= sel.max.x; x++) { if ((g = fieldget(x, y)) == '.') g = ' '; Bputc(out, g); } Bputc(out, '\n'); } Bterm(out); if (*s != '>') selpasteb(in); Bterm(in); } static void midiopen(char *path) { if (midi >= 0) { close(midi); midi = -1; } if (path != nil) { free(midipath); midipath = strdup(path); } if (midi < 0 && midipath[0] && (midi = open(midipath, OWRITE)) < 0) { fprint(2, "midi failed: %r\n"); /* FIXME display error */ } } static void netdial(char *newip, char *newudpport) { if (udp >= 0) { close(udp); udp = -1; } if (newip != nil) { free(ip); ip = strdup(newip); } if (newudpport != nil) { free(udpport); udpport = strdup(newudpport); } if (udp < 0 && ip[0] && udpport[0]) { if (udpport[0] == '/') udp = open(udpport, OWRITE); else udp = dial(netmkaddr(ip, "udp", udpport), nil, nil, nil); if (udp < 0) /* FIXME display error */ fprint(2, "udp failed: %r\n"); } } static void selset(Rune key) { int y; bool commented; if (key == '#') { commented = true; for (y = sel.min.y; y <= sel.max.y && commented; y++) commented = fieldget(sel.min.x, y) == key && fieldget(sel.max.x, y) == key; if (commented) key = '.'; } else { commented = false; } for (y = sel.min.y; y <= sel.max.y; y++) { if (key == '#' || commented) { fieldset(sel.min.x, y, key); fieldset(sel.max.x, y, key); } else { fieldsetn(sel.min.x, y, key, Dx(sel)+1); } } } static void selcopy(void) { Biobuf *b; int y; if ((b = Bopen("/dev/snarf", OWRITE)) != nil) { for (y = sel.min.y; y <= sel.max.y; y++) { Bwrite(b, &field.buffer[sel.min.x + field.width*y], Dx(sel)+1); Bputc(b, '\n'); } Bterm(b); } } static void inject(char *filename) { Biobuf *b; if ((b = Bopen(filename, OREAD)) != nil) { selpasteb(b); Bterm(b); } } static void nosnapshot(void) { } static Point ptclamp(Point p) { p.x = MAX(0, MIN((int)field.width-1, p.x)); p.y = MAX(0, MIN((int)field.height-1, p.y)); return p; } static void curmove(int x, int y) { Point xy; xy = Pt(x, y); cur = ptclamp(addpt(cur, xy)); sel.min = ptclamp(addpt(sel.min, xy)); sel.max = ptclamp(addpt(sel.max, xy)); } static void selext(int xdt, int ydt) { if (sel.max.x > cur.x || (sel.min.x == cur.x && xdt > 0)) sel.max.x = MAX(sel.max.x+xdt, sel.min.x); else sel.min.x = MIN(sel.min.x+xdt, sel.max.x); if (sel.max.y > cur.y || (sel.min.y == cur.y && ydt > 0)) sel.max.y = MAX(sel.max.y+ydt, sel.min.y); else sel.min.y = MIN(sel.min.y+ydt, sel.max.y); rectclip(&sel, Rect(0, 0, (int)field.width-1, (int)field.height-1)); } /* * nsec() is wallclock and can be adjusted by timesync * so need to use cycles() instead, but fall back to * nsec() in case we can't */ uvlong nanosec(void) { static uvlong fasthz, xstart; uvlong x, div;