RakuDoc is a markup language with simple instructions for simple tasks and more complex structures to suit larger projects. There is a clear distinction between documenting intended to help maintain and develop the software, and the visually presentations needed by a newcomer to understand how to use software.

SYNOPSIS§

Consider the two ways in which documentation is used.

Case 1: You are writing internal documentation to aid software design§

    unit class Beginners;
 
    #| a variable to hold number of people 
    has $.participants;
 
    #| data that is initially provided by default, but will be overwritten 
    has $.new-participant = $=finish;
 
    ... # code 
 
    =finish
    default data string for a new participant

A RakuDoc compliant editor or Integrated Design Environment will pick up the text following #| and put it into a pop-up menu whenever you select (e.g. by hovering over) a use of $.participants.

The =finish statement is the last piece of code. Everything after it is treated as a string and placed in the $=finish variable.

There are other possibilities described below.

Case2: You are writing external documentation to accompany some software§

Consider the following short description:

    =begin rakudoc
    =TITLE Tutorial about Flavorizing 
    =SUBTITLE
    A short tutorial on Flavorizing your quarks
 
    =head1 Starting out 
 
    In the section you will learn about how to add flavors to quarks produced
    by the I<Imagiton>.
    It goes without saying that these techniques should B<NOT> be carried out
    without a precocious child nearby; they will strain the imagination of
    an ossified adult.
 
    =head2 What is a flavour 
 
    It is well-known (see the L<Wikipedia article|https://en.wikipedia.org/wiki/Flavour_(particle_physics)>
    that quarks N<a quark is a constituent of a hadron> come in six flavors, for example:
    =item Up 
    =item Bottom 
    =item Charm 
 
    Z< Lots more text >
    =end rakudoc

To indicate that all of the markup above is not Raku code, it is enclosed in a block labelled rakudoc. This is an example of the delimited form of the RakuDoc block (so named because it is specified between =begin and =end directives).

The =TITLE, =SUBTITLE, and =SYNOPSIS are semantic blocks containing standard information that can be searched by other tools. For all other purposes, they can be considered to the same as =head1 blocks.

A =head1 block begins a top-level heading. The =head2 is a second level heading. These are examples of the abbreviated form of RakuDoc blocks. Any non-empty text lines following a heading specifier are collectively treated as the text of the heading.

The =item components are abbreviated blocks with text entries for a list. There is no need to start or stop a list explicitly; the renderer will place each consecutive =item in a list. The first non-=item paragraph or block will end the list.

Within the text there are several examples of inline markup instructions, which have the form Upper Unicode character < > . In the example above, we used: I B N L Z. These are for Important, Basis, Note (a footnote), Link, and Zero (a comment) markup.

Introduction§

RakuDoc has a variety of components that allow for rich structured documents, provide markup hints to renderers without assuming an output format, extract information from compiled programs, provide information to programs, and enable custom developer extensions.

This document describes a revision of RakuDoc modifying the original speculation S26 that was implemented as Raku was developed. RakuDoc is intended to be backwards compatible with the POD6 markup language based on S26.

RakuDoc is extensible and renderers are free to provide extra functionality beyond the minimum set of instructions described here.

Two use cases for RakuDoc§

Rakudoc can be thought of as having components that are closely connected to a program or module that is being documented (code-oriented Rakudoc), and components that can be used for text-oriented documents, such as the source for a webpage or a book (text-oriented Rakudoc).

Code-oriented RakuDoc is expected to be "consumed" by users in an editor or Integrated Design Environment (IDE), while text-oriented RakuDoc is consumed in some rendered version, such as an HTML web page, a command-line manpage, or a chapter in an e-book.

When RakuDoc components are viewed in an editor or IDE to provide information about variables, methods, roles, classes and the like, the information could be made available in a pop-up whenever a documented term is selected in some way (e.g. hovering a mouse over it). In the editor context, RakuDoc blocks and markup should then be treated as a comment to the code. Editors are not expected to render the RakuDoc other than to show the RakuDoc components verbatim, but may do so if it seems expedient.

When RakuDoc components are viewed in a rendered version (for example, as HTML), components related to a running program should be ignored.

Within the body of a program there may be several sections of code, which is called the ambient context, interleaved between sections of RakuDoc.

Sections of code that are intended to be examples within the documentation (i.e. code that is not actual interleaved executable code) can be specified in =code blocks, which are treated as integral parts of the RakuDoc, not as source code in ambient context.

Consider a source file containing the definition of a class. When the file is edited in an IDE (e.g. the class is being developed or maintained) the code-oriented RakuDoc is useful to help the developer understand the internal structure and function of specific elements within the code.

Furthermore, when the class is imported into another Raku program the IDE will be able to access the information in declarator blocks attached to specific terms, without needing the source code to be available.

However, by including text-oriented RakuDoc in the same file, end-user documentation can be provided for the class within the same source file. By passing the source through a renderer, a documentation file (e.g. a README.md file for a github repo) can be generated.

This document describes the minimum version of Rakudoc that a renderer or editor must recognise along with some expected rendering behaviors for text-oriented renderers. "Expected behaviors" means that a renderer should approximate the behavior as far as possible given the limitations of the output format, and that the approximation should be a reasonable interpretation of the standard described here.

The RakuDoc design assumes certain types of customisability, such as the ability to define new blocks or markup instructions. In order to access blocks or functionality not described in this document, the file containing such RakuDoc instructions should contain a use statement that loads a module that provides the information needed to render the extensions. The information provided by this module may be renderer-specific.

Components§

RakuDoc has four main types of components, which are distinguished by their scope and by effect they have on other components.

Directives
Directives define how blocks work. Directives have a similar syntax to regular blocks, but they actually operate on other blocks. New directives cannot be defined.
Blocks
Blocks define complete text components, such as a new paragraph or a code sample or a table. New kinds of blocks can be defined.
Markup instructions
Markup instructions typically define inline items embedded within a block. Some markup instructions only affect the visual rendering of their contents. Others may have side-effects (such as including items into an index or glossary). New markup instructions can be defined.
Metadata options
Options provide information to a block. They may produce side-effects or alter the way a block should be rendered. A document writer can associate any metadata option with any block or directive. A renderer is only required to comply with those listed in this document.

Directive syntax§

These are the syntax forms for each directive. The = of each directive must be the first non-whitespace character on a given line.

  • =begin specifies the start of a delimited block

  • =end specifies the end of a delimited block

  • =for specifies the start of an extended block

  • =finish ends ambient code and is followed by text

  • =alias specifies a text substitution available in subsequent A<...> markup instructions. The general syntax for an alias directive is:

        =alias ALIAS_NAME Text for substitution 
        =                 Optional extra text
  • =config specifies default options to be applied to specific types of blocks or markup instructions. The general syntax for configuration directives is:

        =config BLOCK_TYPE  CONFIG OPTIONS 
        =                   OPTIONAL EXTRA CONFIG OPTIONS

    If the block-type is single uppercase character X, the =config directive applies the specified configuration options to the X markup instruction. For example:

    =config C :allow<B I> 

    This configures the C<> markup instruction to recognize nested B<> and I<> markup instructions (both of which would otherwise be treated as verbatim within a C<> instruction).

    To avoid ambiguities Naming rules are applied to blocks and markup instructions.

Block syntax§

Even though visually similar in some contexts, a block is not a directive...nor vice versa.

Blocks may be specified in three ways:

  • Delimited form

    A delimited block starts with the directive =begin as the first non-whitespace on a line, followed by a valid Raku identifier indicating the name of the block, followed optionally by metadata (see "Metadata" below), followed by content lines. A delimited block is only terminated by an =end directive followed by the same block name. A delimited block that is not terminated by an =end same-block-name instruction throws an error.

    For example, to specify a para block in delimited form:

        =begin para :meta<data>
        This text is the content of the block.
     
        The preceding blank line is also a part of the block,
        as are these two non-blank lines.
        =end para

    The general syntax is:

         =begin BLOCK_TYPE  OPTIONAL CONFIG INFO
         =                  OPTIONAL EXTRA CONFIG INFO
         BLOCK CONTENTS
         =end BLOCK_TYPE
  • Extended form

    An extended block begins with the directive =for as the first non-whitespace on a line, followed by the name of the block, followed by optional metadata. The next non-blank lines after the metadata specify the content of the block, which is terminated either by the first entirely blank line after the content or by the first line that begins with a RakuDoc directive. For example, to specify a para block in extended format:

        =for para :meta<data>
        This text is the content of the block.
     
        This text is NOT content of the block.
        After a blank linea new block is started.

    The general syntax is:

         =for BLOCK_TYPE  OPTIONAL CONFIG INFO
         =                OPTIONAL EXTRA CONFIG INFO
         BLOCK DATA
  • Abbreviated form

    In an abbreviated block, the name of the block immediately follows an = sign, which must be the first non-whitespace character on the line. Everything after the block name (up to the first blank line or directive line) is considered the content of the block. For example, to specify a para block in abbreviated form:

        =para This text is the content of the block.
     
        This text is NOT content of the block.
        After a blank linea new block is started.

    Note that abbreviated blocks cannot be specified with metadata. Any apparent metadata elements placed after an abbreviated block name are instead considered to be part of the block contents.

Markup instruction syntax§

The general syntax of a markup instruction is

<Instruction><opening marker><content>|<meta list><closing marker>
  • <Instruction>

    This is a single uppercase letter, or a unicode entity with the UPPER property

  • <opening marker>

    This is either one-or-more < characters or a single Β« character (i.e. The Unicode entity E<00AB>)

  • <content>

    This is a string that does not contain the | character (i.e. Unicode entity E<007C>), unless that character is inside a nested markup instruction.

  • <meta list>

    Is a list of strings separated by , or ;, depending on the semantics imposed by the <Instruction>

  • <closing marker>

    Is one-or-more > or a single Β» (i.e. Unicode entity E<00BB>). The closing marker must be symmetrical with the markup instruction's opening marker. That is, it must consist of the same number of > or Β» as there were < or Β« in the opening marker.

For example:

This is U<unusual> textand this is I<important>.
And this is a L<link to the Raku Programming Language|https://raku.org>.

Which would be rendered as:

For example: This is unusual text, and this is important. And this is a link to the Raku Programming Language.

Metadata syntax§

Metadata is specified using Raku option pairs. The following are examples:

Value is...Specify with...
True:key
False:!key
Literal:key<answer>
List:key("foo", 42)
Hash:key{ :note('Rosebud, they said'), :emphasize }

Numerical values can be specified in any Raku-compatible format (42, 42.0, 42e0, 0x2a, 0d42, 0o52, 0b101010). Strings can either be specified using single or double quotes, or angle brackets ('foo', "bar", <baz> ). Note that if a string with whitespace is specified in angle brackets, it is in fact a list of strings: <foo bar baz> is the same as ('foo','bar','baz') .

Within the context of the parser of the Raku Programming Language, it is also possible to refer to any compile-time value inside the meta-data.

The metadata of an extended block or abbreviated block may extend beyond the first line declaring the block. Each subsequent line must start with an = in the first virtual column, meaning that it must vertically align with the = of the RakuDoc block declaration, and it must be followed by at least one horizontal whitespace character.

For example:

     =for head1 :a-first-line-key<firstvalue> :another-first-line-key<xyz>
     =          :a-second-line-key(42)
     = :a-third-line-key<third>
     Content for the header block

Directives§

Directives are similar in form to block instructions, but they do not have the extended or delimited forms. If a directive name is preceded by a =begin, =for or =end, then an error will be thrown.

Aliases§

The =alias directive provides a way to define block-scoped synonyms for longer RakuDoc sequences, (meta)object declarators from the code, or even entire chunks of ambient source. These synonyms can then be inserted into subsequent Pod using the A<> formatting code.

An =alias is scoped to the surrounding RakuDoc block.

The alias directive takes two arguments. The first is an identifier (which is usually specified in uppercase, though this is not mandatory). The second argument consists of one or more lines of replacement text.

Each =alias directive creates a block-scoped RakuDoc macro that can be invoked during document generation by placing the identifier (i.e. the first argument of the alias) in an A<> formatting code. This formatting code is then replaced by the text returned by the new macro.

The replacement text returned by the alias macro begins at the first non-whitespace character after the alias's identifier, and continues to the end of the line. You can extend the replacement text over multiple lines by starting the following line(s) with an = (at the same level of indentation as the =alias directive itself) followed by at least one whitespace. Each additional line of replacement text uses the original line's (virtual) left margin, as specified by the indentation of the replacement text on the =alias line.

For example:

    =alias PROGNAME    Earl Irradiatem Evermore 
    =alias VENDOR      4D Kingdoms 
    =alias TERMS_URLS  =item L<http://www.4dk.com/eie> 
    =                  =item L<http://www.4dk.co.uk/eie.io/>
    =                  =item L<http://www.fordecay.ch/canttouchthis>
 
    The use of A<PROGNAME> is subject to the terms and conditions
    laid out by A<VENDOR>as specified at:
 
        A<TERMS_URLS>
 

This would produce:

The use of Earl Irradiatem Evermore is subject to the terms and
conditions laid out by 4Kingdoms Incas specified at:
 
    =item L<http://www.4dk.com/eie> 
    =item L<http://www.4dk.co.uk/eie.io/> 
    =item L<http://www.fordecay.ch/canttouchthis>

The advantage of using aliases is, obviously, that the same alias can be reused in multiple places in the documentation. Then, if the replacement text ever has to be changed, it need only be modified in a single place:

    =alias PROGNAME    Count Krunchem Constantly 
    =alias VENDOR      Last Chance Receivers Intl 
    =alias TERMS_URLS  L<http://www.c11.com/generic_conditions> 

Block specifiers§

The =begin, =end, and =for directives all specify types of blocks. They have already been illustrated in multiple examples and will not be described further here.

Config§

All block forms can be associated with metadata options. Typically the metadata are specified for a block using the extended or delimited forms.

If the same option needs to be added to multiple blocks, this can be done using a config directive, and then the abbreviated block form can be used in the same block scope.

For example, suppose we want all =code blocks to be labeled with a `:delta` within some section of a document (More information on developer notes). Rather than add a :delta modifier to every individual =code, we could configure every =code block to be automatically given the same developer note, like so:

    =config code :delta(v2.3.2+'oFun enhancements'
    =code method droll { say 'what a cool operator' } 
    =code method drool { say 'what a slob' } 
    =code method drill { say 'keep up' } 

Document termination§

The =finish directive indicates the end of all ambient contexts within the document. This means that the parser will treat all the remaining text in the file as a string.

Any text after the =finish block can be accessed as a string within the program (i.e. the ambient code) via the $=finish variable. This can be used to provide data to a program, such as a test.

    use JSON::Fast;
    my %h = from-json$=finish );
    say %h.raku;
    # more lines of code 
 
    =finish
    { "key1": "a string value""key2": "another value" }

This will generate the following output:

    {:key1("a string value"), :key2("another value")}

Table constructors§

The =row and =column instructions are directives, not blocks, and they are described in more detail in the section on the procedural =table block.

Code-oriented RakuDoc§

The following RakuDoc components are primarily intended for use when editing within an editor. Standalone renderers may ignore them.

Declarator blocks§

Declarator blocks differ from other blocks in that they do not have a specific type. Instead, they are attached to a particular element of the ambient source code.

Declarator blocks are introduced by a special comment: either #| or #=, which must be immediately followed by either a space or an opening bracket character, such as a curly brace {, ( or Β«. If followed by a space, the block is terminated by the end of line; if followed by one or more opening bracket character, the block may extend over multiple lines and is terminated by the matching sequence of closing bracket characters.

RakuDoc markup instructions may be used inside declarator blocks.

Blocks starting with #| are attached to the code after them, and blocks starting with #= are attached to the code before them.

Since declarator blocks are attached to source code, they can be used to document classes, roles, subroutines and in general any statement or block.

The WHY method can be used on these classes, roles, subroutines, etc. to return the attached RakuDoc value.

For example:

#| Base class for magicians 
class Magician {
  has Int $.level;
  has Str @.spells;
}
 
 
#| Fight mechanics 
sub duel(  #= Magicians only, no mortals. 
  Magician $a,  #= first magician 
  Magician $b,  #= second magician 
{
}
 
say Magician.WHY# OUTPUT: Β«Base class for magicians␀» 
say &duel.WHY.leading# OUTPUT: Β«Fight mechanics␀» 
say &duel.WHY.trailing# OUTPUT: Β«Magicians only, no mortals.␀» 
say &duel.signature.params[0].WHY;  # OUTPUT: Β«first magician␀» 
say &duel.signature.params[1].WHY;  # OUTPUT: Β«second magician␀» 

These declarations can extend to several lines. For example:

#|( This is an example of stringification: 
    * Numbers turn into strings
    * Regexes operate on said strings
    * C<with> topicalizes and places result into $_
)
sub search-in-seq
#=Β« Uses 
    * topic
    * decont operator
Β»
  ( Int $endInt $number ) {
    with (^$end).grep( /^$number/ ) {
        .say for $_<>;
    }
}

A useful idiom is to place trailing declarator blocks on the parameters of the MAIN sub. These comments will be picked up automatically by USAGE.

    sub MAIN(
        Str $first,    #= the first CLI parameter 
        Int :$verbose#= an integer to indicate output, 0 = no output 
    )

Data blocks§

=data blocks are used to specify named and/or ordered chunks of data for the ambient code. They may appear anywhere within a source file, and as many times as required.

The corresponding variable, $=data holds an object that does both the Associative and Positional roles.

Each =data block can be given a :key option, to name it. The contents of any =data block with a key are accessible (as a single string) via the Associative aspect of $=data object. For example:

    =begin data :key<Virtues>
    Laziness
    Impatience
    Hubris
    =end data
 
    say 'The three virtues are:';
    say $=data<Virtues>;
 

The contents of any =data block that does not have a :key are accessible (as a single string) via the Positional aspect of $=data. Unkeyed =data blocks are stored in the same order they appear in the file. For example:

    say 'The second anti-virtue is: '$=data[1];
 
    =data Industry 
    =data Patience 
    =data Humility 
 

Note that, as the preceding example illustrates, because RakuDoc is a compile-time phenomenon, it is possible to specify =data blocks after the point in the source where their contents will be used (provided they're not being used in a BEGIN, of course).

When $=data itself is stringified, it returns the concatenation of all the unkeyed =data blocks the parser has seen.

=data blocks are never rendered by the text-oriented Rakudoc renderers.

Text-oriented RakuDoc§

The Rakudoc instructions in this section are primarily intended for text-oriented rendering. However, text-oriented and code-oriented Rakudoc can be freely intermixed with Raku code in a single file; this may help to create code that is well-documented.

When a Raku compiler parses a file, line contents are expected to be Raku code (ambient text). When a RakuDoc block is finished, the next line is assumed to revert to ambient text.

    #start of file 
    my $text# ambient code 
 
    =head this is some text 
    this line continues the header
 
    #this line is now ambient code and so must be specified as a comment 

A rakudoc block reverses this assumption.

    #start of file 
    my $text# ambient code 
    =begin rakudoc
 
    =head this is some text 
    this line continues the header
 
    this line is not ambient code and so
    it will be treated as an ordinary paragraph
    =end rakudoc
    # this line is now ambient code 

Files that are intended to contain text-oriented documentation alone should be entirely enclosed in a rakudoc block.

Historically the name pod was used for this functionality. For compatibility it will still be possible to use the name pod instead of rakudoc in the foreseeable future. Note however that the Raku Programming Language may assign slightly different semantics to rakudoc at some time in the future.

Headings§

Headings can be defined using =headN, where N is greater than zero (e.g. =head1, =head2, etc.). =head is an alias for =head1.

=head1 A top level heading 
 
=head2 A second level heading 
 
=head3 A third level heading 

Numbered headings§

You can specify that a heading is numbered using the =numhead block. For example:

    =numhead1 The Problem 
 
    =numhead1 The Solution 
 
        =numhead2 Analysis 
 
            =head3 Overview 
 
            =head3 Details 
 
        =numhead2 Design 
 
    =numhead1 The Implementation 

which would produce:

1. The Problem
 
2. The Solution
 
    2.1. Analysis
 
        Overview
 
        Details
 
    2.2. Design
 
3. The Implementation

A document has an inherent numbering for every heading, but only the =numheadN block makes the numeration visible in the heading and in the Table of Contents.

Note that, even though renderers are not required to distinctly render more than the first four levels of heading, they are required to correctly honour arbitrarily nested numberings. That is:

    =numhead6 The Rescue of the Kobayashi Maru 

should produce something like:

2.3.8.6.1.9. The Rescue of the Kobayashi Maru

Block scope§

A block scope is important for the =config and =alias directives. In addition, some renderers may generate secondary pages from primary source files, for example, gathering together the same method names in multiple classes. It is desirable for all the relevant blocks to be gathered together.

Sections§

The section block will typically only be used in the delimited form so that the document writer can define an explicit block scope. The =begin section declaration starts a new block scope, and the =end section returns the scope to the previous one. Unlike an =end rakudoc, an =end section does not always change the scope back to ambient code. It only does so when its corresponding =begin section changed the scope from ambient code. In contrast, an =end rakudoc always reverts to ambient code.

Sections may be embedded within other sections.

When a =begin section is not present, a renderer may apply the following heuristic to determine the block scope (assuming X, Y, and Z are digits such that 0 < X < Y < Z ):

  • A =headY declaration starts a new block scope.

  • The next =headY declaration ends the block scope of the previous =headY

  • A =headZ declaration following a =headY is within the block scope of the preceding =headY declaration, and does not end it.

  • A =headX declaration ends the scope of any preceding =headY and =headZ declarations.

Note that a =begin section declaration overrides the heuristic, meaning that multiple =headX declarations can be placed within the same block scope.

A renderer is not expected to render blocks differently when they are embedded in a section block.

Providing metadata to a =begin section block definition is not the same as declaring metadata using a =config directive. Metadata in a config is provided to all matching blocks in the current block scope. Metadata in the =begin section declaration is only applied to the section itself, not to the blocks it contains.

For example, suppose the following RakuDoc text was included in a source file

    =begin section :delta(v2.3.2-, 'removed due to conflict with chancellors')
    =head2 role fool 
 
    This role is especially important in authoritarian kingdoms to remind kings of their humanity.
 
    =end section

If a user indicates to a renderer that they wish to view documentation valid today, which corresponds (for example) to v3.1.1 then, because v3.1.1 is after v2.3.2, the section above – including the nested =head2 block and the following plain paragraph – would not be rendered.

If however, a user indicates they wish to view documentation for v2, the renderer would render the section above, including an indication the section will be removed in v2.3.2.

Document scope§

A =begin rakudoc declaration (or equivalently a =begin pod) also defines a new scope, and also has the effect that code following it is not considered Raku code.

An =end rakudoc will return scope to the ambient code. This also means that rakudoc blocks cannot be nested, while section blocks may be nested.

The first =begin rakudoc declaration in a document starts the RakuDoc scope of the document. Metadata following the first such declaration are made available to all blocks in the document.

Ordinary paragraphs§

An ordinary paragraph consists of text that is to be formatted into a document at the current level of nesting, with whitespace squeezed, lines filled, and any special inline mark-up applied.

Ordinary paragraphs consist of one or more consecutive lines of text, each of which starts with a non-whitespace character. The paragraph is terminated by the first blank line or directive.

For example:

=head1 This is a heading block 
 
This is an ordinary paragraph.
Its text  will   be     squeezed     and
short lines filled. It is terminated by
the first blank line.
 
This is another ordinary paragraph.
Its     text    will  also be squeezed and
short lines filled. It is terminated by
the trailing directive on the next line.
 
    =head2 This is another heading block 
 
    This is yet another ordinary paragraph,
    at the first virtual column set by the
    previous directive

Ordinary paragraphs do not require an explicit marker or delimiters (within a rakudoc block).

Alternatively, there is also an explicit =para marker that can be used to explicitly mark a paragraph, which would be necessary outside a rakudoc block.

=para
This is an ordinary paragraph.
Its text  will   be     squeezed     and
short lines filled.

This is rendered as:

This is an ordinary paragraph. Its text will be squeezed and short lines filled.

In addition, the longer =begin para and =end para form can be used. For example:

=begin para
This is an ordinary paragraph.
Its text  will   be     squeezed     and
short lines filled.
 
This is still part of the same paragraph,
which continues until an...
=end para

As demonstrated by the previous example, within a delimited =begin para and =end para block, any blank lines are preserved.

Nesting or indenting a block§

RakuDoc provides a =nested block that marks all its contents as being nested:

    =begin nested
    We are all of us in the gutter,
 
    but some of us are looking at the stars!
        =begin nested
        -- Oscar Wilde
        =end nested
    =end nested

...which would produce:

We are all of us in the gutter,

but some of us are looking at the stars!

-- Oscar Wilde

Nesting blocks can contain any other kind of block, including implicit paragraph and code blocks. Note that the relative physical indentation of the nested blocks plays no role in determining their ultimate indentation in the final rendering. The preceding example could equally have been specified:

    =begin nested
    We are all of us in the gutter,
 
    but some of us are looking at the stars!
    =begin nested
    -- Oscar Wilde
    =end nested
    =end nested

Verbatim blocks§

Normally a writer does not want to consider the way text flows on a page. They want the end of each line to be treated the same as a space, and for extra spaces to be eliminated. However, the exact placing of whitespace sometimes is important, especially for code.

Code blocks§

Code blocks are used to specify pre-formatted text (typically source code), which should be rendered without rejustification, without whitespace squeezing, and by default without recognizing any inline markup instructions. Code blocks also have an implicit nesting associated with them. Typically these blocks are used to show examples of code, mark-up, data formats, or other textual specifications. They are usually rendered using a fixed-width font.

A code block may be implicitly specified as one or more lines of text, each of which starts with a whitespace character at the block's virtual left margin. The implicit code block is then terminated by a blank line or an explicit directive. For example:

    This ordinary paragraph introduces a code block:
 
        $this = 1 * code('block');
        $which.is_specified(:by<indenting>);

Implicit code blocks may be used elsewhere with some caveats.

There is also an explicit =code block (which can be specified within any block type, not just =rakudoc, =item, etc.):

     The C<loud_update()> subroutine adds feedback:
 
        =begin code
 
        sub loud_update ($who, $status) {
            say "$who -> $status";
 
            silent_update($who, $status);
        }
 
        =end code

As the previous example demonstrates, within an explicit =code block the code does not have to be indented; it can start at the (virtual) left margin. Furthermore, lines that start with whitespace characters after that margin have subsequent whitespace preserved exactly (in addition to the implicit nesting of the code). Explicit =code blocks may also contain empty lines.

Preprocessing and postprocessing of code§

The code in a document is almost always related to a specific programming language, by default Raku. But examples of Ruby, C, RakuDoc, or other languages may also appear in the Raku documentation sources.

A renderer should offer the option to use syntax highlighting to render code in a code block, perhaps by specifying a :syntax-highlighting metadata option for code blocks. By default, a renderer will not change the contents of a code block, but see the caveat when :allow is used.

The :lang< ... > metadata option may be used to specify that the contents of a given =code block are in a given language. If the specified language is unknown to a renderer, it may choose either to default to Raku syntax highlighting, or may apply some other heuristic.

I/O blocks§

RakuDoc provides blocks for specifying the input and output of programs. These are similar to code blocks in that they preserve whitespace and are rendered distinctly from regular text paragraphs.

The =input block is used to specify pre-formatted keyboard input, which should be rendered without re-justification or squeezing of whitespace.

The =output block is used to specify pre-formatted terminal or file output, which should also be rendered without re-justification or whitespace-squeezing.

Although they are rendered with verbatim whitespace, like a code block, input and output blocks differ from code blocks in that they do recognize any inline mark-up instructions within their text.

For example:

    =begin output
            Name:    Baracus, B.A.
            Rank:    Sgt
            Serial:  1PTDF007
 
            Do you want additional personnel details? K<y>
 
            Height:  180cm/5'11"
            Weight:  104kg/230lb
            Age:     49
 
            Print? K<n>
        =end output
 

In this example, the two embedded K<...> sequences would be recognized as inline mark-up and rendered appropriately (i.e. as keyboard input).

Markup within verbatim blocks§

Although =code blocks automatically disregard all markup instructions, occasionally you may still need to specify some markup within a code block. For example, you may wish to emphasize a particular keyword in an example (using a B<> code). Or you may want to indicate that part of the example is metasyntactic (using the R<> code). Or you might need to insert a non-ASCII character (using the E<> code).

You can specify a list of markup instructions that should still be recognized within a code block using the :allow option. The value of the :allow option must be a list of the (single-letter) names of one or more markup instructions. Those codes will then remain active inside the code block. For example:

    =begin code :allow< B R > :lang<rakudoc>
    sub demo {
        B<say> 'Hello R<name>';
        I<note> 'The I format is not recognised';
    }
    =end code

This would be rendered:

sub demo {
    say 'Hello name';
    I<note> 'The I format is not recognised';
}

It should be noted that both :allow and :lang (if :syntax-highlighting is true) will affect the rendering of the content of the block. This is likely to cause conflicts in some cases. The renderer is free to choose how to resolve such conflicts, e.g. by disregarding the :allow metadata.

Lists§

Lists in RakuDoc are specified as a series of contiguous =item blocks. No special "container" directives or other list delimiters are required to enclose the entire list.

Note that =item is just an abbreviation for =item1.

Unordered lists§

Lists in RakuDoc are by default unordered. For example:

The three suspects are:
 
=item  Happy 
=item  Sleepy 
=item  Grumpy 

This produces:

The three suspects are:

  • Happy

  • Sleepy

  • Grumpy

The bulleting strategy used for different levels within a nested list is entirely up to the renderer.

Multi-level lists§

Lists may be multi-level, with items at each level specified using the =item1, =item2, =item3, etc. blocks. (The indentation depends on the rendering engine and does not need to be included in the RakuDoc markup.) Up to four levels are normally differentiated.

For example:

=item1  Animal 
=item2     Vertebrate 
=item3     Mammals 
=item4     Primates 
=item2     Invertebrate 
 
=item1  Phase 
=item2     Solid 
=item3        Crystalline 
=item3        Amorphous 
=item2     Liquid 
=item2     Gas 

This would produce:

  • Animal

    • Vertebrate

      • Mammals

        • Primates

    • Invertebrate

  • Phase

    • Solid

      • Crystalline

      • Amorphous

    • Liquid

    • Gas

Note, however, that item blocks within the same list are not physically nested. That is, lower-level items should not be specified inside higher-level items:

    =comment THE WRONG WAY... 
    =begin item1          β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    The choices are:                     |
    =item2 Liberty          β”€β”€β”€ Level 2  β”œβ”€β”€β”€ Level 1 
    =item2 Death            β”€β”€β”€ Level 2  | 
    =item2 Beer             β”€β”€β”€ Level 2  | 
    =end item1            β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
 
    =comment THE CORRECT WAY... 
    =begin item1          β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    The choices are:                     β”œβ”€β”€β”€ Level 1
    =end item1            β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    =item2 Liberty        β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Level 2 
    =item2 Death          β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Level 2 
    =item2 Beer           β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Level 2 

Multi-paragraph lists§

Using the delimited form of the =item block (=begin item and =end item), we can specify items that contain multiple paragraphs.

For example:

Let's consider two common proverbs:
 
=begin item
I<The rain in Spain falls mainly on the plain.>
 
This is a common myth and an unconscionable slur on the Spanish people,
the majority of whom are extremely attractive.
=end item
 
=begin item
I<The early bird gets the worm.>
 
In deciding whether to become an early riser, it is worth considering
whether you would actually enjoy annelids for breakfast.
=end item
 
As you can seefolk wisdom is often of dubious value.

This renders as:

Let's consider two common proverbs:

  • The rain in Spain falls mainly on the plain.

    This is a common myth and an unconscionable slur on the Spanish people, the majority of whom are extremely attractive.

  • The early bird gets the worm.

    In deciding whether to become an early riser, it is worth considering whether you would actually enjoy annelids for breakfast.

As you can see, folk wisdom is often of dubious value.

Ordered lists§

A =numitemN expresses the inherent numeration of a list:

     =numitem1 Visito 
     =numitem2 Veni 
     =numitem2 Vidi 
     =numitem2 Vici 

This would produce something like:

1. Visito

1.1. Veni

1.2. Vidi

1.3. Vici

The numbering scheme is at the discretion of the renderer. A renderer might, for example, provide a scheme similar to the examples here, and also provide an enhancement, such as `:html-ordered` that leverages the `<ul type="A">` markup.

The numbering of successive =numitem1 list items increments automatically, but is reset to 1 whenever any other kind of non-ambient Pod block appears between two =numitem1 blocks. For example:

    The options are:
 
    =numitem1 Liberty 
    =numitem1 Death 
    =numitem1 Beer 
 
    The tools are:
 
    =numitem1 Revolution 
    =numitem1 Deep-fried peanut butter sandwich 
    =numitem1 Keg 

This would produce:

The options are:

1. Liberty

2. Death

3. Beer

The tools are:

1. Revolution

2. Deep-fried peanut butter sandwich

3. Keg

The numbering of nested items (=numitem2, =numitem3, etc.) only resets to 1 when a higher-level item's numbering either resets or increments.

To prevent a =numitemN from resetting after a non-item block, you can specify the :continued option:

     =numitem1 Retreat to remote Himalayan monastery 
 
     =numitem1 Learn the hidden mysteries of space and time 
 
     I<????>
 
     =for numitem1 :continued
     Prophet!

This produces:

1. Retreat to remote Himalayan monastery

2. Learn the hidden mysteries of space and time

????

3. Prophet!

Normally, if two =numitemN blocks are separated by some other kind of block (for example, a =para, =code, or =table block), then the numbering of the second =numitemN block resets to 1.

However, if the second =numitemN block is specified with a :continued option the numbering of that second block does not reset, but increments instead (i.e. as if there had been no intervening non-numbered block).

The :continued option has no effect on any higher- or lower-numbered =numitem blocks that are currently active in the same scope. That is: a =for numitemN :continued causes the numbering of every active =numitemZ block (where Z > N) to reset to 1, and the numbering of every active =numitemA block (where A < N) stays the same.

A =numitem is the same as a =numitem1, by analogy with =item and =head.

The underlying paradigm is that every sequence of list instructions (that is: =itemN and/or =numitemN instructions) has an inherent numeration. The =numitemN instructions express the numeration when rendered, while the =itemN instructions do not.

When a sequence of list instructions is terminated by another sort of block then by default a new list is created with its own inherent numeration. By specifying :continued on the next list instruction, the previous inherent numeration is preserved and continued.

Definition lists§

Lists that define terms or commands can be specified using the =defn block, which is equivalent to HTML DL lists in HTML.

A definition contains two parts: a term and a defining text. The term is the contents of the first line of the defn block (i.e. the text immediately after an abbreviated =defn, or the first line after a =for defn or =begin defn). The defining text is the remaining lines within the scope of the defn block. A renderer is expected to distinguish between the term and the defining text.

For example:

=defn Happy 
When you're not blue.
 
=defn Blue 
When you're not happy.

...will be rendered as:

Happy
When you're not blue.
Blue
When you're not happy.

A renderer is expected to retain the information generated by a definition list, and the defining text may be targeted by a link markup instruction.

Numbered definitions§

Definitions can be numbered in the same way as =item lists. That is a =numdefn instruction will express the inherent numeration of the definition list when it is rendered.

As with ordinary lists, if a =numdefn instruction is associated with a :continued metadata option, then the preceding definition list's inherent numeration is preserved and continued.

For example:

    =numdefn AAA
    first letters

    =numdefn BBB
    second letters

    A normal para

    =numdefn XXX
    ending letters

    =numdefn YYY
    finals

will yield something like:

1. ΓΏΓΏ<strong>ΓΏΓΏAAAΓΏΓΏ</strong>ΓΏΓΏ
  first letters
2. ΓΏΓΏ<strong>ΓΏΓΏBBBΓΏΓΏ</strong>ΓΏΓΏ
  second letters
A normal paragraph
1. ΓΏΓΏ<strong>ΓΏΓΏXXXΓΏΓΏ</strong>ΓΏΓΏ
  ending letters
2. ΓΏΓΏ<strong>ΓΏΓΏYYYΓΏΓΏ</strong>ΓΏΓΏ
  finals

In order to continue a list, an explicit :continued is needed, such as:

    =numdefn AAA
    first letters

    =numdefn BBB
    second letters

    A normal para

    =for numdefn ΓΏΓΏ<strong>ΓΏΓΏ:continuedΓΏΓΏ</strong>ΓΏΓΏ
    XXX
    ending letters

    =numdefn YYY
    finals

will yield something like

1. ΓΏΓΏ<strong>ΓΏΓΏAAAΓΏΓΏ</strong>ΓΏΓΏ
  first letters
2. ΓΏΓΏ<strong>ΓΏΓΏBBBΓΏΓΏ</strong>ΓΏΓΏ
  second letters
A normal paragraph
3. ΓΏΓΏ<strong>ΓΏΓΏXXXΓΏΓΏ</strong>ΓΏΓΏ
  ending letters
4. ΓΏΓΏ<strong>ΓΏΓΏYYYΓΏΓΏ</strong>ΓΏΓΏ
  finals

Suppose a writer needs every numbered definition to form a single monotonic sequence within some block scope (e.g. for every definition within a document section, or every definition throughout the entire document). This would require every =numdefn to be specified with a :continued option. Or the writer could simply pre-configure every =numdefn within the scope, as follows:

    =config numdefn :continued

Tables§

Tables can be specified in RakuDoc using a =table block using either a visual definition, or a procedural definition. The visual semantics allow for a simple table to be quickly specified, but the simplicity imposes a number of constraints. The procedural semantics overcome those constraints by describing the contents of rows, columns, and cells.

A table may be given an associated description or title using the :caption option and included in the Table of Contents.

A procedural table may only be specified in the delimited form. As will become clear below, procedural semantics are assumed if the next Rakudoc instruction after a =begin table is one of =row, =column, or =cell.

Visual description of simple tables§

In a visual table specification, columns are separated by two or more consecutive whitespace characters (e.g. double-space or twin-tabs), or by a vertical line (|) or a border intersection (+), either of which must be separated from any content by at least one whitespace character. Note that only one column separator type is allowed in a single line, but different lines are allowed to use different visible column separator types (though that style is not recommended). Using a mixture of visible and non-visible column separator types in a table is an error.

Rows can be specified in one of two ways: either one row per line, with no separators; or multiple lines per row with explicit horizontal separators (whitespace, intersections (+), or horizontal lines: -, =, _) between every row. Either style can also have an explicitly separated header row at the top. If rows are using the two-whitespace-character separator, the row cells should be carefully aligned to ensure the table is interpreted as the user intended.

Each individual table cell is separately formatted, as if it were a nested =para. Note that table rows are expected to all have the same number of cells.

This means you can create tables compactly, line-by-line:

    =table
        The Shoveller   Eddie Stevens     King Arthur's singing shovel
        Blue Raja       Geoffrey Smith    Master of cutlery
        Mr Furious      Roy Orson         Ticking time bomb of fury
        The Bowler      Carol Pinnsler    Haunted bowling ball

or line-by-line with multi-line headers:

    =table
        Superhero     | Secret          |
                      | Identity        | Superpower
        ==============|=================|================================
        The Shoveller | Eddie Stevens   | King Arthur's singing shovel
        Blue Raja     | Geoffrey Smith  | Master of cutlery
        Mr Furious    | Roy Orson       | Ticking time bomb of fury
        The Bowler    | Carol Pinnsler  | Haunted bowling ball

or with multi-line headers and multi-line data:

    =begin table :caption('The Other Guys')
 
                        Secret
        Superhero       Identity          Superpower
        =============   ===============   ===================
        The Shoveller   Eddie Stevens     King Arthur's
                                          singing shovel
 
        Blue Raja       Geoffrey Smith    Master of cutlery
 
        Mr Furious      Roy Orson         Ticking time bomb
                                          of fury
 
        The Bowler      Carol Pinnsler    Haunted bowling ball
 
    =end table

Valid tables§

Following are examples of valid tables.

=begin table
        The Shoveller   Eddie Stevens     King Arthur's singing shovel
        Blue Raja       Geoffrey Smith    Master of cutlery
        Mr Furious      Roy Orson         Ticking time bomb of fury
        The Bowler      Carol Pinnsler    Haunted bowling ball
=end table
=table
    Constants           1
    Variables           10
    Subroutines         33
    Everything else     57
 
=for table
    mouse    | mice
    horse    | horses
    elephant | elephants
 
=table
    Animal | Legs |    Eats
    =======================
    Zebra  +   4  + Cookies
    Human  +   2  +   Pizza
    Shark  +   0  +    Fish
 
=table
        Superhero     | Secret          |
                      | Identity        | Superpower
        ==============|=================|================================
        The Shoveller | Eddie Stevens   | King Arthur's singing shovel
 
=begin table
 
                        Secret
        Superhero       Identity          Superpower
        =============   ===============   ===================
        The Shoveller   Eddie Stevens     King Arthur's
                                          singing shovel
 
        Blue Raja       Geoffrey Smith    Master of cutlery
 
        Mr Furious      Roy Orson         Ticking time bomb
                                          of fury
 
        The Bowler      Carol Pinnsler    Haunted bowling ball
 
=end table
=table
    X | O |
   ---+---+---
      | X | O
   ---+---+---
      |   | X
 
=table
    X   O
   ===========
        X   O
   ===========
            X
 
=begin table
 
foo
bar
 
=end table

Invalid tables§

Following are examples of invalid tables, and they should trigger an unhandled exception during parsing.

  • Mixed column separator types in the same row are not allowed:

=begin table
r0c0 +  r0c1 | r0c3
=end table
  • Mixed visual and whitespace column separator types in the same table are not allowed:

=begin table
r0c0 +  r0c1 | r0c3
r1c0    r0c1   r0c3
=end table
  • Two consecutive interior row separators are not allowed:

=begin table
r0c0 |  r0c1
============
============
r1c0 |  r1c1
=end table

Unexpected tables§

Following are examples of valid tables that are probably intended to be two columns. However, the columns in these examples are not aligned well, so each will parse as a single-column table.

  • Unaligned columns with WS column separators:

    Notice the second row has the two words separated by only one WS character, while it takes at least two adjacent WS characters to define a column separation. This is a valid table but will be parsed as a single-column table.

        =begin table
        r0c0    r0c1
         r1c0 r0c1
        =end table
  • Unaligned columns with visual column separators:

    Notice the second row has the two words separated by a visible character ('|') but the character is not recognized as a column separator because it doesn't have an adjacent WS character on both sides of it. Although this is a legal table, the result will not be what the user intended because the first row has two columns while the second row has only one column, and it will thus have an empty second column.

    =begin table
    r0c0  |  r0c1
     r1c0 |r0c1
    =end table

Procedural description of tables§

A visual table is useful for most purposes, but a procedural description is needed if one or more of the following are required:

  • row labels,

  • vertical or horizontal alignments of individual cells, of complete rows or columns, or of the entire table,

  • cells spanning multiple rows and/or columns,

  • cells that include other RakuDoc blocks, such as a nested sub-table or a code block.

Table semantics are procedural if the =table declarator is immediately followed by =cell, =row, or =column, otherwise visual semantics are assumed.

Only =cell, =row, =column, or =comment declarations are permitted within the immediate block scope of a procedural table. Note that both =cell and =comment introduce their own block scopes, so other RakuDoc blocks (including nested tables) may be included within their block scopes.

The fundamental idea is that a procedural =table sets up a semi-infinite 2D grid of cells, all of which are initially empty. The grid also tracks the fill position ($POS: the next empty cell to be filled), and the fill direction ($DIR: the direction to move $POS after filling; either across or down).

Subsequent =cell blocks start filling that grid in, with any intervening =row and =column directives adjusting $POS and $DIR.

=cell blocks can be specified as spanning multiple rows and/or columns, using the :row-span(WIDTH), :col-span(HEIGHT), or :span(WIDTH, HEIGHT) annotations, in which case the block fills more than one grid cell (and merges them into a single logical cell), with the top-left corner of the fill starting at $POS.

A =cell block has the following effects:

  • The specified contents are considered to fill in the cell(s) at $POS (even if the contents are actually null/empty)

  • $POS is moved to the next unfilled cell in the direction specified by $DIR (i.e. either across or down)

A =row directive has the following effects:

  • $DIR is set to across

  • If the previous action was not a =cell (i.e. it was a =table , =row, or =column) then the =row directive has no other effects (i.e. the subsequent effect is skipped)

  • Otherwise, starting at the row specified by $POS, find the uppermost row R that is at-or-below the row specified by $POS, and where row R has at least one empty cell in a column strictly to the left of the column specified by $POS, then move $POS left-and-down, to the left-most empty cell in row R.

A =column directive has the following effects:

  • $DIR is set to down

  • If the previous action was not a =cell (i.e. it was a =table , =row, or =column) then the =column directive has no other effects (i.e. the subsequent effect is skipped)

  • Otherwise, starting at the column specified by $POS, find the left-most column C that is at-or-to-the-right-of the column specified by $POS, and where column C has at least one empty cell in a row strictly above the row specified by $POS, then move $POS up-and-right, to the upper-most empty cell in column C

In other words, =row searches the south-west quadrant from $POS to find the most north-westerly empty cell ... and moves $POS to that cell. And =column searches the north-east quadrant from $POS to find the most north-westerly empty cell ... and moves $POS to that cell.

In addition, =table and =cell blocks and =row and =column directives can be annotated with any of the following metadata, which subsequently act as defaults for any =cell in their scope:

  • :align< ALIGNMENTS > : changes how contents are aligned in a cell ALIGNMENTS may be any one of: left, centre, center, right, and/or any one of: top, middle, bottom.

  • :header : specifies that the cell(s) should be considered column headers

  • :label : specifies that the cell(s) should be considered row labels (i.e. horizontal headers)

Let’s see how it works...

The following RakuDoc specification:

    =begin table
        =row :header 
            =for cell :row-span(2) 
            Date
            =for cell :column-span(3) 
            Samples
            =for cell :row-span(2) 
            Mean
        =row :header 
            =cell I<Sample 1> 
            =cell I<Sample 2> 
            =cell I<Sample 3> 
        =row
        =column
            =cell 2023-03-08 
            =cell 2023-04-14 
            =cell 2023-06-23 
        =column
            =cell 0.4 
            =cell 0.8 
            =cell 0.2 
        =column
            =cell 0.1 
            =cell 0.6 
            =cell 0.9 
        =column
            =cell 0.3 
            =cell 0.5 
            =cell 0.0 
        =column
            =cell 0.26667 
            =cell 0.63333 
            =cell 0.36667 
        =row
            =for cell :label 
            Mean:
            =cell 0.46667 
            =cell 0.53333 
            =cell 0.26667 
            =cell 0.42222 
    =end table

... produces the following table:

Table

Date

Samples

Mean

Sample 1

Sample 2

Sample 3

2023-03-08

0.4

0.1

0.3

0.26667

2023-04-14

0.8

0.6

0.5

0.63333

2023-06-23

0.2

0.9

0.0

0.36667

Mean:

0.46667

0.53333

0.26667

0.42222

Let’s examine how that specification creates that layout, step by step. Note that, in the following diagram, the various symbols have these meanings:

    β”Œβ”€β”€β”€β”
    β”‚   β”‚ : An empty table cell
    β””β”€β”€β”€β”˜
    β”Œβ”€β”€β”€β”
    β”‚ β†’ β”‚ : The empty cell at $POS$DIR is currently "across"
    β””β”€β”€β”€β”˜
    β”Œβ”€β”€β”€β”
    β”‚ β†“ β”‚ : The empty cell at $POS$DIR is currently "down"
    β””β”€β”€β”€β”˜
    β”Œβ”€β”€β”€β”
    β”‚+++β”‚ : The most recently filled cell
    β””β”€β”€β”€β”˜
    β”Œβ”€β”€β”€β”
    β”‚###β”‚ : A previously filled cell 
    β””β”€β”€β”€β”˜

And now the step-by-step explanation:

    =begin table                   β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ
                                   β”‚ β†’ β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
    (Create a new table grid       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     Default $POS is [0,0]         β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     Default $DIR is across)       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =row :header                   β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚ β†’ β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
    (Previous action was not =cell β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     So set $DIR to "across"       β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     and don't change $POS)        β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
 
    =for cell :row-span(2)         β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    Date                           β”‚+++β”‚ β†’ β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”‚+++β”‚β”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
    (Fill in 1x2 cells             β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     starting from $POS            β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     Then move $POS to             β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     first empty cell              β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in $DIR direction)            β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
 
    =for cell :column-span(3)      β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    Samples                        β”‚###β”‚+++++++++++β”‚ β†’ β”‚   β”‚
                                   β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
    (Fill in 3x1 cells             β”‚###β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     starting from $POS            β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     Then move $POS to             β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     first empty cell              β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in $DIR direction)            β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =for cell :row-span(2)         β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    Mean                           β”‚###β”‚###########β”‚+++β”‚ β†’ β”‚
                                   β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€+++β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
    (Fill in 1x2 cells             β”‚###β”‚   β”‚   β”‚   β”‚+++β”‚   β”‚
     starting from $POS            β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     Then move $POS to             β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     first empty cell              β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in $DIR direction)            β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =row :header                   β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Find the next row at or       β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     below the current $POS        β”‚###β”‚ β†’ β”‚   β”‚   β”‚###β”‚   β”‚
     that has an empty cell        β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     to the left of $POS, then     β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     move $POS to the leftmost     β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     cell on that row, and set     β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     $DIR to "across")             β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =cell Sample 1                 β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Fill in 1x1 cell at $POS      β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     then move $POS to             β”‚###β”‚+++β”‚ β†’ β”‚   β”‚###β”‚   β”‚
     the first empty cell          β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in $DIR direction)            β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =cell Sample 2                 β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Fill in 1x1 cell at $POS      β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     then move $POS to             β”‚###β”‚###β”‚+++β”‚ β†’ β”‚###β”‚   β”‚
     the first empty cell          β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in $DIR direction)            β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =cell Sample 3                 β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Fill in 1x1 cell at $POS      β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     then move $POS to             β”‚###β”‚###β”‚###β”‚+++β”‚###β”‚ β†’ β”‚
     the first empty cell          β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in $DIR direction)            β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =row                           β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Move $POS down to the         β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     next row with an empty cell   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     that's to the left of $POS    β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     and to left-most empty cell   β”‚ β†’ β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     on that row)                  β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =column                        β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Previous action was not a     β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     =cell so set $DIR to "down",  β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚ 
     with no other effect)         β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚ β†“ β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =cell 2023-03-08               β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    =cell 2023-04-14               β”‚###β”‚###########β”‚###β”‚   β”‚ 
    =cell 2023-06-23               β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ 
                                   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
    (Each =cell block              β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     fills in a 1x1 cell           β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     at $POS, then moves           β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     $POS to the first empty       β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
     cell in $DIR direction)       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚ β†“ β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
 
    =column                        β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    (Previous action was           β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     a =cell, so move $POS         β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     to the uppermost empty        β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     cell in the first non-full    β”‚###β”‚ β†“ β”‚   β”‚   β”‚   β”‚   β”‚
     column to the right,          β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     and set $DIR to "down")       β”‚###β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚###β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =cell 0.4                      β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    =cell 0.8                      β”‚###β”‚###########β”‚###β”‚   β”‚ 
    =cell 0.2                      β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ 
                                   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
    (Each =cell block              β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     fills in a 1x1 cell           β”‚###β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚
     at $POS, then moves           β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     $POS to the first empty       β”‚###β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚
     cell in $DIR direction)       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚###β”‚+++β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚   β”‚ β†“ β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
 
    =column                        β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    =cell 0.1                      β”‚###β”‚###########β”‚###β”‚   β”‚ 
    =cell 0.6                      β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.9                      β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚ 
    =column                        β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.3                      β”‚###β”‚###β”‚+++β”‚+++β”‚+++β”‚   β”‚ 
    =cell 0.5                      β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.0                      β”‚###β”‚###β”‚+++β”‚+++β”‚+++β”‚   β”‚ 
    =column                        β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.26667                  β”‚###β”‚###β”‚+++β”‚+++β”‚+++β”‚   β”‚ 
    =cell 0.63333                  β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.36667                  β”‚   β”‚   β”‚   β”‚   β”‚ β†“ β”‚   β”‚ 
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
    (Rinse and repeat)             β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =row                           β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
                                   β”‚###β”‚###########β”‚###β”‚   β”‚
    ($POS row is entirely empty    β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ
     so it's the first row with    β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     an empty cell to the left     β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     of $POS, so stay on current   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     row and move $POS to the      β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     left-most empty cell in row;  β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     change $DIR to "across")      β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚ β†’ β”‚   β”‚   β”‚   β”‚   β”‚   β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =for cell :label               β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”ˆβ”ˆ 
    Mean:                          β”‚###β”‚###########β”‚###β”‚   β”‚
    =cell 0.46667                  β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚β”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.53333                  β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚ 
    =cell 0.26667                  β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ 
    =cell 0.42222                  β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚ 
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
    (Fill in 1x1 cells,            β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     moving $POS each time         β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
     in the direction              β”‚###β”‚###β”‚###β”‚###β”‚###β”‚   β”‚
     specified by $DIR)            β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”‚+++β”‚+++β”‚+++β”‚+++β”‚+++β”‚ β†’ β”‚
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”ˆβ”ˆ
                                   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š   β”Š
 
 
    =end table                     β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”
                                   β”‚###β”‚###########β”‚###β”‚ 
    (Terminate grid-filling        β”‚###β”œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€###β”‚ 
     then trim the table to        β”‚###β”‚###β”‚###β”‚###β”‚###β”‚ 
     the bounding box around       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
     all filled cells)             β”‚###β”‚###β”‚###β”‚###β”‚###β”‚ 
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
                                   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚ 
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
                                   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚ 
                                   β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
                                   β”‚###β”‚###β”‚###β”‚###β”‚###β”‚ 
                                   β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜

RakuDoc comments§

RakuDoc comments are components that both RakuDoc renderers and ambient-code compilers ignore.

Comments are useful for meta-documentation (documenting the documentation). Single-line comments use the =comment marker:

=comment Add more here about the algorithm 

For multi-line comments, use a delimited comment block:

=begin comment
This comment is
multi-line.
=end comment

Semantic blocks§

All uppercase block typenames are reserved for specifying standard documentation, publishing components, source constructs, or meta-information. The following must be recognised:

=NAME
=AUTHOR
=VERSION
=TITLE
=SUBTITLE
=LICENSE
=LICENCE
=SYNOPSIS

The block name of a semantic block is to be rendered as if it were =head1 BLOCKNAME, and the contents of the block are then to be rendered as one or more regular paragraphs. Consequently, if a semantic block has multiple lines, then its contents must be enclosed using the delimited form.

A semantic block may be defined, but omitted from the text in the place it is written. This is because sections about Authors, or Licensing, are sometimes required at the end, or at the beginning, or in the meta section of an HTML document.

A renderer is expected to gather the contents of a semantic block for it to be accessible by an external program.

If the metadata option :hidden is associated with a semantic block (by using a =config directive, or as a metadata option with the extended or abbreviated forms) then the renderer will not render the semantic block at the position it is placed in the RakuDoc document. It will be placed in a data structure by the renderer and the contents can be rendered at a place defined by a Placement instruction.

The block name of a rendered semantic block will be placed in the Table of Contents table in the position that it is rendered, unless the :toc, :headlevel, and or :caption options are set. A :hidden metadata option will also remove the block's entry from the ToC. But if it is placed by a P<semantic:> instruction, the block entry will be placed at the appropriate point in the ToC.

User-defined blocks§

When a block name contains both an upper case and a lower case character, as specified in the naming rules below, it is interpreted as a developer-defined block. The naming rules are to ensure that built-in blocks, semantic blocks, and custom blocks are never mixed up.

The way in which a renderer styles the contents of a custom block depends on the renderer, and each renderer may specify a procedure for using user-supplied templates or code.

The DOC phaser in Raku is the way an author can define which renderer to use, e.g.:

    DOC use My::Special::Renderer;
    DOC use My::Other::Special::Renderer;
 
    =begin rakudoc
    ...
    =end rakudoc

Non-Raku environments might specify their own mechanisms for loading custom renderers. For example, they might require a RakuDoc comment at the start of the document:

    =begin rakudoc
    =comment load MySpecialRenderer, MyOtherSpecialRenderer
    ...
    =end rakudoc

Or they might require that any special handlers be specified as metadata on the rakudoc block itself:

    =begin rakudoc :Load< MySpecialRenderer MyOtherSpecialRenderer >
    ...
    =end rakudoc

If a renderer does not recognise a custom block, then the renderer should treat the block name as the contents of a =head1 block, which can be overridden as described in Table of Contents. The contents of the unrecognised custom block should be rendered verbatim, like a =code block.

Consequently, multi-paragraph contents should be enclosed using the delimited form of the block.

Naming rules§

In order to avoid conflicts between built-in blocks, semantic blocks, custom blocks, and markup instructions, the following rules must be followed:

  • Builtin blocks (e.g. head, item, table)

    • names must be all lowercase and at least two characters long

    • renderers may choose how to render builtin blocks, but must respect all the defined metadata options specified here, and may respect additional metadata options

  • Semantic blocks (e.g. AUTHOR, TITLE)

    • names must be all uppercase and at least two characters long

    • renderers should treat these as if they are head1 with a caption consisting of the semantic block name

    • the contents of the block should be treated as a paragraph.

  • Custom blocks (e.g. MyNewBlock)

    • names must contain at least one uppercase, and at least one lowercase character

    • renderers will define how users may specify metadata options and syntax

    • renderers will define how the contents of the block are interpreted and rendered

  • Custom markup codes (e.g. Γ†, Ø, ß)

    • names must consist of exactly one uppercase Unicode character (i.e. with the Upper property)

    • names may not be a character in the ASCII range (these are reserved for current and future built-in markup codes)

    • the built-in markup instruction M<> is also provided for custom markup

Implied code and indentation§

An example of implied code was given in the section on Code blocks. Implied code can be used in other blocks.

Each block creates a virtual margin (at the column before its leading =) and that virtual margin extends only to the end of the block (i.e. not to the start of the next named block). Thus:

β”Š=begin rakudoc
β”ŠThis is an implicit =para block
β”Š
β”Š   This is implicit =code block
β”Š
   β”Š=begin nested
   β”ŠThis is an implicit =para block
   β”Š
   β”Š   This is implicit =code block
   β”Š
      β”Š=begin nested
      β”ŠThis is an implicit =para block
      β”Š
      β”Š   This is implicit =code block
      β”Š
      β”Š=end nested
   β”Š
              β”Š=for nested
              β”ŠThis is an implicit =para block
              β”Šover multiple lines
              β”Šending at this final non-blank line
   β”Š
   β”Š           This is implicit =code block (NOT a =para)
   β”Š
   β”Š=end nested
β”Š
β”ŠThis is an implicit =para block
β”Š
β”Š    This is implicit =code block
β”Š
β”Š=end rakudoc

Which means that:

=begin rakudoc
    =for Podcast 
        this is not code
 
    this is code
=end rakudoc

...because the final line is indented from the virtual margin of its containing =begin rakudoc/=end rakudoc block, so it must be code.

Whereas:

    =begin rakudoc
    =for Podcast 
        this is not code
 
    this is not code either
    =end rakudoc

...because the final content line starts at the virtual margin of its containing =begin rakudoc/=end rakudoc block.

Care must be taken with abbreviated and extended blocks where the block ends at the next blank line.

    =begin pod
    This is an ordinary paragraph
 
        While this is not an ordinary paragraph;
        it is a code block.
 
        =head1 Mumble mumble 
 
        Surprisingly, this is a code block
            (with fancy indentation too)
 
    This is just an ordinary paragraph.
 
    =end pod

The Surprisingly ... paragraph is a code block because a block only sets the virtual margin within that block, and the =head1 block terminates at the blank line immediately after the =head1 line, and before the apparent code block begins. At which point, the virtual margin reverts to the previous virtual margin set by the surrounding =begin pod...=end pod block.

The current virtual margin terminates at the end of the block whose opener set it, and not at the start of the next block that sets a virtual margin. In other words, the virtual margin is a local feature of each individual block, not a collective feature of the entire document, and therefore a block's virtual margin always ends at the end of the block itself (and reverts at that point to the virtual margin of the surrounding block, if any).

Which means:

    =begin pod
    This is an ordinary paragraph
 
        While this is not
        This is a code block
 
        =head1 Mumble mumble 
 
        This IS also a code block
           because the preceding =head's virtual margin ended
           at the end of the preceding =head block, which was
           at the preceding blank line. So the virtual margin for
           this implicit block is the virtual margin of the surrounding
           C<=begin pod ... =end pod> block. This block is indented
           relative to that C<=pod block>'s virtual margin, so it's
           a code block.
 
    This is a para block
        (with fancy indentation too, because the indentation of first line alone
         determines whether an implicit block is a C<=para> or a C<=code> block,
         and all subsequent lines, regardless of their indentation, become part
         of that block ... until the end of the implicit block, which occurs at
         the next blank line or the next explicit RakuDoc block or directive.)
 
    =end pod

And if, instead, you wanted the block straight after the =head to be an implicit paragraph block (i.e. not an implicit code block), you'd write it:

    =begin pod
    This is an ordinary paragraph
 
        While this is not
        This is a code block
 
        =begin section
 
        =head1 Mumble mumble 
 
        This is a para block, NOT a code block
           because the virtual margin for this implicit block
           is the virtual margin of the surrounding
           =begin section ... =end section block.
           The first line of this implicit block is NOT indented
           relative to that =section block's virtual margin,
           so it's a para block.
 
        =end section
 
    This is a para block too...because its first line is not indented
       relative to the virtual margin of the current =begin pod ... =end pod block.
 
    =end pod

Indentation from the current virtual margin only implies a para or code block in blocks that don’t already explicitly specify otherwise. Hence, all the following β€œcontainer blocks” should honour the indented=code and on-margin=para shortcuts: =defn, =item, =itemN, =nested, =rakudoc, =section, =pod, =cell.

None of the following blocks should infer para or code from indentation: =para, =code, =input, =output, =comment, =table, =graphic, =data, =head, =headN, =SEMANTIC.

That’s because each of them specifies explicitly what type of information their contents are supposed to be, so there’s no need to infer anything. In particular, =para and =code are specifically provided to circumvent inference from indentation.

Finally, user-defined custom blocks should always pass their contents verbatim to whatever appropriate user-defined handler is in scope, and it’s up to that handler to infer the meaning of any indentation.

Metadata§

A powerful feature of RakuDoc is the ability to associate metadata with a block. Metadata can be used to change the way a block is rendered, or to allow a renderer to access data in the cloud, or receive data from a microservice.

Some metadata options are defined for certain blocks and a renderer must produce the behaviour described in this section (or in the section for the relevant block), to the extent possible for a given output format,

A renderer may ignore metadata options not specified in this document, or define other metadata tabs that it will recognise.

Anchors§

Whenever a =head block such as:

=head Table of Contents and Index 

...is rendered, it is also associated with an anchor, so that when a link of the form L<link to an internal heading|#Table of Contents and Index> is rendered, the renderer will place a link to the correct heading in the output format. The anchor will also be used in the Table of Contents.

Note that the text in the L<...> before the | is the display text, and the tag after the | is the content of the target =head block.

In order for a link to work correctly, the anchor must be unique. The renderer is free to chose the algorithm it uses for the internal anchor. This is because different outputs, such as Markdown and HTML, have different formats for anchors.

An author may want to shorten an internal link to a title, and also to place an anchor on every block.

The :id<name of a link> metadata option can be attached to any block. For example:

=for head :id<ToCaI>
Table of Contents and Index
 
...and later we can add: L<link to an internal heading|#ToCaI>

The renderer is expected to create a link with that name to the start of the block. It is up to the author of the document to ensure that all :id links are unique.

A renderer may mangle the link name (e.g. the contents of a header) to create an anchor ID internally because different output formats may place restrictions on the characters that can be used in a link. However, a document author may not rely on a renderer's ID generation algorithm.

Internal links (links to anchors within the same document) must be specified by a leading # followed by either:

  • the target block's explicit :id<LABEL>, or

  • the exact contents of the corresponding =header block, or

  • the exact contents of a block’s explicit :caption<TEXT>.

Internal links cannot be specified by a # followed by

  • a =header block's implicit autogenerated-from-content ID, or

  • a block’s implicit autogenerated-from-caption ID.

That is, the in-document link target cannot be the mangled contents of a =header block or a :caption<...> metatag; it can only be the original contents.

For example:

    =for header :id<h123>
    A sample header
 
    =for table :id<t456> :caption<Example table>
    A  B  C
    1  2  3
 
    This is a L<valid link (to an explicit block ID) | #h123 >
    This is a L<valid link (to an explicit block ID) | #t456 >
 
    This is a L<valid link (to a heading) | #A sample header >
    This is a L<valid link (to a caption) | #Example table   >
 
    This is L<NOT a valid link | #A_sample_header >
    This is L<NOT a valid link | #Example_table   >

Table of Contents and Index§

When a renderer parses a file containing RakuDoc, heading and X<> markup information is collected. This information can be rendered using a P<> markup instruction, or may be used in another way by the renderer (e.g. to create a sidebar with the Table of Contents).

Named blocks are considered by default to be equivalent to =head for the purposes of a Table of Contents. The exceptions are para, nested, code, input and output blocks.

This default can be changed with the :toc and :headlevel meta tabs.

Setting :toc on a block will include the contents of the block in the Table of Contents. Including the entire block contents is usually not desirable, so the :caption<...> meta tab can be used to provide a text for the Table of Contents.

Setting :!toc will prevent a block's information from being included in the Table of Contents.

Setting :headlevel(N), where N is an integer greater than 0, will cause the block information to be treated in the same way as a headN heading is treated. Setting N to less than 1 has the same effect as :!toc. If it is not explicitly set, :toc will set the headlevel to 1.

Developer or delta notes§

When a set of source files is related to a project with versions (such as the Raku language), documentation may get out of date, or may only apply to features of a future release.

A delta note can be attached to a block using the :delta metadata tab, or specified inline with the Ξ”< ... > markup instruction. Both the metadata tab and the markup instruction have two arguments: the first is the version specification, and the second is an optional text note.

Note: This is an example of a built in markup code that uses a Unicode Upper character. The mnemonic is Delta, which is commonly used to indicate an incremental component.

The version specification is summarised as follows:

SyntaxMeaning
'*'Any version
v1.2.3specific version
v1.2.3+specific version or later
v1.2.3-specific version or earlier
v1.2.3..v2.3.4inclusive range of versions
v1.2.3^..^v2.3.4exclusive range of versions
v1.2.3..^v2.3.4 and v1.2.3^..v2.3.4semi-inclusive range of versions

The version specification (e.g. v1.2.3) shown here follows the rules of semantic versioning, which is the preferred form for Raku documentation, but is not mandatory. Note that the .. and ^ characters create Raku ranges.

With no extra information about which version should be displayed, a renderer should have a way to include both the string and the version specification.

Alternatively, if there is information about the version to be shown, a renderer should only show blocks that correspond to the version information. A block that does not have a :delta is treated as if it has :delta<*>.

An example is given in the description of the section block

Markup instructions§

Markup instructions provide a way to add inline mark-up to a piece of text.

All RakuDoc markup instructions consist of a single capital letter followed immediately by a set of single or double angle brackets; Unicode double angle brackets may be used.

Markup instructions may nest other markup instructions.

Some markup instructions only affect their contents and do not have any metadata associated with them. These are sometimes called formatting codes. Other markup instructions have side effects.

Formatting codes§

RakuDoc characterises formatting codes semantically, allowing a renderer to choose any appropriate visual representation. Thus B<> is for the Basis of a sentence, although a visual equivalent might involve a bold font.

The following should be made available in all renderers.

Inline markupInstructionMnemonicHTML equivalentMarkdown equivalent
BasisB<text>"B for Basis"<b>text</b>**text**
ImportantI<text>"I for Important"<i>text</i>*text*
UnusualU<text>"U for Unusual"<u>text</u>__text__
StrikethroughO<text>"O for Overstrike"<s>text</s>~~text~~
SuperscriptH<text>"H for High text"<sup>text</sup>^text^
SubscriptJ<text>"J for Junior text"<sub>text</sub>~text~
CodeC<text>"C for Code"<code>text</code>`text`

The table contains suggested HTML and Markdown equivalents, a renderer may choose other representations.

Instructions with side effects§

Markup instructions, including all customisable instructions, will typically have associated metadata.

To create a link, enclose it in L< >. RakuDoc links are more general than the conventional HTML links.

The general syntax is L< LABEL | TARGET >

where the optional label is text that is rendered and the target may include a schema. If the label is omitted, then the target is used as the label. Whitespace on either side of the bar is not significant.

When the schema is missing, then the https:// schema is implied, which means that if the website url is missing as well, the link is to the same host as the document.

Several schemas are possible:

  • https:// or http:// The renderer may style the label and cause a jump in a networked environment, as is normal for HTML documents.

  • rakudoc: A reference to a Rakudoc source, which might be in a Raku module or a Rakudoc file.

  • mailto: An email address. Typically, activating this type of link invokes a mailer.

  • man: A link to the system manpages.

  • isbn: and issn: The International Standard Book Number or International Standard Serial Number for a publication.

  • defn: A link to a block-form definition or an inline definition of the specified term within the current document.

To refer to a specific section within a webpage, manpage, or RakuDoc document, add the name of that section after the main link, separated by a #. To refer to a section of the current document, omit the external address.

A renderer is expected to render a link with a schema as follows:

  • At a minimum, a link like rakudoc: ModuleName is simply rendered as text, to something like: β€œthe ModuleName documentation”, and man: appname to something like: β€œThe appname manpage”. And neither of them attempt to add any kind of actual operational link.

  • At the next level of sophistication, a renderer encountering either link scheme may attempt to shell out a call to raku --doc ModuleName or man appname, and present the results in a pop-up.

  • If the renderer is in a networked environment, the renderer is expected to provide a set of user selectable options that provide links to such documentation, for example, a set of HTML links in a pop-down box. A renderer might also allow users to preconfigure their preferred website(s) for these schemes, perhaps offering rakudoc: links to https://raku.land/ or man: links to https://www.kernel.org/doc/man-pages/ as defaults.

Renderers are not expected to handle all schemas beyond the minimum above. Renderers offering more sophisticated styling or operational links should provide ways to configure schemas, whilst offering reasonable defaults.

Examples§

    I<ACM Transactions on Programming Languages and Systems>
    is a registered serial publication (L<issn:0164-0925>)
 
    This module implements the standard Unix L<man:find(1)> facilities.
 
    Please forward bug reports to L<mailto:abyss@example.org>
 
    This module needs the L<LAME library|http://www.mp3dev.org/mp3/>.
 
    You could also write the code L<in gibberish|rakudoc:Acme::Anguish>
 
    Also see: L<man:bash(1)#Compound Commands>,
 
    =defn lexiphania 
    An unfortunate proclivity for
    employing grandiloquisms (for example, words such as "proclivity", "grandiloquism", and indeed "lexiphania").
 
    =defn glossoligation 
    Restraint of the tongue (voluntary or otherwise)
 
    To treat his chronic L<defn:lexiphania> the doctor prescribed an immediate L<defn:glossoligation>
    orif that proved ineffectivea complete cephalectomy.
 

A second kind of link — the P<> or placement link — works in the opposite direction. Instead of directing focus out to another document, it allows you to assimilate the contents of another document into your own.

In other words, the P<> markup instruction takes a URI and (where possible) inserts the contents of the corresponding document inline in place of the code itself.

P<> markup is handy for breaking out standard elements of your documentation set into reusable components that can then be incorporated directly into multiple documents. For example:

=COPYRIGHT
P<file:/shared/docs/std_copyright.rakudoc>
 
=DISCLAIMER
P<http://www.MegaGigaTeraPetaCorp.com/std/disclaimer.txt>

might produce:

Copyright

This document is copyright (c) MegaGigaTeraPetaCorp, 2006. All rights reserved.

Disclaimer

ABSOLUTELY NO WARRANTY IS IMPLIED. NOT EVEN OF ANY KIND. WE HAVE SOLD YOU THIS SOFTWARE WITH NO HINT OF A SUGGESTION THAT IT IS EITHER USEFUL OR USABLE. AS FOR GUARANTEES OF CORRECTNESS...DON'T MAKE US LAUGH! AT SOME TIME IN THE FUTURE WE MIGHT DEIGN TO SELL YOU UPGRADES THAT PURPORT TO ADDRESS SOME OF THE APPLICATION'S MANY DEFICIENCIES, BUT NO PROMISES THERE EITHER. WE HAVE MORE LAWYERS ON STAFF THAN YOU HAVE TOTAL EMPLOYEES, SO DON'T EVEN *THINK* ABOUT SUING US. HAVE A NICE DAY.

If a renderer cannot find or access the external data source for a placement link, it must issue a warning and render the URI directly in some form, possibly as an outwards link. For example:

Copyright

See: file:/shared/docs/std_copyright.rakudoc

Disclaimer

You can use any of the following URI forms (see #Links) in a placement link:

  • http: and https:

  • file:

  • toc:

  • index:

  • semantic:

The toc: form is a special pseudo-scheme that inserts a table of contents in place of the P<> code. After the colon, list the block types that you wish to include in the table of contents. For example, to place a table of contents listing only top- and second-level headings:

See: toc: 1, 2 

To place a table of contents that lists the top four levels of headings:

See: toc: 1..4 

A document may have as many P<toc:...> placements as necessary.

The index: form is a special pseudo-scheme that inserts an index table in place of the P<> code.

The semantic: XXX form places the XXX semantic block at the position of the P<> instruction.

Alias placement§

A variation on the placement instruction is the A<> instruction, which is replaced by the contents of the named alias or object specified within its delimiters. For example:

    =alias PROGNAME    Earl Irradiatem Eventually 
    =alias VENDOR      4D Kingdoms 
    =alias TERMS_URL   L<http://www.4dk.com/eie> 
 
    The use of A<PROGNAME> is subject to the terms and conditions
    laid out by A<VENDOR>as specified at A<TERMS_URL>.

Any Raku object after the Check Phase, such as an object that starts with a sigil, is available within an alias placement. Unless the object is already a string type, it is converted to a string during document-generation by implicitly calling .raku on it.

So, for example, a document can refer to its own filename (as A<$?FILE>), or to the subroutine inside which the specific Pod is nested (as A<&?ROUTINE>), or to the current class (as A<$?CLASS>). Similarly, the value of any program constants defined with sigils can be easily reproduced in documentation:

# Actual code... 
constant Num $GROWTH_RATE = 1.6;
=begin rakudoc
=head4 Standard Growth Rate 
 
The standard growth rate is assumed to be A<$GROWTH_RATE>.
=end rakudoc

Non-mutating method calls on these objects are also allowed, so a document can reproduce the surrounding subroutine's signature (A<&?ROUTINE.signature>) or the type of a constant (A<$GROWTH_RATE.WHAT>).

See Aliases for further details of the aliasing macro mechanism.

Graphic placement§

Another variant on the placement instruction is the G<> instruction.

Like P<>, the G<Alt text|url schema> takes appropriately formatted image data from the url and places it inline.

Inline definitions§

A D<> formatting code marks a piece of text as being the β€œinline definition” of a term. That is: it’s like a =defn block, but it’s not a list item; it’s just part of the regular text. Well-written documentation often includes sentences/paragraphs that introduce a new term, and define it. Typically we want to visually distinguish those newly defined terms, and to be able to link back to the paragraph where they’re defined.

For example:

    There ensued a terrible moment of D<coyotus interruptus>: a brief
    suspension of the effects of gravityaccompanied by a sudden
    to-the-camera realization of imminent downwards acceleration.

The contents of the D<> represent the term being defined, the location of the D<> implies a link target location, and the paragraph containing the D<> suggests a suitable pop-up definition of the term (if a renderer supports such).

The definition term in a D<> is rendered distinctly (typically in bold italics), and the D<> sets up a link target to that term, and possibly a pop-up for the corresponding L<> link to display the entire paragraph in which the D<> appeared.

In other words, when rendered to HTML, a D<term being defined> would be translated to something like:

...a ΓΏΓΏ<strong>ΓΏΓΏ<dfn id="term being defined">term being defined</dfn>ΓΏΓΏ</strong>ΓΏΓΏ would be...

And a L<defn:term being defined> link would be translated to something like:

...a ΓΏΓΏ<strong>ΓΏΓΏ<a href="#term being defined">term being defined</a>ΓΏΓΏ</strong>ΓΏΓΏ link would be...

A definition may be given synonyms, which are specified after a vertical bar and separated by semicolons:

    A D<formatting code|formatting codes;formatters> provides a way
    to add inline mark-up to a piece of text.

Space-preserving text§

Any text enclosed in an unknown format-code S<|> code is formatted normally, except that every whitespace character in it β€” including any newline β€” is preserved. These characters are also treated as being non-breaking (except for the newlines, of course). For example:

The emergency signal is: S<
dot dot dot   dash dash dash   dot dot dot>.

would be formatted like so:

The emergency signal is:
dot dot dot   dash dash dash    dot dot dot.

rather than:

The emergency signal is: dot dot dot dash dash dash dot dot dot.

Comments§

A comment is text that is never rendered.

To create a comment enclose it in Z< >:

Raku is awesome Z<Of course it is!>

This would be rendered as:

Raku is awesome

Notes§

Notes are ancillary information that may be rendered as footnotes or sidenotes or pop-up notes, depending on the renderer and environment.

To create a note enclose it in N< >

Raku is multi-paradigmatic N<Supporting Procedural, Object Oriented, and Functional programming>

Which produces:

Raku is multi-paradigmatic [1]

Keyboard input§

To flag text as keyboard input enclose it in K< >

=output Enter your name: K<John Doe> 

Which is rendered like so:

Enter your name: K<John Doe>

Replaceable§

The R<> markup instruction specifies that the contained text is a replaceable item, a placeholder, or a metasyntactic variable. It is used to indicate a component of a syntax or specification that should eventually be replaced by an actual value. For example:

The basic C<ln> command is: C<ln> R<source_file> R<target_file>

This is rendered like so:

The basic ln command is: ln source_file target_file

Terminal output§

To flag text as terminal output enclose it in T< >

=input T<Enter your name:> John Doe 

Which would be rendered:

T<Enter your name:> John Doe

Unicode and HTML references§

Unicode codepoint names or numbers may be included in a RakuDoc document by enclosing them in E< >. When E< > encloses a number, it is treated as the Unicode value for the code point using binary, octal, decimal, or hexadecimal numbers using the Raku notations for explicitly based numbers. Numbers without an explicit base, as per Raku convention, are decimal.

For example, each of the following:

Raku makes considerable use of the E<171> and E<187> characters.

Raku makes considerable use of the E<0b10101011> and E<0b10111011> characters.

Raku makes considerable use of the E<0o253> and E<0o273> characters.

Raku makes considerable use of the E<0d171> and E<0d187> characters.

Raku makes considerable use of the E<0xAB> and E<0xBB> characters.

will yield the same rendering:

Raku makes considerable use of the Β« and Β» characters.

It is also possible to specify Unicode codepoint names. Multiple codepoints separated by , will be considered as a single grapheme. So:

E<LEFT-POINTING DOUBLE ANGLE QUOTATION MARK>
E<REGIONAL INDICATOR SYMBOL LETTER U, REGIONAL INDICATOR SYMBOL LETTER A> Ukraine
 E<RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK>

will be rendered as: Β« πŸ‡ΊπŸ‡¦ Ukraine Β».

Alternatively, HTML5 character references may be used. For example:

Raku makes considerable use of the E<laquo> and E<raquo> characters.

also yields: Raku makes considerable use of the Β« and Β» characters.

The E<> markup may be used for a list of characters separated by ;

Raku code often contains the E<0xff62;0xff63> bracketing characters to avoid using quotes.

This would yield: Raku code often contains the ο½’ο½£ bracketing characters to avoid using quotes.

Verbatim text§

The V<> markup instruction treats its entire contents as being verbatim, disregarding every apparent markup instruction within it. For example:

The B<V< V<> >> markup instruction disarms other codes
such as V< I<>C<>B<>and M<> >.

Note, however that the V<> code only changes the way its contents are parsed, not the way they are rendered. That is, the contents are still wrapped and formatted like plain text, and the effects of any markup instructions surrounding the V<> code are still applied to its contents. For example the previous example is rendered as:

The V<> markup instruction disarms other codes such as I<>, C<>, B<>, and M<> .

Note that C<> also by default keeps its contents verbatim, the difference between C<> and V<> is that C<> 'colors' the contents to show that it is code, whilst V<> uses the default text presentation.

The default behaviors of both V<> and C<> can be changed using a =config directive, e.g.,

=config C :allow< B I U > 
=config V :allow< N L X > 

Indexing terms§

Anything enclosed in an X<> code is an index entry. The contents of the code are both formatted into the document and used as the (case-insensitive) index entry:

An X<array> is an ordered list of scalars indexed by number,
starting with 0. A X<hash> is an unordered collection of scalar
values indexed by their associated string key.

You can specify an index entry in which the indexed text and the index entry are different, by separating the two with a vertical bar:

An X<array|arrays> is an ordered list of scalars indexed by number,
starting with 0. A X<hash|hashes> is an unordered collection of
scalar values indexed by their associated string key.

In the two-part form, the index entry comes after the bar and is case-sensitive.

You can specify hierarchical index entries by separating indexing levels with commas:

An X<array|arrays, definition of> is an ordered list of scalars
indexed by numberstarting with 0. A X<hash|hashes, definition of>
is an unordered collection of scalar values indexed by their
associated string key.

You can specify two or more entries for a single indexed text, by separating the entries with semicolons:

A X<hash|hashes, definition of; associative arrays>
is an unordered collection of scalar values indexed by their
associated string key.

The indexed text can be empty, creating a "zero-width" index entry:

X<|puns, deliberate>This is called the "Orcish Maneuver"
because you "OR" the "cache".

Markup extras§

In order to allow for renderers to add customisable markup code, whilst at the same time abiding by the naming rules, the markup instruction M< visible text | list-of-strings > is defined as a built-in markup instruction.

The visible text is shown in the text, and may be blank.

The list-of-strings is specified in the same way as the X<> markup instruction for indexing. The semantics of the string is defined by the renderer. If a renderer does not recognise the list of strings, it is expected that the visible text will be rendered and marked in some way (such as with a border or highlight color), and at least the first string will be made available in the same way as the D<> markup instruction. It is also recommended that the first string is used by the renderer to identify the functionality being provided.

For example, suppose a Rakudoc document is used to create part of a website in which a button is to be styled that accesses the API of a payment service (e.g. 'PayMe'). A developer can then create some functionality according to the rules of a RakuDoc renderer, and present it to the service point. In an HTML document, this might be coded as a <button class="PayMeApp" data-token="vendor-id" data-price="$0.99"> with a specific class and structure. The RakuDoc instruction might then be:

    To sample this marvelous libation M<order now by PayMeApp|PayMeApp; vendor-id; $0.99>

An HTML renderer would the convert this to, for example,

    <p>To sample this marvelous libation
        <button class="PayMeApp" data-token="vendor-id" data-price="$0.99">
        order now by PayMeApp
        </button>
    </p>

AUTHORS§

  • Damian Conway (@thoughtstream)

  • Richard Hainsworth (@finanalyst)

  • Elizabeth Mattijen (@lizmat)

Summary§

Directives§

Table

Directive

Specifies

=alias

Define a Pod macro

=begin

Start of an explicitly terminated block

=column

Start a new column in a procedural table

=config

Block scope modifications to a block or markup instruction

=end

Explicit termination of a begin block

=finish

No ambient blocks after this point

=for

Start of an implicitly (blank-line) terminated block

=row

Start a new row in a procedural table

Blocks§

Table

Block typename

Specifies

=cell

Contents of a table cell, only valid in a procedural table context

=code

Verbatim pre-formatted sample source code

=input

Pre-formatted sample input

=output

Pre-formatted sample output

=comment

Content to be ignored by all renderers

=head

First-level heading

=headN

Nth-level heading

=numhead

First-level numbered heading

=numheadN

Nth-level numbered heading

=defn

Definition of a term

=item

First-level list item

=itemN

Nth-level list item

=numitem

First-level numbered list item

=numitemN

Nth-level numbered list item

=nested

Nest block contents within the current context

=para

Ordinary paragraph

=rakudoc

No "ambient" blocks inside

=section

Defines a section

=pod

Legacy version of rakudoc

=table

Visual or procedural table

=graphic

Insert an image from a url

=data

Raku data section

RESERVED

Semantic blocks (SYNOPSIS, TITLE, etc.)

CustomName

User-defined block

Metadata options§

Table

Metadata option

Blocks applied to

Description

:allow

=code

Change default of verbatim blocks

=input

=output

=table

:id

all blocks

Specify the anchor for a block

:continued

=item

Continue numbering from the previous numbered list

=numitem

:toc

=para

Include content or caption in Table of contents

=nested

=code

=input

=output

=table

=graphic

:!toc

SEMANTIC block

Do not include content or caption in Table of contents

Custom block

=headN

=numheadN

:headlevel

SEMANTIC block

Define the head level at which the caption is included in the Table of contents

Custom block

=para

=nested

=code

=input

=output

=table

=graphic

:caption

Semantic block

Caption to be associated with a block in the Table of Contents

Custom block

=nested

=code

=input

=output

=table

=graphic

:hidden

Semantic block

Remove block from rendered text and ToC (use P<semantic: ...> to inject elsewhere)

:header

=table (procedural semantics only)

Specify rows, columns, or cells to be rendered as headers

=cell

=row directive

=column directive

:label

=table (procedural semantics only)

Specify rows, columns, or cells to be rendered as labels

=cell

=row directive

=column directive

:align<ALIGNMENTS>

=table (procedural semantics only)

Specify how cell contents are to be vertically and/or horizontally aligned

=cell

=row directive

=column directive

:row-span(HEIGHT)

=cell

Specify how many rows a single cell should span in a procedural table

:column-span(WIDTH)

=cell

Specify how many columns a single cell should span in a procedural table

:span(WIDTH, HEIGHT)

=cell

A shortcut for :column-span(WIDTH) :row-span(HEIGHT)

:delta

=table

Developer information associated with a block

=nested

=code

=input

=output

=headN

=numheadN

Semantic block

Custom block

Markup instructions§

Table

Markup instruction

Specifies

A<...>

Alias to be replaced by contents of specified =alias directive

B<...>

Basis/focus of sentence (typically rendered bold)

C<...>

Code (typically rendered fixed-width)

D<...>

Definition inline (D<term being defined|synonym1; synonym2>)

Ξ”<...|...;...>

Delta note (Ξ”<visible text|version; Notification text>)

E<...;...>

Entity (HTML or Unicode) description (E<entity1;entity2; multi,glyph;...>)

F<...>

(This markup code is not yet defined, but is reserved for future use)

G<...|...>

Insert an inline graphic (G<alt text|url>)

H<...>

High text (typically rendered superscript)

I<...>

Important (typically rendered in italics)

J<...>

Junior text (typically rendered subscript)

K<...>

Keyboard input (typically rendered fixed-width)

L<...|...>

Link (L<display text|destination URI>)

M<...|..,..;...>

Markup extra (M<display text|functionality;param,sub-type;...>)

N<...>

Note (not rendered inline, but visible in some way: footnote, sidenote, pop-up, etc.))

O<...>

Overstrike or strikethrough

P<...>

Placement link

Q<...>

(This markup code is not yet defined, but is reserved for future use)

R<...>

Replaceable component or metasyntax

S<...>

Space characters to be preserved

T<...>

Terminal output (typically rendered fixed-width)

U<...>

Unusual (typically rendered with underlining)

V<...>

Verbatim (internal markup instructions ignored)

W<...>

(This markup code is not yet defined, but is reserved for future use)

X<...|..,..;...>

Index entry (X<display text|entry,subentry;...>)

Y<...>

(This markup code is not yet defined, but is reserved for future use)

Z<...>

Zero-width comment (contents never rendered)

LICENSE§

Artistic-2.0

1 [↑] Supporting Procetypo line 743dural, Object Oriented, and Functional programming