implement Find; # # Copyright © 2003 Vita Nuova Holdings Limited. All rights reserved. # include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Rect: import draw; include "tk.m"; tk: Tk; include "tkclient.m"; tkclient: Tkclient; include "arg.m"; include "sh.m"; include "registries.m"; registries: Registries; Registry, Attributes, Service: import registries; include "grid/announce.m"; announce: Announce; Find: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; sys->pctl(sys->FORKNS | sys->NEWPGRP, nil); draw = load Draw Draw->PATH; arg := load Arg Arg->PATH; if (arg == nil) badmod(Arg->PATH); if (draw == nil) badmod(Draw->PATH); tk = load Tk Tk->PATH; if (tk == nil) badmod(Tk->PATH); tkclient = load Tkclient Tkclient->PATH; if (tkclient == nil) badmod(Tkclient->PATH); tkclient->init(); registries = load Registries Registries->PATH; if (registries == nil) badmod(Registries->PATH); registries->init(); command := ""; attrs := Attributes.new(nil); arg->init(argv); arg->setusage("find [-a attributes] action1 { cmd [args...] } .. actionN { cmd [args...] }"); title := "a resource"; while ((opt := arg->opt()) != 0) { case opt { 't' => title = arg->earg(); 'a' => attr := arg->earg(); val := arg->earg(); attrs.set(attr, val); * => arg->usage(); } } argv = arg->argv(); if (argv == nil || len argv % 2) arg->usage(); arg = nil; cmds := array[len argv / 2] of (string, string); for (i := 0; i < len cmds; i++) { cmds[i] = (hd argv, hd tl argv); argv = tl tl argv; } reg := Registry.connect(nil, nil, nil); if (reg == nil) error(ctxt, ((0,0),(0,0)), "Could not find registry"); (matches, err) := reg.find(attrs.attrs); if (err != nil) error(ctxt, ((0,0),(0,0)), "Registry error: "+err); spawn tkwin(ctxt, matches, cmds, title); } mainscr := array[] of { "frame .f", "frame .f.flb", "listbox .f.flb.lb1 -yscrollcommand {.f.flb.sb1 set} -selectmode single -bg white -selectbackground blue -font /fonts/charon/plain.normal.font", "bind .f.flb.lb1 {send butchan double %y}", "scrollbar .f.flb.sb1 -command {.f.flb.lb1 yview}", "pack .f.flb.sb1 -fill y -side left", "pack .f.flb.lb1 -fill both -expand 1", "frame .f.fb", "pack .f.flb -fill both -expand 1 -side top", "pack .f.fb", "pack .f -fill both -expand 1", }; errscr := array[] of { "frame .f", "frame .f.fl", "label .f.fl.l1 -text {} -font /fonts/charon/plain.normal.font ", "label .f.fl.l2 -text {Please try again later} -font /fonts/charon/plain.normal.font", "pack .f.fl.l1 .f.fl.l2 -side top", "button .f.b -text { Close } -command {send butchan exit} "+ "-font /fonts/charon/bold.normal.font", "grid .f.fl -row 0 -column 0 -padx 10 -pady 5", "grid .f.b -row 1 -column 0 -pady 5", "pack .f", }; tkwin(ctxt: ref Draw->Context, lsrv: list of ref Service, cmds: array of (string, string), title: string) { (top, titlectl) := tkclient->toplevel(ctxt, "", "Find "+title, tkclient->Appl); butchan := chan of string; tk->namechan(top, butchan, "butchan"); if (lsrv == nil) { tkcmds(top, errscr); tkcmd(top, ".f.fl.l1 configure -text {Could not find "+title+"}"); } else { tkcmds(top, mainscr); for (tmp := lsrv; tmp != nil; tmp = tl tmp) tkcmd(top, ".f.flb.lb1 insert end {"+(hd tmp).attrs.get("name")+"}"); for (i := 0; i < len cmds; i++) { si := string i; tkcmd(top, "button .f.fb.b"+si+" -font /fonts/charon/bold.normal.font "+ "-text {"+cmds[i].t0+"} -command {send butchan go "+si+"}"); tkcmd(top, "grid .f.fb.b"+si+" -row 0 -column "+si+" -padx 5 -pady 5"); } tkcmd(top, ".f.flb.lb1 selection set 0"); tkcmd(top, "pack propagate . 0"); } tkclient->onscreen(top, nil); tkclient->startinput(top, "kbd"::"ptr"::nil); for(;;) alt { s := <-top.ctxt.kbd => tk->keyboard(top, s); s := <-top.ctxt.ptr => tk->pointer(top, *s); inp := <- butchan => (nil, lst) := sys->tokenize(inp, " \t\n"); case hd lst { "exit" => return; "go" => n := int hd tl lst; id := tkcmd(top, ".f.flb.lb1 curselection"); if (id != nil) connect(ctxt, lsrv, cmds[n].t1 :: nil, tk->rect(top, ".",0), int id); "double" => y := hd tl lst; id := int tkcmd(top, ".f.flb.lb1 nearest "+y); connect(ctxt, lsrv, cmds[0].t1 :: nil, tk->rect(top, ".",0), id); } s := <-top.ctxt.ctl or s = <-top.wreq or s = <- titlectl => if (s == "exit") exit; else tkclient->wmctl(top, s); } } connect(ctxt: ref Draw->Context, lsrv: list of ref Service, argv: list of string, r: Rect, id: int) { for (tmp := lsrv; tmp != nil; tmp = tl tmp) { if (id-- == 0) { spawn mountit(ctxt, hd tmp, argv, r); break; } } } tkcmd(top: ref Tk->Toplevel, cmd: string): string { e := tk->cmd(top, cmd); if (e != "" && e[0] == '!') sys->print("tk error: '%s': %s\n",cmd,e); return e; } tkcmds(top: ref Tk->Toplevel, cmds: array of string) { for (i := 0; i < len cmds; i++) tkcmd(top, cmds[i]); } mountit(ctxt: ref Draw->Context, srv: ref Registries->Service, argv: list of string, r: Rect) { sys->pctl(Sys->FORKNS| Sys->NEWPGRP, nil); attached := srv.attach(nil,nil); if (attached != nil) { if (sys->mount(attached.fd, nil, "/n/client", sys->MREPL, nil) != -1) { sh := load Sh Sh->PATH; if (sh == nil) badmod(Sh->PATH); sys->chdir("/n/client"); err := sh->run(ctxt, argv); if (err != nil) error(ctxt, r, "failed to run: "+err); } else error(ctxt, r, sys->sprint("failed to mount: %r")); } else error(ctxt, r, sys->sprint("could not connect")); } stderr(): ref Sys->FD { return sys->fildes(2); } badmod(path: string) { sys->fprint(stderr(), "Find: cannot load %s: %r\n", path); exit; } errorwin := array[] of { "frame .f", "label .f.l -font /fonts/charon/plain.normal.font", "button .f.b -text {Ok} -font /fonts/charon/bold.normal.font "+ "-command {send butchan ok}", "pack .f.l .f.b -side top -padx 5 -pady 5", "pack .f", }; error(ctxt: ref Draw->Context, oldr: Draw->Rect, errstr: string) { (top, titlectl) := tkclient->toplevel(ctxt, "", "Error", tkclient->Appl); butchan := chan of string; tk->namechan(top, butchan, "butchan"); tkcmds(top, errorwin); tkcmd(top, ".f.l configure -text {"+errstr+"}"); r := tk->rect(top, ".", 0); newx := ((oldr.dx() - r.dx())/2) + oldr.min.x; if (newx < 0) newx = 0; newy := ((oldr.dy() - r.dy())/2) + oldr.min.y; if (newy < 0) newy = 0; tkcmd(top, ". configure -x "+string newx+" -y "+string newy); tkclient->onscreen(top, "exact"); tkclient->startinput(top, "kbd"::"ptr"::nil); for(;;) alt { s := <-top.ctxt.kbd => tk->keyboard(top, s); s := <-top.ctxt.ptr => tk->pointer(top, *s); <- butchan => tkclient->wmctl(top, "exit"); s := <-top.ctxt.ctl or s = <-top.wreq or s = <- titlectl => tkclient->wmctl(top, s); } }