Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346############################################################################# ## #W manual.g GAP 4 package `browse' Thomas Breuer ## #Y Copyright (C) 2006, Lehrstuhl D für Mathematik, RWTH Aachen, Germany ## ############################################################################# ## #F BrowseGapManuals( [<start>] ) ## ## <#GAPDoc Label="GAPManual_section"> ## <Section Label="sec:manualdisp"> ## <Heading>Access to &GAP; Manuals–a Variant</Heading> ## ## A &Browse; adapted way to access several manuals is ## to show the hierarchy of books, chapters, sections, and subsections ## as collapsible category rows, ## and to regard the contents of each subsection as a data row of a matrix ## with only one column. ## <P/> ## This application is mainly intended as an example with table cells that ## exceed the screen, and as an example with several category levels. ## ## <ManSection> ## <Func Name="BrowseGapManuals" Arg="[start]"/> ## ## <Description> ## This function displays the contents of the &GAP; manuals ## (the main &GAP; manuals as well as the loaded package manuals) ## in a window. ## The optional argument <A>start</A> describes the initial status, ## admissible values are the strings ## <C>"inline/collapsed"</C>, ## <C>"inline/expanded"</C>, ## <C>"pager/collapsed"</C>, and ## <C>"pager/expanded"</C>. ## <P/> ## In the <C>inline</C> cases, the parts of the manuals are shown in the ## browse table, ## and in the <C>pager</C> case, the parts of the manuals are shown in a ## different window when they are <Q>clicked</Q>, ## using the user's favourite help viewer, ## see <Ref Sect="Changing the Help Viewer" BookName="ref"/>. ## <P/> ## In the <C>collapsed</C> cases, all category rows are collapsed, ## and the first row is selected; ## typical next steps are moving down the selection and expanding single ## category rows. ## In the <C>expanded</C> cases, all category rows are expanded, ## and nothing is selected; ## a typical next step in the <C>inline/expanded</C> case is a search ## for a string in the manuals. ## (Note that searching in quite slow: ## For viewing a part of a manual, ## the file with the corresponding section is read into &GAP;, ## the text is formatted, ## the relevant part is cut out from the section, ## perhaps markup is stripped off, ## and finally the search is performed in the resulting strings.) ## <P/> ## If no argument is given then the user is asked for selecting an initial ## status, using <Ref Func="NCurses.Select"/>. ## <P/> ## The full functionality of the function ## <Ref Func="NCurses.BrowseGeneric"/> is available. ## <P/> ## <Example><![CDATA[ ## gap> n:= [ 14, 14, 14 ];; # ``do nothing'' ## gap> BrowseData.SetReplay( Concatenation( ## > "xdxd", # expand a Tutorial section ## > n, "Q" ) ); # and quit ## gap> BrowseGapManuals( "inline/collapsed" ); ## gap> BrowseData.SetReplay( Concatenation( ## > "/Browse", [ NCurses.keys.ENTER ], # search for "Browse" ## > "xdxddxd", # expand a section ## > n, "Q" ) ); # and quit ## gap> BrowseGapManuals( "inline/collapsed" ); ## gap> BrowseData.SetReplay( false ); ## ]]></Example> ## <P/> ## <E>Implementation remarks</E>: ## The browse table has a dynamic header showing the name of the currently ## selected manual, no footer, no row or column labels, ## and exactly one column of fixed width equal to the screen width. ## The category rows are precomputed, i. e., ## they do not arise from a table column; ## this way, the contents of each data cell can be computed on demand, ## as soon as it is shown on the screen, ## in particular the category hierarchy is computed without reading the ## manuals into &GAP;. ## Also, the data rows are not cached. ## There is no return value. ## The heights of many cells are bigger than the screen height, ## so scrolling is a mixture of scrolling to the next cell and scrolling ## inside a cell. ## The different initial states are realized via executing different ## initial steps before the table is shown to the user. ## <P/> ## For the variants that show the manuals in a pager, ## the code temporarily replaces the <C>show</C> function ## of the default viewer <C>"screen"</C> ## (see <Ref Sect="Changing the Help Viewer" BookName="ref"/>) ## by a function that uses <Ref Func="NCurses.Pager"/>. ## Note that in the case that the manual bit in question fits into ## one screen, ## the default <C>show</C> function writes this text directly to the screen, ## but this is used already by the browse table. ## <P/> ## The implementation should be regarded as a sketch. ## <P/> ## For example, the markup available in the text file format of ## <Package>GAPDoc</Package> manuals (using <B>Esc</B> sequences) ## is stripped off instead of being transferred to the attribute lines ## that arise, because of the highlighting problem mentioned in ## Section <Ref Subsect="NCurses.IsAttributeLine"/>. ## <P/> ## Some heuristics used in the code are due to deficiencies of the ## manual formats. ## <P/> ## For the inline variant of the browse table, ## the titles of chapters, sections, and subsections are <E>not</E> regarded ## as parts of the actual text since they appear already as category rows; ## however, the functions of the &GAP; help system deliver the text ## <E>together with</E> these titles, ## so these lines must be stripped off afterwards. ## <P/> ## The category hierarchy representing the tables of contents is created ## from the <F>manual.six</F> files of the manuals. ## These files do not contain enough information ## for determining whether several functions define the same subsection, ## in the sense that there is a common description text ## after a series of manual lines introducing different functions. ## In such cases, the browse table contains a category row for each of ## these functions (with its own number), ## but the corresponding text appears only under the <E>last</E> of these ## category rows, the data rows for the others are empty. ## (This problem does not occur in the <Package>GAPDoc</Package> manual ## format because this introduces explicit subsection titles, ## involving only the <E>first</E> of several function definitions.) ## <P/> ## Also, index entries and sectioning entries in <F>manual.six</F> files ## of manuals in <Package>GAPDoc</Package> format are not explicitly ## distinguished. ## <P/> ## The code can be found in the file <F>app/manual.g</F> of the package. ## </Description> ## </ManSection> ## </Section> ## <#/GAPDoc> ## BindGlobal( "BrowseGapManuals", function( arg ) local values, start, yx, getdata, width, keys, cats, i, sep, book, bookinfo, longname, dirs, toadd, known, toadd2, x, j, lastindex, entry, index, str, sel_action, manSection, click, table; # Determine the initial status. values:= [ "inline/collapsed", "inline/expanded", "pager/collapsed", "pager/expanded", "cancel" ]; if Length( arg ) = 1 and arg[1] in values then start:= arg[1]; else yx:= NCurses.getmaxyx( 0 ); start:= values[ NCurses.Select( rec( items:= values, single:= true, none:= false, size:= [ 8, 45 ], begin:= [ QuoInt( yx[1] - 5, 2 ), QuoInt( yx[2] - 45, 2 ) ], border:= true, header:= "Please choose an initial status.", ) ) ]; fi; if start = "cancel" then return; fi; # The following code is copied from `lib/helpbase.gi': # read the manual.six file # read the first non-empty line to find out the handler for the corresp. # manual format (no explicit format implies the "default" handler) getdata:= function( six ) local stream, line, handler; if six = fail then return fail; fi; stream := InputTextFile(six); line := ""; while Length(line) = 0 do line := ReadLine(stream); if line=fail then CloseStream(stream); return fail; fi; line := NormalizedWhitespace(line); od; if Length(line)>10 and line{[1..10]}="#SIXFORMAT" then handler := line{[12..Length(line)]}; NormalizeWhitespace(handler); else handler := "default"; RewindStream(stream); fi; # give up if handler functions are not (yet) loaded if not IsBound(HELP_BOOK_HANDLER.(handler)) then return fail; fi; # Compute the label lines, ignore index entries. return HELP_BOOK_HANDLER.( handler ).ReadSix( stream ); end; width:= NCurses.getmaxyx( 0 )[2]; keys:= []; cats:= []; i:= 1; sep:= ""; for book in [ 1 .. Length( HELP_KNOWN_BOOKS[1] ) ] do bookinfo:= HELP_KNOWN_BOOKS[2][ book ]; if IsDirectory( bookinfo[3] ) then # package manual longname:= Concatenation( bookinfo[1], " - ", bookinfo[2] ); dirs:= [ bookinfo[3] ]; else # one of the main manuals longname:= bookinfo[2]; dirs:= DirectoriesLibrary( bookinfo[3] ); fi; toadd:= getdata( Filename( dirs, "manual.six" ) ); if toadd <> fail then for j in [ 1 .. Length( toadd.entries ) ] do toadd.entries[j][7]:= j; od; if not IsBound( toadd.handler ) then # Omit index entries. toadd:= Filtered( toadd.entries, x -> x[3] <> "I" ); # Compute indices of function entries. lastindex:= [ 0, 0 ]; for entry in toadd do if entry[3] = "F" then if lastindex = entry{ [ 4, 5 ] } then index:= index + 1; else index:= 1; fi; lastindex:= entry{ [ 4, 5 ] }; entry[6]:= index; else entry[6]:= 0; fi; od; # We need the sorted information [ C, S, F, text, nr ]. toadd:= List( toadd, x -> x{ [ 4, 5, 6, 1, 7 ] } ); Sort( toadd ); elif toadd.handler = "GapDocGAP" then # Omit title page, copyright, table of contents, bibliography, # index, and index entries. # We need the sorted information [ C, S, F, text, nr ]. known:= []; toadd2:= []; for entry in toadd.entries do x:= entry[3]; if x[1] <> 0 and not IsString( x[1] ) and not x in known then AddSet( known, Immutable( x ) ); Add( toadd2, Concatenation( entry[3], [ StripEscapeSequences( entry[1] ), entry[7] ] ) ); fi; od; toadd:= toadd2; Sort( toadd ); fi; # Create a category row for each book, chapter, section, function; # they are not separated from each other and from data lines. Add( cats, rec( pos:= 2*i, level:= 1, value:= longname, separator:= sep, isUnderCollapsedCategory:= false, isRejectedCategory:= false ) ); for entry in toadd do Add( keys, [ book, entry[5], entry[3] = 0, entry[4] ] ); str:= List( entry, String ); str[4]:= BrowseData.SimplifiedString( str[4] ); if entry[3] <> 0 then Add( cats, rec( pos:= 2*i, level:= 4, value:= Concatenation( str[1], ".", str[2], ".", str[3], " ", str[4] ), separator:= sep, isUnderCollapsedCategory:= true, isRejectedCategory:= false ) ); elif entry[2] <> 0 then Add( cats, rec( pos:= 2*i, level:= 3, value:= Concatenation( str[1], ".", str[2], " ", str[4] ), separator:= sep, isUnderCollapsedCategory:= true, isRejectedCategory:= false ) ); else Add( cats, rec( pos:= 2*i, level:= 2, value:= Concatenation( str[1], " ", str[4] ), separator:= sep, isUnderCollapsedCategory:= true, isRejectedCategory:= false ) ); fi; i:= i + 1; od; fi; od; if 'i' in start then # ``inline'': Fetch a prescribed piece of the manual. manSection:= function( pos ) local book, info1, from, info2, to, lines; book:= HELP_BOOK_INFO( HELP_KNOWN_BOOKS[1][ keys[ pos ][1] ] ); info1:= HELP_BOOK_HANDLER.( book.handler ).HelpData( book, keys[ pos ][2], "text" ); from:= info1.start; if pos = Length( keys ) or keys[ pos+1 ][1] <> keys[ pos ][1] then info2:= info1; else # next piece of the manual, in the same book info2:= HELP_BOOK_HANDLER.( book.handler ).HelpData( book, keys[ pos+1 ][2], "text" ); if info2.lines = info1.lines then to:= info2.start; fi; fi; lines:= info1.lines; if IsString( lines ) then lines:= SplitString( lines, "\n" ); fi; # Remove the chapter or section header. if book.handler = "GapDocGAP" then if keys[ pos ][3] or NormalizedWhitespace( lines[ from ] ) = "" then from:= from + 2; else # This happens for subsections generated with `<ManSection>'. from:= from + 1; fi; if not IsBound( to ) then to:= Length( lines ) + 1; fi; lines:= List( lines{ [ from .. to - 1 ] }, StripEscapeSequences ); lines:= List( lines, BrowseData.SimplifiedString ); elif keys[ pos ][3] then if not IsBound( to ) then to:= Length( lines ); fi; while from <= to and lines[ from ] <> "" do from:= from + 1; od; lines:= lines{ [ from .. to ] }; if from < to or lines[ Length( lines ) ] <> "" then Add( lines, "" ); fi; fi; return rec( rows:= lines, align:= "l" ); end; click:= rec(); else # Use a pager for showing text from the manual. # If the user defined pager is "builtin" then we replace the pager # by `NCurses.Pager', otherwise we give the control to the user defined # pager. sel_action:= rec( helplines:= [ "open the chosen manual part in a pager" ], action:= function( t ) local pos, showfun; if t.dynamic.selectedEntry <> [ 0, 0 ] then pos:= t.dynamic.indexRow[ t.dynamic.selectedEntry[1] ] / 2; showfun:= HELP_VIEWER_INFO.screen.show; if UserPreference( "Pager" ) = "builtin" then HELP_VIEWER_INFO.screen.show:= function( lines ) if IsList( lines ) then lines:= List( lines, StripEscapeSequences ); elif IsString( lines.lines ) then lines.lines:= StripEscapeSequences( lines.lines ); lines.lines:= BrowseData.SimplifiedString( lines.lines ); else lines.lines:= List( lines.lines, StripEscapeSequences ); lines.lines:= List( lines.lines, BrowseData.SimplifiedString ); fi; NCurses.Pager( lines ); NCurses.update_panels(); NCurses.doupdate(); NCurses.curs_set( 0 ); end; fi; if BrowseData.IsDoneReplay( t.dynamic.replay ) then HELP_PRINT_MATCH( [ HELP_KNOWN_BOOKS[1][ keys[ pos ][1] ], keys[ pos ][2] ] ); # Without the following `endwin' call, the pager `less' # does not return to the window with the browse table! NCurses.endwin(); NCurses.update_panels(); NCurses.doupdate(); NCurses.curs_set( 0 ); fi; # Reinstall the pager for "builtin". HELP_VIEWER_INFO.screen.show:= showfun; fi; return t.dynamic.changed; end ); manSection:= function( pos ) return rec( rows:= [ " (hit <Enter> to show this part)" ], align:= "l" ); end; click:= rec( select_entry:= sel_action, select_row:= sel_action, ); fi; # Construct the browse table. table:= rec( work:= rec( align:= "tl", header:= function( t ) local pos; if t.dynamic.selectedCategory <> [ 0, 0 ] then pos:= t.dynamic.selectedCategory[1]; elif t.dynamic.selectedEntry <> [ 0, 0 ] then pos:= t.dynamic.selectedEntry[1]; else pos:= t.dynamic.topleft[1] + ( t.dynamic.topleft[1] mod 2 ); fi; return [ [ NCurses.attrs.UNDERLINE, true, "GAP Documentation: ", HELP_KNOWN_BOOKS[2][ keys[ pos / 2 ][1] ][1] ], "" ]; end, main:= [], Main:= function( t, i, j ) return manSection( i ); end, widthCol:= [ 0, width, 0 ], m:= Length( keys ), n:= 1, Click:= click, sepCategories:= sep, startCollapsedCategory:= [ [ NCurses.attrs.BOLD, true, "> ", NCurses.attrs.UNDERLINE, true ], [ NCurses.attrs.BOLD, true, " > " ], [ NCurses.attrs.BOLD, true, " > " ], "> ", ], startExpandedCategory:= [ [ NCurses.attrs.BOLD, true, "* ", NCurses.attrs.UNDERLINE, true ], [ NCurses.attrs.BOLD, true, " * " ], [ NCurses.attrs.BOLD, true, " * " ], "* ", ], ), dynamic:= rec( categories:= [ List( cats, x -> x.pos ), cats, [] ], isCollapsedRow:= List( [ 1 .. 2*Length( keys ) + 1 ], x -> true ), ), ); table.dynamic.isCollapsedRow[1]:= false; # Set the initial steps, depending on `start'. if 'c' in start then table.dynamic.initialSteps:= "se"; else table.dynamic.initialSteps:= "X"; fi; # Show the table. NCurses.BrowseGeneric( table ); end ); ############################################################################# ## ## Add the Browse application to the list shown by `BrowseGapData'. ## BrowseGapDataAdd( "GAP Manuals", BrowseGapManuals, false, "\ an overview of GAP documentation (main manuals and package manuals), \ in a browse table which is categorized hierarchically by book names \ and chapter, section, subsection headings; \ the actual contents is shown either inside the table or in a pager" ); ############################################################################# ## #E