# AutoDoc: Generate documentation from GAP source code
#
# Copyright of AutoDoc belongs to its developers.
# Please refer to the COPYRIGHT file for details.
#
# SPDX-License-Identifier: GPL-2.0-or-later

#! @Chapter Reference

#! @Section The AutoDoc() function

#! @Description
#! This is the main function of the &AutoDoc; package. It can perform
#! any combination of the following tasks:
#! <Enum>
#! <Item>
#!     It can (re)generate a scaffold for your package manual.
#!     That is, it can produce two XML files in &GAPDoc; format to be used as part
#!     of your manual: First, a file named <F>doc/_main.xml</F>
#!     which is used as main XML file for the package manual, i.e. this file sets the
#!     XML doctype and defines various XML entities, includes
#!     other XML files (both those generated by &AutoDoc; as well
#!     as additional files created by other means), tells &GAPDoc;
#!     to generate a table of contents and an index, and more.
#!     Secondly, it creates a file <F>doc/title.xml</F> containing a title
#!     page for your documentation, with information about your package
#!     (name, description, version), its authors and more, based
#!     on the data in your <F>PackageInfo.g</F>.
#! </Item>
#! <Item>
#!     It can scan your package for &AutoDoc; based documentation, using
#!     documentation comments and commands. This produces additional XML files
#!     to be used as part of the package manual.
#! </Item>
#! <Item>
#!     It can use &GAPDoc; to generate PDF, text and HTML (with
#!     MathJax enabled) documentation from the &GAPDoc; XML files it
#!     generated as well as additional such files provided by you. For
#!     this, it invokes <Ref Func='MakeGAPDocDoc' BookName='gapdoc'/>
#!     to convert the XML sources, and it also instructs &GAPDoc; to copy
#!     supplementary files (such as CSS style files) into your doc directory
#!     (see <Ref Func='CopyHTMLStyleFiles' BookName='gapdoc'/>).
#! </Item>
#! </Enum>
#! These tasks can be enabled independently, so you can use as much or as
#! little of &AutoDoc; as your package currently needs.
#! For more information and some examples, please refer to Chapter <Ref Chap='Chapter_Tutorials'/>.
#! <P/>
#! The parameters have the following meanings:
#! <List>
#!
#! <Mark><A>pkgdir</A></Mark>
#! <Item>
#!     This optional parameter is used to determine the package
#!     directory in which &AutoDoc; will operate, and to find the metadata
#!     concerning the package being documented. If given, it should be
#!     an <C>IsDirectory</C> object. If the argument is omitted, then &AutoDoc;
#!     checks if it was called from a <F>makedoc.g</F> file or similar, and if so,
#!     uses the directory this is contained in. Otherwise the current
#!     directory is used. In both cases, the specified directory must contain a
#!     <F>PackageInfo.g</F> file, and &AutoDoc; extracts all needed metadata
#!     from that. The <C>IsDirectory</C> form is for example useful if you
#!     have multiple versions of the package around and want to make sure the
#!     documentation of the correct version is built.
#!     <P/>
#!     For backwards compatibility, it is also possible to pass a package name
#!     as this argument, which then is resolved to the package directory of
#!     the first instance of this package &GAP; knows about. However, this is
#!     deprecated, as it is unreliable in the presence of multiple copies of a
#!     package.
#!     <P/>
#!     Note that when using <C>AutoDocWorksheet</C> (see
#!     <Ref Sect='Section_AutoDocWorksheet'/>), there is
#!     no parameter corresponding to <A>pkgdir</A> and so the
#!     <Q>package directory</Q> is always the current directory, and
#!     there is no metadata.
#! </Item>
#!
#!
#! <Mark><A>optrec</A></Mark>
#! <Item>
#!     <A>optrec</A> can be a record with some additional options.
#!     The following are currently supported:
#!     <List>
#!     <Mark><A>dir</A></Mark>
#!     <Item>
#!         This should either be a string, in which case it must be a path
#!         <E>relative</E> to the specified package directory, or a
#!         <C>Directory()</C> object. (Thus, the only way to designate an
#!         absolute directory is with a <C>Directory()</C> object.) This
#!         option specifies where the package documentation
#!         (e.g. the &GAPDoc; XML or the manual PDF, etc.) files are stored
#!         and/or will be generated.
#!         <Br/>
#!         <E>Default value: <C>"doc/"</C>.</E>
#!     </Item>
#!     <Mark><A>scaffold</A></Mark>
#!     <Item>
#!         This controls whether and how to generate scaffold XML files
#!         for the package documentation.
#!         <P/>
#!         The value should be either <K>true</K>, <K>false</K> or a
#!         record. If it is a record or <K>true</K> (the latter is
#!         equivalent to specifying an empty record), then this feature is
#!         enabled. It is also enabled if <A>opt.scaffold</A> is missing but the
#!         package's info record in <F>PackageInfo.g</F> has an <C>AutoDoc</C> entry.
#!         In all other cases (in particular if <A>opt.scaffold</A> is
#!         <K>false</K>), scaffolding is disabled.
#!         <P/>
#!         If scaffolding is enabled, and <A>PackageInfo.AutoDoc</A> exists, then it is
#!         assumed to be a record, and its contents are used as default values for
#!         the scaffold settings.
#!         <P/>
#!
#!         If <A>opt.scaffold</A> is a record, it may contain the following entries.
#!
#!         <List>
#!
#!         <Mark><A>includes</A></Mark>
#!         <Item>
#!             A list of XML files to be included in the body of the main XML file.
#!             If you specify this list and also are using &AutoDoc; to document
#!             your operations with &AutoDoc; comments,
#!             you can add <F>_AutoDocMainFile.xml</F> to this list
#!             to control at which point the documentation produced by &AutoDoc;
#!             is inserted. If you do not do this, it will be added after the last
#!             of your own XML files.
#!         </Item>
#!
#!         <Mark><A>index</A></Mark>
#!         <Item>
#!             By default, the scaffold creates an index. If you do not want an index,
#!             set this to <K>false</K>.
#!         </Item>
#!
#!         <Mark><A>appendix</A></Mark>
#!         <Item>
#!             This entry is similar to <A>opt.scaffold.includes</A> but is used
#!             to specify files to include after the main body of the manual,
#!             i.e. typically appendices written directly in &GAPDoc; XML.
#!             Appendices created with <C>@Appendix</C> are included automatically
#!             after these files when scaffolding generates the main XML file.
#!         </Item>
#!
#!         <Mark><A>bib</A></Mark>
#!         <Item>
#!             The name of a bibliography file, in BibTeX or XML format.
#!             If this key is not set, but there is a file <F>doc/PACKAGENAME.bib</F>
#!             then it is assumed that you want to use this as your bibliography.
#!         </Item>
#!
#!         <Mark><A>bibstyle</A></Mark>
#!         <Item>
#!             Overrides the bibliography style used for LaTeX output.
#!             This is written as the <C>Style</C> attribute of the generated
#!             <C>&lt;Bibliography .../&gt;</C> element, so valid values are the
#!             bibliography style names understood by &GAPDoc; and BibTeX, such
#!             as <C>alpha</C>, <C>alphaurl</C>, or <C>plain</C>.
#!         </Item>
#!
#!         <Mark><A>entities</A></Mark>
#!         <Item>
#!             A record whose keys are taken as entity names, set to the corresponding
#!             (string) values. For example, if you pass the record <Q>SomePackage</Q>,
#!             <Listing><![CDATA[
#!             rec( SomePackage := "<Package>SomePackage</Package>",
#!                  RELEASEYEAR := "2015" )]]></Listing>
#!             then the following entity definitions are added to the XML preamble:
#!             <Listing><![CDATA[<!ENTITY SomePackage '<Package>SomePackage</Package>'>
#!             <!ENTITY RELEASEYEAR '2015'>]]></Listing>
#!             This allows you to write <Q>&amp;SomePackage;</Q> and <Q>&amp;RELEASEYEAR;</Q>
#!             in your documentation, which will be replaced by respective values specified
#!             in the entities definition.
#!             <P/>
#!             Note that &AutoDoc; predefines several entities:
#!             <List>
#!             <Mark><A>VERSION</A></Mark>
#!             <Item>Set to the <C>Version</C> field of your package info record.</Item>
#!             <Mark><A>RELEASEYEAR</A></Mark>
#!             <Item>Set to a string containing the release year, as derived
#!                   from the <C>Date</C> field of your package info record.</Item>
#!             <Mark><A>RELEASEDATE</A></Mark>
#!             <Item>Derived from the <C>Date</C> field of your package info record.</Item>
#!             <Mark><A>SomePackage</A></Mark>
#!             <Item>
#!                 The precise name of this entity is derived from the
#!                 <C>PackageName</C> field of your package info record. Note
#!                 that it is case sensitive. The content is defined as
#!                 suggested by the example above.
#!             </Item>
#!             </List>
#!         </Item>
#!
#!         <Mark><A>TitlePage</A></Mark>
#!         <Item>
#!             A record with extra title-page fields for the generated manual.
#!             Field names are interpreted as title-page XML element names, and
#!             their values are written as element content. For example, you can
#!             set a custom acknowledgements block with
#!             <Listing><![CDATA[
#!             rec( Acknowledgements := "Many thanks to ..." )]]></Listing>
#!             If this is set in <F>PackageInfo.g</F> as
#!             <C>PkgInfo.AutoDoc.TitlePage</C>, it has the same meaning as this
#!             option; see subsection <Ref Subsect='Subsection_Tut:PackageInfo'/> in chapter
#!             <Ref Chap='Chapter_Tutorials'/> for details and an example.
#!             <P/>
#!             For the list of valid title-page elements, see the
#!             &GAPDoc; manual, specifically section <Ref Subsect='TitlePage' BookName='gapdoc'/>.
#!         </Item>
#!         <Mark><A>MainPage</A></Mark>
#!         <Item>
#!             If scaffolding is enabled, by default a main XML file is generated (this
#!             is the file which contains the XML doctype and more). If you do not
#!             want this (e.g. because you have a handwritten main XML file), but
#!             still want &AutoDoc; to generate a title page for you, you can set this
#!             option to <K>false</K>
#!         </Item>
#!         <Mark><A>document_class</A></Mark>
#!         <Item>
#!             Sets the document class of the resulting PDF. The value can either be a string
#!             which has to be the name of the new document class, a list containing this string, or
#!             a list of two strings. Then the first one has to be the document class name, the second one
#!             the option string ( contained in [ ] ) in &LaTeX;.
#!         </Item>
#!         <Mark><A>latex_header_file</A></Mark>
#!         <Item>
#!             Replaces the standard header from &GAPDoc; completely with the header in this &LaTeX; file.
#!             Please be careful here, and look at &GAPDoc;'s <F>latexheader.tex</F> file for an example.
#!         </Item>
#!
#!         </List>
#!     </Item>
#!
#!
#!     <Mark><A>autodoc</A></Mark>
#!     <Item>
#!         This controls whether and how to generate additional XML documentation files
#!         by scanning for &AutoDoc; documentation comments.
#!         <P/>
#!         The value should be either <K>true</K>, <K>false</K> or a
#!         record. If it is a record or <K>true</K> (the latter is
#!         equivalent to specifying an empty record), then this feature is
#!         enabled. It is also enabled if <A>opt.autodoc</A> is missing but the
#!         package depends (directly) on the &AutoDoc; package.
#!         In all other cases (in particular if <A>opt.autodoc</A> is
#!         <K>false</K>), this feature is disabled.
#!         <P/>
#!
#!         If <A>opt.autodoc</A> is a record, it may contain the following entries.
#!
#!         <List>
#!
#!         <Mark><A>files</A></Mark>
#!         <Item>
#!             A list of files (given by paths relative to the package directory)
#!             to be scanned for &AutoDoc; documentation comments.
#!             Usually it is more convenient to use <A>autodoc.scan_dirs</A>, see below.
#!         </Item>
#!
#!         <Mark><A>scan_dirs</A></Mark>
#!         <Item>
#!             A list of subdirectories of the package directory (given as relative paths)
#!             which &AutoDoc; then scans recursively for .gi, .gd, .g, and
#!             .autodoc files; all of these files are then scanned for
#!             &AutoDoc; documentation comments. The special entries <C>"."</C>
#!             and <C>""</C> still only scan the package root itself.
#!             This controls where &AutoDoc; looks for source comments beginning with <C>#!</C>
#!             and for standalone <F>.autodoc</F> files.
#!             It does not affect where &GAPDoc; looks for GAPDoc comments; that is controlled
#!             separately by <A>gapdoc.scan_dirs</A>.
#!             <Br/>
#!             <E>Default value: <C>[ ".", "gap", "lib", "examples", "examples/doc" ]</C>.</E>
#!         </Item>
#!
#!         <Mark><A>level</A></Mark>
#!         <Item>
#!             This defines the level of the created documentation. The default value is 0.
#!             When parts of the manual are declared with a higher value
#!             they will not be printed into the manual.
#!         </Item>
#!
#!         </List>
#!     </Item>
#!
#!
#!     <Mark><A>gapdoc</A></Mark>
#!     <Item>
#!         This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text
#!         files from your various XML files.
#!         <P/>
#!         The value should be either <K>true</K>, <K>false</K> or a
#!         record. If it is a record or <K>true</K> (the latter is
#!         equivalent to specifying an empty record), then this feature is
#!         enabled. It is also enabled if <A>opt.gapdoc</A> is missing.
#!         In all other cases (in particular if <A>opt.gapdoc</A> is
#!         <K>false</K>), this feature is disabled.
#!         <P/>
#!
#!         If <A>opt.gapdoc</A> is a record, it may contain the following entries.
#!
#!         <List>
#!
#!
#### Note: 'main' is strictly speaking also used for the scaffold.
#### However, if one uses the scaffolding mechanism, then it is not
#### really necessary to specify a custom name for the main XML file.
#### Thus, the purpose of this parameter is to cater for packages
#### that have existing documentation using a different XML name,
#### and which do not wish to use scaffolding.
####
#### This explains why we only allow specifying gapdoc.main.
#### The scaffolding code will still honor it, though, just in case.
#!         <Mark><A>main</A></Mark>
#!         <Item>
#!             The name of the main XML file of the package manual.
#!             This exists primarily to support packages with existing manual
#!             which use a filename here which differs from the default.
#!             In particular, specifying this is unnecessary when using scaffolding.
#!             <Br/>
#!             <E>Default value: <C>_main.xml</C> when scaffolding is enabled for
#!             package manuals, otherwise <C>PACKAGENAME.xml</C>.</E>
#!         </Item>
#!
#!         <Mark><A>files</A></Mark>
#!         <Item>
#!             A list of files (given by paths relative to the package directory)
#!             to be scanned for &GAPDoc; documentation comments.
#!             Usually it is more convenient to use <A>gapdoc.scan_dirs</A>, see below.
#!         </Item>
#!
#!         <Mark><A>scan_dirs</A></Mark>
#!         <Item>
#!             A list of subdirectories of the package directory (given as relative paths)
#!             which &AutoDoc; then scans recursively for .gi, .gd and .g
#!             files; all of these files are then scanned for &GAPDoc;
#!             documentation comments. The special entries <C>"."</C> and
#!             <C>""</C> still only scan the package root itself.
#!             This controls only where &GAPDoc; comments are searched for.
#!             It does not affect where &AutoDoc; looks for source comments beginning with <C>#!</C>
#!             or for <F>.autodoc</F> files; use <A>autodoc.scan_dirs</A> for that.
#!             <Br/>
#!             <E>Default value: <C>[ ".", "gap", "lib", "examples", "examples/doc" ]</C>.</E>
#!         </Item>
#!
#!         <Mark><A>LaTeXOptions</A></Mark>
#!         <Item>
#!             Must be a record with entries which can be understood by
#!             <Ref Func='SetGapDocLaTeXOptions' BookName='gapdoc'/>. Each entry can be a
#!             string, which will be given to &GAPDoc; directly, or a list containing of
#!             two entries: The first one must be the string "file", the second one a
#!             filename. This file will be read and then its content is passed to &GAPDoc;
#!             as option with the name of the entry.
#!         </Item>
#!
#!         <Mark><A>gap_root_relative_path</A></Mark>
#!         <Item>
#!             Either a boolean, or a string containing a relative path.
#!             By default (if this option is not set, or is set to <K>false</K>),
#!             references in the generated documentation referring to external documentation
#!             (such as the &GAP; manual) are encoded using absolute paths.
#!             This is fine as long as the documentation stays on only a single
#!             computer, but is problematic when preparing documentation that should be
#!             used on multiple computers, e.g., when creating a distribution archive of
#!             a &GAP; package.<Br/>
#!             Thus, if a relative path is provided via this option (or if it is set to <K>true</K>,
#!             in which case the relative path <F>../../..</F> is used), then &AutoDoc;
#!             and &GAPDoc; attempt to replace all absolute paths in references to &GAP;
#!             manuals by paths based on this relative path.<P/>
#!             
#!             On a technical level, &AutoDoc; passes the relative path to the
#!             <A>gaproot</A> parameter of <Ref Func='MakeGAPDocDoc'
#!             BookName='gapdoc'/><P/>
#!         </Item>
#!
#!         </List>
#!     </Item>
#!
#!     <Mark><A>extract_examples</A></Mark>
#!     <Item>
#!         Either <K>true</K> or a record.
#!         If set to <K>true</K>, then all manual examples are extracted and placed
#!         into files <F>tst/PACKAGENAME01.tst</F>,  <F>tst/PACKAGENAME02.tst</F>, ...
#!         and so on, with one file for each chapter. For chapters with no examples,
#!         no file is created.<P/>
#!         If set to a record, it may contain the following entries:
#!         <List>
#!         <Mark>subdir</Mark>
#!         <Item>
#!             A string or <C>Directory()</C> object selecting where the generated
#!             <F>.tst</F> files are written. The default is <F>tst</F>. If a string is
#!             given, it is interpreted relative to the package directory, so values
#!             such as <F>tst/generated</F> are supported.
#!         </Item>
#!         <Mark>units</Mark>
#!         <Item>
#!             This controls how examples are grouped into files. Recognized values are
#!             "Chapter" (default), "Section", "Subsection" or "Single". Depending on the value,
#!             one file is created for each chapter, each section, each subsection or each example.
#!             For all other values only a single file is created.
#!             
#!             On a technical level, &AutoDoc; passes the value to the
#!             <A>units</A> parameter of <Ref Func='ExtractExamples' BookName='gapdoc'/>.
#!         </Item>
#!         <Mark>skip_empty_in_numbering</Mark>
#!         <Item>
#!             If set to <K>true</K> (the default), the generated files use
#!             filenames with strictly sequential numbering; that means that
#!             if chapter 1 (or whatever units are being used) contains no
#!             examples but chapter 2 does, then the examples for chapter 2
#!             are put into the file <F>tst/PACKAGENAME01.tst</F>. If this
#!             option is set to <K>false</K>, then the chapter numbers are
#!             used to generate the filenames; so the examples for chapter 2
#!             would be put into the file <F>tst/PACKAGENAME02.tst</F>.
#!         </Item>
#!         </List>
#!     </Item>
#!
#!     </List>
#! </Item>
#! </List>
#!
#! The function also checks the following GAP global options, i.e. options
#! supplied via GAP's value-option syntax and visible through nested calls.
#! These are not entries of <A>optrec</A>. See
#! <Ref Chap="Options Stack" BookName="ref"/> for more information
#! about GAP's global options system.
#! <List>
#! <Mark><A>nopdf</A></Mark>
#! <Item>
#!     If this global option is set to `true`, then &AutoDoc; tells &GAPDoc;
#!     not to build the PDF version of the manual. HTML and text output are
#!     still generated.
#!     <P/>
#!     This is useful on systems without a working `pdflatex`
#!     installation, or when you only need the non-PDF outputs while
#!     iterating on the manual.
#!     <P/>
#!     For example:
#!     <Listing><![CDATA[
#!     AutoDoc( rec( autodoc := true ) : nopdf );]]></Listing>
#!     Also, if the environment variable `NOPDF` is set, then &AutoDoc;
#!     behaves as if the global option <A>nopdf</A> had been enabled.
#! </Item>
#! <Mark><A>relativePath</A></Mark>
#! <Item>
#!     This has the same effect as <A>gapdoc.gap_root_relative_path</A>, but
#!     as a GAP global option. It takes precedence over that record entry if
#!     both are specified.
#!     <P/>
#!     If <A>relativePath</A> is `true`, then the default relative path
#!     <F>../../..</F> is used. If it is a string, then that string is used as
#!     the relative path from the documentation directory to the GAP root.
#!     <P/>
#!     For example:
#!     <Listing><![CDATA[
#!     AutoDoc( rec( autodoc := true ) : relativePath := "../../.." );]]></Listing>
#! </Item>
#! </List>
#! In particular, a call such as
#! <Listing><![CDATA[
#! Read( "makedoc.g" : nopdf, relativePath );]]></Listing>
#! sets both global options to `true`, and they remain visible to the
#! <Ref Func="AutoDoc"/> call inside <F>makedoc.g</F>.
#!
#! @Returns nothing
#! @Arguments [pkgdir], [optrec]
DeclareGlobalFunction( "AutoDoc" );

DeclareGlobalFunction( "AutoDoc_INTERN" );

#! @Description
#!   Info class for the <Package>AutoDoc</Package> package.  Set this to
#!   0 to suppress info messages, 1 to allow most messages, and 2 to allow all
#!   messages including those that contain file paths.
#!
#!   This can be set by calling, for example,
#!   <C>SetInfoLevel(InfoAutoDoc, 0)</C>. Default value is 1.
DeclareInfoClass("InfoAutoDoc");
SetInfoLevel(InfoAutoDoc, 1);
