summaryrefslogtreecommitdiff
path: root/appl/cmd/tkcmd.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/tkcmd.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/tkcmd.b')
-rw-r--r--appl/cmd/tkcmd.b190
1 files changed, 190 insertions, 0 deletions
diff --git a/appl/cmd/tkcmd.b b/appl/cmd/tkcmd.b
new file mode 100644
index 00000000..4dd607b1
--- /dev/null
+++ b/appl/cmd/tkcmd.b
@@ -0,0 +1,190 @@
+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);
+}