# # xmenu.icn # copyright 1992 Ronald Florence # @(#) version 1.1 (ron@mlfarm.com, 12 May 1992) # # main window: # left button to select recipe # q, ^c, ^d to quit # recipe windows: # , m, or left button for more # b or middle button for less # p to print # q or right button to return to main screen # .Xdefaults options: # Xmenu.maxwin # Xmenu.index # Xmenu.datadir # Xmenu.font # Configuration: # Maxwin : maximum # of lines in the windows # indexfile: full path of the indexfile # Data_dir: full path of directory with recipe files # Font: X-Windows display font # Print_cmd: pretty-printer and/or spooler; the name of # the recipe will be substituted for %s # link evmux, button, xdefault record rec_record (win, title, recipe, proc, but) global Data_dir, Maxwin, Font, Print_cmd, R, W procedure main(arg) local indexfile, pchar, hits, online, meta_keys, keys, xres, egrep_cmd, k, m, found, r, index, winsize, title, but "X Windows" == &features | stop("Sorry, requires X-Windows.") xres := xdefault("Xmenu") Maxwin := \xres["maxwin"] | %MAXWIN% indexfile := \xres["index"] | "%INDEXFILE%" Data_dir := \xres["datadir"] | "%DATADIR%" Font := \xres["font"] | "%FONT%" Print_cmd := "%PRINTCMD%" (*arg > 0) | stop("usage: menu keyword [keyword,...]") close(open(indexfile)) | stop("can't read indexfile") pchar := &ascii[32:127] hits := [] online := [] meta_keys := [] keys := [] egrep_cmd := "cat " || indexfile every k := !arg do put(if metas(k) then meta_keys else keys, map(k)) \meta_keys[1] | put(meta_keys, pop(keys)) every k := !meta_keys do egrep_cmd ||:= " | egrep -i '" || k || "'" index := open(egrep_cmd || " 2>&1", "rp") every !index ? { find("error"|"grep") & stop("search expression error") m := map(&subject) found := 1 every k := !keys do { find(k, m) | break found := &null } \found & { put(if match("Comp-", &subject) then online else hits, left(tab(many(pchar)), 20) || (tab(upto(pchar)), tab(many(pchar)))) tab(0) } } *hits + *online = 0 & stop("No matching recipes.") (winsize := *online * 2 + *hits + 1) <= Maxwin | { hits |||:= online online := [] winsize := *hits + 1 } winsize >=:= Maxwin W := open("menu", "x", "font=" || Font, "cursor=off", "lines=" || winsize, "columns=80") | stop("no window") quitsensor(W) if *hits > winsize then page(W, hits, "menu") else { every write(W, !hits) (*online > 0) | evhandle(W) } R := table() every !online ? { ="Comp-" r := tab(many(&digits)) title := (tab(many(' \t')), tab(0)) but := button(W, r, setup, r, XAttrib(W, "x"), XAttrib(W, "y"), 70, 20) XGotoRC(W, XAttrib(W, "row"), 21) write(W, title) R[r] := rec_record (&null, title, [], &null, but) } if *online > 0 then evmux(W) end procedure setup(win, r) local rpath, rf, heading if *R[r].recipe = 0 then { rpath := Data_dir || r rf := open(rpath) | open("zcat " || rpath || ".Z", "rp") | return writes("\^g") every put(R[r].recipe, !rf) close(rf) } if /R[r].win then { heading := R[r].title || " [" || r || "]" R[r].win := open(heading, "x", "font=" || Font, "cursor=off", "lines=" || (Maxwin > (*R[r].recipe + 2) | Maxwin), "columns=80") | stop("no page window") shadebutton(R[r].but) R[r].proc := create page(R[r].win, R[r].recipe, R[r].title) } @R[r].proc | (R[r].win := &null) end procedure page(win, rec, title) local base, x, k, i, e, lines lines := XAttrib(win, "lines") base := 0 repeat { XClearArea(win) XGotoRC(win,1,1) every i := 0 to lines - 2 do { if i + base < *rec then writes(win, rec[i+base+1]) write(win) } if lines = Maxwin then { XAttrib(win, "reverse=on") writes(win, "--More--(", ((100 > (base+lines-2) * 100/*rec) | 100), "%)") XAttrib(win, "reverse=off") } case (x := XActive()) of { win : &null W : @&main default: every k := key(R) do if (x === R[k].win) then break @R[k].proc } if type(e := XEvent(win)) == "integer" then XEvent(win) else e := map(e) case e of { " "|"m"|&lpress: base := *rec > (base+lines-2) "b"|&mpress: base := (0 < (base-lines+2) | 0) "q"|&rpress: close(win) & fail "p": print(rec, title) } } end procedure print(recipe, head) local prn, rp Print_cmd ? { prn := (\tab(find("%s")) || head) | tab(0) move(2) & prn ||:= tab(0) } rp := open(prn, "wp") every write(rp, !recipe) return close(rp) end procedure metas(str) str ? { tab(many('*+?|')) # initials don't count while tab(upto('\\*+()|?.$^[')) do { # a naked backslash is NG if ="\\" then move(1) | stop("badly-formed search string") else return .&pos } } fail end procedure shadebutton(b) XAttrib(W, "fillstyle=opaquestippled") XSetStipple(W, 4, 10, 7, 5, 15) XFillRectangle(b.win, b.x+1, b.y+1, b.w-1, b.h-1) XGotoXY(b.win, b.lx, b.ly) writes(b.win, b.label) end