lcmark is a high-level CommonMark converter
built upon cmark. It comes as both a
command-line program and a Lua module. It supports:
-
YAML metadata at the top of the document.
-
Filters, which allow the document to be transformed between parsing and rendering, making a large number of customizations possible.
-
Templates, which allow the body and metadata values to be embedded into a pre-defined structure.
Also see the documentation.
To install: luarocks install lcmark
(This installs both the library and the program).
Additionally, you'll also need a YAML parsing library. lcmark will
automatically attempt to load and use one of
yaml,
lua-yaml or
lyaml, so make sure you have one of those
installed. Alternatively, a custom parser can be used (see the yaml_parser
option below).
The YAML metadata section (if present) must occur at the beginning of the
document. It begins with a line containing --- and ends with a line
containing ... or ---. Between these, a YAML key/value map is expected.
String values found in the metadata will be parsed and rendered as CommonMark. If a string value contains only a single paragraph, it will be rendered as an inline string.
If the yaml_parser option (a function) is provided, lcmark will use it to
parse YAML. The function should take a string as input and should return a
table. In case of failure, it should either throw an error or return a
nil, err tuple; other returns will be discarded silently.
Example:
---
# This is a comment!
# Note that the quotes below are needed because of the
# colon in the title:
title: 'This is my *article*: subtitle here'
author:
- name: Sam Smith
institute: U of X
- name: Sasha Xi
institute: NXQ
abstract: |
Here is a multiline abstract.
- It can even
- contain
- lists and other block elements
...
Document body starts here...
Filters modify the parsed document prior to rendering.
A filter is a function that takes three arguments (doc, meta, to), where
doc is a cmark node, meta is the YAML metadata as a (potentially nested) Lua
table with all strings replaced with cmark nodes, and to is a string
specifying the output format (the same string as passed to lcmark.convert).
The filter may destructively modify doc and meta.
Some sample filters are provided in
filters/.
Templates are used to build standalone documents from the parsed document body and metadata.
lcmark supports a small subset of the templating language used by
pandoc, and lcmark templates can be used with pandoc
(with the caveat that pandoc sets many variables automatically that lcmark
does not).
nil, false and {} (an empty table) are considered to be "falsy" values.
Any other value is considered "truthy".
A quick guide:
-
The only special character in templates is
$. To get a literal$character, use$$. -
$name$will be replaced with the value of thenamemetadata field. Variable names can contain alphanumerics,-, and_. -
$name.subname$will be replaced with the value of thesubnamefield of thenamemetadata field (assumed to be a map). Multiple indexes can be chained together this way. -
$if(name)$...$endif$will be replaced by the content in...if the value of thenamemetadata field is "truthy", otherwise by nothing....may contain nested templating directives. -
$if(name)$...$else$,,,$endif$will be replaced by the content in...ifnamehas a truthy value, and by the content in,,,otherwise. Both...and,,,may contain nested templating directives. -
$for(name)$...$endfor$is a loop, producing successive concatenated copies of.... If the value ofnameis a non-empty table, then in each occurrence of..., the value ofnamewill be replaced by a different element from the table (in order). For example,$for(authors)$$authors$$endfor$will concatenate all the values of theauthorstable.Otherwise, if the value of
nameisn't a table, the loop behaves like anif. -
$for(name)$...$sep$,,,$endfor$behaves like the above, except that the content in,,,is inserted between each copy of....,,,supports nested templating directives.
Additionally, if newlines occurs directly after both $for()$ and
$endfor$ (or $if()$ and $endif$), they will be ignored. This is to
prevent spurious blank lines in the rendered document if the template contains
many directives that span multiple lines and evaluate to false.
Some sample templates are provided in
templates/.
lcmark --help will print a short list of options.
For a more detailed description, see the lcmark(1) man page.
Basic usage:
local lcmark = require("lcmark")
local body, metadata = lcmark.convert("Hello *world*",
"latex", {smart = true, columns = 40})The module exports the following fields:
-
lcmark.version: a string with the version number. -
lcmark.yaml_parser_name: a string holding the name of the automatically-loaded module and function used to parse YAML. Possible values are:"lyaml.load"(lyaml)"yaml.load"(yaml)"yaml.eval"(lua-yaml)nil(none)
-
lcmark.convert(str, to, options): Convertsstr(a CommonMark formatted string) to the output format specified byto(a string; one ofhtml,commonmark,latex,man, orxml).optionsis a table with the following fields (all optional):smart- enable "smart punctuation"hardbreaks- treat newlines as hard breakssafe- filter out potentially unsafe HTML and linkssourcepos- include source position in HTML and XML outputfilters- an array of filters to run (seeload_filterbelow)columns- column width, or 0 to preserve wrapping in inputyaml_metadata- whether to parse initial YAML metadata blockyaml_parser- a function to parse YAML with (see YAML Metadata)
Returns
body,metaon success, wherebodyis the rendered document body andmetais the YAML metadata as a table. If theyaml_metadataoption is false or if the document contains no YAML metadata,metawill be an empty table. In case of an error, the function returnsnil, nil, msg. -
lcmark.load_filter(filename): Loads a filter from a Lua file (see Filters) and populates the loaded function's environment with all the fields fromcmark-lua. Returns the filter function on success, ornil, msgon failure. -
lcmark.compile_template(str): Compiles a template stringstr(see Templates) into an arbitrary template object which can then be passed tolcmark.apply_template(). Returns the template object on success, ornil, msgon failure. -
lcmark.apply_template(template, context): Renders a compiled template object into a string using a context table (typically the document's metadata). -
lcmark.render_template(str, context): Compiles and applies a template string to a context table. Returns the resulting document string on success, ornil, msgon failure. -
lcmark.writers: a table with strings as keys (html,latex,man,xml,commonmark) and renderers as values. A renderer is a function that takes three arguments (a cmark node, cmark options (a number), and a column width (a number). It returns the rendered output as a string.
make builds the rock and installs it locally.
make test runs some tests. These are in test.t and tests/.
You'll need the prove executable,
as well as luacheck and
lua-TestMore.
make update will update the spec tests from the
../cmark directory.
make -C standalone will create a fully self-contained version
of lcmark which embeds the lua interpreter and all required
libraries, resulting in no external dependencies.