implement WmMan; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Font: import draw; include "tk.m"; tk: Tk; include "tkclient.m"; tkclient: Tkclient; include "plumbmsg.m";include "man.m"; man: Man; WmMan: module { init: fn (ctxt: ref Draw->Context, argv: list of string);}; window: ref Tk->Toplevel; W: adt { textwidth: fn(nil: self ref W, text: Text): int;}; ROMAN: con "/fonts/lucidasans/unicode.7.font";BOLD: con "/fonts/lucidasans/typelatin1.7.font";ITALIC: con "/fonts/lucidasans/italiclatin1.7.font";HEADING1: con "/fonts/lucidasans/boldlatin1.7.font";HEADING2: con "/fonts/lucidasans/italiclatin1.7.font";rfont, bfont, ifont, h1font, h2font: ref Font; GOATTR: con Parseman->ATTR_LAST << iota;MANPATH: con "/man/1/man";INDENT: con 40; metrics: Parseman->Metrics;parser: Parseman;Text: import parser; tkconfig := array [] of { "frame .input", "frame .view", "text .view.t -state disabled -width 0 -height 0 -bg white -yscrollcommand {.view.yscroll set} -xscrollcommand {.view.xscroll set}", "scrollbar .view.yscroll -orient vertical -command {.view.t yview}", "scrollbar .view.xscroll -orient horizontal -command {.view.t xview}", "entry .input.e -bg white", "button .input.back -state disabled -bitmap small_color_left.bit -command {send nav b}", "button .input.forward -state disabled -bitmap small_color_right.bit -command {send nav f}", "pack .input.back .input.forward -side left -anchor w", "pack .input.e -expand 1 -fill x", "pack .view.yscroll -fill y -side left", "pack .view.t -expand 1 -fill both", "bind .input.e <Key-\n> {send nav e}", "bind .input.e <Button-1> +{grab set .input.e}", "bind .input.e <ButtonRelease-1> +{grab release .input.e}", "bind .view.t <Button-1> +{grab set .view.t}", "bind .view.t <ButtonRelease-1> +{grab release .view.t}", "bind .view.t <ButtonRelease-3> {send plumb %x %y}", "pack .input -fill x", "pack .view -expand 1 -fill both", "pack propagate . 0", ". configure -width 500 -height 500", "focus .input.e",}; History: adt { prev: cyclic ref History; next: cyclic ref History; topline: string; searchstart: string; searchend: string; pick { Search => search: list of string; Go => path: string; }}; history: ref History; init(ctxt: ref Draw->Context, argv: list of string){ doplumb := 0; sys = load Sys Sys->PATH; if (ctxt == nil) { sys->fprint(sys->fildes(2), "man: no window context\n"); raise "fail:bad context"; } sys->pctl(Sys->NEWPGRP, nil); draw = load Draw Draw->PATH; if (draw == nil) loaderr("Draw"); tk = load Tk Tk->PATH; if (tk == nil) loaderr(Tk->PATH); man = load Man Man->PATH; if (man == nil) loaderr(Man->PATH); tkclient = load Tkclient Tkclient->PATH; if (tkclient == nil) loaderr(Tkclient->PATH); parser = load Parseman Parseman->PATH; if (parser == nil) loaderr(Parseman->PATH); parser->init(); plumber := load Plumbmsg Plumbmsg->PATH; if (plumber != nil) { if (plumber->init(1, nil, 0) >= 0) doplumb = 1; } argv = tl argv; rfont = Font.open(ctxt.display, ROMAN); bfont = Font.open(ctxt.display, BOLD); ifont = Font.open(ctxt.display, ITALIC); h1font = Font.open(ctxt.display, HEADING1); h2font = Font.open(ctxt.display, HEADING2); em := rfont.width("m"); en := rfont.width("n"); metrics = Parseman->Metrics(490, 80, em, en, 14, 40, 20); tkclient->init(); buts := Tkclient->Resize | Tkclient->Hide; winctl: chan of string; (window, winctl) = tkclient->toplevel(ctxt, nil, "Man", buts); nav := chan of string; plumb := chan of string; tk->namechan(window, nav, "nav"); tk->namechan(window, plumb, "plumb"); for(tc:=0; tc<len tkconfig; tc++) tkcmd(window, tkconfig[tc]); if ((err := tkcmd(window, "variable lasterror")) != nil) { sys->fprint(sys->fildes(2), "man: tk initialization failed: %s\n", err); raise "fail:tk"; } fittoscreen(window); tkcmd(window, "update"); mktags(); vw := int tkcmd(window, ".view.t cget -actwidth") - 10; if (vw <= 0) vw = 1; metrics.pagew = vw; linechan := chan of list of (int, Text); man->loadsections(nil); pidc := chan of int; if (argv != nil) { if (hd argv == "-f") { first: ref History; for (argv = tl argv; argv != nil; argv = tl argv) { hnode := ref History.Go(history, nil, "", "", "", hd argv); if (history != nil) history.next = hnode; history = hnode; if (first == nil) first = history; } history = first; } else history = ref History.Search(nil, nil, "", "", "", argv); } if (history == nil) history = ref History.Go(nil, nil, "", "", "", MANPATH); setbuttons(); spawn printman(pidc, linechan, history); layoutpid := <- pidc; tkclient->onscreen(window, nil); tkclient->startinput(window, "kbd"::"ptr"::nil); for (;;) alt { s := <-window.ctxt.kbd => tk->keyboard(window, s); s := <-window.ctxt.ptr => tk->pointer(window, *s); s := <-window.ctxt.ctl or s = <-window.wreq or s = <-winctl => e := tkclient->wmctl(window, s); if (e == nil && s[0] == '!') { topline := tkcmd(window, ".view.t yview"); (nil, toptoks) := sys->tokenize(topline, " "); if (toptoks != nil) history.topline = hd toptoks; vw = int tkcmd(window, ".view.t cget -actwidth") - 10; if (vw <= 0) vw = 1; if (vw != metrics.pagew) { if (layoutpid != -1) kill(layoutpid); metrics.pagew = vw; tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; } } line := <- linechan => if (line == nil) { # layout done if (history.topline != "") { topline := tkcmd(window, ".view.t yview"); (nil, toptoks) := sys->tokenize(topline, " "); if (toptoks != nil) if (hd toptoks == "0") tkcmd(window, ".view.t yview moveto " + history.topline); } tkcmd(window, "update"); } else setline(line); go := <- nav => topline := tkcmd(window, ".view.t yview"); (nil, toptoks) := sys->tokenize(topline, " "); if (toptoks != nil) history.topline = hd toptoks; case go[0] { 'f' => # forward history = history.next; setbuttons(); if (layoutpid != -1) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; 'b' => # back history = history.prev; setbuttons(); if (layoutpid != -1) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; 'e' or 'l' => t := ""; if (go[0] == 'l') { # link t = go[1:]; } else { # entry t = tkcmd(window, ".input.e get"); for (i := 0; i < len t; i++) if (!(t[i] == ' ' || t[i] == '\t')) break; if (i == len t) break; t = t[i:]; if (t[0] == '/' || t[0] == '?') { search(t); break; } } (n, toks) := sys->tokenize(t, " \t"); if (n == 0) continue; h := ref History.Search(history, nil, "", "", "", toks); history.next = h; history = h; setbuttons(); if (layoutpid != -1) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; 'g' => # goto file h := ref History.Go(history, nil, "", "", "", go[1:]); history.next = h; history = h; setbuttons(); if (layoutpid != 0) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; } p := <- plumb => if (!doplumb) break; (nil, l) := sys->tokenize(p, " "); x := int hd l; y := int hd tl l; index := tkcmd(window, ".view.t index @"+string x+","+string y); selindex := tkcmd(window, ".view.t tag ranges sel"); insel := 0; if(selindex != "") insel = tkcmd(window, ".view.t compare sel.first <= "+index)=="1" && tkcmd(window, ".view.t compare sel.last >= "+index)=="1"; text := ""; attr := ""; if (insel) text = tkcmd(window, ".view.t get sel.first sel.last"); else{ # have line with text in it # now extract whitespace-bounded string around click (nil, w) := sys->tokenize(index, "."); charno := int hd tl w; left := tkcmd(window, ".view.t index {"+index+" linestart}"); right := tkcmd(window, ".view.t index {"+index+" lineend}"); line := tkcmd(window, ".view.t get "+left+" "+right); for(i:=charno; i>0; --i) if(line[i-1]==' ' || line[i-1]=='\t') break; for(j:=charno; j<len line; j++) if(line[j]==' ' || line[j]=='\t') break; text = line[i:j]; attr = "click="+string (charno-i); } msg := ref Plumbmsg->Msg( "WmMan", "", "", "text", attr, array of byte text); plumber->msg.send(); layoutpid = <- pidc => ; }} search(pat: string){ dir: string; start: string; if (pat[0] == '/') { dir = "-forwards"; start = history.searchend; } else { dir = "-backwards"; start = history.searchstart; } pat = pat[1:]; if (start == "") start = "1.0"; r := tkcmd(window, ".view.t search " + dir + " -- " + tk->quote(pat) + " " + start); if (r != nil) { history.searchstart = r; history.searchend = r + "+" + string len pat + "c"; tkcmd(window, ".view.t tag remove sel 1.0 end"); tkcmd(window, ".view.t tag add sel " + history.searchstart + " " + history.searchend); tkcmd(window, ".view.t see " + r); tkcmd(window, "update"); }} setbuttons(){ if (history.prev == nil) tkcmd(window, ".input.back configure -state disabled"); else tkcmd(window, ".input.back configure -state normal"); if (history.next == nil) tkcmd(window, ".input.forward configure -state disabled"); else tkcmd(window, ".input.forward configure -state normal");} dolayout(linechan: chan of list of (int, Text), path: string){ fd := sys->open(path, Sys->OREAD); if (fd == nil) { layouterror(linechan, sys->sprint("cannot open file %s: %r", path)); return; } w: ref W; parser->parseman(fd, metrics, 0, w, linechan);} printman(pidc: chan of int, linechan: chan of list of (int, Text), h: ref History){ pidc <-= sys->pctl(0, nil); args: list of string; pick hp := h { Search => args = hp.search; Go => dolayout(linechan, hp.path); pidc <-= -1; return; } sections: list of string; argstext := ""; addsections := 1; keywords: list of string; for (; args != nil; args = tl args) { arg := hd args; if (arg == nil) continue; if (addsections && !isint(trimdot(arg))) { addsections = 0; keywords = args; } if (addsections) sections = arg :: sections; argstext = argstext + " " + arg; } manpages := man->getfiles(sections, keywords); pagelist := sortpages(manpages); if (len pagelist == 1) { (nil, path, nil) := hd pagelist; dolayout(linechan, path); pidc <-= -1; return; } tt := Text(Parseman->FONT_ROMAN, 0, "Search:", 1, nil); at := Text(Parseman->FONT_BOLD, 0, argstext, 0, nil); linechan <-= (0, tt)::(0, at)::nil; tt.text = ""; linechan <-= (0, tt)::nil; if (pagelist == nil) { donet := Text(Parseman->FONT_ROMAN, 0, "No matches", 0, nil); linechan <-= (INDENT, donet) :: nil; linechan <-= nil; pidc <-= -1; return; } linelist: list of list of Text; pathlist: list of Text; maxkwlen := 0; comma := Text(Parseman->FONT_ROMAN, 0, ", ", 0, ""); for (; pagelist != nil; pagelist = tl pagelist) { (n, p, kwl) := hd pagelist; l := 0; keywords: list of Text = nil; for (; kwl != nil; kwl = tl kwl) { kw := hd kwl; kwt := Text(Parseman->FONT_ITALIC, GOATTR, kw, 0, p); nt := Text(Parseman->FONT_ROMAN, GOATTR, "(" + string n + ")", 0, p); l += textwidth(kwt) + textwidth(nt); if (keywords != nil) { l += textwidth(comma); keywords = nt :: kwt :: comma :: keywords; } else keywords = nt :: kwt :: nil; } if (l > maxkwlen) maxkwlen = l; linelist = keywords :: linelist; ptext := Text(Parseman->FONT_ROMAN, GOATTR, p, 0, ""); pathlist = ptext :: pathlist; } for (; pathlist != nil; (pathlist, linelist) = (tl pathlist, tl linelist)) { line := (10 + INDENT + maxkwlen, hd pathlist) :: nil; for (ll := hd linelist; ll != nil; ll = tl ll) { litem := hd ll; if (tl ll == nil) line = (INDENT, litem) :: line; else line = (0, litem) :: line; } linechan <-= line; } linechan <-= nil; pidc <-= -1;} layouterror(linechan: chan of list of (int, Text), msg: string){ text := "ERROR: " + msg; t := Text(Parseman->FONT_ROMAN, 0, text, 0, nil); linechan <-= (0, t)::nil; linechan <-= nil;}Lines 1–500 of 780. Load more
implement WmMan; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Font: import draw; include "tk.m"; tk: Tk; include "tkclient.m"; tkclient: Tkclient; include "plumbmsg.m"; include "man.m"; man: Man; WmMan: module { init: fn (ctxt: ref Draw->Context, argv: list of string); }; window: ref Tk->Toplevel; W: adt { textwidth: fn(nil: self ref W, text: Text): int; }; ROMAN: con "/fonts/lucidasans/unicode.7.font"; BOLD: con "/fonts/lucidasans/typelatin1.7.font"; ITALIC: con "/fonts/lucidasans/italiclatin1.7.font"; HEADING1: con "/fonts/lucidasans/boldlatin1.7.font"; HEADING2: con "/fonts/lucidasans/italiclatin1.7.font"; rfont, bfont, ifont, h1font, h2font: ref Font; GOATTR: con Parseman->ATTR_LAST << iota; MANPATH: con "/man/1/man"; INDENT: con 40; metrics: Parseman->Metrics; parser: Parseman; Text: import parser; tkconfig := array [] of { "frame .input", "frame .view", "text .view.t -state disabled -width 0 -height 0 -bg white -yscrollcommand {.view.yscroll set} -xscrollcommand {.view.xscroll set}", "scrollbar .view.yscroll -orient vertical -command {.view.t yview}", "scrollbar .view.xscroll -orient horizontal -command {.view.t xview}", "entry .input.e -bg white", "button .input.back -state disabled -bitmap small_color_left.bit -command {send nav b}", "button .input.forward -state disabled -bitmap small_color_right.bit -command {send nav f}", "pack .input.back .input.forward -side left -anchor w", "pack .input.e -expand 1 -fill x", "pack .view.yscroll -fill y -side left", "pack .view.t -expand 1 -fill both", "bind .input.e <Key-\n> {send nav e}", "bind .input.e <Button-1> +{grab set .input.e}", "bind .input.e <ButtonRelease-1> +{grab release .input.e}", "bind .view.t <Button-1> +{grab set .view.t}", "bind .view.t <ButtonRelease-1> +{grab release .view.t}", "bind .view.t <ButtonRelease-3> {send plumb %x %y}", "pack .input -fill x", "pack .view -expand 1 -fill both", "pack propagate . 0", ". configure -width 500 -height 500", "focus .input.e", }; History: adt { prev: cyclic ref History; next: cyclic ref History; topline: string; searchstart: string; searchend: string; pick { Search => search: list of string; Go => path: string; } }; history: ref History; init(ctxt: ref Draw->Context, argv: list of string) { doplumb := 0; sys = load Sys Sys->PATH; if (ctxt == nil) { sys->fprint(sys->fildes(2), "man: no window context\n"); raise "fail:bad context"; } sys->pctl(Sys->NEWPGRP, nil); draw = load Draw Draw->PATH; if (draw == nil) loaderr("Draw"); tk = load Tk Tk->PATH; if (tk == nil) loaderr(Tk->PATH); man = load Man Man->PATH; if (man == nil) loaderr(Man->PATH); tkclient = load Tkclient Tkclient->PATH; if (tkclient == nil) loaderr(Tkclient->PATH); parser = load Parseman Parseman->PATH; if (parser == nil) loaderr(Parseman->PATH); parser->init(); plumber := load Plumbmsg Plumbmsg->PATH; if (plumber != nil) { if (plumber->init(1, nil, 0) >= 0) doplumb = 1; } argv = tl argv; rfont = Font.open(ctxt.display, ROMAN); bfont = Font.open(ctxt.display, BOLD); ifont = Font.open(ctxt.display, ITALIC); h1font = Font.open(ctxt.display, HEADING1); h2font = Font.open(ctxt.display, HEADING2); em := rfont.width("m"); en := rfont.width("n"); metrics = Parseman->Metrics(490, 80, em, en, 14, 40, 20); tkclient->init(); buts := Tkclient->Resize | Tkclient->Hide; winctl: chan of string; (window, winctl) = tkclient->toplevel(ctxt, nil, "Man", buts); nav := chan of string; plumb := chan of string; tk->namechan(window, nav, "nav"); tk->namechan(window, plumb, "plumb"); for(tc:=0; tc<len tkconfig; tc++) tkcmd(window, tkconfig[tc]); if ((err := tkcmd(window, "variable lasterror")) != nil) { sys->fprint(sys->fildes(2), "man: tk initialization failed: %s\n", err); raise "fail:tk"; } fittoscreen(window); tkcmd(window, "update"); mktags(); vw := int tkcmd(window, ".view.t cget -actwidth") - 10; if (vw <= 0) vw = 1; metrics.pagew = vw; linechan := chan of list of (int, Text); man->loadsections(nil); pidc := chan of int; if (argv != nil) { if (hd argv == "-f") { first: ref History; for (argv = tl argv; argv != nil; argv = tl argv) { hnode := ref History.Go(history, nil, "", "", "", hd argv); if (history != nil) history.next = hnode; history = hnode; if (first == nil) first = history; } history = first; } else history = ref History.Search(nil, nil, "", "", "", argv); } if (history == nil) history = ref History.Go(nil, nil, "", "", "", MANPATH); setbuttons(); spawn printman(pidc, linechan, history); layoutpid := <- pidc; tkclient->onscreen(window, nil); tkclient->startinput(window, "kbd"::"ptr"::nil); for (;;) alt { s := <-window.ctxt.kbd => tk->keyboard(window, s); s := <-window.ctxt.ptr => tk->pointer(window, *s); s := <-window.ctxt.ctl or s = <-window.wreq or s = <-winctl => e := tkclient->wmctl(window, s); if (e == nil && s[0] == '!') { topline := tkcmd(window, ".view.t yview"); (nil, toptoks) := sys->tokenize(topline, " "); if (toptoks != nil) history.topline = hd toptoks; vw = int tkcmd(window, ".view.t cget -actwidth") - 10; if (vw <= 0) vw = 1; if (vw != metrics.pagew) { if (layoutpid != -1) kill(layoutpid); metrics.pagew = vw; tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; } } line := <- linechan => if (line == nil) { # layout done if (history.topline != "") { topline := tkcmd(window, ".view.t yview"); (nil, toptoks) := sys->tokenize(topline, " "); if (toptoks != nil) if (hd toptoks == "0") tkcmd(window, ".view.t yview moveto " + history.topline); } tkcmd(window, "update"); } else setline(line); go := <- nav => topline := tkcmd(window, ".view.t yview"); (nil, toptoks) := sys->tokenize(topline, " "); if (toptoks != nil) history.topline = hd toptoks; case go[0] { 'f' => # forward history = history.next; setbuttons(); if (layoutpid != -1) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; 'b' => # back history = history.prev; setbuttons(); if (layoutpid != -1) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; 'e' or 'l' => t := ""; if (go[0] == 'l') { # link t = go[1:]; } else { # entry t = tkcmd(window, ".input.e get"); for (i := 0; i < len t; i++) if (!(t[i] == ' ' || t[i] == '\t')) break; if (i == len t) break; t = t[i:]; if (t[0] == '/' || t[0] == '?') { search(t); break; } } (n, toks) := sys->tokenize(t, " \t"); if (n == 0) continue; h := ref History.Search(history, nil, "", "", "", toks); history.next = h; history = h; setbuttons(); if (layoutpid != -1) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; 'g' => # goto file h := ref History.Go(history, nil, "", "", "", go[1:]); history.next = h; history = h; setbuttons(); if (layoutpid != 0) kill(layoutpid); tkcmd(window, ".view.t delete 1.0 end"); tkcmd(window, "update"); spawn printman(pidc, linechan, history); layoutpid = <- pidc; } p := <- plumb => if (!doplumb) break; (nil, l) := sys->tokenize(p, " "); x := int hd l; y := int hd tl l; index := tkcmd(window, ".view.t index @"+string x+","+string y); selindex := tkcmd(window, ".view.t tag ranges sel"); insel := 0; if(selindex != "") insel = tkcmd(window, ".view.t compare sel.first <= "+index)=="1" && tkcmd(window, ".view.t compare sel.last >= "+index)=="1"; text := ""; attr := ""; if (insel) text = tkcmd(window, ".view.t get sel.first sel.last"); else{ # have line with text in it # now extract whitespace-bounded string around click (nil, w) := sys->tokenize(index, "."); charno := int hd tl w; left := tkcmd(window, ".view.t index {"+index+" linestart}"); right := tkcmd(window, ".view.t index {"+index+" lineend}"); line := tkcmd(window, ".view.t get "+left+" "+right); for(i:=charno; i>0; --i) if(line[i-1]==' ' || line[i-1]=='\t') break; for(j:=charno; j<len line; j++) if(line[j]==' ' || line[j]=='\t') break; text = line[i:j]; attr = "click="+string (charno-i); } msg := ref Plumbmsg->Msg( "WmMan", "", "", "text", attr, array of byte text); plumber->msg.send(); layoutpid = <- pidc => ; } } search(pat: string) { dir: string; start: string; if (pat[0] == '/') { dir = "-forwards"; start = history.searchend; } else { dir = "-backwards"; start = history.searchstart; } pat = pat[1:]; if (start == "") start = "1.0"; r := tkcmd(window, ".view.t search " + dir + " -- " + tk->quote(pat) + " " + start); if (r != nil) { history.searchstart = r; history.searchend = r + "+" + string len pat + "c"; tkcmd(window, ".view.t tag remove sel 1.0 end"); tkcmd(window, ".view.t tag add sel " + history.searchstart + " " + history.searchend); tkcmd(window, ".view.t see " + r); tkcmd(window, "update"); } } setbuttons() { if (history.prev == nil) tkcmd(window, ".input.back configure -state disabled"); else tkcmd(window, ".input.back configure -state normal"); if (history.next == nil) tkcmd(window, ".input.forward configure -state disabled"); else tkcmd(window, ".input.forward configure -state normal"); } dolayout(linechan: chan of list of (int, Text), path: string) { fd := sys->open(path, Sys->OREAD); if (fd == nil) { layouterror(linechan, sys->sprint("cannot open file %s: %r", path)); return; } w: ref W; parser->parseman(fd, metrics, 0, w, linechan); } printman(pidc: chan of int, linechan: chan of list of (int, Text), h: ref History) { pidc <-= sys->pctl(0, nil); args: list of string; pick hp := h { Search => args = hp.search; Go => dolayout(linechan, hp.path); pidc <-= -1; return; } sections: list of string; argstext := ""; addsections := 1; keywords: list of string; for (; args != nil; args = tl args) { arg := hd args; if (arg == nil) continue; if (addsections && !isint(trimdot(arg))) { addsections = 0; keywords = args; } if (addsections) sections = arg :: sections; argstext = argstext + " " + arg; } manpages := man->getfiles(sections, keywords); pagelist := sortpages(manpages); if (len pagelist == 1) { (nil, path, nil) := hd pagelist; dolayout(linechan, path); pidc <-= -1; return; } tt := Text(Parseman->FONT_ROMAN, 0, "Search:", 1, nil); at := Text(Parseman->FONT_BOLD, 0, argstext, 0, nil); linechan <-= (0, tt)::(0, at)::nil; tt.text = ""; linechan <-= (0, tt)::nil; if (pagelist == nil) { donet := Text(Parseman->FONT_ROMAN, 0, "No matches", 0, nil); linechan <-= (INDENT, donet) :: nil; linechan <-= nil; pidc <-= -1; return; } linelist: list of list of Text; pathlist: list of Text; maxkwlen := 0; comma := Text(Parseman->FONT_ROMAN, 0, ", ", 0, ""); for (; pagelist != nil; pagelist = tl pagelist) { (n, p, kwl) := hd pagelist; l := 0; keywords: list of Text = nil; for (; kwl != nil; kwl = tl kwl) { kw := hd kwl; kwt := Text(Parseman->FONT_ITALIC, GOATTR, kw, 0, p); nt := Text(Parseman->FONT_ROMAN, GOATTR, "(" + string n + ")", 0, p); l += textwidth(kwt) + textwidth(nt); if (keywords != nil) { l += textwidth(comma); keywords = nt :: kwt :: comma :: keywords; } else keywords = nt :: kwt :: nil; } if (l > maxkwlen) maxkwlen = l; linelist = keywords :: linelist; ptext := Text(Parseman->FONT_ROMAN, GOATTR, p, 0, ""); pathlist = ptext :: pathlist; } for (; pathlist != nil; (pathlist, linelist) = (tl pathlist, tl linelist)) { line := (10 + INDENT + maxkwlen, hd pathlist) :: nil; for (ll := hd linelist; ll != nil; ll = tl ll) { litem := hd ll; if (tl ll == nil) line = (INDENT, litem) :: line; else line = (0, litem) :: line; } linechan <-= line; } linechan <-= nil; pidc <-= -1; } layouterror(linechan: chan of list of (int, Text), msg: string) { text := "ERROR: " + msg; t := Text(Parseman->FONT_ROMAN, 0, text, 0, nil); linechan <-= (0, t)::nil; linechan <-= nil; }