diff --git a/doc/Comments.xml b/doc/Comments.xml index 77b871b0..2cfbb429 100644 --- a/doc/Comments.xml +++ b/doc/Comments.xml @@ -408,21 +408,34 @@ not finished or temporary files. @BeginChunk, @EndChunk, and @InsertChunk -@BeginChunk name, @EndChunk, and @InsertChunk name -Text insider of a @BeginChunk / @EndChunk part will not be inserted into +@BeginChunk name[ param1,...], @EndChunk, and @InsertChunk name[ param1_value,...] +Text inside of a @BeginChunk / @EndChunk part will not be inserted into the final documentation directly. Instead, the text is stored in an internal buffer. That chunk of text can then later on be inserted in any other place by using the @InsertChunk name command. +Chunks may optionally be parametrized, by specifying a comma-separated +list of parameter names after the chunk name given to @BeginChunk. +Each parameter name must be a valid &GAP; identifier +(and hence may only contain letters, digits and underscores). +When inserting a parametrized chunk, a comma-separated list of +parameter values must follow the chunk name given to @InsertChunk. +The number of parameter values must match the number of parameter names. +When this is done, instead of directly inserting the chunk text, +for every parameter param, every occurrence of the string %{param} +is substituted by the corresponding parameter value. + If you do not provide an @EndChunk, the chunk ends at the end of the file. You can use this to define an example like this in one file: diff --git a/gap/DocumentationTree.gd b/gap/DocumentationTree.gd index 9d91156d..fe6aa565 100644 --- a/gap/DocumentationTree.gd +++ b/gap/DocumentationTree.gd @@ -16,6 +16,9 @@ ## ###################################### +BindGlobal( "AUTODOC_IdentifierLetters", + "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" ); + DeclareGlobalFunction( "AUTODOC_TREE_NODE_NAME_ITERATOR" ); DeclareGlobalFunction( "AUTODOC_LABEL_OF_CONTEXT" ); DeclareGlobalFunction( "AUTODOC_INSTALL_TREE_SETTERS" ); @@ -57,6 +60,7 @@ DeclareOperation( "DocumentationExample", [ IsTreeForDocumentation, IsList ] ); DeclareOperation( "DocumentationExample", [ IsTreeForDocumentation ] ); DeclareOperation( "DocumentationDummy", [ IsTreeForDocumentation, IsString, IsList ] ); DeclareOperation( "DocumentationDummy", [ IsTreeForDocumentation, IsString ] ); +DeclareOperation( "DocumentationDummyInstance", [ IsTreeForDocumentation, IsTreeForDocumentationNode ] ); DeclareOperation( "DocumentationCode", [ IsTreeForDocumentation, IsString, IsList ] ); DeclareOperation( "DocumentationCode", [ IsTreeForDocumentation, IsString ] ); DeclareOperation( "DocumentationManItem", [ IsTreeForDocumentation ] ); diff --git a/gap/DocumentationTree.gi b/gap/DocumentationTree.gi index 30ed3337..d2a2c2c3 100644 --- a/gap/DocumentationTree.gi +++ b/gap/DocumentationTree.gi @@ -10,10 +10,6 @@ ## ############################################################################# -## -BindGlobal( "AUTODOC_IdentifierLetters", - "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" ); - DeclareRepresentation( "IsTreeForDocumentationRep", IsAttributeStoringRep and IsTreeForDocumentation, [ ] ); @@ -117,6 +113,15 @@ BindGlobal( "TheTypeOfDocumentationTreeCodeNodes", NewType( TheFamilyOfDocumentationTreeNodes, IsTreeForDocumentationCodeNodeRep ) ); +## DocumentationDummyInstance +DeclareRepresentation( "IsTreeForDocumentationDummyInstanceNodeRep", + IsTreeForDocumentationNodeRep, + [ ] ); + +BindGlobal( "TheTypeOfDocumentationTreeDummyInstanceNodes", + NewType( TheFamilyOfDocumentationTreeNodes, + IsTreeForDocumentationDummyInstanceNodeRep ) ); + ################################### ## ## Tools @@ -263,6 +268,15 @@ InstallMethod( DocumentationDummy, [ IsTreeForDocumentation, IsString ], return node; end ); +InstallMethod( DocumentationDummyInstance, [ IsTreeForDocumentation, IsTreeForDocumentationDummyNodeRep ], + function( tree, dummy_node ) + local node; + node := rec( dummy_node := dummy_node ); + ObjectifyWithAttributes( node, TheTypeOfDocumentationTreeDummyInstanceNodes, + Label, Concatenation( Label( dummy_node ), "_", String( AUTODOC_TREE_NODE_NAME_ITERATOR( tree ) ) ) ); + return node; +end ); + ## InstallMethod( DocumentationCode, [ IsTreeForDocumentation, IsString, IsList ], function( tree, name, context ) @@ -637,6 +651,36 @@ InstallMethod( WriteDocumentation, [ IsTreeForDocumentationDummyNodeRep, IsStrea fi; end ); +## +InstallMethod( WriteDocumentation, [ IsTreeForDocumentationDummyInstanceNodeRep, IsStream ], + function( node, filestream ) + local dummy, variables, variable_values, new_content, current_variable, current_variable_value, + i, j, current_string, dummy_label; + + dummy := node!.dummy_node; + dummy_label := Label( dummy ); + if not IsBound( dummy!.content ) then + return; + fi; + new_content := ShallowCopy( dummy!.content ); + variables := dummy!.variable_names; + variables := List( variables, i -> Concatenation( "%{", i, "}" ) ); + variable_values := node!.variable_values; + if Length( variables ) <> Length( variable_values ) then + Error( "While inserting chunk ", dummy_label, ": wrong number of parameter values" ); + fi; + for i in [ 1 .. Length( variables ) ] do + current_variable := variables[ i ]; + current_variable_value := variable_values[ i ]; + for j in [ 1 .. Length( new_content ) ] do + new_content[ j ] := ReplacedString( new_content[ j ], current_variable, current_variable_value ); + od; + od; + + WriteDocumentation( new_content, filestream ); + +end ); + ## InstallMethod( WriteDocumentation, [ IsTreeForDocumentationExampleNodeRep, IsStream ], function( node, filestream ) diff --git a/gap/Parser.gi b/gap/Parser.gi index 5ea1fc50..cd58aea5 100644 --- a/gap/Parser.gi +++ b/gap/Parser.gi @@ -613,14 +613,50 @@ InstallGlobalFunction( AutoDoc_Parser_ReadFiles, current_item!.level := Int( current_command[ 2 ] ); end, @InsertChunk := function() - Add( current_item, DocumentationDummy( tree, current_command[ 2 ] ) ); + local parameters, vars, title, inserted_dummy, position_first_space; + parameters := current_command[ 2 ]; + position_first_space := Position( parameters, ' ' ); + if position_first_space = fail then + title := parameters; + vars := [ ]; + elif IsInt( position_first_space ) then + title := parameters{[ 1 .. position_first_space - 1 ]}; + vars := parameters{[ position_first_space + 1 .. Length( parameters ) ]}; + vars := SplitString( vars, "," ); + else + ErrorWithPos( Concatenation( "Wrong InsertChunk parameters: ", parameters ) ); + fi; + inserted_dummy := DocumentationDummyInstance( tree, DocumentationDummy( tree, title ) ); + inserted_dummy!.variable_values := vars; + Add( current_item, inserted_dummy ); end, @InsertSystem := ~.@InsertChunk, @BeginChunk := function() + local parameters, title, vars, current_var; if IsBound( current_item ) then Add( context_stack, current_item ); fi; - current_item := DocumentationDummy( tree, current_command[ 2 ] ); + parameters := SplitString( current_command[ 2 ], " " ); + if Length( parameters ) = 1 then + vars := [ ]; + title := parameters[ 1 ]; + elif Length( parameters ) = 2 then + vars := parameters[ 2 ]; + vars := SplitString( vars, "," ); + title := parameters[ 1 ]; + else + ErrorWithPos( Concatenation( "Wrong chunk parameters: ", current_command[ 2 ] ) ); + fi; + if not ForAll( title, i -> i in AUTODOC_IdentifierLetters ) then + ErrorWithPos( Concatenation( "Wrong character in chunk title: ", title ) ); + fi; + for current_var in vars do + if not ForAll( current_var, i -> i in AUTODOC_IdentifierLetters ) then + ErrorWithPos( Concatenation( "Wrong character in chunk parameter: ", current_var ) ); + fi; + od; + current_item := DocumentationDummy( tree, title ); + current_item!.variable_names := vars; end, @Chunk := ~.@BeginChunk, @System := ~.@BeginChunk,