diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4edc581..8bb7ca4 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -74,7 +74,8 @@ "skills": [ "./brand-yml", "./quarto/quarto-authoring", - "./quarto/quarto-alt-text" + "./quarto/quarto-alt-text", + "./quarto/quarto-lua" ] } ] diff --git a/README.md b/README.md index f882fac..ba7558d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Skills for Quarto document creation and publishing. - **[brand-yml](./brand-yml/)** - Create and apply brand.yml files for consistent styling across Quarto projects, supporting HTML documents, dashboards, RevealJS presentations, Typst PDFs, and websites with automatic brand discovery and theme layering - **[authoring](quarto/README.md#quarto-authoring-skill)** - Comprehensive guidance for Quarto document authoring and R Markdown migration. Write new Quarto documents with best practices, convert R Markdown files, migrate bookdown/blogdown/xaringan/distill projects, and use Quarto-specific features like hashpipe syntax, cross-references, callouts, and extensions - **[quarto-alt-text](./quarto/quarto-alt-text/)** - Generate accessible alt text for figures in Quarto documents using Amy Cesal's three-part formula (chart type, data description, key insight). Supports code-generated plots and static images +- **[quarto-lua](./quarto/quarto-lua/)** - Write Lua shortcodes and filters for Quarto, with runtime access to Quarto's LLM-optimised API documentation ## Installation diff --git a/quarto/README.md b/quarto/README.md index 61a853e..9cc15c5 100644 --- a/quarto/README.md +++ b/quarto/README.md @@ -76,10 +76,11 @@ Comprehensive guidance for Quarto document authoring and R Markdown migration. W Create and use `_brand.yml` files for consistent branding across Quarto documents and Shiny applications. Use when working with brand styling, corporate identity, colors, fonts, or logos in Quarto projects. **Organization**: Main skill file includes workflows and decision tree. Reference files provide framework-specific integration guides: -- `brand-yml-spec.md` - Complete brand.yml specification -- `shiny-r.md` - Shiny for R integration with bslib -- `shiny-python.md` - Shiny for Python integration with ui.Theme -- `quarto.md` - Quarto integration for all formats (HTML, dashboards, RevealJS presentations, Typst PDFs, websites) + +- `brand-yml-spec.md` - Complete brand.yml specification. +- `shiny-r.md` - Shiny for R integration with bslib. +- `shiny-python.md` - Shiny for Python integration with ui.Theme. +- `quarto.md` - Quarto integration for all formats (HTML, dashboards, RevealJS presentations, Typst PDFs, websites). **Note**: This skill is also registered in the shiny category since brand.yml works across both Shiny and Quarto projects. @@ -92,6 +93,16 @@ Create and use `_brand.yml` files for consistent branding across Quarto document --- +### `lua` + +Write Lua shortcodes and filters for Quarto. Covers shortcode handlers, Pandoc AST filters, Lua coding conventions, Quarto-specific Lua APIs, and common patterns. Includes runtime access to Quarto's LLM-optimised documentation (`.llms.md` pages) for detailed API reference. + +#### Authors + +- [Mickaël CANOUIL](https://github.com/mcanouil) + +--- + ### `quarto-alt-text` Generate accessible alt text for data visualizations in Quarto documents. Use when adding, improving, or reviewing `fig-alt` for figures in `.qmd` files, or when making documents more accessible for screen readers. @@ -106,13 +117,12 @@ Generate accessible alt text for data visualizations in Quarto documents. Use wh This category could include skills for: -- Publishing workflows -- Extension development -- Template creation -- Multi-format output -- Parameterized reports -- Website and book publishing -- Presentation design +- Publishing workflows. +- Template creation. +- Multi-format output. +- Parameterized reports. +- Website and book publishing. +- Presentation design. ## Contributing diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md new file mode 100644 index 0000000..7cd7d5a --- /dev/null +++ b/quarto/quarto-lua/SKILL.md @@ -0,0 +1,181 @@ +--- +name: quarto-lua +description: > + Write Lua shortcodes and filters for Quarto. + Use when creating, debugging, or modifying Lua code that runs inside + Quarto, including shortcode handlers, Quarto Lua filters, and + Quarto-specific Lua APIs. +metadata: + author: Mickaël Canouil (@mcanouil) + version: "1.0" +license: MIT +--- + +# Quarto Lua + +Write Lua shortcodes and filters for Quarto. + +> This skill is based on Quarto CLI v1.9.30 (2026-03-09). + +## When to Use What + +Task: Write a shortcode -> "Writing a Shortcode" below +Task: Write a filter -> "Writing a Filter" below +Task: Pandoc Lua API (constructors, types, methods) -> WebFetch `https://quarto.org/docs/extensions/lua-api.llms.md` +Task: Debug Lua / tooling -> WebFetch `https://quarto.org/docs/extensions/lua.llms.md` +Task: Shortcode details (args, raw output) -> WebFetch `https://quarto.org/docs/extensions/shortcodes.llms.md` +Task: Filter details (AST traversal, multi-pass) -> WebFetch `https://quarto.org/docs/extensions/filters.llms.md` +Task: Metadata / project filters -> WebFetch `https://quarto.org/docs/extensions/metadata.llms.md` +Task: Custom AST nodes / filter timing -> Read `references/custom-ast-nodes.md` in this skill directory + +Fetch only pages relevant to the current task. + +## Writing a Shortcode + +A shortcode exports a function called whenever `{{< name ... >}}` appears in `.qmd`. +Register under `shortcodes:` in `_extension.yml` or document YAML. +Add a file header (see "Lua File Header Convention"), then: + +```lua +return function(args, kwargs, meta, raw_args) + local name = pandoc.utils.stringify(args[1] or "world") + return pandoc.Str("Hello, " .. name .. "!") +end +``` + +Parameters: `args` (positional, 1-indexed), `kwargs` (named), `meta` (document metadata), `raw_args` (unparsed strings). +Both `args` and `kwargs` contain `pandoc.Inlines`; use `pandoc.utils.stringify()` to get strings. +Return `pandoc.Inlines` or `pandoc.Blocks`. Use `pandoc.RawInline`/`pandoc.RawBlock` for format-specific output. +Verify the exact handler signature against the shortcodes `.llms.md` page when targeting a specific Quarto version. + +## Writing a Filter + +A filter returns a list of handler tables mapping AST element types to transform functions. +Register under `filters:` in `_extension.yml` or document YAML. +Add a file header (see "Lua File Header Convention"), then: + +```lua +local function convert_emph(el) + return pandoc.SmallCaps(el.content) +end + +return { + { Emph = convert_emph } +} +``` + +Each table is a separate traversal pass. Handlers return a replacement element, a list, or `nil` (or nothing) to skip. +Use a `Pandoc(doc)` handler to process the entire document, or `Meta(meta)` to read/modify metadata. +Multiple passes: `return { { Header = fix_headers }, { Link = fix_links } }`. + +## Lua File Header Convention + +Every `.lua` file must start with: + +```lua +--- name - Short description +--- @module name.lua +--- @license MIT +--- @copyright 2026 Author Name +--- @author Author Name +--- @version 0.1.0 +--- @brief One-line summary. +--- @description Longer explanation of purpose and behaviour. +--- Wrap at ~72 chars, indent continuation with two spaces. +``` + +Fields: `@module` (filename), `@license`, `@copyright`, `@author`, `@version` (semver), `@brief` (one-liner), `@description` (multi-line). +Always generate for new files. Update `@version`/`@description` when modifying. + +## Lua Style and Conventions + +- **Naming**: `snake_case` for variables/functions, `PascalCase` for module-level tables only. +- **Indentation**: 2 spaces. +- **Strings**: double quotes for user-facing text, single quotes for identifiers/keys. +- **Scoping**: always `local` unless intentionally global. +- **Errors**: fail fast with `error("context: what went wrong")`. +- **Docs**: `---` comment blocks above functions (LDoc-compatible): + +```lua +--- Convert a Pandoc inline element to plain text. +--- @param el pandoc.Inline The inline element to convert. +--- @return string The plain text representation. +local function stringify_inline(el) + return pandoc.utils.stringify(el) +end +``` + +## Common Patterns + +### `pandoc.utils.stringify()` + +Converts any AST element to plain text. Use for shortcode arguments and metadata fields. + +### Format Detection + +Check the output format before emitting format-specific content: + +```lua +if quarto.doc.is_format("html") then + -- HTML-only logic +end +``` + +### Quarto Document APIs + +```lua +-- HTML only; no-op for PDF/Typst +quarto.doc.add_html_dependency({ + name = "my-dep", version = "0.1.0", + stylesheets = { "style.css" }, scripts = { "script.js" } +}) + +-- Works for all formats (HTML, LaTeX/PDF, Typst) +quarto.doc.include_text("in-header", "...") +-- Positions: "in-header", "before-body", "after-body" +``` + +### Debugging + +```lua +quarto.log.output("my-var:", my_var) +``` + +### Multi-file Modules + +```lua +local utils = require("utils") +``` + +Quarto resolves `require` paths relative to the calling script's directory. + +### Testing + +```bash +quarto render example.qmd +``` + +## Custom AST Nodes + +Quarto extends Pandoc's AST with custom node types that filters can match by name. + +**Block-level:** Callout, ConditionalBlock, Tabset, PanelLayout, FloatRefTarget, DecoratedCodeBlock, Theorem, Proof. + +**Inline-level:** Shortcode. + +**Other:** LatexEnvironment, LatexInlineCommand, HtmlTag. + +Constructors exist for: `quarto.Callout(tbl)`, `quarto.ConditionalBlock(tbl)`, `quarto.Tabset(tbl)`, `quarto.Tab(tbl)`. + +Cross-referenceable elements (figures, tables, listings) are represented as `FloatRefTarget` nodes. + +Filter timing supports eight phases (`pre-ast` through `post-finalize`) via the `at` property in `_extension.yml`. + +For full constructor signatures and filter timing details, read `references/custom-ast-nodes.md`. + +## Resources + +- [Quarto Lua API](https://quarto.org/docs/extensions/lua-api.html) +- [Pandoc Lua Filters reference](https://pandoc.org/lua-filters.html) +- [Pandoc community Lua filters](https://github.com/pandoc/lua-filters) +- [LuaRocks style guide](https://github.com/luarocks/lua-style-guide) diff --git a/quarto/quarto-lua/references/custom-ast-nodes.md b/quarto/quarto-lua/references/custom-ast-nodes.md new file mode 100644 index 0000000..92dbc01 --- /dev/null +++ b/quarto/quarto-lua/references/custom-ast-nodes.md @@ -0,0 +1,84 @@ +# Custom AST Nodes + +Quarto extends Pandoc's AST with custom node types. +Filters match these by name in handler tables (e.g., `{ Callout = handle_callout }`). + +## Available Node Types + +**Block-level:** Callout, ConditionalBlock, Tabset, PanelLayout, FloatRefTarget, DecoratedCodeBlock, Theorem, Proof. + +**Inline-level:** Shortcode. + +**Other:** LatexEnvironment, LatexInlineCommand, HtmlTag. + +Note: `_quarto.ast.add_handler()` is internal to Quarto. +Extension authors interact via standard filter handlers. + +## Constructor Signatures + +### `quarto.Callout(tbl)` + +- `type`: `string` - callout type (note, caution, warning, tip, important). +- `title`: `pandoc.Inlines` or `string` (optional). +- `icon`: `boolean` or `string` (optional, defaults based on type). +- `appearance`: `string` - "minimal", "simple", or "default" (optional). +- `collapse`: collapse state (optional). +- `content`: `pandoc.Blocks` or list (optional, defaults to empty Blocks). +- `attr`: `pandoc.Attr` (optional, defaults to empty Attr). + +### `quarto.ConditionalBlock(tbl)` + +- `node`: `pandoc.Div` - the div holding the content. +- `behavior`: `string` - "content-visible" or "content-hidden". +- `condition`: list of 2-element lists (optional, defaults to `{}`). + Each sublist: `{"when-format"|"unless-format"|"when-profile"|"unless-profile", value}`. + +### `quarto.Tabset(tbl)` + +- `tabs`: list of `quarto.Tab` objects (optional, defaults to empty list). +- `level`: `number` - heading level for tabs (optional, default `2`). +- `attr`: `pandoc.Attr` (optional, defaults to `pandoc.Attr("", {"panel-tabset"})`). + +### `quarto.Tab(tbl)` + +- `title`: `pandoc.Inlines` or `string` (required). +- `content`: `pandoc.Blocks` or `string` (optional, string parsed as markdown). +- `active`: `boolean` (optional, default `false`). + +## Filter Timing + +Eight phases available via the `at` property in `_extension.yml` or document YAML: + +1. `pre-ast` +2. `post-ast` +3. `pre-quarto` +4. `post-quarto` +5. `pre-render` +6. `post-render` +7. `pre-finalize` +8. `post-finalize` + +Syntax in `_extension.yml` or document YAML: + +```yaml +filters: + - path: my-filter.lua + at: pre-quarto +``` + +Default (no `at`): filters listed before a "quarto" marker get `pre-quarto`, filters listed after get `post-render`. + +## FloatRefTarget + +Cross-referenceable elements (figures, tables, listings) are represented as `FloatRefTarget` custom AST nodes. +Filters operating on these should use the `FloatRefTarget` handler: + +```lua +return { + { FloatRefTarget = function(el) + -- el.caption, el.content, el.identifier, etc. + return el + end + } +} +```