Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  manual.g   Sprache: unbekannt

 
#############################################################################
##
#W  manual.g              GAP 4 package `browse'                Thomas Breuer
##


#############################################################################
##
#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, "\
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


[ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge