Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/octopus/port/x/x.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.