diff --git a/CHANGES.md b/CHANGES.md
index 1511fd05..b3a45bae 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -19,6 +19,7 @@ This file describes changes in the AutoDoc package.
environment variable and `relativePath` global option
- Add Markdown-style headings `#`/`##`/`###` as aliases for
`@Chapter`/`@Section`/`@Subsection` in `.autodoc` files and doc comments
+ - Add `@Appendix` for generating appendix XML from `.autodoc` input
- Add support for documenting `DeclareSynonym` and
`DeclareSynonymAttr` declarations
- Add `@ItemType` to override the type of a declaration, which is
diff --git a/doc/Comments.autodoc b/doc/Comments.autodoc
index 219426b4..baf67219 100644
--- a/doc/Comments.autodoc
+++ b/doc/Comments.autodoc
@@ -243,6 +243,23 @@ If you use all three commands, i.e.,
title is used for the headline, label for cross-referencing, and name
for setting the same chapter as active chapter again.
+@Subsection @Appendix name
+@SubsectionLabel @Appendix
+
+@Index "@Appendix" `@Appendix`
+This is analogous to @Chapter, but generates `Appendix`
+elements instead of `Chapter` elements. When scaffolding generates the main
+XML file, appendices created this way are included automatically after any
+files listed in `scaffold.appendix`.
+
+Example:
+
+```@listing
+@Appendix Supplementary material
+
+@Section Additional tables
+```
+
@Subsection @Section name
@SubsectionLabel @Section
diff --git a/gap/AutoDocMainFunction.gi b/gap/AutoDocMainFunction.gi
index 80215fc5..f4deaeda 100644
--- a/gap/AutoDocMainFunction.gi
+++ b/gap/AutoDocMainFunction.gi
@@ -155,6 +155,10 @@ InstallGlobalFunction( CreateMainPage,
AppendTo( filestream, "<#Include SYSTEM \"", i, "\">\n" );
od;
fi;
+ if IsBound( opt.autodoc_appendix_file ) and
+ ( not IsBound( opt.appendix ) or not opt.autodoc_appendix_file in opt.appendix ) then
+ AppendTo( filestream, "<#Include SYSTEM \"", opt.autodoc_appendix_file, "\">\n" );
+ fi;
if IsBound( opt.bib ) and opt.bib <> false then
AppendTo( filestream, "\n" );
diff --git a/gap/DocumentationTree.gd b/gap/DocumentationTree.gd
index 0764222e..6ada159c 100644
--- a/gap/DocumentationTree.gd
+++ b/gap/DocumentationTree.gd
@@ -45,6 +45,7 @@ DeclareAttribute( "GroupName", IsTreeForDocumentationNode );
DeclareOperation( "DocumentationTree", [ ] );
DeclareOperation( "StructurePartInTree", [ IsTreeForDocumentation, IsList ] );
DeclareOperation( "ChapterInTree", [ IsTreeForDocumentation, IsString ] );
+DeclareOperation( "AppendixInTree", [ IsTreeForDocumentation, IsString ] );
DeclareOperation( "SectionInTree", [ IsTreeForDocumentation, IsString, IsString ] );
DeclareOperation( "SubsectionInTree", [ IsTreeForDocumentation, IsString, IsString, IsString ] );
DeclareOperation( "DocumentationExample", [ IsString ] );
diff --git a/gap/DocumentationTree.gi b/gap/DocumentationTree.gi
index 1478121e..934606f0 100644
--- a/gap/DocumentationTree.gi
+++ b/gap/DocumentationTree.gi
@@ -377,12 +377,24 @@ end );
##
####################################
-##
+##
InstallMethod( ChapterInTree, [ IsTreeForDocumentation, IsString ],
function( tree, name )
return StructurePartInTree( tree, [ name ] );
end );
+##
+InstallMethod( AppendixInTree, [ IsTreeForDocumentation, IsString ],
+ function( tree, name )
+ local node;
+
+ node := ChapterInTree( tree, name );
+ node!.is_appendix := true;
+ SetLabel( node,
+ Concatenation( "Appendix_", AUTODOC_NormalizeGeneratedLabel( name ) ) );
+ return node;
+end );
+
##
InstallMethod( SectionInTree, [ IsTreeForDocumentation, IsString, IsString ],
function( tree, chapter_name, section_name )
@@ -476,17 +488,32 @@ end );
##
InstallMethod( WriteDocumentation, [ IsTreeForDocumentation, IsDirectory ],
function( tree, path_to_xmlfiles )
- local stream, i;
+ local stream, appendix_stream, i;
stream := AUTODOC_OutputTextFile( path_to_xmlfiles, _AUTODOC_GLOBAL_OPTION_RECORD.AutoDocMainFile );
AppendTo( stream, AUTODOC_XML_HEADER );
+ appendix_stream := fail;
for i in tree!.content do
- if not IsTreeForDocumentationNodeForChapterRep( i ) then
+ if IsTreeForDocumentationNodeForChapterRep( i ) then
+ if IsBound( i!.is_appendix ) and i!.is_appendix = true then
+ if appendix_stream = fail then
+ appendix_stream := AUTODOC_OutputTextFile(
+ path_to_xmlfiles,
+ "_AutoDocAppendicesMainFile.xml"
+ );
+ AppendTo( appendix_stream, AUTODOC_XML_HEADER );
+ fi;
+ WriteDocumentation( i, appendix_stream, path_to_xmlfiles );
+ else
+ WriteDocumentation( i, stream, path_to_xmlfiles );
+ fi;
+ else
Error( "this should never happen" );
fi;
- ## FIXME: If there is anything else than a chapter, this will break!
- WriteDocumentation( i, stream, path_to_xmlfiles );
od;
+ if appendix_stream <> fail then
+ CloseStream( appendix_stream );
+ fi;
WriteChunks( tree, path_to_xmlfiles );
@@ -500,7 +527,7 @@ end );
##
InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForChapterRep, IsStream, IsDirectory ],
function( node, stream, path_to_xmlfiles )
- local filename, chapter_stream;
+ local filename, chapter_stream, element_name;
if ForAll( node!.content, IsEmptyNode ) then
return;
@@ -510,7 +537,11 @@ InstallMethod( WriteDocumentation, [ IsTreeForDocumentationNodeForChapterRep, Is
chapter_stream := AUTODOC_OutputTextFile( path_to_xmlfiles, filename );
AppendTo( stream, "<#Include SYSTEM \"", filename, "\">\n" );
AppendTo( chapter_stream, AUTODOC_XML_HEADER );
- AUTODOC_WriteStructuralNode( node, "Chapter", chapter_stream );
+ element_name := "Chapter";
+ if IsBound( node!.is_appendix ) and node!.is_appendix = true then
+ element_name := "Appendix";
+ fi;
+ AUTODOC_WriteStructuralNode( node, element_name, chapter_stream );
CloseStream( chapter_stream );
end );
diff --git a/gap/Magic.gd b/gap/Magic.gd
index e9c75a73..6af80b98 100644
--- a/gap/Magic.gd
+++ b/gap/Magic.gd
@@ -136,7 +136,9 @@
#! -
#! This entry is similar to opt.scaffold.includes but is used
#! to specify files to include after the main body of the manual,
-#! i.e. typically appendices.
+#! i.e. typically appendices written directly in &GAPDoc; XML.
+#! Appendices created with @Appendix are included automatically
+#! after these files when scaffolding generates the main XML file.
#!
#!
#! bib
diff --git a/gap/Magic.gi b/gap/Magic.gi
index 16846caf..bbc3bae0 100644
--- a/gap/Magic.gi
+++ b/gap/Magic.gi
@@ -510,6 +510,10 @@ function( arg )
CreateEntitiesPage( gapdoc.bookname, doc_dir, scaffold );
if IsBound( scaffold.MainPage ) and scaffold.MainPage <> false then
+ if ForAny( tree!.content,
+ node -> IsBound( node!.is_appendix ) and node!.is_appendix = true ) then
+ scaffold.autodoc_appendix_file := "_AutoDocAppendicesMainFile.xml";
+ fi;
CreateMainPage( gapdoc.bookname, doc_dir, scaffold );
fi;
fi;
diff --git a/gap/Parser.gi b/gap/Parser.gi
index 7306e2f3..8af927f0 100644
--- a/gap/Parser.gi
+++ b/gap/Parser.gi
@@ -800,8 +800,18 @@ InstallGlobalFunction( AutoDoc_Parser_ReadFiles,
local scope_chapter;
scope_chapter := ReplacedString( current_command[ 2 ], " ", "_" );
SetCurrentItem( ChapterInTree( tree, scope_chapter ) );
+ Unbind( chapter_info[ 2 ] );
+ Unbind( chapter_info[ 3 ] );
chapter_info[ 1 ] := scope_chapter;
end,
+ @Appendix := function()
+ local scope_appendix;
+ scope_appendix := ReplacedString( current_command[ 2 ], " ", "_" );
+ SetCurrentItem( AppendixInTree( tree, scope_appendix ) );
+ Unbind( chapter_info[ 2 ] );
+ Unbind( chapter_info[ 3 ] );
+ chapter_info[ 1 ] := scope_appendix;
+ end,
@ChapterLabel := function()
local scope_chapter, label_name;
if not IsBound( chapter_info[ 1 ] ) then
diff --git a/tst/AutoDocTest/doc/appendix.autodoc b/tst/AutoDocTest/doc/appendix.autodoc
new file mode 100644
index 00000000..9083a735
--- /dev/null
+++ b/tst/AutoDocTest/doc/appendix.autodoc
@@ -0,0 +1,4 @@
+@Appendix Plain-text appendix
+
+This appendix is written in `.autodoc` format and is expected to be included
+through scaffold.appendix.
diff --git a/tst/AutoDocTest/doc/appendix1.xml b/tst/AutoDocTest/doc/appendix1.xml
new file mode 100644
index 00000000..c74817b6
--- /dev/null
+++ b/tst/AutoDocTest/doc/appendix1.xml
@@ -0,0 +1,9 @@
+
+
+
+ XML fixture appendix
+
+ This hand-written XML appendix exercises the existing
+ scaffold.appendix hook alongside generated @Appendix
+ content.
+
diff --git a/tst/AutoDocTest/gap/AutoDocTest.gd b/tst/AutoDocTest/gap/AutoDocTest.gd
index d1ef500e..3cde42a0 100644
--- a/tst/AutoDocTest/gap/AutoDocTest.gd
+++ b/tst/AutoDocTest/gap/AutoDocTest.gd
@@ -25,3 +25,8 @@ DeclareAttribute( "AutoDocTest_Attribute", IsGroup );
#!
#! `AutoDocTest_Property` is a tiny property used to exercise method docs.
DeclareProperty( "AutoDocTest_Property", IsGroup );
+
+#!
+#! `AutoDocTest_Method` is declared separately so the fixture package loads
+#! cleanly when building its manual.
+DeclareOperation( "AutoDocTest_Method", [ IsGroup ] );
diff --git a/tst/AutoDocTest/makedoc.g b/tst/AutoDocTest/makedoc.g
index 4033297a..ecbdf4ea 100644
--- a/tst/AutoDocTest/makedoc.g
+++ b/tst/AutoDocTest/makedoc.g
@@ -3,13 +3,14 @@ LoadPackage("AutoDocTest");
AutoDoc(rec(
autodoc := rec(
- files := [ "doc/chapter2.autodoc" ],
+ files := [ "doc/chapter2.autodoc", "doc/appendix.autodoc" ],
),
gapdoc := rec(
files := [ "gap/AutoDocTest.gd", "gap/AutoDocTest.gi" ],
),
scaffold := rec(
includes := [ "chapter1.xml" ],
+ appendix := [ "appendix1.xml" ],
bib := "AutoDocTest.bib",
),
));
diff --git a/tst/AutoDocTest/tst/manual.expected/_Appendix_Plain-text_appendix.xml b/tst/AutoDocTest/tst/manual.expected/_Appendix_Plain-text_appendix.xml
new file mode 100644
index 00000000..da2a62dd
--- /dev/null
+++ b/tst/AutoDocTest/tst/manual.expected/_Appendix_Plain-text_appendix.xml
@@ -0,0 +1,11 @@
+
+
+
+
+Plain-text appendix
+
+
+This appendix is written in .autodoc format and is expected to be included
+through scaffold.appendix.
+
+
diff --git a/tst/AutoDocTest/tst/manual.expected/_AutoDocAppendicesMainFile.xml b/tst/AutoDocTest/tst/manual.expected/_AutoDocAppendicesMainFile.xml
new file mode 100644
index 00000000..c198a949
--- /dev/null
+++ b/tst/AutoDocTest/tst/manual.expected/_AutoDocAppendicesMainFile.xml
@@ -0,0 +1,4 @@
+
+
+
+<#Include SYSTEM "_Appendix_Plain-text_appendix.xml">
diff --git a/tst/AutoDocTest/tst/manual.expected/_Chapter_SourceAPI.xml b/tst/AutoDocTest/tst/manual.expected/_Chapter_SourceAPI.xml
index e310947c..c04aaaf6 100644
--- a/tst/AutoDocTest/tst/manual.expected/_Chapter_SourceAPI.xml
+++ b/tst/AutoDocTest/tst/manual.expected/_Chapter_SourceAPI.xml
@@ -46,6 +46,16 @@
+
+ AutoDocTest_Method is declared separately so the fixture package loads
+ cleanly when building its manual.
+
+
+
+
+
+
+
diff --git a/tst/manual.expected/_Chapter_Comments.xml b/tst/manual.expected/_Chapter_Comments.xml
index a6690c1f..7f86a5b9 100644
--- a/tst/manual.expected/_Chapter_Comments.xml
+++ b/tst/manual.expected/_Chapter_Comments.xml
@@ -274,6 +274,26 @@ for setting the same chapter as active chapter again.
+
+@Appendix name
+
+
+@Appendix
+This is analogous to @Chapter, but generates Appendix
+elements instead of Chapter elements. When scaffolding generates the main
+XML file, appendices created this way are included automatically after any
+files listed in scaffold.appendix.
+
+Example:
+
+
+
+
+
@Section name
diff --git a/tst/manual.expected/_Chapter_Reference.xml b/tst/manual.expected/_Chapter_Reference.xml
index 5fa123b4..fbdca2d6 100644
--- a/tst/manual.expected/_Chapter_Reference.xml
+++ b/tst/manual.expected/_Chapter_Reference.xml
@@ -161,7 +161,9 @@
-
This entry is similar to opt.scaffold.includes but is used
to specify files to include after the main body of the manual,
- i.e. typically appendices.
+ i.e. typically appendices written directly in &GAPDoc; XML.
+ Appendices created with @Appendix are included automatically
+ after these files when scaffolding generates the main XML file.
bib
-