GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#############################################################################
##
#W HelpBookHandler.g GAPDoc Frank Lübeck
##
##
#Y Copyright (C) 2000, Frank Lübeck, Lehrstuhl D für Mathematik,
#Y RWTH Aachen
##
## This file contains the HELP_BOOK_HANDLER functions for the GapDocGAP
## format. This is the interface between the converter programs
## contained in the GAPDoc package and GAP's help system.
##
## We support some user preferences for the display of GAPDoc manuals from
## the GAP help system. They explain themselves.
DeclareUserPreference( rec(
name:= "UseMathJax",
description:= [
"Change this to true, if you want to use MathJax for display of formulae \
in HTML manuals pages. This will only work if your browser supports \
javascript (e.g., help viewer \"firefox\") and if you are online (because \
the MathJax code and math fonts are loaded from a central AMS server)."
],
default:= false,
values:= [ true, false ],
multi:= false,
package:= "GAPDoc",
) );
DeclareUserPreference( rec(
name:= "TextTheme",
description:= [
"Influences the layout of the onscreen help (help viewers \"screen\", \
\"less\", \"more\"), this is a list of arguments for 'SetGAPDocTextTheme'; \
current choices are shown by 'SetGAPDocTextTheme(\"\");'."
],
default:= [ "default" ],
values:= function() return RecNames( GAPDoc2TextProcs.OtherThemes ); end,
multi:= true,
package:= "GAPDoc",
) );
DeclareUserPreference( rec(
name:= "HTMLStyle",
description:= [
"Influences the layout of the HTML manuals when called from the GAP help \
system. Only relevant if your configured browser supports javascript \
e.g., help viewer \"firefox\"). To see the current choices click on \
the [Style] link at the top of each HTML manual page. \
This is a list of arguments for 'SetGAPDocHTMLStyle'."
],
default:= [ "default" ],
) );
HELP_BOOK_HANDLER.GapDocGAP := rec();
##
## The .entries info in the GapDocGAP six-format has entries of form
##
## [ showstring,
## sectionstring, (allows searching of section numbers, like: "1.3-4")
## [chapnr, secnr, subsecnr],
## linenr (for "text" format),
## pagenr (for .dvi, .pdf-formats),
## idstring (for a link L.<idstring> in PDF file,
## searchstring (simplified lowercased version of <showstring>)
## ]
##
HELPBOOKINFOSIXTMP := 0;
# helper to set the text theme
HELP_BOOK_HANDLER.GapDocGAP.setTextTheme := function()
local theme;
theme := UserPreference("GAPDoc", "TextTheme");
if IsString(theme) then
theme := [theme];
fi;
if theme = ["default"] then
if UserPreference("UseColorsInTerminal") <> true then
SetGAPDocTextTheme("none");
else
SetGAPDocTextTheme(rec());
fi;
else
CallFuncList(SetGAPDocTextTheme, theme);
fi;
end;
HELP_BOOK_HANDLER.GapDocGAP.setTextTheme();
# helper function for showing matches in current text theme
HELP_BOOK_HANDLER.GapDocGAP.apptheme := function(res, theme)
local a;
if not IsBound(res.theme) or res.theme <> theme then
for a in res.entries do
a[1] := SubstituteEscapeSequences(a[8], theme);
od;
res.theme := ShallowCopy(theme);
fi;
end;
## <#GAPDoc Label="SetGAPDocHTMLStyle">
## <ManSection >
## <Func Arg="[style1[, style2] ...]" Name="SetGAPDocHTMLStyle" />
## <Returns>nothing</Returns>
## <Description>
## This utility function is for readers of the HTML version of &GAP;
## manuals which are generated by the &GAPDoc; package. It allows to
## configure the display style of the manuals. This will only have an
## effect if you are using a browser that supports
## <Package>javascript</Package>.
## There is a default which can be reset by calling this function
## without argument. <P/>
##
## The arguments <A>style1</A> and so on must be strings. You can find out
## about the valid strings by following the <B>[Style]</B> link on top
## of any manual page. (Going back to the original page, its address has a
## setting for <C>GAPDocStyle</C> which is the list of strings, separated
## by commas, you want to use here.)
##
## <Example>
## gap> # show/hide subsections in tables on contents only after click,
## gap> # and don't use colors in GAP examples
## gap> SetGAPDocHTMLStyle("toggless", "nocolorprompt");
## </Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
BindGlobal("SetGAPDocHTMLStyle", function(arg)
if Length(arg) = 0 then
SetUserPreference("GAPDoc", "GAPDocHTMLStyle", "default");
else
SetUserPreference("GAPDoc", "GAPDocHTMLStyle",
JoinStringsWithSeparator(arg, ","));
fi;
end);
# set HTML style from gap.ini file
HELP_BOOK_HANDLER.GapDocGAP.f := function()
local st;
st := UserPreference("GAPDoc", "HTMLStyle");
if IsString(st) then
st := [st];
fi;
CallFuncList(SetGAPDocHTMLStyle, st);
end;
HELP_BOOK_HANDLER.GapDocGAP.f();
Unbind(HELP_BOOK_HANDLER.GapDocGAP.f);
HELP_BOOK_HANDLER.GapDocGAP.ReadSix := function(stream)
local fname, res, bname, nam, a, apptheme;
# our .six file is directly GAP-readable
fname := ShallowCopy(stream![2]);
#Read(stream);
# this seems better on NFS file systems ...
CloseStream(stream);
Read(fname);
res := HELPBOOKINFOSIXTMP;
Unbind(HELPBOOKINFOSIXTMP);
# adjust search strings to current text theme, save original in position 8
for a in res.entries do
a[8] := a[1];
od;
## HELP_BOOK_HANDLER.GapDocGAP.setTextTheme();
HELP_BOOK_HANDLER.GapDocGAP.apptheme(res, GAPDocTextTheme);
# in position 6 of each entry we put the corresponding search string
for a in res.entries do
if not IsBound(a[6]) then
a[6] := SIMPLE_STRING(StripEscapeSequences(a[1]));
NormalizeWhitespace(a[6]);
fi;
od;
# We check the current availability of the different
# formats. And we add the help directory.
res.handler := "GapDocGAP";
res.directory := Directory(fname{[1..Length(fname)-10]});
res.types := ["text"];
# check if .dvi and .pdf files and HTML-version available
bname := fname{[1..Length(fname)-4]};
nam := Concatenation(bname, ".dvi");
if IsExistingFile(nam) then
res.dvifile := nam;
Add(res.types, "dvi");
fi;
nam := Concatenation(bname, ".pdf");
if IsExistingFile(nam) then
res.pdffile := nam;
Add(res.types, "pdf");
fi;
nam := Concatenation(bname{[1..Length(bname)-6]}, "chap0.html");
if IsExistingFile(nam) then
Add(res.types, "url");
Add(res.types, "url-text");
fi;
nam := Concatenation(bname{[1..Length(bname)-6]}, "chap0_sym.html");
if IsExistingFile(nam) then
Add(res.types, "url");
Add(res.types, "url-sym");
fi;
nam := Concatenation(bname{[1..Length(bname)-6]}, "chap0_mml.xml");
if IsExistingFile(nam) then
Add(res.types, "url");
Add(res.types, "url-mml");
fi;
nam := Concatenation(bname{[1..Length(bname)-6]}, "chap0_mj.html");
if IsExistingFile(nam) then
Add(res.types, "url");
Add(res.types, "url-mj");
fi;
return res;
end;
Unbind(HELPBOOKINFOSIXTMP);
# Our help output format contains the table of contents,
# so we just delegate.
HELP_BOOK_HANDLER.GapDocGAP.ShowChapters := function(book)
local info, match;
info := HELP_BOOK_INFO(book);
match := Concatenation(HELP_BOOK_HANDLER.GapDocGAP.SearchMatches(book,
"table of contents", true))[1];
return HELP_BOOK_HANDLER.GapDocGAP.HelpData(info, match, "text");
end;
HELP_BOOK_HANDLER.GapDocGAP.ShowSections :=
HELP_BOOK_HANDLER.GapDocGAP.ShowChapters;
# very similar to the .default handler, but we allow search for
# (sub-)section numbers as well
HELP_BOOK_HANDLER.GapDocGAP.SearchMatches := function (book, topic, frombegin)
local info, exact, match, i;
info := HELP_BOOK_INFO(book);
exact := [];
match := [];
for i in [1..Length(info.entries)] do
if topic=info.entries[i][6] or topic=info.entries[i][2] then
Add(exact, i);
elif frombegin = true then
if MATCH_BEGIN(info.entries[i][6], topic) or
MATCH_BEGIN(info.entries[i][2], topic) then
Add(match, i);
fi;
else
if IS_SUBSTRING(info.entries[i][6], topic) then
Add(match, i);
fi;
fi;
od;
## HELP_BOOK_HANDLER.GapDocGAP.setTextTheme();
HELP_BOOK_HANDLER.GapDocGAP.apptheme(info, GAPDocTextTheme);
return [exact, match];
end;
## The data are all easy to get.
if not IsBound(BROWSER_CAP) then
BROWSER_CAP := [];
fi;
HELP_BOOK_HANDLER.GapDocGAP.HelpData := function(book, entrynr, type)
local info, a, fname, str, formatted, enc, outenc, sline, pos,
tmp, ext, label, res, st;
info := HELP_BOOK_INFO(book);
# we handle the special type "ref" for cross references first
if type = "ref" then
a := HELP_BOOK_HANDLER.HelpDataRef(info, entrynr);
a[1] := StripEscapeSequences(a[1]);
return a;
fi;
a := info.entries[entrynr];
# section number info
if type = "secnr" then
return a{[3,2]};
fi;
if not type in info.types then
return fail;
fi;
if type = "text" then
fname := Filename(info.directory, Concatenation("chap", String(a[3][1]),
".txt"));
str := StringFile(fname);
if str = fail then
return rec(lines := Concatenation("Sorry, file '", fname, "' seems to ",
"be corrupted.\n"), formatted := true);
fi;
# maybe change encoding
if IsBound(info.encoding) then
enc := info.encoding;
else
# from older versions, so latin1
enc := "ISO-8859-1";
fi;
if IsBound(GAPInfo.TermEncoding) then
outenc := GAPInfo.TermEncoding;
else
outenc := "ISO-8859-1";
fi;
enc := UNICODE_RECODE.NormalizedEncoding(enc);
outenc := UNICODE_RECODE.NormalizedEncoding(outenc);
if enc <> outenc then
str := Unicode(str, enc);
if outenc = "ISO-8859-1" then
str := SimplifiedUnicodeString(str, "latin1");
elif outenc = "ANSI_X3.4-1968" then
str := SimplifiedUnicodeString(str, "ascii");
fi;
str := Encode(str, outenc);
fi;
sline := a[4];
# set the text theme
## HELP_BOOK_HANDLER.GapDocGAP.setTextTheme();
# substitute pseudo escape sequences via GAPDocTextTheme
# split into two pieces to find new start line
pos := PositionLinenumber(str, sline);
tmp := SubstituteEscapeSequences(str{[1..pos-1]}, GAPDocTextTheme);
str := SubstituteEscapeSequences(str{[pos..Length(str)]},
GAPDocTextTheme);
sline := NumberOfLines(tmp)+1;
str := Concatenation(tmp, str);
return rec(lines := str, formatted := true, start := sline);
fi;
if type = "url" and "url" in info.types then
## # check preferred HTML version/extension
## if not IsBound(BROWSER_CAP) then
## BROWSER_CAP := [];
## fi;
## if "MathML" in BROWSER_CAP and "url-mml" in info.types then
## ext := "_mml.xml";
## elif ("MathML" in BROWSER_CAP or "Symbol" in BROWSER_CAP) and
## "url-sym" in info.types then
## ext := "_sym.html";
## elif "url-text" in info.types then
## ext := ".html";
## else
## return fail;
## fi;
if UserPreference("GAPDoc", "UseMathJax") = true and
"url-mj" in info.types then
ext := "_mj.html";
elif "url-text" in info.types then
ext := ".html";
else
return fail;
fi;
st := UserPreference("GAPDoc", "GAPDocHTMLStyle");
if st <> "default" then
ext := Concatenation(ext, "?GAPDocStyle=", st);
fi;
fname := Filename(info.directory, Concatenation("chap",
String(a[3][1]), ext));
if IsBound(a[7]) then
label := a[7];
else
# from older version of GAPDoc
label := Concatenation("s", String(a[3][2]),
"ss", String(a[3][3]));
fi;
# ??? return Concatenation("file:", fname, label);
return Concatenation("", fname, "#", label);
fi;
if type = "dvi" then
return rec(file := info.dvifile, page := a[5]);
fi;
if type = "pdf" then
res := rec(file := info.pdffile, page := a[5]);
if IsBound(a[7]) then
res.label := Concatenation("L.", a[7]);
fi;
return res;
fi;
return fail;
end;
## cache list of chapter numbers, but only if we need them
HELP_BOOK_HANDLER.GapDocGAP.ChapNumbers := function(info)
local l, sp;
if not IsBound(info.ChapNumbers) then
l := Set(List(info.entries,a->a[3][1]));
sp := IntersectionSet(l, ["Bib", "Ind"]);
l := Difference(l, sp);
Append(l, sp);
info.ChapNumbers := l;
fi;
end;
## for ?<<, ?>>, ?< and ?>
HELP_BOOK_HANDLER.GapDocGAP.MatchPrevChap := function(book, entrynr)
local info, chnums, ent, cnr, new, nr;
info := HELP_BOOK_INFO(book);
HELP_BOOK_HANDLER.GapDocGAP.ChapNumbers(info);
chnums := info.ChapNumbers;
ent := info.entries;
cnr := ent[entrynr][3];
if cnr[2] <> 0 or cnr[3] <> 0 or cnr[1] = chnums[1] then
new := [cnr[1], 0, 0];
else
new := [chnums[Position(chnums, cnr[1])-1], 0, 0];
fi;
nr := First([1..Length(ent)], i-> ent[i][3] = new);
if nr = fail then
# return current
nr := entrynr;
fi;
return [info, nr];
end;
HELP_BOOK_HANDLER.GapDocGAP.MatchNextChap := function(book, entrynr)
local info, chnums, ent, cnr, new, nr;
info := HELP_BOOK_INFO(book);
HELP_BOOK_HANDLER.GapDocGAP.ChapNumbers(info);
chnums := info.ChapNumbers;
ent := info.entries;
cnr := ent[entrynr][3];
if cnr[1] = chnums[Length(chnums)] then
new := [cnr[1], 0, 0];
else
new := [chnums[Position(chnums, cnr[1])+1], 0, 0];
fi;
nr := First([1..Length(ent)], i-> ent[i][3] = new);
if nr = fail then
# return current
nr := entrynr;
fi;
return [info, nr];
end;
HELP_BOOK_HANDLER.GapDocGAP.MatchPrev := function(book, entrynr)
local info, ent, old, new, nr, i;
info := HELP_BOOK_INFO(book);
ent := info.entries;
old := ent[entrynr][3];
new := [-1,0,0];
nr := entrynr;
for i in [1..Length(ent)] do
if ent[i][3] < old and ent[i][3] > new and
not ent[i][3][1] in ["Bib", "Ind"] then
new := ent[i][3];
nr := i;
fi;
od;
return [info, nr];
end;
HELP_BOOK_HANDLER.GapDocGAP.MatchNext := function(book, entrynr)
local info, ent, old, new, nr, i;
info := HELP_BOOK_INFO(book);
ent := info.entries;
old := ent[entrynr][3];
new := ["ZZZ",0,0];
nr := entrynr;
for i in [1..Length(ent)] do
if ent[i][3] > old and ent[i][3] < new and
not ent[i][3][1] in ["Bib", "Ind"] then
new := ent[i][3];
nr := i;
fi;
od;
return [info, nr];
end;
HELP_BOOK_HANDLER.GapDocGAP.SubsectionNumber := function(info, entrynr)
return info.entries[entrynr][3];
end;