{"id":19227356,"url":"https://github.com/quarto-dev/quarto-shortcodes","last_synced_at":"2026-02-23T06:03:19.468Z","repository":{"id":39633155,"uuid":"493642301","full_name":"quarto-dev/quarto-shortcodes","owner":"quarto-dev","description":null,"archived":false,"fork":false,"pushed_at":"2022-05-30T13:13:10.000Z","size":19,"stargazers_count":8,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-19T04:40:23.057Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quarto-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-18T11:54:54.000Z","updated_at":"2022-08-02T23:51:26.000Z","dependencies_parsed_at":"2022-08-09T15:07:32.960Z","dependency_job_id":null,"html_url":"https://github.com/quarto-dev/quarto-shortcodes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/quarto-dev/quarto-shortcodes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quarto-dev%2Fquarto-shortcodes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quarto-dev%2Fquarto-shortcodes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quarto-dev%2Fquarto-shortcodes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quarto-dev%2Fquarto-shortcodes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quarto-dev","download_url":"https://codeload.github.com/quarto-dev/quarto-shortcodes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quarto-dev%2Fquarto-shortcodes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29738521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T04:51:08.365Z","status":"ssl_error","status_checked_at":"2026-02-23T04:49:15.865Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T15:22:52.849Z","updated_at":"2026-02-23T06:03:19.453Z","avatar_url":"https://github.com/quarto-dev.png","language":"Lua","readme":"# shortcodes\n\n## Overview\n\nThis is a stanalone version of the [Quarto Shortcodes](https://quarto.org/docs/authoring/shortcodes.html) feature that can be used with base Pandoc outside of Quarto.\n\nShortcodes are special markdown directives that generate various types of content. For example, the following built-in shortcode prints the `title` from document metadata:\n\n``` markdown\n{{\u003c meta title \u003e}}\n```\n\nRender a document using this shortcode by adding the [shortcodes.lua](shortcodes.lua) filter:\n\n```bash\npandoc document.md --lua-filter shortcodes.lua --to html\n```\n\nThe `shortcodes.lua` filter supports several shortcodes natively:\n\n| Shortcode                                    | Description                            |\n|----------------------------------------------|----------------------------------------|\n| `meta`                                       | Print value from document metadata     |\n| `env`                                        | Print system environment variable      |\n| `pagebreak`                                  | Insert a native page-break             |\n\nIn addition, you can create custom shortcodes (read on for details). \n\n## Shortcode Basics \n\nYou can create your own shortcodes using Lua. Before working on custom shortcodes you should familiarize yourself with the documentation on [Pandoc Lua Filters](https://pandoc.org/lua-filters.html), which describes the Lua extension API for Pandoc.\n\nCustom shortcodes are implemented as Lua functions that take one or more arguments and return a Pandoc AST node (or list of nodes).\n\nHere's the implementation of the `env` shortcode:\n\n**env.lua**\n\n``` lua\nfunction env(args)\n  local var = pandoc.utils.stringify(args[1])\n  local value = os.getenv(var)\n  if value ~= nil then\n    return pandoc.Str(value)\n  else\n    return pandoc.Null()\n  end\nend\n```\n\nNote that arguments to shortcodes are provided in `args` (a 1-based array), and that each argument is a list of Pandoc inlines (i.e. markdown AST parsed from the text).\n\nWe use the `pandoc.utils.stringify()` function to convert the inlines to an ordinary string, and then the `os.getenv()` function to get its value.\n\nIf this function was included in a source file named `env.lua`, you could register it for use with:\n\n``` yaml\nshortcodes:\n  - env.lua\n```\n\nThen use it with:\n\n``` markdown\n{{\u003c env HOME \u003e}}\n```\n\nBelow we'll provide a few a few more examples of custom shortcodes and their implementation.\n\n## Example: Raw Output\n\nShortcodes can tailor their output to the format being rendered to. This is often useful when you want to conditionally generate rich HTML output but still have the same document render properly to PDF or MS Word.\n\nThe `pagebreak` shortcode generates \"native\" pagebreaks in a variety of formats. Here's the implementation of `pagebreak`:\n\n**pagebreak.lua**\n\n``` lua\nfunction pagebreak()\n \n  local raw = {\n    epub = '\u003cp style=\"page-break-after: always;\"\u003e \u003c/p\u003e',\n    html = '\u003cdiv style=\"page-break-after: always;\"\u003e\u003c/div\u003e',\n    latex = '\\\\newpage{}',\n    ooxml = '\u003cw:p\u003e\u003cw:r\u003e\u003cw:br w:type=\"page\"/\u003e\u003c/w:r\u003e\u003c/w:p\u003e',\n    odt = '\u003ctext:p text:style-name=\"Pagebreak\"/\u003e',\n    context = '\\\\page'\n  }\n\n  if FORMAT == 'docx' then\n    return pandoc.RawBlock('openxml', raw.ooxml)\n  elseif FORMAT:match 'latex' then\n    return pandoc.RawBlock('tex', raw.latex)\n  elseif FORMAT:match 'odt' then\n    return pandoc.RawBlock('opendocument', raw.odt)\n  elseif FORMAT:match 'html.*' then\n    return pandoc.RawBlock('html', raw.html)\n  elseif FORMAT:match 'epub' then\n    return pandoc.RawBlock('html', raw.epub)\n  elseif FORMAT:match 'context' then\n    return pandoc.RawBlock('context', raw.context)\n  else\n    -- fall back to insert a form feed character\n    return pandoc.Para{pandoc.Str '\\f'}\n  end\n\nend\n```\n\nWe use the `pandoc.RawBlock()` function to output the appropriate raw content for the target `FORMAT`. Note that raw blocks are passed straight through to the output file and are not processed as markdown.\n\nIf this function was implemented within `pagebreak.lua`, you could register it for use with:\n\n``` yaml\nshortcodes:\n  - pagebreak.lua\n```\n\nThen use it with:\n\n``` markdown\n{{\u003c pagebreak \u003e}}\n```\n\n## Example: Named Arguments\n\nThe examples above use either a single argument (`env`) or no arguments at all (`pagebreak`). Here we demonstrate named argument handling by implementing a `git-rev` shortcode that prints the current git revision, providing a `short` option to determine whether a short or long SHA1 is displayed:\n\n**git.lua**\n\n``` lua\n-- run git and read its output\nfunction git(command)\n  local p = io.popen(\"git \" .. command)\n  local output = p:read('*all')\n  p:close()\n  return output\nend\n\n-- return a table containing shortcode definitions\n-- defining shortcodes this way allows us to create helper \n-- functions that are not themselves considered shortcodes \nreturn {\n  [\"git-rev\"] = function(args, kwargs)\n    -- command line args\n    local cmdArgs = \"\"\n    local short = pandoc.utils.stringify(kwargs[\"short\"])\n    if short == \"true\" then\n      cmdArgs = cmdArgs .. \"--short \"\n    end\n    \n    -- run the command\n    local cmd = \"rev-parse \" .. cmdArgs .. \"HEAD\"\n    local rev = git(cmd)\n    \n    -- return as string\n    return pandoc.Str(rev)\n  end\n}\n```\n\nThere are some new things demonstrated here :\n\n1.  Rather than defining our shortcode functions globally, we return a table with the shortcode definitions. This allows us to define helper functions that are not themselves registered as shortcodes. It also enables us to define a shortcode with a dash (`-`) in its name.\n\n2.  There is a new argument to our shortcode handler: `kwargs`. This holds any named arguments to the shortcode. As with `args`, values in `kwargs` will always be a list of Pandoc inlines (allowing you to accept markdown as an argument). Since `short` is a simple boolean value we need to call `pandoc.utils.stringify()` to treat it as a string and then compare it to `\"true\"`.\n\nWe'd register and use this shortcode as follows:\n\n``` markdown\n---\ntitle: \"My Document\"\nshortcodes:\n  - git.lua\n---\n\n{{\u003c git-rev \u003e}}\n{{\u003c git-rev short=true \u003e}}\n```\n\n## Example: Metadata Options\n\nIn some cases you may want to provide options that affect how you shortcode behaves. There is a third argument to shortcode handlers (`meta`) that provides access to document and/or project level metadata.\n\nLet's implement a different version of the `git-rev` shortcode that emits the revision as a link to GitHub rather than plain text. To do this we make use of `github.owner` and `github.repo` metadata values:\n\n**git.lua**\n\n``` lua\nfunction git(command)\n  local p = io.popen(\"git \" .. command)\n  local output = p:read('*all')\n  p:close()\n  return output\nend\n\nreturn {\n  \n  [\"git-rev\"] = function(args, kwargs, meta)\n    -- run the command\n    local rev = git(\"rev-parse HEAD\")\n    \n    -- target repo\n    local owner = pandoc.utils.stringify(meta[\"github.owner\"])\n    local repo = pandoc.utils.stringify(meta[\"github.repo\"])\n    local url = \"https://github.com/\" \n                .. owner .. \"/\" .. repo .. \"/\" .. rev \n    \n    -- return as link\n    return pandoc.Link(pandoc.Str(rev), url)\n  end\n}\n```\n\nAs with `args` and `kwargs`, `meta` values are always provided as a list of Pandoc inlines so often need to be converted to string using `pandoc.utils.stringify()`.\n\nTo use this shortcode in a document we register it, provide the GitHub info as document options, then include the shortcode where we want the link to be:\n\n``` markdown\n---\ntitle: \"My Document\"\nshortcodes:\n  - git.lua\ngithub:\n  owner: quarto-dev\n  repo: quarto-cli\n---\n\n{{\u003c git-rev \u003e}}\n```\n\nThe shortcode registration and GitHub metadata could just as well been provided in a project-level `_quarto.yml` file or a directory-level `_metadata.yml` file.\n\n## Escaping \n\nIf you are writing documentation about using variable shortcodes (for example, this article!) you might need to prevent them from being processed. You can do this in two ways:\n\n1.  Escape the shortcode reference with extra braces like this:\n\n    ``` markdown\n    {{{\u003c var version \u003e}}}\n    ```\n\n2.  Add a `shortcodes=false` attribute to any code block you want to prevent processing of shortcodes within:\n\n    ```` markdown\n    ```{shortcodes=false}\n\n    {{\u003c var version \u003e}}\n    ```\n    ````\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquarto-dev%2Fquarto-shortcodes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquarto-dev%2Fquarto-shortcodes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquarto-dev%2Fquarto-shortcodes/lists"}