Nimble
An elegant markup language for a more civilized age.
Nimble is a markup language that tries to make it easy to author semantically-useful documents with special consideration given to HTML5 output. Things like blog posts, wiki articles, and documentation are meant to be easy to write using Nimble. Some parts of Nimble syntax rely on aligning things using indentation, and so Nimble likes to be written in a monospaced font. If you've ever used a wiki markup language, you should feel right at home using Nimble.
Nimble markup is used to express the semantics of a document, not the style; you use Nimble to express things like "this text is a quotation", but not things like "this text should be in its own box with a large quotation mark on one side" (for that, use CSS). Documents written in Nimble represent a hierarchy of elements, much like documents written in HTML. In fact, internally, a Nimble renderer first converts your text to a parse tree, and then a separate process renders that tree. A parsed Nimble document includes the tree itself (which represents the semantics of the document) as well as extra metadata such as document attributes or macro definitions.
For a more thorough example, you can also see the Nimble source of this page. You might want to wait until you've read it the normal way, though.
If you'd like to use Nimble in your own project, it is available as a Perl module on CPAN complete with an HTML renderer. The source code is also available on GitHub.
On the other hand, you might just want to test out Nimble before you install it. Feel free to play along with the examples in this document.
When to choose Nimble
There are many different markup languages available these days. To help you know when to choose Nimble, here are some things that make Nimble special:
- Nimble is structured — that is, Nimble has a syntax, and documents using Nimble should conform to that syntax. Nimble documents describe a syntax tree, a list of instructions for a renderer about how to arrange paragraphs, lists, links, and so on. This means that you need to be precise about what you write, but in return, you get fine control over the structure of your document.
- Nimble is fast. To render documents of similar size and complexity, Nimble is 6-7x faster than Markdown. (A ~35kb syntax test file took Nimble 25ms and Markdown 166ms.)
- Nimble is embeddable. Not only is there a library for including it in your own programs, but it exposes things like full syntax trees, detailed parse errors, and document attributes, allowing you to fully integrate Nimble with your application's caching decisions, database metadata, or editor feedback.
- Nimble is semantic. Nimble tries to avoid constructs that are about presentation and focus on the meaning of the parts of a document. Rather than specifying things like "this content should be in a right-aligned gray box", you specify that content is a figure and let the presentation layer (for HTML, that's usually CSS) handle the presentation.
- Nimble is expressive. Nimble contains a powerful but simple macro system which lets document authors define their own repeatable output patterns complete with placeholders for per-use values and rules about how to encode them.
To prevent you from making the wrong choice, here are some things Nimble is not:
- Nimble is not a mechanism for styling content. Once your document is rendered to an output format (like HTML), another system is responsible for styling it (like CSS).
- Nimble is not a website builder. While you could use #raw declarations to produce the headers, styles, scripts, and other parts of a page, those sorts of problems are better left to other tools. You could use Nimble to produce the content of your pages, though.
- Nimble is not a wiki engine. Nimble provides no mechanism for storing pages or letting users edit them. Instead, you might use Nimble as the markup language inside a wiki.
- Nimble is not a template engine. Template engines typically take bits of content to combine with some larger document and often include constructs like looping or conditionals; Nimble provides none of these mechanisms. Nimble is intended for writing whole, self-contained documents by humans, not pieced together by computers.
- Nimble is not HTML. HTML will always provide more features and options than Nimble. While you can always get at those features through #raw or #macro declarations of format
html
(thereby letting you inject whatever HTML you happen to need right into your document), native Nimble syntax is intentionally more limited. Because Nimble is for writing documents rather than websites, it makes the related tasks easy and the remaining tasks possible. For example, Nimble will take care of things like entity encoding or markup validity for you, which can be cumbersome when writing a document in raw HTML.
Syntax basics
Nimble syntax is divided into two categories: block, which includes containers for text (such as lists or figures) and some kinds of special declarations (such as macro definitions or document attributes), and inline, which includes designations done within text (such as indicating emphasis, strong wording, links, or code
). The system displaying the rendered output chooses how to style these blocks and inline designations (for HTML, CSS is used).
You can place a backslash (\
) before any single character to escape it, removing any special meaning it might have and rendering it literally — except within code blocks, where everything is always literal.
Inline-level elements
To indicate that text has strong importance, wrap it in asterisks (*
). To indicate that text has emphasis, wrap it in slashes (/
).
Code | Result |
---|---|
This section is /very/ important. *Don't miss it!* | This section is very important. Don't miss it! |
To reduce the need for escaping in other uses of these characters, an asterisk or slash followed by whitespace does not count as starting an inline element, and an asterisk or slash preceeded by whitespace does not count as ending an inline element.
Code | Result |
---|---|
What is 2 * 3 / 4? My favorite color is /orange / blue/, but people find that strange. What do you get if you multiply *6 * 9*? 42! | What is 2 * 3 / 4? My favorite color is orange / blue, but people find that strange. What do you get if you multiply 6 * 9? 42! |
To express some inline text as code
, wrap it in at least one backtick (`
). If the code itself contains sequences of backticks, more backticks can be used to wrap the code (but use the same number for the start and end). Spaces at the start or end of the wrapped code are ignored (unless there isn't anything but spaces).
Code | Result |
---|---|
Always start your Perl scripts with `use strict;` and `use warnings;`. In Nimble, wrap `code` in at least one backtick (`` ` ``). | Always start your Perl scripts with In Nimble, wrap |
Make a link by writing [http://example.com/url link text]
, which becomes link text. This is actually shorthand for [link http://example.com/url link text]
. If the link text is omitted, the URL is used: [http://example.com/]
becomes http://example.com/.
Include an image by writing [img path/to/image.jpg alt text]
. If the alt text is omitted, an empty string will be used.
You can use HTML entities directly: typing ¥
produces ¥, and typing £
produces £. There are also some shorthands for useful entities: --
creates an endash (–), ---
creates an emdash (—). You can create arrows using --> ==> <== <--
, which gives → ⇒ ⇐ ←. Of course, if you want those actual symbols, you could put them in code blocks (`-->`
becomes -->
) or escape them (\-->
becomes -->).
Most of the inline syntaxes can be nested; for example, the text of a link can be an image, or strong text can have emphasis. This isn't true in cases where it doesn't make sense, like in the alt text of an image.
Macros can be used as inline elements; this will be covered later.
Block-level elements
Blocks are typically written with a blank line between them. This increases document legibility, but it isn't required except where adjacent blocks would be ambiguous (primarily, where a plain paragraph would consider syntax on the next line to be inline markup instead of block markup). Many blocks can contain other blocks; this is done by keeping the indent level from the content of the first line of the block (for an example of this, see the section on lists). A blank line (empty or only containing whitespace) has no effect on indentation level.
Paragraphs
Text on its own is converted to a paragraph element:
Code | Result |
---|---|
This is one paragraph. This is another paragraph; you can use single newlines to hard-wrap your text if you prefer. | This is one paragraph. This is another paragraph; you can use single newlines to hard-wrap your text if you prefer. |
Code blocks
To create a code block, place at least three backticks (```
) on a line before your code, and the same number on a line after it. The code will be taken verbatim, and no Nimble syntax will be parsed within the block.
Code | Result |
---|---|
Here is a simple Perl script: ``` #!/usr/bin/perl -w use strict; print "Hello, world!\n"; ``` When run, it prints `Hello, world!`. | Here is a simple Perl script: #!/usr/bin/perl -w use strict; print "Hello, world!\n"; When run, it prints |
Document attributes
Nimble documents can define any number of key-value pairs which are returned by the parser in addition to the other parts of the document. (Check your parser's documentation for how to access them.) They are useful for specifying values that need to be used outside the Nimble document, such as the page title, related tags, or the name of the author. The code using your document can use these values however it likes. Attribute values are a single line of raw text — they do not get parsed as Nimble markup. To define an attribute, write @name value
:
@title How to slay a dragon in twelve easy steps @author King Arthur @tags dragonslaying, self-help guides To kill a dragon...
Again, these attributes aren't used by Nimble. They're merely returned by the parser for use elsewhere. For example, with the above document, the application might choose to put the @title
within part of the page's <title>
tags, use the @author
to link the article from the author's page, and split the @tags
by commas to index them in a database.
Lists
Several kinds of lists are supported by Nimble syntax.
An unordered list is simply a series of items for which the order is irrelevant. It is often drawn as a bulletted list, and so Nimble uses lines prefixed by asterisks (*
) to indicate elements of an unordered list:
Code | Result |
---|---|
Today's menu: * Roast flank of dragon * Dragon ribs with a honey glaze * Dragonscale stew with fresh bread | Today's menu:
|
Lists allow nesting; you can put several elements within a list, such as paragraphs and other lists:
Code | Result |
---|---|
Places I'd like to visit: * The dragon's cave Why? * It's full of tasty dragon meat * Also probably treasure * The castle kitchen * It's /also/ full of tasty dragon meat * (we just killed a dragon) | Places I'd like to visit:
|
An ordered list is a series of items for which the order does matter. It is often drawn as a numbered list, and so Nimble uses lines prefixed by numbers and a dot (1.
, 2.
, ...) or just a number sign and a dot (#.
) if you'd like the item to be numbered automatically:
Code | Result |
---|---|
Top three reasons to kill a dragon: 3. They're scary. 2. Their treasure. 1. There is tasty meat. | Top three reasons to kill a dragon:
|
Code | Result |
---|---|
How to kill a dragon: #. Hire a fighter with a proven track record for killing dragons. #. Hire a bunch of clerics to constantly heal the fighter. #. Hire at least twelve high-level wizards. Seriously, more like a hundred would be better. #. Tell them to go kill the dragon. #. At this point, there are only two outcomes: * They kill the dragon; pay them with part of its vast treasure. * The dragon kills them; don't pay them. That would be silly. | How to kill a dragon:
|
As shown above, by continuing the indent level of the first line of a list item, sub-elements are placed within that item.
A definition list is a list of topics and their definitions. Topics are given on lines starting with a question mark (?
), and definitions are given on lines starting with an equals sign (=
). A definition list must begin with a topic, after which topics and definitions can be freely intermixed in any amounts.
Code | Result |
---|---|
Parts of a dragon: ? Mouth = Contains teeth = Can breathe fire ? Claws = Very pointy, probably avoid ? Tasty meats = ? Flank = Good for cooking on its own ? Ribs = Let's try this one with a honey glaze ? Other bits = Maybe turn them into a stew? ? Scales = Good for fashioning into armor! | Parts of a dragon:
|
Figures
A figure is a self-contained piece of content that often has a caption and is referred to from the main document. A figure's contents and optional caption are all contained by a block starting with a percent symbol (%
); a caption is denoted by a sub-element block starting with an equals sign (=
). When rendering to HTML, if a caption is used, there should only be one at either the start or the end of the figure.
Code | Result |
---|---|
% ``` #!/usr/bin/perl -w use strict; use Dragon::Meat; my $bits = Dragon::Meat::bits->new("tasty"); my $stew = $bits->dice->cook; ``` = Mom's recipe for Dragon stew. |
Blockquotes
A blockquote is a block-level quotation; it is similar to merely writing something like He said, "how are you?"
, but is more semantically meaningful and often uses styling meant for larger sections of text. A blockquote is indicated by a line starting with a quotation mark ("
). To include a citation, add a sibling block-level element starting with a dash (-
); in the HTML renderer, this will place the quotation's resulting <blockquote>
in a <figure>
with CSS class quote
and the citation in a corresponding <figcaption>
.
Code | Result |
---|---|
Just a blockquote: " I once killed a dragon the size of a castle! A blockquote with a citation: " Wow, these dragons sure are delicious! - Anybody who has tasted one. | Just a blockquote: I once killed a dragon the size of a castle! A blockquote with a citation: |
Headers and sections
Much like in HTML, there are two ways to semantically define the outline of your document. The first way, taken from old-style HTML and often seen in other markup languages, is to use headers with explicitly specified depth. In Nimble, you can create an explicit header element (HTML's <h1>
– <h6>
tags) by starting a line with an exclamation mark (!
) immediately followed by a number (1 – 6) to indicate the depth (or no number, which defaults to depth 1).
Code | Result |
---|---|
! All About Dragons This document covers all aspects of dragons. !2 Weapons Stuff to avoid while hunting dragons. !3 Claws Pointy. Avoid. !3 Teeth Pointier. Definitely avoid. !2 Meat Delicious. Bring back to castle. |
The second mechanism for defining the outline of your document is by implicitly expressing depth through nested sections. HTML support for this sort of document structure is new as of HTML5. Using sections alleviates many issues with headers with explicit depths; for example, reorganizing a document no longer requires renumbering headers.
Nimble syntax uses a block starting with an open curly brace ({
), optionally followed by the section header, to begin a section, and a closed curly brace (}
) to end one. In addition, you can simultaneously close any number of sections and optionally start a new one by stacking all of the braces together; for example to close one section and start a new sibling section, you might write }{ Section Title
. Any sections left open at the end of the document will be automatically closed.
In HTML rendering, the block started by an open curly brace actually corresponds to a <header>
at the start of a section; if the header contains a single paragraph, that paragraph is converted to an <h1>
tag.
Code | Result |
---|---|
{ All About Dragons This document covers all aspects of dragons. { Weapons Stuff to avoid while hunting dragons. { Claws Pointy. Avoid. }{ Teeth Pointier. Definitely avoid. } }{ Meat Delicious. Bring back to castle. }} |
Sometimes, like above, it can be clearer to close a section separately from its parent (see Meat
, above) rather than all at once (like }}{ Meat
).
The contents of a section aren't indented any more than the section itself. Extra elements you'd like to appear within the header of the section are indented, however. For example, a section header with a paragraph subtitle might look like this:
{ ! Nimble markup language -- syntax documentation An elegant markup language for a more civilized age. ... }
Because the contents of the above example section's header isn't a lone paragraph, an explicit !
is used to create the <h1>
in the section's header element.
Advanced features
These features require understanding of the output format (like HTML) and can be a little complicated to use.
Raw data
Sometimes, you need to include some particular raw data in the middle of your output. Maybe you need to create an HTML tag that isn't supported by Nimble. To do this, Nimble provides a mechanism to produce raw data for a specific output format. When using a raw data declaration, it is up to you to ensure that the output is valid for your output format. Nimble makes no attempt to protect you from invalid output.
Every use of a raw data declaration requires the target output format to be specified. If the current output format does not match the format specified in the raw data declaration, no output is produced.
Block-level syntax for raw data has two ways to use it. For raw data that fits on a single line, use #raw <format> <data>
, replacing <format>
with the output format for which this raw declaration is enabled, and replacing <data>
with the raw text you would like produced at the location of the declaration.
#raw html <aside> When in HTML output mode, this paragraph will end up in an `<aside>` block. #raw html <input type="button" value="Click me!"/> Another paragraph that will end up inside the `<aside>` block. #raw html </aside>
The second way to use block-level syntax allows for multiple lines of raw data. To do this, omit the <data>
part of the declaration, and instead merely write #raw <format>
. After this, all subsequent lines indented further than the #raw
declaration will be treated as raw output.
Code | Result | ||||
---|---|---|---|---|---|
#raw html <table style="width:100%;"> <tr><td>1</td><td>2</td></tr> <tr><td>3</td><td>4</td></tr> </table> |
|
There also exists an inline syntax for raw data: anywhere within inline text, write [raw <format> <data>]
, again replacing <format>
with the target output format and <data>
with the raw text you would like produced at the location of the declaration. This syntax comes with a caveat: the square brackets must be balanced, but backslashes can be used to escape square brackets or other backslashes if necessary. Thus, [raw html [a]]
is legal, but to produce [\[
as raw data using inline syntax, one would write [raw html \[\\\[]
.
Macros
Nimble includes a simple system for defining and reusing custom output structures via macros. A macro is a named set of raw data declarations which support variable substitution. Macros must be declared before they can be used.
Each macro can define a raw data output (called a #result
) for each output format you'd like to target; if a macro has no #result
for the current output format, no output is produced by the macro. Each macro can also have zero or more arguments (each called an #arg
); each argument has a name, whether it should be parsed as nimble markup or raw data, and optionally a default value to use when it is not given.
When a macro is used, arguments of type nimble
will be parsed as Nimble text and rendered to the current output format before variable substitution. Arguments of type raw
will be passed through verbatim. Examples of this are below.
Declaration
A macro declaration consists of three parts: a starting line with its name, argument (input) definitions, and result (output) definitions.
To declare a macro, use the block-level declaration #macro <name>
, replacing <name>
with the desired name of the macro. This name can only contain letters, numbers, and underscores. A macro declaration produces no output.
#macro example
After the #macro
line and indented further, define zero or more arguments using #arg <name> <type> <default>
, replacing <name>
with the argument name (only letters, numbers, and underscores), <type>
with either nimble
(to parse that argument as nimble code) or raw
(to do no processing of the argument), and <default>
with the desired single-line default value for the argument. Much like the syntax for #raw
, a multi-line default may instead be given by omitting the default on the #arg
line and instead including it on lines below indented further than the #arg
line itself.
#arg apple nimble This is /Nimble/-style markup. #arg banana raw This text will be taken <em>literally</em>. #arg pear nimble * This text is the default value for argument `pear`. * It will only be used if no `pear` argument is given to the macro.
Finally, define one or more results using #result <format> <data>
, replacing <format>
with the output format for which this result is targeted and <data>
with the raw data to be output for that format. The rules for indicating where in the <data>
section variables should be substituted depend on the output format being targeted. Much like the syntax for #raw
, a multi-line value may instead be given by omitting the data on the #result
line and instead including it on lines below indented further than the #result
line itself.
HTML
In a #result html ...
declaration, variable substitution is indicated by {{name}}
, where name
is the name of the argument to substitute.
#result html <div>{{content}}</div>
You can also specify filters to be applied to argument values before they are substituted. These are given after the argument name as |filter
in the order in which they should be applied. Available filters are:
xmlenc
- XML-encodes any
&"<>
characters within the value urlenc
- URL-encodes any non-alphanumeric characters within the value
Here's an example which uses both of these mechanisms to properly encode the arguments:
#macro phpdoc #arg topic raw #result html <a class="phplink" href="http://php.net/{{topic|urlenc|xmlenc}}">{{topic|xmlenc}}</a>
Use
Macros can be used in both block and inline contexts.
The block-level syntax for macro use begins with a line consisting of a dollar sign ($
) immediately followed by the name of the macro: $example
. After this, zero or more of the arguments defined for the macro can be passed; this is done by a further-indented line consisting of the argument name immediately followed by a colon (:
) and either a single-line value on the same line or a multi-line value on futher-indented subsequent lines.
$example apple: The *actual* value for this argument. banana: This raw text input spans several lines.
The inline syntax for macro use consists of a square-bracketed block starting with a dollar sign ($
) immediately followed by the name of the macro: [$example ...]
. Within the block, arguments are given as key=value
pairs separated by whitespace; if a value contains spaces, it should instead be written in double or single quotation marks like arg1="value with spaces" arg2='value with spaces'
. Within a quoted argument value, quotation marks (of the type enclosing the value) and backslashes must be escaped to be used: arg1="' \\ \"" arg2='\' \\ "'
. Because Nimble locates the end of the macro before it's parsed, any square brackets within argument values need to either be balanced or escaped.
Examples
Let's say you want to easily make links to PHP documentation.
#macro phpdoc #arg topic raw #result html <a class="phplink" href="http://php.net/{{topic|urlenc|xmlenc}}">{{topic|xmlenc}}</a>
This macro takes a single argument, topic
, as raw text. It produces a link with a special class (for later CSS targetting), an appropriate URL (by taking the topic, URL-encoding it, and then XML-encoding it), and then using the same topic again as the link text (by simply XML-encoding it). While it would be possible to replicate parts of this (no class attribute, no URL encoding) by writing [http://php.net/topic topic]
repeatedly, using a macro allows easy maintenance of your document if the URL for PHP documentation changes or you want to update the class. It also means that you can merely type [$phpdoc topic=something]
to make such a link, saving typing and reducing errors (what if you accidentally update a URL but not the label?).
Code | Result |
---|---|
#raw html <style> /* Add some extra styles to make phpdoc links stand out. */ .phplink { background-color: #eeeeee; border: 1px solid #777bb4; color: #3b3d5a; padding-right: 4px; } .phplink:hover { color: #999999; } .phplink:before { content: "php"; background-color: #777bb4; color: #000000; padding: 0 4px; margin-right: 4px; } </style> In PHP, [$phpdoc topic=array_map] takes its callback first, but [$phpdoc topic=array_filter] takes it last. | In PHP, array_map takes its callback first, but array_filter takes it last. |
Suppose you want to make a macro to help demonstrate Nimble code easliy — say, have the Nimble code on the left and the result on the right, like this:
Code | Result |
---|---|
/Example/ Nimble *syntax*. | Example Nimble syntax. |
In fact, there are many uses of this macro all over this very documentation! Here's what it looks like:
#macro example #arg code raw #arg result nimble #result html <table class="example"> <tr><th>Code</th><th>Result</th></tr> <tr><td><pre>{{code|xmlenc}}</pre></td><td>{{result}}</td></tr> </table>
The first argument, code
, takes raw text to be rendered. Upon output, it is XML-encoded: {{code|xmlenc}}
. This causes the Nimble syntax given for that argument to appear as literal text in the output. The second argument, result
, is of type nimble
, causing it to be parsed as Nimble code. Its resulting syntax is not XML-encoded, and so it appears as regular rendered HTML in the output: {{result}}
. Thus, the above example is created like this:
Code | Result | ||||
---|---|---|---|---|---|
$example code: /Example/ Nimble *syntax*. result: /Example/ Nimble *syntax*. |
|
(Yes, the above example used an $example
macro within an $example
macro.)
You could achieve a similar result for demonstrating raw HTML by making the result
argument of type raw
, instead:
#macro example_html #arg code raw #arg result raw #result html <table class="example"> <tr><th>Code</th><th>Result</th></tr> <tr><td><pre>{{code|xmlenc}}</pre></td><td>{{result}}</td></tr> </table> $example_html code: <s>Strikethrough!</s> result: <s>Strikethrough!</s>
...produces...
Code | Result |
---|---|
<s>Strikethrough!</s> |
Suppose you embed a lot of YouTube videos using the <object>
tag interface.
#macro youtube #arg id raw #result html <object width="640" height="390"> <param name="movie" value="https://www.youtube.com/v/{{id|xmlenc}}?version=3"></param> <param name="allowScriptAccess" value="always"></param> <embed src="https://www.youtube.com/v/{{id|xmlenc}}?version=3" type="application/x-shockwave-flash" allowscriptaccess="always" width="640" height="390"></embed> </object>
Then, anywhere in your document, simply write...
Code | Result |
---|---|
$youtube id: w-nBuRToaNQ |
Want to be able to tag things with [citation needed] like you can on Wikipedia?
Code | Result |
---|---|
#macro citation_needed #result html <sup>[citation needed]</sup> That dragon was delicious. [$citation_needed] | That dragon was delicious. [citation needed] |
Or, to actually cite thigs, maybe something like....
Code | Result |
---|---|
#macro ref #arg id raw #result html <sup ><a href="#cite-{{id|urlenc|xmlenc}}">[{{id|xmlenc}}]</a ></sup> #macro cite #arg id raw #arg text nimble #result html <div> <a name="cite-{{id|xmlenc}}" id="cite-{{id|xmlenc}}"></a> {{id|xmlenc}}. {{text}} </div> That dragon was delicious.[$ref id=1] We could catch another in that cave.[$ref id=2] [$cite id=1 text="I should know; I just ate it."] [$cite id=2 text="I just saw a dragon in that cave."] | That dragon was delicious.[1] We could catch another in that cave.[2] |
The weird newlines in the ref
macro are to prevent extra whitespace from appearing within the <sup>
tag.
Output formats
Many output formats are possible; Nimble syntax is first converted to a syntax tree, and then the syntax tree is rendered. Future possibilities include LaTeX, Perl POD, Markdown, or Wikipedia (MediaWiki) markup.
HTML
The HTML output format tries to produce semantically-useful HTML5 — sections ({
... }
) are <section>
s, blockquotes with citations are contained within <figure>
s, and so forth.
In general, the HTML renderer tries to keep stray whitespace within tags rather than outside them. This prevents extra text nodes from being generated. For example, paragraphs might look like this:
<p>paragraph 1</p ><p>paragraph 2</p ><p>paragraph 3</p >
This is valid HTML; when an application reads it, it will generate only a series of paragraph nodes with no intervening text nodes containing merely unnecessary newlines. This means that newline-separated inline or inline-block elements won't have extra spaces between them, and any JavaScript using the Node.childNodes
DOM interface will only see the nodes you intended.
You can see an example of HTML output from Nimble by viewing the source of this page, specifically the section within the <article>
tags.
Try it!
You can test out Nimble if you like. The test page has some limits on CPU time and input size to prevent anyone from doing something too ridiculous.