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);
}
|