Skip to content

Commit 4d377b7

Browse files
committed
Add AST changes from 1.3 and 1.4
1 parent 3f1926a commit 4d377b7

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

docs/advanced/quarto-ast.qmd

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
title: Quarto AST
3+
summary: Quarto extends Pandoc's AST processing to allow more flexible customization in filters
4+
---
5+
6+
## Overview
7+
8+
Quarto extends Pandoc's AST processing to allow more flexible customization in filters:
9+
10+
* [Custom nodes](#custom-nodes): Quarto defines custom AST node types for Quarto specific types of content like Callouts, Tabsets etc. This allows filters to target, modify or create these elements.
11+
12+
* [Custom renderers](#custom-formats-and-custom-renderers): Add custom renderers for Quarto's custom node types to facilitate handling Quarto specific elements in custom formats.
13+
14+
* [Targeting AST Processing Phases](#targeting-of-ast-processing-phases): Apply filters at precise points in the AST processing.
15+
16+
## Custom Nodes
17+
18+
Quarto defines some custom AST nodes for use in Pandoc filters.
19+
This allows more flexibility in defining and using Lua filters.
20+
For example, by using the `Callout` custom node this filter forces every callout to be of type "caution":
21+
22+
``` lua
23+
function Callout(callout)
24+
-- do something with the callout
25+
callout.type = "caution"
26+
27+
-- note that custom AST nodes are passed by reference. You can
28+
-- return the value if you choose, but you do not need to.
29+
end
30+
```
31+
32+
Finally, custom AST node constructors are available in the `quarto` object: `quarto.Callout`, `quarto.Tabset`, etc. See the sections below for details.
33+
34+
### Callouts
35+
36+
You can create callout AST nodes in Lua filters with the `quarto.Callout` constructor. The constructor takes a single parameter, a table with entries `type`, `title`, and `content`, as described below. In Lua filters, callouts are represented as a table with the following fields:
37+
38+
- `type`: the type of callout: `note`, `caution`, `warning`, etc (optional in the constructor).
39+
- `title`: The callout title (if any) (optional in the constructor),
40+
- `icon`: the callout icon (or `false` if none) (optional in the constructor)
41+
- `appearance`: `"minimal"`, `"simple"`, or `"default"` (optional in the constructor)
42+
- `collapse`: whether to render the callout as collapsible (optional in the constructor, default `false`)
43+
- `content`: the content of the callout (a `pandoc.Blocks` object, or a plain list in the constructor)
44+
45+
### Tabsets
46+
47+
You can create conditional blocks in Lua filters with the `quarto.Tabset` constructor, with parameters `tabs`, `level` and `attr` as described above. In
48+
addition, you can use `quarto.Tab` to create the tab objects for the `tabs` field. `quarto.Tab` is more lenient with parameter types, converting strings to `Blocks` and `Inlines` as needed. In Lua filters, tabsets are represented as a table with the following fields:
49+
50+
- `tabs`: a table containing the content for each tab. Each entry is a table with two entries: `title` (a `pandoc.Inlines`) and `content` (a `pandoc.Blocks`) (optional in the contructor, default value `{}`)
51+
- `level`: the level of the tab headings to be used in rendering the tabset (optional in the constructor, default value `2`)
52+
- `attr`: the `Attr` object for the resulting tabset div (optional in the constructor)
53+
54+
### Conditional Blocks
55+
56+
You can create conditional block AST nodes in Lua filters with the `quarto.ConditionalBlock` constructor. The constructor takes a single parameter, a table with entries `node`, `behavior`, and `condition`, as described below.
57+
58+
In Lua filters, conditional blocks are represented as a table with the following fields:
59+
60+
- `node`: the div containing the content
61+
- `behavior`: either `content-visible` or `content-hidden`
62+
- `condition`: a list of 2-element lists, such as `{ { "unless-format", "html" } }` (optional in the constructor, default value `{}`). The first element of each sublist must be one of `when-format`, `unless-format`, `when-profile`, and `unless-profile`. The second element is the relevant format or profile.
63+
64+
### Cross-referenceable Elements
65+
66+
Crossreferenceable elements all have a single generic type, `FloatRefTarget`.
67+
This element can be constructed explicitly in a Lua filter.
68+
It can also be used as the element to be processed in a Lua filter directly.
69+
70+
```{.lua}
71+
-- A filter targeting FloatRefTarget nodes
72+
return {
73+
FloatRefTarget = function(float)
74+
if float.caption_long then
75+
float.caption_long.content:insert(pandoc.Str("[This will appear at the beginning of every caption]"))
76+
return float
77+
end
78+
end
79+
}
80+
```
81+
82+
`FloatRefTarget` nodes have the following fields:
83+
84+
- `type`: The type of element: `Figure`, `Table`, `Listing`, etc. Quarto v1.4 supports
85+
custom node types that can be declared at the document or project level.
86+
- `content`: The content of the Figure, Table, etc. Quarto v1.4
87+
accepts any content in any `FloatRefTarget` type (so if your tables are better displayed
88+
as an image, you can use that.).
89+
- `caption_long`: The caption that appears in the main body of the document
90+
- `caption_short`: The caption that appears in the element collations (such as a list of tables,
91+
list of figures, etc.)
92+
- `identifier`, `attributes`, `classes`: these are analogous to `Attr` fields in Pandoc AST elements like spans and divs.
93+
`identifier`, in addition, needs to be the string that is used in a crossref (`fig-cars`, `tbl-votes`, `lst-query`, and so on).
94+
- `parent_id`: if a `FloatRefTarget` is a subfloat of a parent multiple-element float, then `parent_id` will hold the identifier
95+
of the parent float.
96+
97+
## Custom Formats and Custom Renderers
98+
99+
Quarto has support for extensible renderers of quarto AST nodes such as `FloatRefTarget`, `Callout` etc.
100+
In order to declare a custom renderer, add the following to a Lua filter:
101+
102+
```lua
103+
local predicate = function(float)
104+
-- return true if this renderer should be used;
105+
-- typically, this will return true if the custom format is active.
106+
end
107+
local renderer = function(float)
108+
-- returns a plain Pandoc representation of the rendered figure.
109+
end
110+
quarto._quarto.ast.add_renderer(
111+
"FloatRefTarget",
112+
predicate,
113+
renderer)
114+
```
115+
116+
## Targeting of AST Processing Phases
117+
118+
Quarto's AST processing phase is split into three parts: `ast`, `quarto`, and `render`.
119+
120+
- `ast`: normalizes the input syntax from Pandoc, recognizing constructs such as `Callout`, `FloatRefTarget`, and so on.
121+
- `quarto`: processes the normalized syntax, for example by resolving cross-references.
122+
- `render`: produces format-specific output from the processed input.
123+
124+
Lua filters can be inserted before or after any of these stages:
125+
126+
```yaml
127+
filters:
128+
- at: pre-ast
129+
path: filter1.lua
130+
- at: post-quarto
131+
path: filter2.lua
132+
- at: post-render
133+
path: filter3.lua
134+
```
135+
136+
Any of the stages can be prefixed by `pre-` or `post-`.
137+
Currently `pre-quarto` and `post-ast` correspond to the same insertion location in the filter chain, as do `post-quarto` and `pre-render`.
138+
139+
You can also use JSON filters with this syntax.
140+
Either use `type: json` explicitly, or use a path that doesn't end in `.lua`.
141+
Conversely, `type: lua` will force the file to be treated as a Lua filter.
142+
143+
Prior to Quarto 1.4, Lua filters were either "pre" filters (the default setting), or "post" filters.
144+
Those filters are specified like this:
145+
146+
```yaml
147+
# "pre" filters:
148+
filters:
149+
- pre_filter_1.lua
150+
- pre_filter_2.lua
151+
# ...
152+
# "post" filters:
153+
filters:
154+
- quarto
155+
- post_filter_1.lua
156+
- post_filter_2.lua
157+
# ...
158+
```
159+
160+
This syntax continues to work.
161+
"Pre" filters are injected at the `pre-quarto` entry point, and "post" filters are injected at the `post-render` entry point.
162+

docs/extensions/filters.qmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ filters:
4545
- fontawesome
4646
```
4747
48+
Beyond a running filters before or after Quarto's filters, you can also
49+
precisely target the location in the AST processing. Read more in [Targeting of AST Processing Phases](/docs/advanced/quarto-ast.qmd#targeting-of-ast-processing-phases).
50+
4851
You'll notice that one of the extensions (`spellcheck.lua`) has a file extension and the other (`fontawesome`) does not. This difference stems from how the extensions are distributed: an extension distributed as a plain Lua file uses `.lua` whereas a filter distributed as a [Quarto Extension](index.qmd) does not. The next section explores how to create filters as extensions.
4952

5053

docs/extensions/lua-api.qmd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,17 @@ quarto.doc.add_html_dependency({
259259
})
260260
```
261261

262+
### Custom Nodes
263+
264+
Quarto adds some custom AST node types. You can read more about them in [Quarto AST](/docs/advanced/quarto-ast.qmd#custom-nodes). You can create them with the following constructors:
265+
266+
| Function | Node |
267+
|--------------------------------|-----------------------------------------|
268+
| `quarto.Callout(tbl)` | Callout: `tbl` is a table with entries `type`, `title`, and `content`. |
269+
| `quarto.Tabset(tbl)` | Tabset: `tbl` is a table with entries `tabs`, `level` and `attr`. |
270+
| `quarto.ConditionalBlock(tbl)` | Conditional block: `tbl` is a table with entries `node`, `behavior`, and `condition`. |
271+
| `quarto.FloatRefTarget(tbl)` | Cross-referencable element: `tbl` is a table with entries `content`, `caption_long`, and `caption_short`. |
272+
262273
### JSON Encoding
263274

264275
Quarto includes a copy of [json.lua](https://github.com/rxi/json.lua). a lightweight JSON library for Lua. You can access the JSON functions as follows:

0 commit comments

Comments
 (0)