Charles.Forsyth20060303a828770d19 years agoHistory
190 lines · 3.9 KB · Brainfuck
RawDownload
implement Tkcmd; include "sys.m";	sys: Sys;	stderr: ref Sys->FD;include "draw.m";	draw: Draw;	Display, Image, Point: import draw;include "tk.m";	tk: Tk;include "tkclient.m";	tkclient: Tkclient;include "bufio.m";include "arg.m"; Tkcmd : module {	init:	fn(ctxt: ref Draw->Context, argv: list of string);}; usage(){	sys->print("usage: tkcmd [-iu] [toplevelarg]\n");	raise "fail:usage";} badmodule(m: string){		sys->fprint(stderr, "tkcmd: cannot load %s: %r\n", m);		raise "fail:bad module";} init(ctxt: ref Draw->Context, argv: list of string){	sys  = load Sys  Sys->PATH;	stderr = sys->fildes(2);	draw = load Draw Draw->PATH;	tk = load Tk   Tk->PATH;	if (tk == nil)		badmodule(Tk->PATH);	tkclient = load Tkclient Tkclient->PATH;	if (tkclient==nil)		badmodule(Tkclient->PATH);	arg := load Arg Arg->PATH;	if (arg == nil)		badmodule(Arg->PATH); 	arg->init(argv);	update := 1;	interactive := isconsole(sys->fildes(0));	while ((opt := arg->opt()) != 0) {		case opt {		'i' =>			interactive = 1;		'u' =>			update = 0;		* =>			usage();		}	}	argv = arg->argv();	arg = nil;	tkarg := "";	if (argv != nil) {		if (tl argv != nil)			usage();		tkarg = hd argv;	}		sys->pctl(Sys->NEWPGRP, nil);	tkclient->init();	shellit(ctxt, tkarg, interactive, update);} isconsole(fd: ref Sys->FD): int{	(ok1, d1) := sys->fstat(fd);	(ok2, d2) := sys->stat("/dev/cons");	if (ok1 < 0 || ok2 < 0)		return 0;	return d1.dtype == d2.dtype && d1.qid.path == d2.qid.path;} shellit(ctxt: ref Draw->Context, arg: string, interactive, update: int){	(Wwsh, winctl) := tkclient->toplevel(ctxt, arg, "Tk", Tkclient->Appl);	tkclient->onscreen(Wwsh, nil);	tkclient->startinput(Wwsh, "ptr" :: "kbd" :: nil);	wm := Wwsh.ctxt;	if(update)		tk->cmd(Wwsh, "update");	ps1 := "";	ps2 := "";	if (!interactive)		ps1 = ps2 = ""; 	lines := chan of string;	sync := chan of int;	spawn grab_lines(ps1, ps2, lines, sync);	output := chan of string;	tk->namechan(Wwsh, output, "stdout");	pid := <-sync;Loop:	for(;;) alt {	c := <-wm.kbd =>		tk->keyboard(Wwsh, c);	m := <-wm.ptr =>		tk->pointer(Wwsh, *m);	c := <-wm.ctl or	c = <-Wwsh.wreq =>		tkclient->wmctl(Wwsh, c);	line := <-lines =>		if (line == nil)			break Loop;		if (line[0] == '#')			break;		line = line[0:len line - 1];		result := tk->cmd(Wwsh, line);		if (result != nil)			sys->print("#%s\n", result);		if (update)			tk->cmd(Wwsh, "update");		sys->print("%s", ps1);	menu := <-winctl =>		tkclient->wmctl(Wwsh, menu);	s := <-output =>		sys->print("#<stdout>%s\n", s);		sys->print("%s", ps1);	}} grab_lines(new_inp, unfin: string, lines: chan of string, sync: chan of int){	sync <-= sys->pctl(0, nil);	{		bufmod := load Bufio Bufio->PATH;		Iobuf:	import bufmod;		if (bufmod == nil) {			lines <-= nil;			return;		}		sys->print("%s", new_inp);		iob := bufmod->fopen(sys->fildes(0),bufmod->OREAD);		if (iob==nil){			sys->fprint(stderr, "tkcmd: cannot open stdin for reading.\n");			lines <-= nil;			return;		}		line := "";		while((input := iob.gets('\n')) != nil) {			line+=input;			if (!finished(line,0))				sys->print("%s", unfin);			else{				lines <-= line;				line=nil;			}		}		lines <-= nil;	}exception e{	"*" =>		sys->fprint(stderr, "tkcmd: fail: %s\n", e);		lines <-= nil;	}} # returns 1 if the line has matching braces, brackets and # double-quotes and does not end in "\\\n"finished(s : string, termchar : int) : int {	cb:=0;	dq:=0;	sb:=0;	if (s==nil) return 1;	if (termchar=='}') cb++;	if (termchar==']') sb++;	if (len s > 1 && s[len s -2]=='\\')		return 0;	if (s[0]=='{') cb++;	if (s[0]=='}' && cb>0) cb--;	if (s[0]=='[') sb++;	if (s[0]==']' && sb>0) sb--;	if (s[0]=='"') dq=1-dq;	for(i:=1;i<len s;i++){		if (s[i]=='{' && s[i-1]!='\\') cb++;		if (s[i]=='}' && s[i-1]!='\\' && cb>0) cb--;		if (s[i]=='[' && s[i-1]!='\\') sb++;		if (s[i]==']' && s[i-1]!='\\' && sb>0) sb--;		if (s[i]=='"' && s[i-1]!='\\') dq=1-dq;	}	return (cb==0 && sb==0 && dq==0);}