Described operations written in parentheses, the rule telling an operation from a value, and the in operator with its operands.
Described =test blocks with selector assertions, and their =fixture, =assert and =resource children.
Described predicates in selectors: the operators, the outcome for empty and absent values, membership, and the combination of conditions.
Described the universal pattern, which matches a block of any name.
Changed:
Described a selector pattern as a block name or the universal * followed by an optional predicate.
Named the kind of a value in the block configuration table.
Distinguished the two hash notations by the keys each admits.
Stated that the separators of an index entry describe one structure.
Reworked the forms of an attribute value.
Allowed a value in parentheses or braces to span configuration lines.
Described the empty forms of a value.
v2.0
Added:
Attributes on Markdown fenced code blocks,
Per-link configuration attributes for L<> markup code,
Error recovery rules for =table block,
=boundary directive for marking structural section boundaries,
G<> markup code (Guarded) and :masked block attribute for content masking,
=set directive for per-block attribute assignment with multiline values and inline markup support,
Extended :mime-type attribute syntax to accept MIME parameters per RFC 6838, with header=present|absent recognised for CSV/TSV header indication per RFC 4180 §3,
=data-table block for rendering CSV and TSV data, with :src, :columns, :rename attributes.
Changed:
Reclassified =include as directive,
Refined :folded definition,
Fixed attribute name inconsistencies in examples.
Removed:
Outdated string attribute syntax formats.
v1.0
Added:
Notification blocks, :notify attribute for =nested blocks,
:folded attribute,
:folded-levels for =toc block,
embedding binary data into documents, =data, :filename, :encoding,
:mime-type attribute for =include and =data blocks,
introduce data: schema for use in =picture and =table,
render tables from CSV files, =table,
new markdown mode for parser,
M<> - extends inline markup features,
add :id, :caption, :lang attributes,
task lists, =item and :checked attribute,
intro Selectors,
table of contents, =toc,
include block, =include,
inserting pictures, =picture, P<>,
mathematical formulas, =formula, F<>,
Markdown support, =markdown,
mistake marking, O<>,
text positioning, J<>, H<>,
Emoji, ,
contextual backlinks, W<>,
advanced table format, =row, =cell blocks,
:header, :rowspan, :colspan attributes.
Changed:
refactor Named custom blocks and markup custom codes, M<>.
Removed:
Contextual aliases,
=finish,
markers in comments,
:margin attribute,
=encoding directive,
P<toc:> due to =toc block,
P<man:>, P<doc:> due to =include directive,
P<> - placement links,
Declarator block,
:formatted attribute,
:like attribute.
Podlite
Podlite is an easy-to-use markup language with a simple, consistent
underlying document object model. Podlite can be used for writing language
documentation, for documenting programs and modules, as well as for
other types of document composition.
The Podlite is a purely descriptive mark-up notation, with no presentational
components.
General syntactic structure
Podlite documents are specified using directives, which are
used to declare configuration information and to delimit blocks of
textual content.
Every directive starts either with an equals sign (=) followed
immediately by an identifier.
An identifier composed of an alphabetical character followed by
any combination of alphanumeric characters. Alphabetic and numeric
definitions encompass relevant Unicode characters. The underscore
is consistently treated as alphabetic. Additionally, an identifier
can include isolated apostrophes or hyphens, given that the subsequent
character is alphabetic.
Directives that start with = can be indented like the code they
interleave, but their initial = must still be the first non-whitespace
character on their line.
An indented Podlite block is considered to have a virtual left margin,
determined by the indentation of its opening delimiter.
In other words, if a directive is indented from the left margin, the
column at which the first character of its opening delimiter appears is
thereafter considered the first column of the entire block's contents.
The virtual margin treats leading tabs as aligning to tabstops spaced
every ($?TABSTOP // 8) characters.
Podlite blocks
The content of a document is specified within one or more blocks.
Every Podlite block may be declared in any of three forms:
delimited style, paragraph style, or abbreviated style.
All of these forms are equivalent.
Anything in a document that is neither a Podlite directive nor contained
within a Podlite block is treated as "ambient" material. Typically this
would be the source code of the program that the Podlite is documenting.
Podlite parsers still parse this text into the internal representation of the
file, representing it as a "ambient" block. Renderers
will usually ignore such blocks.
This is the default mode of the parser.
All directives have a defined terminator and the Podlite parser always reverts to
"ambient" at the end of each Podlite directive or
block.
The =pod block puts the parser in "pod" mode,
treating all text between blocks as implicit paragraph Podlite, even if
it's not inside an explicit block.
To keep the parser in "pod" mode, enclose the desired Podlite region
in a =pod block:
=begin pod
=head1 A heading
This is Podlite too. Specifically, this is a simple C<para> block
$this = pod('also'); # Specifically, a code block
=end pod
The contents of files with the extensions .podlite and .pod6 are
implicitly wrapped in a =pod directive.
For .md and .markdown files, the parser operates in "Markdown"
mode for the entire file, treating all
text as markdown even if it is not inside an =markdown block.
Any other file extension puts the parser in default mode. The =include
directive provides a mechanism to override this behavior
by using the :mime-type attribute for the included files.
Delimited blocks
Delimited blocks are bounded by =begin and =end markers, both of
which are followed by a valid Podlite identifier, which is the
typename of the block. Typenames that are entirely lowercase (for
example: =begin head1) or entirely uppercase (for example: =begin
SYNOPSIS) are reserved.
After the typename, the rest of the =begin marker line is treated as
configuration information for the block. This information is used in
different ways by different types of blocks, but is always specified using
any of:
Block configuration syntax
Value
Written as
Also accepted
Boolean
:key:!key
:key(True):key(False)
Number
:key(42)
:key(2.3)
String
:key<str>
:key('str'):key"str":key'str':key「str」
String with spaces
:key('str with spaces')
:key("str with spaces"):key'str with spaces':key「str with spaces」
List
:key<a b>
:key('a','b')
Hash, identifier keys
:key{:a<x>, :b(42), :c}
:key{a=>1, b=>'str', c=>True}
Hash, other keys
:key{1=>'x', 2=>'y'}
The first column of the table names the kind of the value. A rule that refers
to the kind of a value refers to these names.
All option keys and values are constants: Podlite is a specification
language, not a programming language. An option value cannot be a closure.
Whitespace surrounding a value is not significant and is removed. The
delimiters that enclose a value determine how it is read.
A single word enclosed in angle brackets is not converted to another type. A
comma is retained as part of the value, so :key<a,b> is read as the
string a,b. Quotation marks delimit a string and suppress separation by
whitespace, which makes :key<'a b'> a string. Guillemets are not
quotation marks and are retained as part of the value.
A delimiter with nothing inside it carries the empty value of its kind, so
:key<> and :key() are an empty list and :key{} is an empty hash.
An empty string is written with quotation marks, as :key('').
Apart from True and False, an unquoted word is not a valid element of a
parenthesised list or value of a hash entry. Inside braces an option is read
as on the marker line: with no value it denotes the boolean true, and negated
it denotes the boolean false. The key of an option is an identifier.
A value that cannot be read is discarded together with its attribute, and
parsing of the block continues. Podlite parsers issue a warning that
identifies the position of the discarded value.
The configuration section may be extended over subsequent lines by
starting those lines with an = in the first (virtual) column followed
by a whitespace character. A value in parentheses or braces may continue on
such a line. A value in angle brackets or in quotation marks ends with its
line.
The lines following the opening delimiter and configuration are the
data or contents of the block, which continue until the block's matching
=end marker line. For most block types, these contents may be
indented if you wish, without them being treated as code blocks. Indented text is only treated as code within
=pod, =nested, =item, =code,
and semantic blocks.
The general syntax is:
=begin BLOCK_TYPEOPTIONAL CONFIG INFO
= OPTIONAL EXTRA CONFIG INFOBLOCK CONTENTS
=end BLOCK_TYPE
For example:
=begin table :caption('Table of Contents')
Constants 1
Variables 10
Subroutines 33
Everything else 57
=end table
=begin Name :required
= :width(50)
The applicant's full name
=end Name
=begin Contact :optional
The applicant's contact details
=end Contact
Note that no blank lines are required around the directives; blank
lines within the contents are always treated as part of the contents.
This is a universal feature of Podlite.
Note also that in the following specifications, a "blank line" is a line
that is either empty or that contains only whitespace characters. That
is, a blank line matches the following pattern: /^^ \h* $$/. Podlite uses
blank lines as delimiters, rather than empty lines, to minimize unpleasant
surprises when stray spaces or tabs mysteriously turn up in hitherto
empty lines.
Paragraph blocks
Paragraph blocks are introduced by a =for marker and terminated by
the next Podlite directive or the first blank line (which is not
considered to be part of the block's contents). The =for marker is
followed by the name of the block and optional configuration
information. The general syntax is:
=for BLOCK_TYPEOPTIONAL CONFIG INFO
= OPTIONAL EXTRA CONFIG INFOBLOCK DATA
For example:
=for table :caption('Table of Contents')
Constants 1
Variables 10
Subroutines 33
Everything else 57
=for Name :required
= :width(50)
The applicant's full name
=for Contact :optional
The applicant's contact details
Abbreviated blocks
Abbreviated blocks are introduced by an '=' sign in the
first column, which is followed immediately by the typename of the
block. The rest of the line is treated as block data, rather than as
configuration. The content terminates at the next Podlite directive or the
first blank line (which is not part of the block data). The general
syntax is:
=BLOCK_TYPEBLOCK DATAMORE BLOCK DATA
For example:
=table
Constants 1
Variables 10
Subroutines 33
Everything else 57
=Name The applicant's full name
=Contact The applicant's contact details
Note that abbreviated blocks cannot specify configuration information. If
configuration is required, use a =for or =begin/=end instead.
Block equivalence
The underlying documentation model treats all block
specifications (delimited, paragraph, and abbreviated) the same way.
It is possible to choose the form is most convenient for a particular
documentation task. In the descriptions that follow, the abbreviated
form will generally be used, but should be read as standing for all
three forms equally.
this automatically implies that you could also write that block as:
=for head1
Top Level Heading
or:
=begin head1
Top Level Heading
=end head1
Standard configuration options
Podlite predefines a small number of standard configuration options that can be
applied uniformly to any built-in block type. These include:
:caption
This option assigns a title to the given block, which is typically used to create
a table of contents.
:id
This option enables the explicit definition of identifiers for blocks and use those
IDs for linking purposes (see #Links).
:nested
This option specifies that the block is to be nested within its current
context. For example, nesting might be applied to block quotes, to textual
examples, or to commentaries. In addition the =code,
=item, =input, and =output
blocks all have implicit nesting.
Nesting of blocks is usually rendered by adding extra indentation to the
block contents, but may also be indicated in other ways:
by boxing the contents, by changing the font or size of the nested text,
or even by folding the text (so long as a visible placeholder is provided).
Occasionally it is desirable to nest content by more than one level:
=begin para :nested
=begin para :nested
=begin para :nested
"We're going deep, deep, deep undercover!"
=end para
=end para
=end para
This can be simplified by giving the :nested option a positive integer
value:
=begin para :nested(3)
"We're going deep, deep, deep undercover!"
=end para
You can also give the option a value of zero, to defeat any implicit
nesting that might normally be applied to a paragraph. For example, to
specify a block of code that should appear without its usual
nesting:
=comment Don't nest this code block in the usual way...
=begin code :nested(0)
1 2 3 4 5 6
123456789012345678901234567890123456789012345678901234567890
|------|-----------------------|---------------------------|
line instruction comments
number code
=end code
Note that :!nested could also be used for this purpose:
=Z<>begin code :!nested
:numbered
This option specifies that the block is to be numbered. The most common
use of this option is to create numbered headings and
ordered lists, but it can be applied to any block.
The numbering conventions for headings and lists are specified in those
sections, but it is up to individual renderers to decide how to display
any numbering associated with other types of blocks.
Note that numbering is never explicit; it is always implied by context.
:checked
This attribute indicates that a checkbox should be added to that block.
It is possible to apply a :checked attributes to any block.
The most common use of this option is to create task lists.
For an unchecked checkbox the :!checked is used.
The task list item marker (checkbox) is added to the output.
In HTML output, this would be represented as an
input type="checkbox" element.
The specification does not define how these checkboxes are interacted with.
Implementors are free to choose whether they render them as disabled,
unchangeable elements, or handle dynamic interactions like checking and unchecking
in the final rendered document.
:folded
This option specifies that the block content is not presented
immediately but is available on demand. The attribute controls the
initial state: :folded or :folded(1) indicates the content is
concealed by default; :!folded or :folded(0) indicates it is
revealed by default.
=for table :folded :caption('Culinary Techniques for Sustainability')
Sous-vide Low energy consumption
---------- -------------------------
Steaming Preserves nutrients
Baking Efficient for batch cooking
When applied to a heading block, the attribute governs the heading
and all associated lower-level content, forming a hierarchical
structure.
=for head2 :folded
Green Energy Overview
In non-interactive contexts, the distinction may be expressed through
visual means such as sidebar placement or reduced emphasis.
:lang
This option is used to provide information about the programming language used in a specific code block.
This helps ensure that the code is displayed and interpreted correctly
by rendering engines or syntax highlighters.
Here's a table that lists a few programming languages along with their possible
values for the :lang attribute:
Matching languages and lang attribute values
Programming language
Possible :lang values
C++
cpp
CSS
css
HTML
html
Java
java
JavaScript
javascript
Python
python
Raku
raku
If the language is not specified, the default language is used based
on the file extension or mime type of the current document.
:allow
This option expects a list of markup codes that are to be recognized
within any V<> codes that appear in (or are implicitly applied to)
the current block. The option is most often used on =code blocks to
allow mark-up within those otherwise verbatim blocks, though it can be
used in any block that contains verbatim text. See #Formatting
within code blocks.
Selectors
Selectors consist of patterns that help identify and filter specific blocks
within documents. Each pattern contains optional source of blocks and block names.
The general syntax is:
EXTERNAL_SOURCE
or
[ EXTERNAL_SOURCE | ] BLOCKS_SELECTOR
...where
EXTERNAL_SOURCE - optional source of blocks for filtering, default current document,
BLOCK_SELECTOR - list of patterns; a pattern is a block name or the
universal *, optionally followed by a predicate
For example:
Selector
Description
head1, head2, item1
all head1, head2 and item1 blocks from document
file:article.pod6
head1, head2 all head1 and head2 blocks from article.pod6 file
file:./includes/*.pod6 | head1, head2
all head1 and head2 blocks from pod6 files placed in includes directory
doc:Data::Dumper
code all code blocks from a module documentation
file:/docs/**/*.md | head1
search headers with first level for all ".md" files within the "docs" directory and its subdirectories.
Please note that while the Selector blocks provide a way to query and filter specific elements
within Markdown files, Markdown itself doesn't have formal named blocks like the Podlite syntax.
Instead, Markdown uses a lightweight markup to structure content. The above table provides a mapping
between Podlite block names and their corresponding Markdown elements.
A table of correspondences for some Podlite blocks and markdown blocks
A pattern may carry a predicate. The predicate is written in square brackets
after the block name. It tests the configuration of a block. A block is
selected when its name matches the pattern and every condition of the
predicate holds.
Conditions are written in the syntax of the
block configuration table, so an operator means the
same thing in a declaration and in a predicate.
Predicate operators
Written as
Holds when
[ :attr ]
the attribute exists and its value is neither empty nor false
[ :!attr ]
the value is false
[ :?attr ]
the attribute exists, whatever its value
[ :!?attr ]
the attribute does not exist
[ :attr<value> ]
the value equals the operand
[ :!attr<value> ]
the attribute exists and its value does not equal the operand
[ :attr~<element> ]
the operand occurs among the values
[ :attr(in V,W) ]
a value of the attribute is any of the operands
Predicates are case-sensitive. No adjustment to case is provided.
A value containing whitespace is written in quotation marks, as it is in a
declaration:
The character * forms a universal pattern, which matches a block of any
name and stands in the position of a block name. It is used when the selection
is by configuration rather than by name:
* is not a valid identifier start, so a pattern and a block name cannot be
confused.
A universal pattern without a predicate selects every block and filters
nothing.
Within a single selection, one attribute may be encountered as several kinds
of value, because a universal pattern matches blocks of every name. Every
predicate is defined for every kind of value. The selection is not interrupted
by a kind it does not expect.
Empty and absent values
An attribute that exists with an empty value is distinct from an attribute
that does not exist and from one whose value is false. The following table
states the outcome for each predicate:
Predicates over empty and absent values
Declared as
[ :attr ]
[ :!attr ]
[ :?attr ]
[ :!?attr ]
:attr<value>
true
false
true
false
:attr(False)
false
true
true
false
:attr<>
false
false
true
false
:attr()
false
false
true
false
:attr('')
false
false
true
false
not declared
false
false
false
true
No predicate distinguishes an empty list from an empty string. An empty list
holds no values. An empty string is one value of zero length. Both are false
and both satisfy the tests above in the same way. The distinction is preserved
in the document tree.
Membership
[ :attr~<V> ] holds when every element of V occurs among the values of
the attribute. Values present in the attribute and absent from the operand do
not affect the outcome. The condition states what is required to be present.
The condition says nothing about what is required to be absent.
The operand of ~<> is read by the
rule that governs any value. Whitespace inside the
operand separates a list. A single word is a string. Quotation marks produce
one element that may contain whitespace.
=for para :id<A> :tags<draft review>
=for para :id<B> :tags<draft review urgent>
=for para :id<C> :tags<draft>
=for para :id<D> :tags<'draft review'>
| para[ :tags~<draft> ] # A, B, C
| para[ :tags~<draft review> ] # A, B
| para[ :tags~<'draft review'> ] # D
An empty operand is an error and is reported when the selector is read. An
empty list occurs among any set of values, so the condition would hold for
every block and would test nothing.
Membership is not a test for a substring. [ :tags~<spec> ] does not hold for
:tags<specification>, and ~<> never falls back to comparing parts of a
value.
Addressing the keys of a hash is not defined. Applied to a hash, ~<> yields
no match.
Operations in parentheses
The operation is named, and its operands follow the name inside parentheses:
| Invoice[ :author('John Doe') ] # a value
| Invoice[ :status(in 'draft','issued') ] # an operation
What follows the opening parenthesis is read as a value when it is one of the
forms of the block configuration table. Every other
name is the name of an operation. A name standing in that position which this
specification does not define is an error, reported when the selector is read.
Operations in parentheses
Written as
Holds when
[ :attr(in V,W) ]
a value of the attribute is any of the operands
in is written with one or more operands. An absent operand and an empty
operand are both errors, reported when the selector is read.
Literal operands are separated by commas, following the parenthesised list
form in the block configuration table. Angle brackets
instead separate values with whitespace.
The condition holds when at least one value of the attribute equals an
operand. Other values of the attribute do not affect the outcome, as in:
The operands are numbers or values in quotation marks, separated by commas.
Alternatively, a selector supplies the values and is the sole
operand. Where the operand is a selector, the condition holds when a value of
the attribute is a value the selector yields:
From a definition the term is taken, as definition lists
state; from a block whose kind defines no single value nothing is taken.
A source is resolved and its content is read before a condition carrying a
selector reports a match or a non-match. A source that cannot be resolved is
an error, not an empty source. Such a failure establishes neither a match nor
a non-match.
Within an operand, a number sign separates an internal address from the path.
A path containing that character cannot be written there.
Combining conditions
Whitespace separates one condition from the next. A block is selected only
when every condition holds. Whitespace enclosed by brackets, by parentheses or
by quotation marks belongs to the condition it appears in.
code[ :lang<python> :numbered ]
A comma separates whole patterns, and a block is selected when it matches any
of them:
head1, head2, code[ :lang<python> ]
The result is a set in document order. A block that matches more than one
pattern appears once.
Non-matching conditions
A condition naming an attribute that no block declares holds for no block. No
diagnostic is required.
A value whose kind does not admit the test is reported as a non-match. The
selection is not interrupted, which the universal pattern requires. Under it,
values of unexpected kinds are encountered by construction.
Block types
Podlite offers notations for specifying a wide range of standard block types...
Headings
Podlite provides an unlimited number of levels of heading, specified by the
=headN block marker. For example:
=head1 A Top Level Heading
=head2 A Second Level Heading
=head3 A third level heading
=head86 A "Missed it by I<that> much!" heading
While Podlite parsers are required to recognize and distinguish all levels
of heading, Podlite renderers are only required to provide distinct
renderings of the first four levels of heading (though they may, of
course, provide more than that). Headings at levels without distinct
renderings would typically be rendered like the lowest distinctly
rendered level.
Numbered headings
You can specify that a heading is numbered using the :numbered option. For
example:
=for head1 :numbered
The Problem
=for head1 :numbered
The Solution
=for head2 :numbered
Analysis
=for head3
Overview
=for head3
Details
=for head2 :numbered
Design
=for head1 :numbered
The Implementation
which would produce:
1. The Problem
2. The Solution
2.1. Analysis
Overview
Details
2.2: Design
3. The Implementation
It is usually better to preset a numbering scheme for each heading
level, in a series of configuration blocks:
=config head1 :numbered
=config head2 :numbered
=config head3 :!numbered
=head1 The Problem
=head1 The Solution
=head2 Analysis
=head3 Overview
=head3 Details
=head2 Design
=head1 The Implementation
Alternatively, as a short-hand, if the first whitespace-delimited word
in a heading consists of a single literal # character, the # is
removed and the heading is treated as if it had a :numbered option:
=head1 # The Problem
=head1 # The Solution
=head2 # Analysis
=head3 Overview
=head3 Details
=head2 # Design
=head1 # The Implementation
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:
=head6 # The Rescue of the Kobayashi Maru
should produce something like:
2.3.8.6.1.9. The Rescue of the Kobayashi Maru
Ordinary paragraph blocks
Ordinary paragraph blocks consist 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 at (virtual) column
1. The paragraph is terminated by the first blank line or block
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
Within a =pod, =item, =defn, =nested, or
semantic block, ordinary paragraphs do not require
an explicit marker or delimiters, but there is also an explicit para
marker (which may be used anywhere):
=para
This is an ordinary paragraph.
Its text will be squeezed and
short lines filled.
and likewise the longer =for and =begin/=end forms. For example:
=begin para
This is an ordinary paragraph.
Its text will be squeezed and
short lines filled.
This is I<still> part of the same paragraph,
which continues until an...
=end para
As the previous example implies, when any form of explicit =para block
is used, any whitespace at the start of each line is removed during rendering.
In addition, within a delimited =begin para/=end para block, any
blank lines are preserved.
Code blocks
Code blocks are used to specify pre-formatted text (typically source
code), which should be rendered without rejustification, without
whitespace-squeezing, and without recognizing any inline markup
codes. Code blocks also have an implicit nesting
associated with them. Typically these blocks are used to show examples
of code, mark-up, or other textual specifications, and are 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.
For example:
This ordinary paragraph introduces a code block:
$this = 1 * code('block');
$which.is_specified(:by<indenting>);
Implicit code blocks may only be used within =pod, =item, =defn,
=nested, or semantic blocks.
There is also an explicit =code block (which can be specified within
any other block type, not just =pod, =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 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.
Formatting within code blocks
Although =code blocks automatically disregard all markup
codes, occasionally you may still need to specify
some formatting 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 code).
You can specify a list of markup codes 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 codes. Those codes will then remain active inside the
code block. For example:
The :lang attribute will be used to provide information about the
programming language used in a particular block of code. This helps
in ensuring that the code is correctly rendered and interpreted by the
renderers or syntax highlighting tools.
For example:
=begin code :lang<raku>
sub demo {
say 'Hello R<name>';
}
=end code
I/O blocks
Podlite also provides blocks for specifying the input and output of programs.
The =input block is used to specify pre-formatted keyboard input,
which should be rendered without rejustification or squeezing of whitespace.
The =output block is used to specify pre-formatted terminal or file
output which should also be rendered without rejustification or
whitespace-squeezing.
Note that, like =code blocks, both =input and =output blocks have an
implicit level of nesting. They are also like =code blocks in that they
are typically rendered in a fixed-width font, though ideally all three blocks
would be rendered in distinct font/weight combinations (for example: regular
serifed for code, bold sans-serif for input, and regular sans-serif for
output).
Unlike =code blocks, both =input and =output blocks honour any
nested markup codes. This is particularly useful since a sample of
input will often include prompts (which are, of course, output).
Likewise a sample of output may contain the occasional interactive
component. Podlite provides special markup codes
(K<> and T<>) to indicate embedded input or output, so you can use
the block type that indicates the overall purpose of the sample (i.e. is
it demonstrating an input operation or an output sequence?) and then use
the "contrasting" markup code within the block.
For example, to include a small amount of input in a sample of output
you could use the K<> markup code:
Lists in Podlite are specified as a series of contiguous =item blocks. No
special "container" directives or other delimiters are required to
enclose the entire list. For example:
Lists may be multi-level, with items at each level specified using the
=item1, =item2, =item3, etc. blocks. Note that =item is just
an abbreviation for =item1. For example:
Podlite parsers must issue a warning if a "level-N+1" =item block
(e.g. an =item2, =item3, etc.) appears anywhere except where there
is a preceding "level-N" =item in the same surrounding block. That
is, an =item3 should only be specified if an =item2 appears
somewhere before it, and that =item2 should itself only appear if
there is a preceding =item1.
Note 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 CORRECT...
=begin item1 ---------------
The choices are: |==< Level 1
=end item1 ---------------
=item2 Liberty ==================< Level 2
=item2 Death ==================< Level 2
=item2 Beer ==================< Level 2
Ordered lists
An item is part of an ordered list if the item has a :numbered
configuration option:
=for item1 :numbered
Visito
=for item2 :numbered
Veni
=for item2 :numbered
Vidi
=for item2 :numbered
Vici
This would produce something like:
1. Visito
1.1. Veni
1.2. Vidi
1.3. Vici
although the numbering scheme is entirely at the discretion of the
renderer, so it might equally well be rendered:
1. Visito
1a. Veni
1b. Vidi
1c. Vici
or even:
A: Visito
(i) Veni
(ii) Vidi
(iii) Vici
Alternatively, if the first word of the item consists of a single #
character, the item is treated as having a :numbered option:
=item1 # Visito
=item2 # Veni
=item2 # Vidi
=item2 # Vici
To specify an unnumbered list item that starts with a literal #, either
make the octothorpe verbatim:
=item V<#> introduces a comment
or explicitly mark the item itself as being unnumbered:
=for item :!numbered
# introduces a comment
The numbering of successive =item1 list items increments
automatically, but is reset to 1 whenever any other kind of non-ambient
Podlite block appears between two =item1 blocks. For example:
The options are:
=item1 # Liberty
=item1 # Death
=item1 # Beer
The tools are:
=item1 # Revolution
=item1 # Deep-fried peanut butter sandwich
=item1 # Keg
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 (=item2, =item3, etc.) only resets
(to 1) when the higher-level item's numbering either resets or increments.
To prevent a numbered =item1 from resetting after a non-item block,
you can specify the :continued option:
=for item1
# Retreat to remote Himalayan monastery
=for item1
# Learn the hidden mysteries of space and time
I<????>
=for item1 :continued
# Prophet!
which produces:
1. Retreat to remote Himalayan monastery
2. Learn the hidden mysteries of space and time
????
3. Prophet!
Task lists
In addition to the ordered list Podlite also supports
task lists, which are commonly known as checklists or to-do lists.
To create a task list item just apply a :checked
attribute to =item block.
Alternatively, if item content starts with brackets with space ([ ])
the item is treated as having a :!checked attribute.
To select a checkbox, add an x in between the brackets ([x]). it eqvivalent
of :checked attribute.
For example:
=item [x] Buy groceries
=itme [ ] Clean the garage
It possiible to create multilevel to-do lists, which permits the
inclusion of various task levels or sub-tasks.
Here's an example:
=item1 [ ] Work
=item2 [ ] Prepare the presentation
=item2 [x] Send emails
=item1 [ ] Home
=item2 [ ] Vacuum the living room
=item2 [ ] Water the plants
Unordered lists
List items that are not :numbered or :checked are treated as defining unordered
lists. Typically, such lists are rendered with bullets. For example:
=item1 Reading
=item2 Writing
=item3 'Rithmetic
might be rendered:
• Reading
— Writing
¤ 'Rithmetic
As with numbering styles, the bulletting strategy used for different levels
within a nested list is entirely up to the renderer.
Multi-paragraph list items
Use the delimited form of the =item block to specify items that
contain multiple paragraphs. For example:
Let's consider two common proverbs:
=begin item :numbered
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 :numbered
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 see, folk wisdom is often of dubious value.
which produces:
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.
Definition lists
To create term/definition lists, use a =defn block. This is
similar in effect to an =item block, in that a series of =defn
blocks implicitly defines a list (but which might then be rendered into
HTML using <DL>...</DL> tags, rather than <UL>...</UL> tags)
The first non-blank line of content is treated as a term being defined,
and the remaining content is treated as the definition for the term.
For example:
=defn MAD
Affected with a high degree of intellectual independence.
=defn MEEKNESS
Uncommon patience in planning a revenge that is worth while.
=defn
MORAL
Conforming to a local and mutable standard of right.
Having the quality of general expediency.
Like other kinds of list items, definitions can be numbered, using either an
option or a leading #:
=for defn :numbered
SELFISH
Devoid of consideration for the selfishness of others.
=defn # SUCCESS
The one unpardonable sin against one's fellows.
Nesting blocks
Any block can be nested by specifying a :nested option on it:
=begin para :nested
We are all of us in the gutter,E<NL>
but some of us are looking at the stars!
=end para
However, qualifying each nested paragraph individually quickly becomes
tedious if there are many in a sequence, or if multiple levels of
nesting are required:
=begin para :nested
We are all of us in the gutter,E<NL>
but some of us are looking at the stars!
=end para
=begin para :nested(2)
-- Oscar Wilde
=end para
So Podlite provides a =nested block that marks all its contents as being
nested:
=begin nested
We are all of us in the gutter,E<NL>
but some of us are looking at the stars!
=begin nested
-- Oscar Wilde
=end nested=end nested
Nesting blocks can contain any other kind of block, including implicit
paragraph and code blocks. Note that the relative physical indentation
of the blocks plays no role in determining their ultimate nesting.
The preceding example could equally have been specified:
=begin nested
We are all of us in the gutter,E<NL>
but some of us are looking at the stars!
=begin nested
-- Oscar Wilde
=end nested=end nested
Tables
Simple tables can be specified in Podlite using a =table block.
The table may be given an associated description or title using the
:caption option.
Columns are separated by two or more consecutive whitespace characters
(double-space),
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
(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 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
With header:
=begin table
Directive Specifies
_________ ____________________________________________________
C<=begin> Start of an explicitly terminated block
C<=config> Lexical modifications to a block or markup code
=end table
Or:
=begin table
Energy Source Benefit
Solar power Reduces electricity bills
Wind energy Clean power source
Hydroelectric power Highly efficient
Geothermal energy Low emissions
Biomass Reduces waste
=end table
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
Advanced Table Format
Tables may be constructed using =row and =cell blocks.
The =row blocks represent individual rows within the table.
The =cell blocks exist within rows and contain the actual content of the table.
These cells can contain text, data, or other blocks.
Each =row block may have an optional :header attribute, designating
it as a header row. Header rows typically contain labels or titles
for columns and are visually distinct.
The =cell blocks can also have two important attributes:
:colspan
This attribute specifies the number of columns a cell should span horizontally.
It allows cells to merge and occupy multiple adjacent columns, creating a visually
unified cell.
:rowspan
This attribute determines how many rows a cell should span vertically.
Cells with :rowspan can cover multiple rows in a table, creating a vertical merge effect.
The following examples demonstrate how :colspan and :rowspan attributes
are used to create tables with merged cells, which is particularly useful
for complex data structures.
=begin table
=begin row :header
=for cell :colspan(2)
Item and Quantity
=cell Description
=end row
=begin row
=cell Apples
=cell 5
=for cell :rowspan(2)
Fruit for snacking
=end row
=begin row
=cell Bananas
=cell 3
=end row
=end table
The resulting table is rendered as follows:
---------------------------------------------------------------
| Item and Quantity | Description |
|----------------------------------|--------------------------|
| Apples | 5 | |
|--------------|-------------------| Fruit for snacking |
| Bananas | 3 | |
---------------------------------------------------------------
Each =row block may only contain =cell blocks or blank lines as delimiters.
All other types of blocks within the =row are implicitly wrapped
by =cell blocks.
For example:
=begin table
=begin row :header
=cell Diagram or Picture
=cell Description
=end row
=begin row
=picture spacecraft_in_orbit.jpg
=para
A vehicle designed for space travel
=end row
=begin row
=Mermaid
graph TD;
A[Space Station] --> B[Mars Base]
A space station connected to a Mars base
=end row
=end table
Cell spanning attributes and nested block content within cells are
semantic properties of the table document model and are preserved
in the document tree.
For loading external CSV or TSV data into tables, use =data-table
(#Data-table blocks).
Error Recovery
The column separator type is determined per line. If visible separators
(| or +) are present, they are used; otherwise, sequences of two
or more consecutive whitespace characters serve as separators. Mixed
separator types across lines produce a warning; the table is not
rejected.
The expected cell count is established from the header row or, in its
absence, the row with the most cells. Rows with fewer cells are padded
with empty cells; rows with excess cells are truncated. In both cases,
a warning is issued.
For =row/=cell tables, separator recovery does not apply, but
mismatched cell counts produce a warning.
For tables sourced from file: or data: references, three levels
of error are defined. If the source cannot be resolved, an error is
issued and the table is rendered as an empty block. If the source
cannot be interpreted as CSV, the content is rendered as a =code
block. If the CSV contains rows with unequal field counts, parsing
proceeds with padding for missing fields, and a warning is issued.
Named or modular custom blocks
Blocks whose names contain at least one uppercase and one lowercase
letter are assumed to be destined for specialized renderers or parser
plug-ins. For example:
Ideally, each named block should have a corresponding handler responsible
for its rendering and processing.
In the absence of a handler for named block, the implementation should
allow the content to degrade gracefully, ensuring that the core message
or functionality remains accessible even if some advanced features cannot
be rendered. As result, that blocks my be displayed as verbatim or
placeholder content or even not rendered at all.
Alongside the verbatim or placeholder content, the renderer could provide
an unobtrusive yet informative error message, explaining that the named block
could not be processed.
Note that all block names consisting entirely of lowercase or entirely of
uppercase letters are reserved. See #Semantic blocks.
The =data-table block renders CSV and TSV tables. It accepts
data in three forms: inline body, an external file via :src, or
a referenced =data block. :columns declares column projection;
:rename declares display name overrides.
=begin data :key<sales> :mime-type('text/csv; header=present')
quarter,region,revenue
Q1,EU,120
=end data
=for data-table :src<data:sales> :columns<quarter revenue>
The body is verbatim and is parsed per :mime-type using RFC 4180
for text/csv or RFC 4180 §3 for text/tab-separated-values.
The standard :allow option enables markup codes within each cell;
listed codes are interpreted after the cell is parsed from CSV or
TSV. Without :allow, cell content is plain text.
The :mime-type option declares the format. With :src<data:X>,
:mime-type is inherited from the referenced block; declaring it
on =data-table in this case produces an error. With
:src<file:X.ext>, :mime-type may be omitted and is inferred
from the file extension. With :src<http:> or :src<https:>,
:mime-type may be omitted and is inferred from the HTTP
Content-Type response header. For inline body, :mime-type is
required.
Each =data-table block can include the following attributes:
:src
This option declares the source URI. Accepted schemes are file:
for local files, data: for references to =data blocks by key,
http: and https: for remote resources, and doc: for
cross-document references. When the scheme is omitted, file: is
the default. For example:
Relative paths in file: URIs resolve against the file declaring
the directive, not the parent including document.
The :src option and inline body content are mutually exclusive;
declaring both produces an error at parse time.
:columns
This option declares ordered column projection: which source columns
appear in the output and in what order. Numeric indices refer to
column position (1-based) in the source, not row position. For
example:
Output order matches list order; columns absent from the list are
excluded. Omitting the option renders all source columns in their
source order.
An empty value for :columns produces an error; omit the option
to render all columns. Out-of-range indices produce an error.
:rename
This option declares display name overrides for projected columns.
The value is a hash mapping source identifiers, either names or
indices, to display strings. For example:
Only columns appearing as hash keys receive overrides; other columns
retain their source name when header=present or numeric index
when header=absent.
Hash keys referring to columns absent from :columns (or from the
source when :columns is omitted) produce an error.
Podlite comments
Podlite comments refers to Podlite blocks that should not
be displayed by any renderer. However, they are still may be part of the
internal Podlite representation.
Comments are useful for meta-documentation (documenting the documentation):
=comment Add more here about the algorithm
and for temporarily removing parts of a document:
=item # Retreat to remote Himalayan monastery
=item # Learn the hidden mysteries of space and time
=item # Achieve enlightenment
=begin comment
=item # Prophet!
=end comment
Data blocks
The =data block is used to embed various types of data directly into a document.
For example, to include a CSV file in a document, it is possible to
use the following syntax:
=begin data :key<sales_data> :mime-type<text/csv>
name,month,amount
John Doe,January,1000
Jane Doe,February,1500
=end data
Each =data block can be given a :key option, to name it. The contents
of any =data block with a key are addressable via
the data: schema. For example:
=begin data :key<employee_data> :mime-type<text/csv>
id,name,position,department
1,John Doe,Manager,Marketing
2,Jane Smith,Developer,Engineering
3,Bob Brown,Designer,Product
=end data
=table data:employee_data
Each =data block can include several attributes to provide additional information
about the contained data:
:filename
This option specifies the original file name of the embedded data, which
can be used to hint at the type of data contained if the :mime-type is not
explicitly provided.
:mime-type
This option indicates the MIME type of the data, such as image/png for PNG images,
which helps determine how the data should be interpreted and processed.
The header MIME parameter (per RFC 4180 §3) is recognised on
:mime-type for CSV and TSV content. It accepts present or
absent, with default absent. When header=present, the
renderer treats the first row as column labels in =table data:X:
=begin data :key<planets> :mime-type('text/csv; header=present')
name,radius_km,moons
Mercury,2440,0
Venus,6052,0
Earth,6371,1
Mars,3390,2
=end data
=for table :caption('Inner planets')
data:planets
For =data-table blocks, the :mime-type option may be omitted
when the format can be inferred from the source. With
:src<file:X.ext>, the format is inferred from the file extension
via the MIME extension table below; matching is case-insensitive and
multi-dot filenames use the last extension component. With
:src<http:> or :src<https:>, the format is inferred from the
HTTP Content-Type response header. With :src<data:X>, the MIME
type is inherited from the referenced =data block.
For inline body and for sources where inference fails (unknown file
extension, missing or generic HTTP Content-Type, absent file
extension), :mime-type is required and its omission produces an
error. An explicit :mime-type always overrides inference.
Here is a list of common MIME types and their corresponding file extensions:
MIME Type
File Extension
text/plain
.txt
text/markdown
.md, .markdown
text/podlite
.podlite, .pod6
application/json
.json
application/xml
.xml
image/jpeg
.jpg, .jpeg
image/png
.png
application/pdf
.pdf
application/zip
.zip
audio/mpeg
.mp3
video/mp4
.mp4
application/msword
.doc, .docx
text/csv
.csv
text/tab-separated-values
.tsv, .tab
:access-time and :modify-time
These attributes record the times when the data was last accessed or
edited.
:encoding
This option specifies the encoding method used to store the data.
For non-text data, such as images in PNG format,
the encoding method base64 is used.
In the example above, we have a =data block with :keyLogo that stores
the base64-encoded image data. We also specify the filename, mime type,
access time, and edit time as attributes of the =data block.
The image can then be referenced using the =picture block with the scheme
data: and the block name Logo.
The =data blocks are just regular Podlite blocks and may appear anywhere
within a source file, and as many times as required.
Note that in Podlite, it is possible to specify =data blocks
after the point in the source where their contents will be used.
=data blocks are never rendered by the standard Podlite renderers.
Semantic blocks
All uppercase block typenames are reserved for specifying standard
documentation, publishing, or source components.
The plural forms of each of these keywords are also reserved, and are
aliases for the singular forms.
Most of these blocks are typically used in their full delimited forms:
=begin SYNOPSIS
use Magic::Parser;
my Magic::Parser $parser .= new();
my $tree = $parser.parse($fh);
=end SYNOPSIS
Semantic blocks can be considered to be variants of the =head1 block
in most respects (and most renderers will treat them as such). The main
difference is that, in a =head1 block, the heading is the contents of
the block; whereas, in a semantic block, the heading is derived from the
typename of the block itself and the block contents are instead treated as
the =para or =code block(s) belonging to the heading.
The use of these special blocks is not required; you can still just write:
=head1 SYNOPSIS
=begin code :lang<raku>
use Magic::Parser
my Magic::Parser $parser .= new();
my $tree = $parser.parse($fh);
=end code
However, using the keywords adds semantic information to the
documentation, which may assist various renderers, summarizers, coverage
tools, document refactorers, and other utilities. This is because a
semantic block encloses the text it controls (unlike a =head1,
which merely precedes its corresponding text), so using semantic blocks
produces a more explicitly structured document.
Note that there is no requirement that semantic blocks be rendered in
a particular way (or at all). Specifically, it is not necessary to
preserve the capitalization of the keyword. For example, the
=SYNOPSIS block of the preceding example might be rendered like so:
3. Synopsis
use Raku::Magic::Parser;
my $rep = Raku::Magic::Parser.parse($fh, :all_pod);
Table of contents
The =toc block creates an autogenerated table of contents (TOC)
in a document. The TOC is an index of section titles within the document,
and its structure is determined by the document's organization.
The first non-blank line of =toc content is treated as a selector.
For example:
=toc head1, head2, head3, item1, item2, table
or:
=toc head1, head2, head3
The TOC displays without a caption by default.
However, a caption can be specified using the :caption
attribute of the =toc block.
For example:
=for toc :caption('Table of contents')
head1, head2, head3
The TOC entries are built using the :caption attribute content
within the block. If this attribute is not present, the text
presentation of the block's content serves as the TOC entry.
The depth of the generated TOC is determined by the "Selector" argument.
The selector is processed, and headers or filtered blocks that
allow levels are used to build the TOC levels. If a block lacks an
associated level, it is rendered at a level one higher than the previous
block with a level in the TOC.
Note that all semantic blocks are treated as equivalent
to head1 headings, and the =item1/=item equivalence is preserved.
The :folded-levels attribute indicates which levels of the TOC should
be folded.
=for toc :folded-levels(2,3) :caption('Table of contents')
head1, head2, item1
If the :folded-levels attribute is provided with a set
of key-value pairs, it indicates the folding state of each
specified level.
The value 0 for level 3 indicates that this level should
remain unfolded. Levels 2 and 4 are folded.
This configuration enables customized folding within the TOC.
The TOC is inserted at the location of the =toc block.
To enable the autogenerated TOC controlled by the renderer, set the :toc
document attribute for the =pod block. In this case, the specific configuration
and outcome of the TOC are determined by the renderer implementation.
Include directive
The =include directive enables reuse of specific parts of documents within
project sources. It is useful for complex documents that combine sections
from different files while maintaining overall context and structure.
The =include construct is classified as a directive, consistent with
=config and =alias. As a directive, =include references external
content rather than containing it directly.
The =include directive is followed by a "Selector" that specifies the
content to be included.
In this example, the content of the file chapter01.pod6 located in the
./includes directory is included:
=include file:./includes/chapter01.pod6
A wildcard "Selector" enables inclusion
of content from all the Markdown files:
=include file:./includes/*.md
It is possible to include blocks from the same document.
This feature proves valuable when reusing parts of existing content.
For instance, a semantic block =VERSION can be included as demonstrated:
=include VERSION
=VERSION 1.0.0
or, equivalently:
=VERSION 1.0.0
=VERSION 1.0.0
Podlite detects the type of the included file by its extension.
For example, if the included file has a .md extension,
it is treated as a Markdown file.
To override the type of the included file, the :mime-type attribute
is placed on the directive line after the source URI. For example:
The :mime-type attribute lets the parser handle files whose extension
does not match their actual type.
External content can introduce vulnerabilities such as code injection.
Tools displaying included content should provide warnings.
=set directives accumulated before =include apply to the first
block of the resolved included content (resolution-time targeting).
The =include directive itself does not receive =set attributes.
Full discipline: Block attribute assignment with =set.
Section boundaries
The =boundary directive marks a structural transition between major
document sections such as chapters, parts, or topics. The transition
is semantic, not presentational.
A =boundary is a directive, not a block. Hence, there is no
paragraph or delimited form of the =boundary directive. It accepts
an optional :caption attribute that describes the transition:
=boundary=boundary :caption<BOUNDARY_DESCRIPTION>
Boundaries are placed between blocks, not within them, at the same
structural level as the blocks they separate:
=head1 Chapter One
Content of chapter one.
=boundary
=head1 Chapter Two
Content of chapter two.
Rendering is format-specific. Renderers may use page breaks
(paginated output), thematic breaks (web), or separator lines (plain
text), and may ignore the directive when boundaries are not supported.
The :caption attribute is descriptive metadata; renderers may
surface it as a header, navigation entry, or omit it.
Test blocks
=test
A block stating a piece of source and one or more statements that must hold of
what a parser makes of it.
The statements are written with selectors. A test contains one or
more =assert blocks. It may contain =fixture blocks, each a document an
assertion of it may be resolved against under the rule stated below. It may
contain =resource blocks where the subject of the test is the resolution of a
path:
=begin test :id<heading-carries-its-level>
=begin fixture
=head2 Overview
=end fixture=for assert :caption('a second-level heading is recognised as such')
head2
=end test
A test containing no =assert does not pass. An implementation that does not
recognise a child of =test reports the test as skipped rather than failed; one
it recognises but cannot satisfy is a failure.
The blocks a test contains
=fixture
A verbatim block whose body is a document in its own right, carried as Podlite
source.
The body of a =fixture is not processed by the document that holds it:
nothing in it is read as that document's markup and nothing in it is resolved.
It is still passed to the parser verbatim where an assertion is resolved
against the fixture. Anything a test requires besides the body is declared as
=resource and is not written into the body.
A test may contain more than one =fixture. Only another =fixture ends the
reach of one, and whatever else stands between, child of the test or not, leaves
it unchanged.
An assertion holds according to whether it carries :absent:
Without :absent, the assertion holds when the selector matches at least
one block, and fails when it matches none.
With :absent, the assertion holds when the selector matches no block,
and fails when it matches one or more.
Where a test contains several =assert blocks, it passes when every assertion
holds. Their order among themselves carries no meaning; position relative to a
=fixture decides which document an assertion takes.
An assertion states that something is present somewhere in the document, not
that it holds for every block. A statement of that kind is written with
:absent over the opposite condition. That every invoice carries the attribute
:number is stated by requiring that none lacks it:
=for assert :absent
Invoice[ :!?number ]
=resource
A verbatim block carrying content the test requires to be reachable by a path.
Two properties are fixed of a declared resource:
The name is reachable only while the body of a =fixture of the same
test is read. A reference in that body, or inside a resource reached from it,
obtains only what the test declares.
How the content is made reachable is not fixed here, and an implementation
that cannot write to a filesystem is not excluded.
A resource is reached from the body of a fixture by the path it declares:
A declared name is given relative to the body of the =fixture an assertion is
resolved against. A directive or markup code in that body resolves its relative
paths against the file declaring it, and not against the parent including
document.
Options
:id and :caption are the standard options
of those names. :id names a test; :caption records what a test, or a single
assertion, is for.
=begin test :id<value-comma-stays>:caption('a comma inside a value stays part of it')
=begin fixture
=for para :one<a,b>
text
=end fixture
=for assert :caption('the value is one string')
para[ :one<a,b> ]
=end test
:name
The path under which the content of a =resource is made reachable. Its form
is the form of the reference that resolves it.
:absent
Written on an =assert, gives the assertion its negative sense.
The document an assertion is resolved against
An assertion that names a source is resolved against that source. An assertion
that names none is resolved against the document the implementation has made
current.
Which document that is follows three cases in order:
a document supplied to the implementation from outside;
where none is supplied, the body of the =fixture nearest preceding the
assertion;
where neither is present, the document in which the test sits.
Where a document is supplied from outside, the bodies of =fixture are not
read as the input of the test. That a supplied document happens to be the one
containing the test does not change this.
The file the tests are taken from is not a supplied document. A document is
supplied only where the implementation is told to examine it, separately from
being told where to find the tests.
A failure against a =fixture is about the implementation: the text is fixed
and its reading is not. A failure against a supplied document is about the
document.
A relative path in the source of an assertion is resolved against the file the
test is written in, and not among the declared resources of the test.
An assertion whose named source cannot be obtained does not hold, whether or not
it carries :absent. A missing source is not a document in which nothing
matched.
A document containing tests
Where the document an assertion is resolved against is the one containing the
test, the =test blocks of that document are part of it and a selector reaches
them: an assertion written over every block of a document matches the tests
written in it.
Walking a document does not run the tests found in it. An implementation
resolves the assertions of the test it was given, and a =test block met while
walking is not a test to obtain.
Inserting pictures
Podlite allows to include images using a =picture block with an inline version
represented as P<alternative text|source of the image>:
=picture astronaut.png
=para In the vast expanse of the cosmos, an intrepid P<astronaut|astronaut.png>
floats weightlessly above the Earth.
The first non-blank line of content within the =picture block specifies the
source of the image, and the remaining content is treated as caption.
This source can be either local or remote, and it can be
specified using different schemas: https: for remote images, file: for
local ones, or data: for embedded images in the document.
If no schema is provided, file: is used as default.
Following the source line, it possible to include an image caption.
=picture astronaut.png
In the vast expanse of the cosmos, an intrepid B<astronaut>
floats weightlessly above the Earth.
In the delimited form of =picture, multiple text blocks can be included:
=begin picture
astronaut.png
In the vast expanse of the cosmos, an intrepid B<astronaut>
floats weightlessly above the Earth.
This astronaut explores the vastness of space.
=end picture
A caption can also be defined using the :caption attribute:
=for picture :caption<diagram>
diag01.png
Mathematical formulas
To include mathematical formulas, use a =formula block with an inline version
represented as F<>.
To insert mathematical expressions, use LaTeX-style syntax, which is
a commonly used format for writing mathematical equations.
=formula
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
In a right triangle, the length of the hypotenuse can be calculated
using the Pythagorean theorem: F<a^2 + b^2 = c^2>.
Euler's identity, F<e^{i\pi} + 1 = 0>, is a fundamental equation in
complex analysis.
The formula caption can be defined using the :caption attribute:
=for formula :caption('Quadratic Formula')
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
Markdown support
Podlite includes built-in support for Markdown, making it easy to include Markdown
content within Podlite documents. This is achieved using the =markdown block.
=begin markdown
## Markdown Example
You can use all the standard Markdown syntax within this block. For example:
- *Italic text* using asterisks or underscores: *italic* or _italic_.
- **Bold text** using double asterisks or underscores: **bold** or __bold__.
- [Links](https://example.com) with the `[text](url)` syntax.
- Unordered lists using `-`, `*`, or `+`:
- Item 1
- Item 2
- Ordered lists using numbers:
1. First item
2. Second item
- Code blocks with backticks:
```python
def hello_world():
print("Hello, World!")
```
- Blockquotes with the `>` symbol:
> This is a blockquote.
=end markdown
This block allows to seamlessly combine Podlite's structured blocks with
the flexibility of Markdown.
Fenced code block attributes
Within markdown content, fenced code blocks may include Podlite configuration
attributes following the language identifier. The language identifier on the
opening fence line maps directly to the :lang attribute of the native
=code block.
```python
def hello():
print("Hello")
```
This fenced code block is semantically equivalent to:
Both backtick (```) and tilde (~~~) fence delimiters are supported.
The two forms are semantically identical.
Extended attributes may be specified after the language identifier using
standard Podlite configuration syntax:
```python :line-numbers :highlight<2,5-7> :caption<Example>
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
```
This is equivalent to:
=begin code :lang<python> :line-numbers :highlight<2,5-7> :caption<Example>
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
=end code
All attributes defined for =code blocks in this specification are available
on fenced code blocks. The complete attribute syntax is described in the
block configuration table.
Implementation of extended attributes beyond the language identifier is optional.
Parsers not supporting extended attributes parse the language identifier and
either ignore trailing content or emit a warning, continuing processing in
accordance with the graceful degradation principle.
Fence to code block attribute equivalence
Markdown fence
Podlite equivalent
```python
=code :lang<python>
```javascript
=code :lang<javascript>
```
=code
~~~rust
=code :lang<rust>
Common attribute patterns found in various markdown implementations may be
mapped to Podlite notation as follows:
Common markdown attributes to Podlite notation
Function
Common pattern
Podlite equivalent
Line numbers
showLineNumbers
:line-numbers
Line numbers
.numberLines
:line-numbers
Start line
startFrom="N"
:start-line<N>
Highlight
{1,3-5}
:highlight<1,3-5>
Title
title="text"
:caption<text>
Element ID
#identifier
:id<identifier>
CSS class
.classname
:class<classname>
Markup codes
Markup codes enable inline markup within the text of (most) Podlite block types.
They are a form of block that can contain only other markup codes. Specifically,
markup codes can nest:
B<I shall say this loudly
Z<and repeatedly>
and with emphasis.>
All Podlite markup codes consist of a single capital letter followed
immediately by a set of angle brackets. The brackets contain the text or
data to which the markup code applies. A set of single
angles (<...>), a set of double angles («...»), or multiple
single-angles (<<<...>>>) can be used.
Within angle delimiters, you cannot use sequences of the same angle
characters that are longer than the delimiters:
=comment
These are errors...
C< $foo<<bar>> >
The Perl 5 heredoc syntax was: C< <<END_MARKER >
Sequences of angles that are the same length as
the delimiters can be used, but they must be balanced. For example:
C< $foo<bar> >
C<< $foo<<bar>> >>
If an unbalanced angle is needed, either use different delimiters:
A markup code ends at the matching closing angle bracket(s), or at
the end of the enclosing block or markup code in which the opening
angle bracket was specified, whichever comes first (this includes paragraph
and abbreviated blocks, ending with blank a line). Podlite parsers are
required to issue a warning whenever a markup code is terminated by
the end of an outer block rather than by its own delimiter (unless the
user explicitly disables the warning).
Significance indicators
Podlite provides three markup codes that flag their contents with
increasing levels of significance:
The U<> markup code specifies that the contained text is
unusual or distinctive; that it is of minor significance. Typically
such content would be rendered in an underlined style.
The I<> markup code specifies that the contained text is
important; that it is of major significance. Such content would
typically be rendered in italics or in <em>...</em> tags
The B<> markup code specifies that the contained text is the
basis or focus of the surrounding text; that it is of fundamental
significance. Such content would typically be rendered in a bold style or
in <strong>...</strong> tags.
Mistake marking
The code O<> can be used for strikethrough text, where 'O' stands
for "Overstrike." This indicates that certain words are a
mistake and should not be included in the document.
O<The sky is green.> Our planet's sky is usually blue.
Text positioning
Podlite provides two markup codes for positioning characters or words.
To create subscript text, use the J<> markup code, where 'J' represents
"Junior text." Subscript positions one or more characters slightly below the normal
line of type.
H2O
This code renders as H<sub>2</sub>O, which signifies that the '2' is positioned
slightly below the baseline, as is often seen in chemical formulas like H₂O (water).
To create superscript text, it possible to use the H<> markup code, where 'H'
stands for "High text." Superscript positions one or more characters slightly
above the normal line of type
X2
This code renders as X<sup>2</sup>, indicating that the '2' is positioned
slightly above the baseline. This is commonly used for mathematical exponents, as in X².
Definitions
The D<> markup code indicates that the contained text is a
definition, introducing a term that the adjacent text
elucidates. It is the inline equivalent of a =defn block.
For example:
There ensued a terrible moment of D<coyotus interruptus>: a brief
suspension of the effects of gravity, accompanied by a sudden
to-the-camera realization of imminent downwards acceleration.
A definition may be given synonyms, which are specified after a vertical bar
and separated by semicolons:
A D<markup code|markup codes;formatters> provides a way
to add inline mark-up to a piece of text.
A definition would typically be rendered in italics or <dfn>...</dfn>
tags and will often be used as a link target for subsequent instances of the
term (or any of its specified synonyms) within a hypertext.
Example specifiers
Podlite provides markup codes for specifying inline examples of input,
output, code, and metasyntax:
The T<> markup code specifies that the contained text is
terminal output; that is: something that a program might print out.
Such content would typically be rendered in a fixed-width font or with
<samp>...</samp> tags. The contents of a T<> code are always
space-preserved (as if they had an implicit
S<...> around them). The T<> code is the inline equivalent of the
=output block.
The K<> markup code specifies that the contained text is
keyboard input; that is: something that a user might type in. Such
content would typically be rendered in a fixed-width font (preferably a
different font from that used for the T<> markup code) or with
<kbd>...</kbd> tags. The contents of a K<> code are always
space-preserved. The K<> code is the
inline equivalent of the =input block.
The C<> markup code specifies that the contained text is code;
that is, something that might appear in a program or specification. Such
content would typically be rendered in a fixed-width font (preferably
a different font from that used for the T<> or K<> markup
codes) or with <code>...</code> tags. The contents of a C<> code
are space-preserved and verbatim.
The C<> code is the inline equivalent of the =code block.
To include other markup codes in a C<> code, the code can be lexically
reconfigured:
=begin para
=config C< :allow<E I>>
Raku makes extensive use of the C<E<laquo>> and C<E<raquo>>
characters, for example, in a hash look-up:
C<%hashI<E<laquo>>keyI<E<raquo>>>
=end para
To enable entities in everyC<...>, place a =config C<> :allow<E>
at the top of the document.
The R<> markup code specifies that the contained text is a
replaceable item, placeholder, or 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>
or:
Then enter your details at the prompt:
=for input
Name: R<your surname>
ID: R<your employee number>
Pass: R<your 36-letter password>
Typically replaceables would be rendered in fixed-width italics or with
<var>...</var> tags. The font used should be the same as that used for
the C<> code, unless the R<> is inside a K<> or T<> code (or
the equivalent =input or =output blocks), in which case their
respective fonts should be used.
Verbatim text
The V<> markup code treats its entire contents as being verbatim,
disregarding every apparent markup code within it. For example:
The B<V< V<> >> markup code disarms other codes
such as V< I<>, C<>, B<>, and M<> >.
Note 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 codes surrounding the V<> code
are still applied to its contents. For example, the previous example
is rendered:
The V<> markup code disarms other codes
such as I<>, C<>, B<>, and M< >.
You can prespecify markup codes that remain active within
a V<> code, using the :allow
option.
Inline comments
The Z<> markup code indicates that its contents constitute a
zero-width comment, which should not be rendered by any renderer.
For example:
The "exeunt" command Z<Think about renaming this command?> is used
to quit all applications.
In certain scenarios, the Z<> code is used to break up text that
would otherwise be considered mark-up:
In certain scenarios, the ZZ<><> code is used to break up text that
would otherwise be considered mark-up.
That technique still works, but it's now easier to accomplish the same goal
using a verbatim markup code:
In certain scenarios, the V<V<Z<>>> code is used to break up text that
would otherwise be considered mark-up.
Moreover, the C<> code automatically treats its contents as being
verbatim, which often eliminates the need for the V<> as well:
In certain scenarios, the V<C<Z<>>> code was widely used to break up text
that would otherwise be considered mark-up.
The Z<> markup code is the inline equivalent of a
=comment block.
Content masking
The G<> markup code marks an inline text fragment, and the
:masked attribute marks an entire block, as guarded. The original
content is preserved in the document model; only the rendered output is
concealed.
The mechanism provides presentation-layer concealment for sensitive
content (API tokens, credentials, personally identifiable information,
age-restricted material). It complements other security layers such as
source file access controls and authenticated build pipelines.
The password is G<hunter2> and must not be exposed.
=for BLOCKTYPE:masked
The mask character is determined by the renderer; the recommended default
is U+2588 (█ FULL BLOCK). Whitespace structure is preserved in the masked
output.
Two render modes are defined:
Production mode (default): guarded content is concealed
Draft mode: guarded content is rendered visibly for editing and review
Selection between modes is implementation-defined (renderer-controlled
through command-line, environment, or interactive interface).
When G<> appears within a block marked :masked, both the inline and
surrounding content are concealed; the masking operation is idempotent.
Guard is a property of content, not of location. Content marked
with G<> or carrying :masked renders concealed wherever it
appears in rendered output. The rule applies when content is
reached through links, inclusion,
aliases, or data references.
The G<> code is not processed inside code blocks by default. To enable
masking in code blocks, the :allow<G> attribute is required on the
=code block (see :allow).
The G<> code marks content for concealment at render time but
does not protect it. The original text remains in plain form in
source files, document model, version control, and any consumer
that does not invoke the renderer. For cryptographic security or
access control, complementary mechanisms (file permissions,
encryption, authenticated access) are required.
Links
The L<> code is used to specify all kinds of links, filenames, citations,
and cross-references (both internal and external).
A link specification consists of a scheme specifier terminated by a
colon, followed by an external address (in the scheme's preferred
syntax), followed by an internal address (again, in the scheme's syntax).
All three components are optional, though at least one must be present in
any link specification.
Usually, in schemes where an internal address makes sense, it will be
separated from the preceding external address by a #, unless the
particular addressing scheme requires some other syntax. When new
addressing schemes are created specifically for Podlite, it is strongly
recommended that # be used to mark the start of internal addresses.
Standard schemes include:
http: and https:
A standard web URL. For example:
This module needs the LAME library
(available from L<http://www.mp3dev.org/mp3/>)
If the link does not start with // it is treated as being relative to
the location of the current document:
See also: L<http:tutorial/faq.html> and
L<http:../examples/index.html>
file:
A filename on the local system. For example:
Next, edit the global config file (that is, either
L<file:/usr/local/lib/.configrc> or L<file:~/.configrc>).
Filenames that don't begin with a / or a ~ are relative
to the current document's location:
Then, edit the local config file (that is, either
L<file:.configrc> or L<file:CONFIG/.configrc>.
mailto:
An email address. Typically, activating this type of link invokes a mailer.
For example:
This module implements the standard
Unix L<man:find(1)> facilities.
doc:
A link to other documents by utilizing semantic blocks
such as =TITLE or =NAME as anchor points for these links.
For example:
=NAME Dumper
You may wish to use L<doc:Dumper> to
view the results.
Moreover, the doc: scheme allows the use of an :id attribute within
the =TITLE or =NAME blocks to create unique identifiers for document
linking. This ensures precision in navigation, as each identifier
corresponds to a specific part of the document set. An example would be:
=for TITLE :id<Specification>
The Specification of Podlite
...
Read the L<spec|doc:Specification>.
...
When Podlite processes a link, it can automatically use the document's title
from the =TITLE or =NAME blocks as the display text for the hyperlink if no
explicit text is provided. For example:
=for TITLE :id<Specification>
The Specification of Podlite
=para
Please read "L<doc:Specification>".
... will be rendered as:
Please read "The Specification of Podlite".
defn:
A link to the block-form or inline
definition of the specified term within the current document. For example:
He was highly prone to D<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)
and later, to link back to the definition:
To treat his chronic L<defn:lexiphania> the doctor prescribed an
immediate L<defn:glossoligation> or, if that proved ineffective,
a complete cephalectomy.
isbn: and issn:
The International Standard Book Number or International Standard
Serial Number for a publication. For example:
The Perl Journal was a registered
serial publication (L<issn:1087-903X>)
To refer to a specific section within a webpage, manpage, or Podlite
document, add the name of that section after the main link, separated by
a #. For example:
Also see: L<man:bash(1)#Compound Commands>,
L<doc:perlsyn#For Loops>, and
L<http://dev.perl.org/perl6/syn/S04.html#The_for_statement>
To refer to a section of the current document, omit the external address:
This mechanism is described under L<doc:#Special Features> below.
The scheme name may also be omitted in that case:
This mechanism is described under L<#Special Features> below.
Podlite includes the possibility of assigning a unique identifier to a block.
These identifiers can be explicitly assigned to any blocks using
the :id attribute. Later, these identifiers are utilized for addressing blocks
and creating links.
=for head1 :id<intro>
Introduction
=for para :id<id1>
This is an introductory paragraph.
For more information, see L<here|#intro> and L<here|#id1>
In this example, the link reference to the header block identified by "intro"
rather than the name "Introduction" and to the paragrapth block with identifier "id1".
Normally a link is presented as some rendered version of the link
specification itself. However, you can specify an alternate
presentation by prefixing the link with the desired text and a
vertical bar. Whitespace is not significant on either side of the bar.
For example:
This module needs the L<LAME library|http://www.mp3dev.org/mp3/>.
You could also write the code
L<in Latin | doc:Lingua::Romana::Perligata>
His L<lexiphanic|defn:lexiphania>> tendencies were, alas, incurable.
Contextual backlinks
Podlite introduces the concept of contextual backward links W<> (or contextual backlinks),
enhancing the traditional linking mechanism by allowing to not
only reference another location but also provide specific
context around that reference. This context can take the form of opinions,
additional information, or any relevant commentary that enhances the understanding
of the referenced material.
For example:
This text can reveal the meaning of W<glossoligation|defn:glossoligation>
or:
We discuss here about W<doc:perldata>.
Contextual backlinks on the destination page can be displayed in various ways.
They may appear with surrounding text chunks, providing context within
the flow of the content. Alternatively, they can be placed at the end
of the text, in the margin of the page, or highlighted in other visually
distinctive ways.
Like traditional links, contextual backlinks allows the use of
all available link schemes, including https: and doc:, to link to external content.
Contextual backlinks might be visually distinguished from
standard links through color coding.
Link configuration attributes
The L<> and W<> markup codes may be extended with optional
configuration attributes following the link specification. These attributes
are specified using the standard Podlite configuration syntax.
The configuration portion begins at the first whitespace character that
is immediately followed by a colon (:). The substring preceding this
boundary constitutes the link specification. This boundary rule is
unambiguous because URL schemes begin with a letter character, not a colon,
and standard URLs do not contain space-colon sequences.
For example:
L<https://example.com :new>
In this example, the boundary occurs at the space before :new.
Colons within URLs (such as port numbers or path parameters) are not
preceded by whitespace and therefore do not trigger attribute parsing:
=comment :8080 is port
L<http://localhost:8080/api :new>
=comment :id is path
L<https://api.example.com/users/:id :title('User profile')>
Parsers that do not implement this extension treat the entire content
of L<> as a link specification. The link remains functional; only
metadata is lost. Renderers that encounter unknown attributes are
required to ignore them without error.
Alias placements
The A<> code 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>.
See #Aliases for further details of the aliasing macro mechanism.
Space-preserving text
Any text enclosed in an 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.
Entities
To include Unicode code points or HTML5 character references in a
Podlite document, specify the required entity using the code.
If the contains a number, that number is treated as the decimal
Unicode value for the desired code point. For example:
Podlite makes considerable use of E<171> and E<187>.
You can also use explicit binary, octal, decimal, or hexadecimal numbers:
Podlite makes considerable use of E<0b10101011> and E<0b10111011>.
Podlite makes considerable use of E<0o253> and E<0o273>.
Podlite makes considerable use of E<0d171> and E<0d187>.
Podlite makes considerable use of E<0xAB> and E<0xBB>.
If the contains anything that is not a number, the contents are
interpreted as a Unicode character name (which is always uppercase), or
else as an HTML5 named character reference. For example:
Podlite makes considerable use of E<LEFT DOUBLE ANGLE BRACKET>
and E<RIGHT DOUBLE ANGLE BRACKET>.
or, equivalently:
Podlite makes considerable use of E<laquo> and E<raquo>.
To include emoji codes, you can use the code along
with the colon-prefixed and postfix emoji shortname:
Podlite uses emoji codes to express emotions and actions,
such as E<:thumbsup:> for approval and E<:smile:> for happiness.
In this example, :smile: and :thumbsup: are emoji codes representing
the respective emojis. You can use any valid emoji code in this format
to include emojis in your Podlite document.
Note that the specific emoji codes and the emojis they represent may vary
depending on the platform or system you are using.
Multiple consecutive entities (in any format) can be specified in a
single code, separated by semicolons:
Podlite makes considerable use of E<LEFT DOUBLE ANGLE BRACKET;hellip;0xBB;:smile:>.
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.
An index entry where the indexed text and the index entry differ can be specified
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.
Hierarchical index entries can be specified by separating indexing levels
with commas:
An X<array|arrays, definition of> is an ordered list of scalars
indexed by number, starting with 0. A X<hash|hashes, definition of>
is an unordered collection of scalar values indexed by their
associated string key.
Multiple entries for a single indexed text can be specified 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.
Both notations describe one structure: a list of entries, each of which is a
list of levels. The order of entries and the order of levels are significant.
Whitespace adjacent to either separator is not part of a value.
The indexed text can be empty, creating a "zero-width" index entry:
X<|puns, deliberate>This is called the "Orcish Manoeuvre"
because you "OR" the "cache".
Annotations
Anything enclosed in an N<> code is an inline note.
For example:
Space stations feature hydroponic gardens N<Plants grow without soil,
using mineral nutrient solutions.>, a necessity for long-term missions.
Renderers may present such annotations in various ways: as
footnotes, endnotes, sidebars, pop-ups, tooltips, or
expandable tags. They are never rendered as unmarked
inline text. The previous example might be rendered as:
Space stations feature hydroponic gardens †, a necessity for
long-term missions.
and later:
Footnotes
† Plants grow without soil, using mineral nutrient solutions.
Module-defined handler for extends markup features
The M<> code in Podlite extends the language's capabilities by allowing users
to specify additional processing instructions within their documents.
This is achieved by combining content text with a custom plug-in specifier,
followed by optional configuration information that is passed to a handler function.
This syntax includes CONTENT-TEXT section, followed by a
name specifier MODULE_NAME and then the OPTIONAL CONFIG INFO
(see "Configuration syntax options").
The name specifier should follow the same rules as for
named blocks.
The M<> markup code is the inline equivalent of a
named block.
An example of how this code might be used is :
M< This text is highlighted in yellow |Marker :color('yellow') >.
In this example, the text "This text is highlighted in yellow" is subject
to special handling specified by the Marker module and
:color('yellow'), indicating that the text should be highlighted in yellow.
If the MODULE_NAME is unrecognized, the content text CONTENT-TEXT should be
rendered as ordinary text. This ensures that documents remain readable even
if specific processing instructions cannot be executed. The renderer could provide
an unobtrusive yet informative error message, explaining that the custom
markup block could not be processed.
Block pre-configuration
The =config directive allows you to prespecify standard configuration
information that is applied to every block of a particular type.
Here, two configurations are outlined. The first one sets
the language for code blocks to python and allows bold markup.
The second establishes that all level 1 headings will be numbered.
The general syntax for configuration directives is:
=config BLOCK_TYPECONFIG OPTIONS
= OPTIONAL EXTRA CONFIG OPTIONS
A =config is a directive, not a block. Hence,
there is no paragraph or delimited form of the =config directive.
Each =config specification is lexically scoped to the surrounding
block or file in which it is specified.
Note that, if a particular block later explicitly specifies a
configuration option with the same key, that option overrides the
pre-configured option. For example, given the code blocks configurations in the
previous example, to specify another language for code block:
You can also lexically preconfigure a markup code,
by naming it with a pair of angles as a suffix. For example:
=comment Always allow E<> codes in any (implicit or explicit) V<> code...
=config V<> :allow<E>
=comment All inline code allows I<>
=config C<> :allow<I>
Note that, even though the markup code is named using single-angles,
the preconfiguration applies regardless of the actual delimiters used on
subsequent instances of the code.
For per-block attribute assignment that targets a single block instance
rather than setting type-wide defaults, see Block attribute assignment
with =set.
Block attribute assignment with =set
The =set directive assigns attribute values to the next block in
the same lexical scope. Like =config, it sets attributes for a
block; unlike =config, it targets a single block instance rather
than all blocks of a type. Attribute values may include multiline
content with inline markup codes.
The directive has two syntax variants. Configuration syntax uses
standard delimited attribute values, for example:
Alias syntax permits multiline values with inline markup codes, for
example:
=set :caption Selected chemical elements with their
= L<atomic numbers|#elements> and symbols
=begin table
Element Symbol Atomic Number
========= ====== =============
Hydrogen H 1
Carbon C 6
Oxygen O 8
=end table
Continuation lines (= followed by whitespace) extend multiline
alias values until the next non-continuation directive or a blank
line. Lines join into the final value before markup processing.
Both syntax variants may be mixed across continuation lines, as in
the following example combining configuration-syntax continuation
(= :folded<true>) with alias-syntax continuation:
The table receives all three attributes (:id, :folded, :caption).
=set assignments override =config defaults but yield to explicit
attributes on the block declaration. When multiple =set directives
assign the same attribute key, the last assignment wins, regardless
of syntax variant.
Directives (=set, =config, =alias, =include, =boundary)
and =comment blocks are transparent to =set targeting and do not
consume the assignment. For example:
=set :caption Renewable energy sources
=config table :width<100%>
=alias COMPANY Acme Corp
=comment Approved
=begin table
Source Type
========= ==========
Solar photovoltaic
Wind turbine
=end table
The =table block receives the :caption attribute despite the
intervening directives and =comment.
For =include, attributes apply to the first block of the resolved
included content. =set directives inside an included file are
lexically scoped to that file and do not leak to the parent file.
If no block follows before the end of the containing block or file,
parsers issue a warning that the =set directive has no target.
Aliases
The =alias directive provides a way to define lexically scoped
synonyms for longer Podlite sequences, (meta)object declarators from the
code, or even entire chunks of ambient source. These synonyms can then
be inserted into subsequent Podlite using the
A<> markup code.
Note that =alias is a fundamental Podlite directive, like =begin or
=for; there are no equivalent paragraph or delimited forms.
Macro aliases are lexically scoped to the surrounding Podlite block.
The simplest form of alias takes two arguments. The first is an
identifier (which is usually specified in uppercase, though this is
certainly not mandatory). The second argument consists of one or more
lines of replacement text.
This creates a lexically scoped Podlite macro that can be invoked during
document generation by placing the identifier (i.e. the first argument
of the alias) in an A<> markup code. This markup code is then
replaced by the text returned by 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. The replacement text can extend over multiple
lines by starting each following line with an = (at the same level
of indentation as the =alias directive itself) followed by at least
one whitespace. Each additional line 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 4D Kingdoms Inc, as specified at:
The advantage of using aliases is that the same alias can be
reused in multiple places in the documentation. If the replacement
text needs to be changed, it requires modification in only a single place:
These blocks, often referred to as admonitions, callouts, or alerts,
serve to draw attention to different types of content,
such as tips, warnings, or important notes.
To create specially formatted blocks highlighting information in Podlite,
the =nested block and :notice attribute are used.
For example:
=begin nested:notify<tip>
Remember to always use oven mitts when handling hot bakeware
to prevent burns.
=end nested
Below is a table outlining the different types of notification blocks
along with a brief description of each type.
Types of Notification blocks
Type
Description
note
Provides additional information and context without interrupting the flow of the main content
tip
Offers advice for doing things better or more easily
important
Signifies that the information is crucial for understanding or success
warning
Indicates urgent information that requires immediate attention to avoid potential problems
caution
Advises readers about potential negative outcomes or risks associated with certain actions
By default, the title of the notification block is its type identifier in title case.
The title of the block and visibility of the information can be customized
using the :caption and :folded options.
=begin nested :caption("Astronaut's Reminder") :notify<important> :folded
Space missions require meticulous planning and adherence to safety protocols.
Neglecting these can lead to mission failure or, worse, endanger lives.
=end nested
Title-only callouts can be created by omitting the body.