
| Current Path : /usr/share/gap/lib/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //usr/share/gap/lib/pager.gi |
#############################################################################
##
#W pager.gi GAP Library Frank Lübeck
##
##
#Y Copyright (C) 2001, Lehrstuhl D für Mathematik, RWTH Aachen, Germany
#Y (C) 2001 School Math and Comp. Sci., University of St Andrews, Scotland
#Y Copyright (C) 2002 The GAP Group
##
## The files pager.g{d,i} contain the `Pager' utility. A rudimentary
## version of this was integrated in first versions of GAP's help system.
## But this utility is certainly useful for other purposes as well.
##
##
## There is a builtin pager `PAGER_BUILTIN', but at least under UNIX one
## should use an external one. This can be set via the variable
## `SetUserPreference("Pager", ...);'
## (e.g., SetUserPreference("Pager", "less");).
## Here, `less' should be in the executable
## PATH of the user and we assume that it supports an argument `+num' for
## starting display in line number `num'. Additional options can be
## given by `SetUserPreference("PagerOptions", ...);' as list of strings.
##
## The user function is `Pager'.
##
## The input of `Pager( lines )' can have one the following forms:
##
## (1) a string (i.e., lines are separated by '\n')
## (2) a list of strings (without '\n') interpreted as lines of output
## (3) a record with component .lines as in (1) or (2) and optional further
## components
##
## In (3) currently the following components are used:
##
## .formatted (true/false) If true, the builtin pager tries to avoid
## line breaks by GAP's Print.
## .start (number) The display is started with line .start, but
## beginning is available via back scrolling.
## .exitAtEnd (true/false) If true (default), the pager is terminated
## as soon as the end of the list is reached;
## if false, entering 'q' is necessary in order to
## return from the pager.
##
# The preferred pager can be specified via a user preference.
DeclareUserPreference( rec(
name:= [ "Pager", "PagerOptions" ],
description:= [
"For displaying help pages on screen and other things GAP has a rudimentary \
builtin pager. We recommend using a more sophisticated external program. \
For example, when you have the program 'less' on your computer we recommend:",
" Pager := \"less\";",
" PagerOptions := [\"-f\", \"-r\", \"-a\", \"-i\", \"-M\", \"-j2\"];",
"If you want to use 'more', we suggest to use the '-f' option. \
If you want to use the pager defined in your environment then \
leave the 'Pager' and 'PagerOptions' preferences empty."
],
default:= function() # copied from GAPInfo.READENVPAGEREDITOR
local str, sp, pager, options;
if IsBound(GAPInfo.KernelInfo.ENVIRONMENT.PAGER) then
str := GAPInfo.KernelInfo.ENVIRONMENT.PAGER;
sp := SplitStringInternal(str, "", " \n\t\r");
if Length(sp) > 0 then
pager:= sp[1];
options:= sp{ [ 2 .. Length( sp ) ] };
# 'less' could have options in variable 'LESS'
if "less" in SplitStringInternal(sp[1], "", "/\\") then
if IsBound(GAPInfo.KernelInfo.ENVIRONMENT.LESS) then
str := GAPInfo.KernelInfo.ENVIRONMENT.LESS;
sp := SplitStringInternal(str, "", " \n\t\r");
Append( options, sp );
fi;
# make sure -r is used
Add( options, "-r" );
elif "more" in SplitStringInternal(sp[1], "", "/\\") then
if IsBound(GAPInfo.KernelInfo.ENVIRONMENT.MORE) then
# similarly for 'more'
str := GAPInfo.KernelInfo.ENVIRONMENT.MORE;
sp := SplitStringInternal(str, "", " \n\t\r");
Append( options, sp );
fi;
# make sure -f is used
Add( options, "-f" );
fi;
return [ pager, options ];
fi;
fi;
# The builtin pager does not work in HPCGAP
if IsHPCGAP then
return [ "less" , ["-f","-r","-a","-i","-M","-j2"] ];
else
return [ "builtin", [] ];
fi;
end,
) );
## HACKUSERPREF temporary until all packages are adjusted
GAPInfo.UserPreferences.Pager := UserPreference("Pager");
#############################################################################
##
#F PAGER_BUILTIN( <lines> ) . . . . . . . . . . . . . . . . format lines
##
# If the text contains ANSI color sequences we reset the terminal before
# we print the last line.
BindGlobal("PAGER_BUILTIN", function( lines )
local formatted, linepos, exitAtEnd, size, wd, pl, count, i, stream, halt,
lenhalt, delhaltline, from, len, emptyline, char, out;
formatted := false;
linepos := 1;
exitAtEnd:= true;
# don't print this to LOG files
out := OutputTextUser();
if IsRecord(lines) then
if IsBound(lines.formatted) then
formatted := lines.formatted;
fi;
if IsBound(lines.start) and IsInt(lines.start) then
linepos := lines.start;
fi;
if IsBound( lines.exitAtEnd ) then
exitAtEnd:= lines.exitAtEnd;
fi;
lines := lines.lines;
fi;
if IsString(lines) then
lines := SplitString(lines, "\n", "");
elif not formatted then
lines := ShallowCopy(lines);
fi;
size := SizeScreen();
wd := QuoInt(size[1]+2, 2);
# really print line without breaking it
pl := function(l)
local r;
r := 1;
while r*wd<=Length(l) do
PrintTo(out, l{[(r-1)*wd+1..r*wd]}, "\c");
r := r+1;
od;
if (r-1)*wd < Length(l) then
PrintTo(out, l{[(r-1)*wd+1..Length(l)]});
fi;
PrintTo(out, "\n");
end;
if not formatted then
# cope with overfull lines
count:=1;
while count<=Length(lines) do
if Length(lines[count])>size[1]-2 then
# find the last blank before this position
i:=size[1]-2;
while i>0 and lines[count][i]<>' ' do
i:=i-1;
od;
if i>0 then
if not IsBound(lines[count+1]) then
lines[count+1]:="";
fi;
lines[count+1]:=Concatenation(
lines[count]{[i+1..Length(lines[count])]}," ", lines[count+1]);
lines[count]:=lines[count]{[1..i-1]};
fi;
fi;
count:=count+1;
od;
fi;
stream := InputTextFile("*errin*");
count := 0;
halt :=
" -- <space> page, <n> next line, <b> back, <p> back line, <q> quit --\c";
# remember number of visible characters
lenhalt := Length(halt)-1;
if UserPreference("UseColorsInTerminal") = true then
halt := Concatenation("\033[0m", halt);
fi;
delhaltline := function()
local i;
for i in [1..lenhalt] do
PrintTo(out, "\b\c \c\b\c" );
od;
end;
from := linepos;
len := Length(lines);
emptyline:= String( "", size[1]-2 );
repeat
for i in [from..Minimum(len, from+size[2]-2)] do
pl(lines[i]);
od;
if len = i then
if exitAtEnd then
break;
fi;
for i in [ len+1 .. from+size[2]-2 ] do
pl( emptyline );
od;
fi;
PrintTo(out, halt);
char := CHAR_INT(ReadByte(stream));
while not char in " nbpq" do
char := CHAR_INT(ReadByte(stream));
od;
if char = ' ' and i < len then
from := from+size[2]-1;
elif char = 'n' and i < len then
from := from+1;
elif char = 'p' and from>1 then
from := from-1;
elif char = 'b' then
from := Maximum(1, from-size[2]+1);
fi;
delhaltline();
until char = 'q';
CloseStream(stream);
end);
# for using `more' or `less' or ... (read from `UserPreference("Pager")')
# we assume that UserPreference("Pager") allows command line option
# +num for starting display in line num
BindGlobal("PAGER_EXTERNAL", function( lines )
local path, pager, linepos, str, i, cmdargs, stream;
pager := UserPreference("Pager");
if not (Length(pager) > 0 and pager[1] = '/' and IsExecutableFile(pager))
then
path := DirectoriesSystemPrograms();
pager := Filename( path, UserPreference("Pager") );
fi;
if pager=fail then
Error( "Pager ", UserPreference("Pager"),
" not found, reset with `SetUserPreference(\"Pager\", ...);'." );
fi;
linepos := 1;
if IsRecord(lines) then
if IsBound(lines.start) then
linepos := lines.start;
fi;
lines := lines.lines;
fi;
if not IsString(lines) then
str:="";
for i in lines do
Append(str,i);
Add(str,'\n');
od;
lines := str;
fi;
if linepos > 1 then
cmdargs := [Concatenation("+", String(linepos))];
else
cmdargs := [];
fi;
stream:=InputTextString(lines);
Process(DirectoryCurrent(), pager, stream, OutputTextUser(),
Concatenation( UserPreference("PagerOptions"), cmdargs ));
end);
InstallGlobalFunction("Pager", function(lines)
if UserPreference("Pager") = "builtin" then
PAGER_BUILTIN(lines);
else
PAGER_EXTERNAL(lines);
fi;
end);
BindGlobal( "PagerAsHelpViewer", function( lines )
if UserPreference( "Pager" ) = "builtin" then
if IsRecord( lines ) then
lines.exitAtEnd:= false;
else
lines:= rec( lines:= lines, exitAtEnd:= false );
fi;
PAGER_BUILTIN( lines );
else
PAGER_EXTERNAL( lines );
fi;
end );