diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0213dbf..b88125b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,21 @@
* Added minimal CI testing using GitHub actions (#10).
+* Make SVG as the default diagram format when using the [Typst output format](https://quarto.org/docs/output-formats/typst.html) (#7, @elipousson).
+
+* Add support for reading d2 diagrams from external files using `file` parameter. Block text is replaced with file contents (#7, @elipousson).
+
+* Use Pandoc mediabag for rendered diagram images when `embed_type="link"` (#7, @elipousson).
+
+* Add support for alternate code block syntax without curly braces (#7, @elipousson).
+
## BUG FIXES
-* Added tala to the list of layouts (#9, thanks @tosaddler!).
+* Added [TALA](https://d2lang.com/tour/tala/) to the list of layouts (#9, @tosaddler).
+
+## OTHER
+
+* Refactor to add helper functions `setPreD2RenderOptions` and `is_nonempty_string`.
# quarto-d2 1.1.0
@@ -14,11 +26,10 @@
- When the output type is html and the image format is svg, also setting the `embed_type="raw"` will embed the svg directly into the html document (#1). This is useful enabling interactive content such as hover or links to work.
-
# quarto-d2 1.0.0
Initial release. Main features:
- Render [D2](https://d2lang.com) diagrams directly within your [Quarto](https://quarto.org) markdown documents.
- Control the appearance and layout of your diagrams using global settings or code block attributes.
-- Tune the width and height of the resulting figures using the "width" and "height" arguments.
\ No newline at end of file
+- Tune the width and height of the resulting figures using the "width" and "height" arguments.
diff --git a/README.md b/README.md
index b0a79e4..d428faa 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
# D2 Extension For Quarto
+
This [Quarto](https://quarto.org) extension allows you to render
[D2](https://d2lang.com) diagrams directly within your markdown
documents.
@@ -34,7 +35,13 @@ quarto add data-intuitive/quarto-d2
This will install the extension under the `_extensions` subdirectory. If
you’re using version control, you will want to check in this directory.
-## Example
+## Examples
+
+D2 can be used for simple diagrams.
+
+![](images/diagram-1.svg)
+
+And for more complex diagrams.
-## Usage
+The enclosing curly brakets are optional if you are only using document
+level options. Quarto block-level options, e.g. `#|`, are not currently
+supported.
-To use the d2 filter, add the d2 filter to your quarto document. Next,
-add the `.d2` class to any code blocks containing D2 diagram code. Here
-is a basic example:
-
-```` markdown
----
-title: "D2 Example"
-filters:
- - d2
----
-
-```{.d2}
-x -> y
-```
-````
-
-With this setup, the `d2` filter will process any code blocks with the
-`.d2` class, applying the attributes you specify.
-
-That’s it! Now you know how to use the `d2` filter to generate diagrams
-in your quarto documents.
+![](images/diagram-3.svg)
## Attributes
You can specify additional attributes to control the appearance and
-layout of the diagram.
+layout of the diagram and document:
- `theme`: Specifies the theme of the diagram. Default is
`"NeutralDefault"`. Options are `"NeutralDefault"`, `"NeutralGrey"`,
- `"FlagshipTerrastruc"t`, `"CoolClassics"`, `"MixedBerryBlue"`,
- `"GrapeSoda"`, `"Aubergine"`, `"ColorblindClear"`,
- `"VanillaNitroCola"`, `"ShirelyTemple"`, `"EarthTones"`,
- `"EvergladeGreen"`, `"ButteredToast"`, `"DarkMauve"`, `"Terminal"`,
- `"TerminalGrayscale"`, `"Origami"`.
+ `"FlagshipTerrastruct"`, `"DarkFlagshipTerrastruct"`,
+ `"CoolClassics"`, `"MixedBerryBlue"`, `"GrapeSoda"`, `"Aubergine"`,
+ `"ColorblindClear"`, `"VanillaNitroCola"`, `"ShirelyTemple"`,
+ `"EarthTones"`, `"EvergladeGreen"`, `"ButteredToast"`, `"DarkMauve"`,
+ `"Terminal"`, `"TerminalGrayscale"`, and `"Origami"`.
- `layout`: Specifies the layout algorithm to use. Default is `"elk"`.
- Options are `"dagre"`, `"elk"`, `"tala"`.
+ Options are `"dagre"`, `"elk"`, `"tala"`. layout is not case sensitive
+ so `"ELK"` or `"TALA"` are also supported.
- `format`: Specifies the format of the output image. Default is `svg`.
- Option are `"svg"`, `"png"`, `"pdf"`.
+ Option are `"svg"`, `"png"`, `"pdf"`, `"gif"`.
- `sketch`: Whether to use a “sketch” style for the diagram. Default is
`false`.
-- `pad`: Amount of padding around the diagram. Default is `100`.
+- `pad`: Amount of padding around the diagram in pixels. Default is
+ `100`.
- `caption`: Caption to add to the diagram.
-- `folder`: Folder where the generated diagram will be saved. If not
- provided, the image will be embedded inline in the document (HTML
- only).
-- `filename`: Name of the output file.
- `width`: Width of the output image. Default is `100%`. Examples are
`"100px"`, `"50%"`, `"3cm"`.
- `height`: Height of the output image. Default is `auto`. Examples are
`"100px"`, `"50%"`, `"3cm"`.
- `echo`: Whether to echo the original diagram code in the output.
Default is `false`.
+
+You can also replace the contents of the block with an external D2 file
+by using the `file` parameter. `file` must be an existing file ending in
+a “d2” or “txt” file extension. Other parameters related to rendering
+and embedding diagrams include:
+
+- `folder`: Folder where the generated diagram will be saved. If not
+ provided, the image will be embedded inline in the document (HTML
+ only).
+- `filename`: Name of the output file.
- `embed_mode`: How to embed the diagram in the output. Default is
`"inline"` for HTML output and `"link"` for other output formats.
Options are `"inline"`, `"link"`, `"raw"`.
+Note that for Typst format output the width and height can’t be supplied
+as a percent value.
+
Here’s an example that uses multiple attributes:
```` markdown
@@ -175,6 +175,16 @@ x -> y -> z
```
````
+## Setting an input file
+
+You can specify an input d2 file. If `echo=true`, the contents of the
+file block is replaced by the contents of the file.
+
+```` markdown
+```{.d2 file="./diagram.d2"}
+```
+````
+
## Setting output folder and file name
You can specify a folder where the generated diagram will be saved using
@@ -187,15 +197,11 @@ x -> y -> z
```
````
-
-
-> **Note**
+> [!NOTE]
>
> If the `folder` attribute is not provided and the output format is
> HTML, the image will be embedded inline in the document.
-
-
## Interactive diagrams
Interactive diagrams will only work when the Quarto output format is
diff --git a/README.qmd b/README.qmd
index 7d150c2..57b1868 100644
--- a/README.qmd
+++ b/README.qmd
@@ -5,6 +5,7 @@ filters:
- d2
d2:
layout: "elk"
+ folder: "images"
---
This [Quarto](https://quarto.org) extension allows you to render [D2](https://d2lang.com) diagrams directly within your markdown documents.
@@ -34,10 +35,17 @@ quarto add data-intuitive/quarto-d2
This will install the extension under the `_extensions` subdirectory.
If you're using version control, you will want to check in this directory.
+## Examples
+D2 can be used for simple diagrams.
-## Example
+```{.d2}
+x -> y: hello world
+```
+
+
+And for more complex diagrams.
```{.d2 width="50%" echo="true"}
logs: {
@@ -87,44 +95,36 @@ user -> network.portal.UI: access {
```
-## Usage
+The enclosing curly brakets are optional if you are only using document level options. Quarto block-level options, e.g. `#|`, are not currently supported.
-To use the d2 filter, add the d2 filter to your quarto document. Next, add the `.d2` class to any code blocks containing D2 diagram code. Here is a basic example:
-
-
-````markdown
----
-title: "D2 Example"
-filters:
- - d2
----
-
-```{.d2}
-x -> y
+```d2
+Database -> S3: backup
+Database -> S3
+Database -> S3: backup
```
-````
-
-With this setup, the `d2` filter will process any code blocks with the `.d2` class, applying the attributes you specify.
-
-That's it! Now you know how to use the `d2` filter to generate diagrams in your quarto documents.
## Attributes
-You can specify additional attributes to control the appearance and layout of the diagram.
+You can specify additional attributes to control the appearance and layout of the diagram and document:
-- `theme`: Specifies the theme of the diagram. Default is `"NeutralDefault"`. Options are `"NeutralDefault"`, `"NeutralGrey"`, `"FlagshipTerrastruc"t`, `"CoolClassics"`, `"MixedBerryBlue"`, `"GrapeSoda"`, `"Aubergine"`, `"ColorblindClear"`, `"VanillaNitroCola"`, `"ShirelyTemple"`, `"EarthTones"`, `"EvergladeGreen"`, `"ButteredToast"`, `"DarkMauve"`, `"Terminal"`, `"TerminalGrayscale"`, `"Origami"`.
-- `layout`: Specifies the layout algorithm to use. Default is `"elk"`. Options are `"dagre"`, `"elk"`, `"tala"`.
-- `format`: Specifies the format of the output image. Default is `svg`. Option are `"svg"`, `"png"`, `"pdf"`.
+- `theme`: Specifies the theme of the diagram. Default is `"NeutralDefault"`. Options are `"NeutralDefault"`, `"NeutralGrey"`, `"FlagshipTerrastruct"`, `"DarkFlagshipTerrastruct"`, `"CoolClassics"`, `"MixedBerryBlue"`, `"GrapeSoda"`, `"Aubergine"`, `"ColorblindClear"`, `"VanillaNitroCola"`, `"ShirelyTemple"`, `"EarthTones"`, `"EvergladeGreen"`, `"ButteredToast"`, `"DarkMauve"`, `"Terminal"`, `"TerminalGrayscale"`, and `"Origami"`.
+- `layout`: Specifies the layout algorithm to use. Default is `"elk"`. Options are `"dagre"`, `"elk"`, `"tala"`. layout is not case sensitive so `"ELK"` or `"TALA"` are also supported.
+- `format`: Specifies the format of the output image. Default is `svg`. Option are `"svg"`, `"png"`, `"pdf"`, `"gif"`.
- `sketch`: Whether to use a "sketch" style for the diagram. Default is `false`.
-- `pad`: Amount of padding around the diagram. Default is `100`.
+- `pad`: Amount of padding around the diagram in pixels. Default is `100`.
- `caption`: Caption to add to the diagram.
-- `folder`: Folder where the generated diagram will be saved. If not provided, the image will be embedded inline in the document (HTML only).
-- `filename`: Name of the output file.
- `width`: Width of the output image. Default is `100%`. Examples are `"100px"`, `"50%"`, `"3cm"`.
- `height`: Height of the output image. Default is `auto`. Examples are `"100px"`, `"50%"`, `"3cm"`.
- `echo`: Whether to echo the original diagram code in the output. Default is `false`.
+
+You can also replace the contents of the block with an external D2 file by using the `file` parameter. `file` must be an existing file ending in a "d2" or "txt" file extension. Other parameters related to rendering and embedding diagrams include:
+
+- `folder`: Folder where the generated diagram will be saved. If not provided, the image will be embedded inline in the document (HTML only).
+- `filename`: Name of the output file.
- `embed_mode`: How to embed the diagram in the output. Default is `"inline"` for HTML output and `"link"` for other output formats. Options are `"inline"`, `"link"`, `"raw"`.
+Note that for Typst format output the width and height can't be supplied as a percent value.
+
Here's an example that uses multiple attributes:
````markdown
@@ -152,6 +152,15 @@ x -> y -> z
```
````
+## Setting an input file
+
+You can specify an input d2 file. If `echo=true`, the contents of the file block is replaced by the contents of the file.
+
+````markdown
+```{.d2 file="./diagram.d2"}
+```
+````
+
## Setting output folder and file name
You can specify a folder where the generated diagram will be saved using the `folder` attribute. The `filename` attribute allows you to set a custom name for the output file.
diff --git a/_extensions/d2/d2.lua b/_extensions/d2/d2.lua
index fccfd6d..f92a262 100644
--- a/_extensions/d2/d2.lua
+++ b/_extensions/d2/d2.lua
@@ -15,6 +15,7 @@ local D2Theme = {
EvergladeGreen = 104,
ButteredToast = 105,
DarkMauve = 200,
+ DarkFlagshipTerrastruct = 201,
Terminal = 300,
TerminalGrayscale = 301,
Origami = 302
@@ -31,8 +32,10 @@ local D2Layout = {
local D2Format = {
svg = 'svg',
png = 'png',
+ gif = 'gif',
pdf = 'pdf'
}
+
-- Enum for Embed mode
local EmbedMode = {
inline = "inline",
@@ -68,15 +71,90 @@ function dump(o)
end
end
+-- Helper for non empty string
+function is_nonempty_string(x)
+ return x ~= nil and type(x) == "string"
+end
-- Counter for the diagram files
local counter = 0
+-- Transform and validate options
+function setPreD2RenderOptions(options)
+ if is_nonempty_string(options.theme) then
+ assert(D2Theme[options.theme] ~= nil,
+ "Invalid theme: " .. options.theme .. ". Options are: " .. dump(D2Theme))
+ options.theme = D2Theme[options.theme]
+ end
+ if is_nonempty_string(options.layout) then
+ assert(D2Layout[string.lower(options.layout)] ~= nil,
+ "Invalid layout: " .. options.layout .. ". Options are: " .. dump(D2Layout))
+ options.layout = D2Layout[string.lower(options.layout)]
+ end
+ if is_nonempty_string(options.format) then
+ assert(D2Format[options.format] ~= nil,
+ "Invalid format: " .. options.format .. ". Options are: " .. dump(D2Format))
+ options.format = D2Format[options.format]
+ end
+ if is_nonempty_string(options.embed_mode) then
+ assert(EmbedMode[options.embed_mode] ~= nil,
+ "Invalid embed_mode: " .. options.embed_mode .. ". Options are: " .. dump(EmbedMode))
+ options.embed_mode = EmbedMode[options.embed_mode]
+ end
+ if is_nonempty_string(options.sketch) then
+ assert(options.sketch == "true" or options.sketch == "false",
+ "Invalid sketch: " .. options.sketch .. ". Options are: true, false")
+ options.sketch = tostring(options.sketch == "true")
+ end
+ if is_nonempty_string(options.pad) then
+ assert(tonumber(options.pad) ~= nil,
+ "Invalid pad: " .. options.pad .. ". Must be a number")
+ end
+ if is_nonempty_string(options.echo) then
+ assert(options.echo == "true" or options.echo == "false",
+ "Invalid echo: " .. options.echo .. ". Options are: true, false")
+ options.echo = options.echo == "true"
+ end
+ if is_nonempty_string(options.animate_interval) and options.format == D2Format.gif then
+ assert(tonumber(options.animate_interval) > 0,
+ "Invalid animate_interval: " .. options.animate_interval .. ". Must be greater than 0 for .gif outputs")
+ end
+ -- Check file extension
+ if is_nonempty_string(options.file) then
+ local d2path,d2ext = pandoc.path.split_extension(options.file)
+ assert(d2ext == ".d2" or d2ext == ".txt",
+ "Invalid file: " .. options.file .. ". Must use a 'd2' or 'txt' file extension")
+ end
+
+ -- Set default filename
+ if not is_nonempty_string(options.filename) then
+ options.filename = "diagram-" .. counter
+ end
+
+ -- Set the default format to pdf since svg is not supported in PDF output
+ if options.format == D2Format.svg and quarto.doc.is_format("latex") then
+ options.format = D2Format.pdf
+ end
+ -- Set the default format to svg since pdf is not supported in Typst output
+ if options.format == D2Format.pdf and quarto.doc.is_format("typst") then
+ options.format = D2Format.svg
+ end
+ -- Set the default embed_mode to link if the quarto format is not html or the figure format is pdf
+ if not quarto.doc.is_format("html") or options.format == D2Format.pdf then
+ options.embed_mode = EmbedMode.link
+ end
+ -- Set the default folder to project output directory when embed_mode is link
+ if options.folder == nil and options.embed_mode == EmbedMode.link then
+ options.folder = quarto.project.output_directory
+ end
+
+ return options
+end
+
local function render_graph(globalOptions)
- local filter = {
- CodeBlock = function(cb)
+ local CodeBlock = function(cb)
-- Check if the CodeBlock has the 'd2' class
- if not cb.classes:includes('d2') or cb.text == nil then
+ if not cb.classes:includes('d2') then
return nil
end
@@ -89,69 +167,22 @@ local function render_graph(globalOptions)
for k, v in pairs(cb.attributes) do
options[k] = v
end
-
- -- Transform options
- if options.theme ~= nil and type(options.theme) == "string" then
- assert(D2Theme[options.theme] ~= nil, "Invalid theme: " .. options.theme .. ". Options are: " .. dump(D2Theme))
- options.theme = D2Theme[options.theme]
- end
- if options.layout ~= nil and type(options.layout) == "string" then
- assert(D2Layout[options.layout] ~= nil, "Invalid layout: " .. options.layout .. ". Options are: " .. dump(D2Layout))
- options.layout = D2Layout[options.layout]
- end
- if options.format ~= nil and type(options.format) == "string" then
- assert(D2Format[options.format] ~= nil, "Invalid format: " .. options.format .. ". Options are: " .. dump(D2Format))
- options.format = D2Format[options.format]
- end
- if options.embed_mode ~= nil and type(options.embed_mode) == "string" then
- assert(EmbedMode[options.embed_mode] ~= nil, "Invalid embed_mode: " .. options.embed_mode .. ". Options are: " .. dump(EmbedMode))
- options.embed_mode = EmbedMode[options.embed_mode]
- end
- if options.sketch ~= nil and type(options.sketch) == "string" then
- assert(options.sketch == "true" or options.sketch == "false", "Invalid sketch: " .. options.sketch .. ". Options are: true, false")
- options.sketch = options.sketch == "true"
- end
- if options.pad ~= nil and type(options.pad) == "string" then
- assert(tonumber(options.pad) ~= nil, "Invalid pad: " .. options.pad .. ". Must be a number")
- options.pad = tonumber(options.pad)
- end
- if options.echo ~= nil and type(options.echo) == "string" then
- assert(options.echo == "true" or options.echo == "false", "Invalid echo: " .. options.echo .. ". Options are: true, false")
- options.echo = options.echo == "true"
- end
-
- -- Set default filename
- if options.filename == nil then
- options.filename = "diagram-" .. counter
- end
-
- -- Set the default format to pdf since svg is not supported in PDF output
- if options.format == D2Format.svg and quarto.doc.is_format("latex") then
- options.format = D2Format.pdf
- end
- -- Set the default embed_mode to link if the quarto format is not html or the figure format is pdf
- if not quarto.doc.is_format("html") or options.format == D2Format.pdf then
- options.embed_mode = EmbedMode.link
+
+ options = setPreD2RenderOptions(options)
+
+ if options.echo then
+ cb.classes:insert('sourceCode')
+ cb.classes:insert('cell-code')
end
-
- -- Set the default folder to ./images when embed_mode is link
- if options.folder == nil and options.embed_mode == EmbedMode.link then
- options.folder = "./images"
+
+ if options.file == nil and cb.text == nil then
+ return nil
end
-- Generate diagram using `d2` CLI utility
- local result = pandoc.system.with_temporary_directory('svg-convert', function (tmpdir)
+ local result = pandoc.system.with_temporary_directory('d2-render', function (tmpdir)
-- determine path name of input file
- local inputPath = pandoc.path.join({tmpdir, "temp_" .. counter .. ".txt"})
-
- -- determine path name of output file
- local outputPath
- if options.folder ~= nil then
- os.execute("mkdir -p " .. options.folder)
- outputPath = options.folder .. "/" .. options.filename .. "." .. options.format
- else
- outputPath = pandoc.path.join({tmpdir, options.filename .. "." .. options.format})
- end
+ local inputPath = pandoc.path.join({tmpdir, "diagram-" .. counter .. ".d2"})
-- write graph text to file
local tmpFile = io.open(inputPath, "w")
@@ -159,9 +190,33 @@ local function render_graph(globalOptions)
print("Error: Could not open file for writing")
return nil
end
+
+ if is_nonempty_string(options.file) then
+ local d2File = io.open(options.file)
+ if d2File == nil then
+ print("Error: Diagram file " .. options.file .. " can't be opened")
+ return nil
+ end
+
+ local d2Text = d2File:read('*all')
+ cb.text = d2Text
+ cb.attributes.filename = pandoc.path.filename(options.file)
+ end
+
tmpFile:write(cb.text)
tmpFile:close()
+
+ -- determine path name of output file
+ local outputPath
+ local outputFilename = options.filename .. "." .. options.format
+ if options.folder ~= nil then
+ os.execute("mkdir -p " .. options.folder)
+ outputPath = pandoc.path.join({options.folder, outputFilename})
+ else
+ outputPath = pandoc.path.join({tmpdir, outputFilename})
+ end
+
-- run d2
os.execute(
"d2" ..
@@ -169,34 +224,48 @@ local function render_graph(globalOptions)
" --layout=" .. options.layout ..
" --sketch=" .. tostring(options.sketch) ..
" --pad=" .. options.pad ..
+ " --animate-interval=" .. options.animate_interval ..
" " .. inputPath ..
" " .. outputPath
)
+ local outputFile = io.open(outputPath, "rb")
+ local data
+
+ if outputFile then
+ data = outputFile:read('*all')
+ outputFile:close()
+ end
+
+ local mimetype
+
+ if options.format == "svg" then
+ mimetype = "image/svg+xml"
+ elseif options.format == "png" then
+ mimetype = "image/png"
+ elseif options.format == "pdf" then
+ mimetype = "application/pdf"
+ elseif options.format == "gif" then
+ mimetype = "image/gif"
+ end
+
if options.embed_mode == EmbedMode.link then
- return outputPath
- else
- local file = io.open(outputPath, "rb")
- local data
- if file then
- data = file:read('*all')
- file:close()
+ if options.folder ~= nil then
+ return outputPath
end
+
+ pandoc.mediabag.insert(outputFilename, mt, data)
+ return outputFilename
+ elseif options.embed_mode == EmbedMode.raw then
os.remove(outputPath)
-
- if options.embed_mode == EmbedMode.raw then
- return data
- elseif options.embed_mode == EmbedMode.inline then
- dump(options)
-
- if options.format == "svg" then
- return "data:image/svg+xml;base64," .. quarto.base64.encode(data)
- elseif options.format == "png" then
- return "data:image/png;base64," .. quarto.base64.encode(data)
- else
- print("Error: Unsupported format")
- return nil
- end
+ return data
+ elseif options.embed_mode == EmbedMode.inline then
+ if options.format ~= "pdf" then
+ os.remove(outputPath)
+ return "data:" .. mimetype .. ";base64," .. quarto.base64.encode(data)
+ else
+ print("Error: Unsupported format")
+ return nil
end
end
end)
@@ -214,7 +283,10 @@ local function render_graph(globalOptions)
end
else
- local image = pandoc.Image({}, result)
+ local image = pandoc.Image({
+ classes = cb.classes,
+ identifier = cb.identifier
+ }, result)
-- Set the width and height attributes, if they exist
if options.width ~= nil then
@@ -239,8 +311,15 @@ local function render_graph(globalOptions)
end
return output
end
+ -- see https://github.com/quarto-dev/quarto-cli/discussions/8926#discussioncomment-8624950
+ local DecoratedCodeBlock = function(node)
+ return CodeBlock(node.code_block)
+ end
+
+ return {
+ CodeBlock = CodeBlock,
+ DecoratedCodeBlock = DecoratedCodeBlock
}
- return filter
end
@@ -253,11 +332,13 @@ function Pandoc(doc)
sketch = false,
pad = 100,
folder = nil,
+ file = nil,
filename = nil,
caption = '',
width = nil,
height = nil,
echo = false,
+ animate_interval = 0,
embed_mode = "inline"
}
diff --git a/images/diagram-1.svg b/images/diagram-1.svg
index bb2eca9..b94a35f 100644
--- a/images/diagram-1.svg
+++ b/images/diagram-1.svg
@@ -1,24 +1,17 @@
-
diff --git a/images/diagram-2.svg b/images/diagram-2.svg
new file mode 100644
index 0000000..2a4609b
--- /dev/null
+++ b/images/diagram-2.svg
@@ -0,0 +1,124 @@
+logsUserNetworkAPI ServerCell TowerData ProcessorOnline PortalsatellitestransmitterStorageUIphone logsMake callpersistdisplayaccess
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/images/diagram-3.svg b/images/diagram-3.svg
new file mode 100644
index 0000000..5f650da
--- /dev/null
+++ b/images/diagram-3.svg
@@ -0,0 +1,105 @@
+DatabaseS3backupbackup
+
+
+
+
+
+
diff --git a/test.qmd b/test.qmd
new file mode 100644
index 0000000..483ae40
--- /dev/null
+++ b/test.qmd
@@ -0,0 +1,216 @@
+---
+title: D2 Extension For Quarto
+format: html
+eval: false
+filters:
+ - d2
+d2:
+ layout: "elk"
+---
+
+This [Quarto](https://quarto.org) extension allows you to render [D2](https://d2lang.com) diagrams directly within your markdown documents.
+
+Main features:
+
+- Render [D2](https://d2lang.com) diagrams directly within your [Quarto](https://quarto.org) markdown documents.
+- Control the appearance and layout of your diagrams using global settings or code block attributes.
+- Tune the width and height of the resulting figures using the "width" and "height" arguments.
+
+This extension was inspired by [`ram02z/d2-filter`](https://github.com/ram02z/d2-filter).
+
+## Installation
+
+### Prerequisites
+
+Ensure that you have [D2](https://d2lang.com/tour/install) installed on your system.
+
+### Install
+
+Run the following command to add this extension to your current project:
+
+``` bash
+quarto add data-intuitive/quarto-d2
+```
+
+This will install the extension under the `_extensions` subdirectory.
+If you're using version control, you will want to check in this directory.
+
+## Examples
+
+D2 can be used for simple diagrams.
+
+
+```{.d2}
+x -> y: hello world
+```
+
+
+And for more complex diagrams.
+
+```{.d2 width="50%" echo="true"}
+logs: {
+ shape: page
+ style.multiple: true
+}
+user: User {shape: person}
+network: Network {
+ tower: Cell Tower {
+ satellites: {
+ shape: stored_data
+ style.multiple: true
+ }
+
+ satellites -> transmitter
+ satellites -> transmitter
+ satellites -> transmitter
+ transmitter
+ }
+ processor: Data Processor {
+ storage: Storage {
+ shape: cylinder
+ style.multiple: true
+ }
+ }
+ portal: Online Portal {
+ UI
+ }
+
+ tower.transmitter -> processor: phone logs
+}
+server: API Server
+
+user -> network.tower: Make call
+network.processor -> server
+network.processor -> server
+network.processor -> server
+
+server -> logs
+server -> logs
+server -> logs: persist
+
+server -> network.portal.UI: display
+user -> network.portal.UI: access {
+ style.stroke-dash: 3
+}
+```
+
+
+The enclosing curly brakets are optional if you are only using document level options. Quarto block-level options, e.g. `#|`, are not currently supported.
+
+
+```d2
+Database -> S3: backup
+Database -> S3
+Database -> S3: backup
+```
+
+
+## Usage
+
+To use the d2 filter, add the d2 filter to your quarto document. Next, add the `.d2` class to any code blocks containing D2 diagram code. Here is a basic example:
+
+
+````markdown
+---
+title: "D2 Example"
+filters:
+ - d2
+---
+
+```{.d2}
+x -> y
+```
+````
+
+With this setup, the `d2` filter will process any code blocks with the `.d2` class, applying the attributes you specify.
+
+That's it! Now you know how to use the `d2` filter to generate diagrams in your quarto documents.
+
+## Attributes
+
+You can specify additional attributes to control the appearance and layout of the diagram and document:
+
+- `theme`: Specifies the theme of the diagram. Default is `"NeutralDefault"`. Options are `"NeutralDefault"`, `"NeutralGrey"`, `"FlagshipTerrastruct"`, `"DarkFlagshipTerrastruct"`, `"CoolClassics"`, `"MixedBerryBlue"`, `"GrapeSoda"`, `"Aubergine"`, `"ColorblindClear"`, `"VanillaNitroCola"`, `"ShirelyTemple"`, `"EarthTones"`, `"EvergladeGreen"`, `"ButteredToast"`, `"DarkMauve"`, `"Terminal"`, `"TerminalGrayscale"`, and `"Origami"`.
+- `layout`: Specifies the layout algorithm to use. Default is `"elk"`. Options are `"dagre"`, `"elk"`, `"tala"`. layout is not case sensitive so `"ELK"` or `"TALA"` are also supported.
+- `format`: Specifies the format of the output image. Default is `svg`. Option are `"svg"`, `"png"`, `"pdf"`.
+- `sketch`: Whether to use a "sketch" style for the diagram. Default is `false`.
+- `pad`: Amount of padding around the diagram. Default is `100`.
+- `caption`: Caption to add to the diagram.
+- `width`: Width of the output image. Default is `100%`. Examples are `"100px"`, `"50%"`, `"3cm"`.
+- `height`: Height of the output image. Default is `auto`. Examples are `"100px"`, `"50%"`, `"3cm"`.
+- `echo`: Whether to echo the original diagram code in the output. Default is `false`.
+
+You can also replace the contents of the block with an external d2 file using the `file` parameter. Other parameters related to rendering and embedding diagrams include:
+
+- `folder`: Folder where the generated diagram will be saved. If not provided, the image will be embedded inline in the document (HTML only).
+- `filename`: Name of the output file.
+- `embed_mode`: How to embed the diagram in the output. Default is `"inline"` for HTML output and `"link"` for other output formats. Options are `"inline"`, `"link"`, `"raw"`.
+
+Note that for Typst format output the width and height can't be supplied as a percent value.
+
+Here's an example that uses multiple attributes:
+
+````markdown
+```{.d2 theme="CoolClassics" layout="elk" pad=20 caption="This is a caption" width="50%"}
+x -> y -> z
+```
+````
+
+## Global Options
+
+You can set global options for the d2 filter using the `d2` field in the document metadata. Here's an example:
+
+````markdown
+---
+title: "D2 Example"
+filters:
+ - d2
+d2:
+ layout: elk
+ theme: "GrapeSoda"
+---
+
+```{.d2 width="40%" echo=true}
+x -> y -> z
+```
+````
+
+## Setting output folder and file name
+
+You can specify a folder where the generated diagram will be saved using the `folder` attribute. The `filename` attribute allows you to set a custom name for the output file.
+
+````markdown
+```{.d2 folder="./images" filename="my_diagram"}
+x -> y -> z
+```
+````
+
+:::{.callout-note}
+If the `folder` attribute is not provided and the output format is HTML, the image will be embedded inline in the document.
+:::
+
+## Interactive diagrams
+
+Interactive diagrams will only work when the Quarto output format is HTML, the figure format is `"svg"`, and the embed mode is `"raw"`. Example:
+
+````markdown
+---
+title: "D2 Example"
+format: html
+filters:
+ - d2
+d2:
+ format: svg
+ embed_mode: raw
+---
+
+```{.d2 width="40%"}
+x {
+ link: "https://quarto.org"
+}
+y {
+ tooltip: "This is a tooltip"
+}
+x -> y -> z
+```
+````
diff --git a/tests/global.qmd b/tests/global.qmd
index fafd284..e30604c 100644
--- a/tests/global.qmd
+++ b/tests/global.qmd
@@ -10,3 +10,7 @@ d2:
```{.d2 width="40%" echo=true}
x -> y -> z
```
+
+```{.d2 file=test.d2 echo=true}
+x -> y -> z
+```
diff --git a/tests/test.d2 b/tests/test.d2
new file mode 100644
index 0000000..cbe7ff3
--- /dev/null
+++ b/tests/test.d2
@@ -0,0 +1 @@
+file -> is -> working
diff --git a/tests/typst.qmd b/tests/typst.qmd
new file mode 100644
index 0000000..2751bd0
--- /dev/null
+++ b/tests/typst.qmd
@@ -0,0 +1,20 @@
+---
+title: "D2 Example"
+format: typst
+filters:
+ - d2
+d2:
+ layout: elk
+ format: svg
+ theme: "GrapeSoda"
+---
+
+```{.d2 width="6in" echo=true}
+direction: right
+x -> y -> z
+```
+
+
+```{.d2 format=png width="3in" echo=true}
+a -> b
+```