SEP 64: Redesign shortcodes
PENDING:
-
Implement
@terminal/shell/command -
Implement
@embedand replaceaside::andimport::substitutions/imports with@embed -
Make assets support backlinks so that
@linkcan be used for assets too, then review all uses of@val(id.slug)and replace with@linkwhere possible -
Finish migrating all instances of old
link::andslug:syntax (slug is now@val($uid.slug)) - Remove last of the legacy substitution code
- Ultimately I would love to get rid of all regex based substitution schemes and instead parse my documents into an AST and then walk the tree, altering nodes directly, but I’m a ways away from that yet.
I want a better design for the shortcodes I use throughout the site.
The current “design” is captured in the regexes used to extract them:
REF_LINK_RE = re.compile(r"!?\[([^\]]*?)\](\((.*?::)([^)]+)\))")
REF_SLUG_RE = re.compile(r"(?<!`)(slug::)([a-zA-Z0-9]*)((?:#[^)\s]*)?)")
REF_TITLE_RE = re.compile(r"(\{\{ *)(title::)([a-zA-Z0-9]*)( *(?:#[^}]*)?)( *\}\})")
REF_CITE_RE = re.compile(r"(\{\{ *)(cite::)([a-zA-Z0-9]*)( *(?:#[^}]*)?)( *\}\})")
REF_IMPT_RE = re.compile(
r"(\{\{ *)((?:aside|import)::)([a-zA-Z0-9]*)( *(?:#[^}]*)?)( *\}\})"
)
text = page.content.get("plain")
if text:
text = replace_import_references(text, REF_IMPT_RE, merged_data, key, page)
text = replace_cite_references(text, REF_CITE_RE, merged_data)
text = replace_title_references(text, REF_TITLE_RE, merged_data)
text = replace_slug_references(text, REF_SLUG_RE, merged_data)
text = process_reference_links(text, REF_LINK_RE, merged_data, key)
page.content["plain"] = text.strip()
For example, ::Author](quote::$UID) would be replaced with a quote embed of the provided uid.
This design was meant to closely follow the semantics of markdown/Djot links.
As my document system expands, and I move further away from existing markup syntax, I want a design that generalises better, provides more legibility and extensibility, and has support for parameters.
TLDR: @keyword(option="value") or something similar.
Core Idea: A single sigil, @, initiates a “function” with a clear name and parameters.
Syntax & Examples:
-
The Function Call:
@command(id, ...)or@command{...} -
Links:
@link(a1b2c3d4, text="Custom Text", fragment="...")- Could use positional params for brevity: @link(a1b2c3d4, “Custom Text”)
-
Images/Media:
-
@img(a1b2c3d4, alt="...") -
@video(a1b2c3d4)
-
-
Inline Data: A dedicated command to retrieve values.
-
The title is
@val(a1b2c3d4.title). -
Find it at
@val(a1b2c3d4.slug).
-
The title is
-
Formatted Content & Transclusion: Each has a clear, named command.
@cite(a1b2c3d4) @quote(a1b2c3d4) @embed(a1b2c3d4) @gallery{ @img(b2c3d4e5) @img(f6g7h8i9) } (Block-form for wrapping content)
-
Key/value parameters vs positional arguments?.
Positional arguments can be more terse, but like short-opts (vs long-opts) they are less legible and they bake in assumptions. A key/value system is more verbose but removes ambiguity and makes changing defaults, and adding or deprecating arguments much safer. - There should be a syntax for escaping/skipping a shortcode, when I want the actual shortcode to remain in a document.