implement Ox; # o/x. In charge of opening files and executing commands from # applications using o/mero include "mods.m"; debug, findpanel, trees, ui, Tree, Edit: import oxedit; Xcmd, deledit, newedit, msg, putedit: import oxex; Ox: module { init: fn(nil: ref Draw->Context, nil: list of string); }; dump() { for (trl := oxedit->trees; trl != nil; trl = tl trl) (hd trl).dump(); } mkhome(s: string) { home := Tree.new(s); home.mk(); scr := hd panels->screens(); col := hd panels->cols(scr); home.col.ctl(sprint("copyto %s\n", col)); newedit(home, s, 0, 0); } mkui(dir: string): chan of list of string { dir = names->rooted(workdir->init(), dir); dir = names->cleanname(dir); ui = Panel.init("ox"); ui.ctl("hold\n"); mkhome(dir); ui.ctl("release\n"); return ui.eventc(); } look(tr: ref Tree, ed: ref Edit, what: string) { path: string; if (ed != nil){ path = names->rooted(ed.dir, what); ed.lru = now(); } else path = names->rooted(tr.path, what); ui.ctl("hold\n"); ned := newedit(tr, path, 0, 0); if (ned == nil){ dir := getenv("home"); if (ed != nil) dir = ed.dir; msg(tr, dir, sprint("%s: %r\n", path)); } ui.ctl("release\n"); } done(tr: ref Tree): int { for (edl := tr.eds; edl != nil; edl = tl edl) pick edp := hd edl{ File => if (edp.dirty){ msg(tr, tr.path, sprint("%s: has unsaved edits\n", tr.path)); return -1; } } tr.close(); return 0; } # These commands go to samcmd.b, sharing code both for the command language and # for the menus. run(tr: ref Tree, ed: ref Edit, what: string) { dir: string; if (ed != nil){ dir = ed.dir; ed.lru = now(); } else dir = tr.path; (nwargs, wargs) := tokenize(what, " \t\n"); if (nwargs < 1) return; cmd := hd wargs; ui.ctl("hold\n"); case cmd { "End" => do { if (trees == nil){ ui.ctl("release\n"); kill(pctl(0,nil), "killgrp"); exit; } } while (done(hd trees) >= 0); "Close" => if (ed == nil){ done(tr); if (len trees == 0) mkhome(getenv("home")); } else deledit(ed); "Get" => if (nwargs > 1){ (e, nil) := stat(hd tl wargs); if (e < 0){ fd := create(hd tl wargs, OWRITE, 8r664); if (fd == nil) msg(tr, dir, sprint("%s: %r\n", hd tl wargs)); else msg(tr, dir, sprint("%s: new file\n", hd tl wargs)); } else newedit(tr, hd tl wargs, 0, 0); } else { if (ed != nil) if ((e := ed.cleanto(cmd, nil)) != nil) msg(tr, dir, sprint("%s: %s\n", ed.path, e)); else if (ed.get() < 0) ed.close(); } "Put" => where := ed.path; if (nwargs > 1) where = hd tl wargs; putedit(ed, where); "Keep" => if (ed != nil) ed.keep = 1; "Set" => if (nwargs == 3) setenv(hd tl wargs, hd tl tl wargs); else msg(tr, dir, "usage: Set var env\n"); "Dup" => nt := Tree.new(dir); nt.mk(); scr := hd panels->screens(); col := hd panels->cols(scr); nt.col.ctl(sprint("copyto %s\n", col)); newedit(nt, dir, 0, 1); "Cmds" => msg(tr, dir, Xcmd.ftext(0)); "Font" => if (nwargs == 2 && ed != nil) ed.body.ctl(sprint("font %s\n", hd tl wargs)); "Tab" => if (nwargs == 2 && ed != nil) ed.body.ctl(sprint("tab %s\n", hd tl wargs)); * => Xcmd.new(what, dir, nil, nil, tr.tid); } ui.ctl("release\n"); } edevent(ed: ref Edit, op: string, arg: string) { tr := Tree.find(ed.tid); if (debug) fprint(stderr, "o/x: edit %s: %s [%s]\n", ed.path, op, arg); case op { "look" => look(tr, ed, arg); "exec" or "apply" => run(tr, ed, arg); "close" or "interrupt" => ed.close(); "clean" or "dirty" => pick edp := ed { File => edp.dirty = (op == "dirty"); } } if (debug) dump(); } trevent(tr: ref Tree, op: string, arg: string) { if (debug) fprint(stderr, "o/x: tree %s: %s [%s]\n", tr.path, op, arg); case op { "look" => ; look(tr, nil, arg); "exec" or "apply" => run(tr, nil, arg); "close" or "interrupt" => tr.close(); } } updatecmdstag(tr: ref Tree) { ui.ctl("hold\n"); t := "cmds: " + Xcmd.ftext(1); fd := open(tr.xtag.path+"/data", OWRITE|OTRUNC); if (fd != nil){ data := array of byte t; write(fd, data, len data); } ui.ctl("release\n"); } eventproc(evc: chan of list of string, xc: chan of int) { if (debug) fprint(stderr, "\necho killgrp >/prog/%d/ctl\n\n", pctl(0, nil)); for(;;){ alt { ev := <-evc => if (ev == nil) break; if (len ev < 3) error("bad event length"); id := int hd ev; what := hd tl tl ev; evarg := ""; if (len ev == 4) evarg = hd tl tl tl ev; (tr, ed) := findpanel(id); if (tr == nil) fprint(stderr, "o/x: event without tree: %s %s %s\n", hd ev, hd tl ev, hd tl tl ev); else if (ed != nil) edevent(ed, what, evarg); else trevent(tr, what, evarg); tid := <-xc => tr := Tree.find(tid); if (tr != nil) updatecmdstag(tr); } } } init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; err = load Error Error->PATH; err->init(); dat = checkload(load Oxdat Oxdat->PATH, Oxdat->PATH); dat->loadmods(sys, err); initmods(dat->mods); arg = checkload(load Arg Arg->PATH, Arg->PATH); arg->init(argv); arg->setusage("o/x [-d] [-o dir] file"); omero := "/mnt/ui"; while ((opt := arg->opt()) != 0) { case opt { 'd' => debug = 1; 'o' => omero = arg->earg(); * => arg->usage(); } } argv = arg->argv(); if (len argv > 1) arg->usage(); setenv("omero", omero); pctl(NEWPGRP, nil); panels->init(); oxedit->init(dat); regx->init(dat); sam->init(dat); samcmd->init(dat); samlog->init(dat); xc := chan of int; oxex->init(dat, xc); tblks->init(sys, str, err, 0); dir := getenv("home"); if (len argv == 1) dir = hd argv; evc := mkui(dir); spawn eventproc(evc, xc); }