markdoll spec (original std tags)

this content of this page is an automatic transclusion from the specification on codeberg
this rest of this page is rendered using the original markdoll standard library tags, click here to see what this page looks like with this site's custom variants of some std tags
the site's CSS applies always, so this will look different than a plain html render

this is markdoll
markdoll is an extensible markup language written in rust, made: by dolls, for dolls

how is it different from other markup languages?

like HTML, markdoll is a tree shaped system. for example, headers always precede sections, which have a defined ending point, an explicit hierarchy, rather than an implicit one

specification

whitespace

in markdoll, tab characters are significant, they help define sections and lists, and provide a boundary for block-content tags
markdoll specifically does not assign importance to spaces, but does prohibit them in certain cases
newlines are also very signficant:
  • unless the last character of the line is a backslash (\), splitting text by a newline instead inserts a space
  • separating text/tags by an empty line splits it into two paragraphs
  • separating list elements by an empty line splits it into two lists
do note that all .doll files must be LF, CR characters will cause a fatal parsing error

tags

markdoll has a concept of "tags", which have a keyword and may choose to have arguments and content
tags can be written multiple ways:
kindsyntaxresult
no-arg & no-content
[sometag]
invokes sometag, does not provide an argument or any content
arg & no-content
[sometag(argument that can have any non-parenthesis tokens in it)]
invokes sometag, providing the argument text, but no content
no-arg & content
[sometag:content]
[sometag::
	block content
]
invokes sometag, does not provide an argument, but provides content[block-tags]
arg & content
[sometag(argument that can have any non-parenthesis tokens in it):content]
[sometag(argument that can have any non-parenthesis tokens in it)::
	block content
]
invokes sometag, providing an argument and content[block-tags]
[block-tags]:
block tags allow far more flexibility in the content of tags, being able to put anything inside of them, without markdoll interpreting it whatsoever, leaving that to that tag (including escape sequences!)
however, this requires that the content is indented one level further than the tag, to let the parser know what is and is not part of the content

escape sequences

most parts of markdoll support escape sequences with the backslash character (\)
for example:
  • [em:\]] results in: ]
  • [em:\\] results in: \
inline tags do not need to escape balanced square brackets, however
  • [em:]] is unbalanced and will end early
  • [em:[]] is balanced and will not end early
block tags completely ignore escaping/balancing, their content is fed as-is into the tag, after the indentation of the tag + 1 has been stripped. they dont have to care about escaping/balancing because the only way to terminate them is to lower the indentation again, which isnt something that could be escaped

lists

unordered and ordered lists are also easy:
kindsyntaxresult
unordered
-	single line
-	[em:can also include formatting]
-	lists can also
	span multiple lines
	if the same indent is kept
  • single line
  • can also include formatting
  • lists can also span multiple lines if the same indent is kept
ordered
=	single line
=	[em:can also include formatting]
=	lists can also
	span multiple lines
	if the same indent is kept
  1. single line
  2. can also include formatting
  3. lists can also span multiple lines if the same indent is kept

sections

a section is preceded by a heading, and its content is indented 1 level higher
syntaxresult
&hello
	&world
		content
	goes
here

hello

world
content
goes
here
when emitting to HTML, it is not recommended to have more than one top-level section, as multiple h1 elements causes accessibility issues

frontmatter

markdoll differentiates between parsing as a document and everything else:
  • each tag parses its content as embedded markdoll source via parse_embedded, so frontmatter would not be parsed in these situations
  • but when parsing a main document via parse_document, frontmatter is permitted.
frontmatter works almost identically to the way it does in many other markup languages, with an optional section at the very beginning of a file that is fenced with ---:
---
whatever
---

normal content goes here
while some languages choose to parse frontmatter as YAML or TOML, markdoll does not wish to take part in the war between the two, and just returns it as a string

extensibility

markdoll and its standard library emits HTML by default, but it doesn't have to!
markdoll does not load any tags automatically, all of them must be manually inserted. the standard library all supports HTML by default, and can be extended with other targets

standard extensions

the standard library is in the markdoll::ext module

common

in module markdoll::ext::common
tagdescriptionsyntaxresult
//the comment tag is very simple, its content is not parsed and is excluded from the output
[//:this will not be included in the output]

formatting

in module markdoll::ext::formatting
tagdescriptionsyntaxresult
em
apply one or more forms of emphasis to the content
flags:
  • i
    italics
    default if no flags are specified
  • b
    bold
  • u
    underline
  • s
    strikethrough
  • h
    highlight
  • q
    quote
[em:italics]
italics
[em(i):italics (explicit)]
italics (explicit)
[em(b):bold]
bold
[em(u):underline]
underline
[em(s):strikethrough]
strikethrough
[em(h):highlight]
highlight
[em(q):quote]
quote
[em(i)(b)(u)(s)(h)(q):everything]
everything
quote
block quotes
an optional cite argument may be provided
[quote::
	block quotes can contain [em:markdoll]
]
block quotes can contain markdoll
[quote(citation goes here)::
	block quotes can contain [em:markdoll]
]
citation goes here
block quotes can contain markdoll

code

in module markdoll::ext::code
tagdescriptionsyntaxresult
codeinline code blocks
[code:whatever code goes here, it is not [parsed]]
whatever code goes here, it is not [parsed]
codeblockmulti-line code blocks
[codeblock::
	anything can go here :3
]
anything can go here :3

links

in module markdoll::ext::links
tagdescriptionsyntaxresult
linklink to content
[link(https://codeberg.org/0x57e11a/markdoll):markdoll]
markdoll
imginsert images
[img(https://codeberg.org/0x57e11a/markdoll/raw/branch/main/button.png)::
	alt text goes here (88x31 button that says MADE WITH MARKDOLL)
]
alt text goes here (88x31 button that says MADE WITH MARKDOLL)
anchorinvisible anchors to be used with the ref tag (ideal for section heads)
[anchor(anchor-tag)]
defin-page anchors to be used with the ref tag
[def(def-tag):some definition]
[def-tag]: some definition
reflink to an anchor defined by the def tag
this is a reference[ref(def-tag)][ref(anchor-tag)]
this is a reference[def-tag][anchor-tag]

table

in module markdoll::ext::table
tagdescriptionsyntaxresult
table
tables
tables have two syntaxes (that can be mix-matched, even within eachother):
  • list syntax
    unordered list elements define normal rows/cells, ordered lists define head rows/cells
    cannot create cells that span multiple rows/columns, use tags for that
  • tag syntax
    using tr/tc tags and their arguments/flags
[table::
	=	=	r1c1
		=	r1c2
		=	r1c3

	-	=	r2c1
		-	r2c2
		-	r2c3

	-	=	r3c1
		-	r3c2
		-	r3c3
]
r1c1r1c2r1c3
r2c1r2c2r2c3
r3c1r3c2r3c3
[table::
	[tr(head)::
		[tc(head):r1c1]
		[tc(head):r1c2]
		[tc(head):r1c3]
	]

	[tr::
		[tc(head):r2c1]
		[tc:r2c2]
		[tc:r2c3]
	]

	[tr::
		[tc(head):r3c1]
		[tc:r3c2]
		[tc:r3c3]
	]
]
r1c1r1c2r1c3
r2c1r2c2r2c3
r3c1r3c2r3c3
tr
create table rows inside tables
pass the head flag to insert it into the head section
[table::
	[tr::
		[tc:cells go here, whether by list or tag syntax]
	]
]
cells go here, whether by list or tag syntax
[table::
	[tr(head)::
		[tc(head)::
			cells go here, they should be [code:head] cells,
			whether by list or tag syntax
		]
	]
]
cells go here, they should be head cells, whether by list or tag syntax
tc
create table cells inside table rows
pass the head flag to make it a head cell
set the rows/cols props to make cells that span multiple rows/columns
[table::
	[tr::
		[tc:content]
	]
]
content
[table::
	[tr::
		[tc(head):content]
	]
]
content
[table::
	[tr::
		[tc(rows=2):two rows]
		[tc:upper]
	]
	[tr::
		[tc:lower]
	]
]
two rowsupper
lower
[table::
	[tr::
		[tc(cols=2):two cols]
	]
	[tr::
		[tc:left]
		[tc:right]
	]
]
two cols
leftright

danger zone

by enabling the crate feature danger, the ext::danger module becomes available for use, and is automatically loaded into the default binary
this contains potentially dangerous tags, proceed with caution
tagdescriptionsyntax
invokeinvoke an external command, passing arguments as cli args, content as stdin, dumping stdout into the output stream
[invoke(./test.sh)(flip):hello world]
imagine test.sh sees the flip argument and returns a version of stdin with all the letters flipped around
MADE WITH MARKDOLL

created:
updated:
built: