Convert {unilur} developed by Eric Koncina to a quarto-ext. The current package does more than the hiding/highlighting of solution code chunks for teaching practicals.
Important: this extension requires Quarto >= 1.4.538 (current release: 1.4.555)
quarto add ginolhac/unilur
More details are available in Quarto docs for managing extensions.
- Activate the extension by adding the following lines to your YAML header (you can use only HTML or PDF outputs):
format:
unilur-html: default
unilur-html+solution:
# You have to specify a different output file otherwise they will
# overwrite themselves
output-file: example-solution.html
unilur-pdf: default
unilur-pdf+solution:
output-file: example-solution.pdf
- Solution code blocks are either highlighted or
discardedaccording to theshow-solution
Boolean and the YAML header:
show-solution: true # or false
-
Add the new variable
unilur-solution
as hashpipe,#|
to the code chunks that are part of practical answers. Otherwise, chunks are left untouched.#| unilur-solution: true
Of note, if show-solution
is absent, it is considered false
.
Solution blocks are collapsed by default but can be shown with the chunk option unilur-collapse
(see example below).
::: unilur-solution
this is not shown in instructions
:::
Fences divs can also be used, and they can contain code chunks too
The third possibility is to use block
chunks with the appropriate chunk option
```{block}
#| unilur-solution: true
this is not shown in instructions
```
From the Quarto doc example.qmd
after running:
quarto render example.qmd
Both HTML files are rendered along with both PDFs
HTML show-solution: true (rendered: example-solution.html ) |
HTML show-solution: false (rendered: example.html ) |
---|---|
PDF show-solution: true (rendered: example-solution.pdf ) |
PDF show-solution: false (rendered: example.pdf ) |
---|---|
People who developed and released extensions I got inspiration from:
- JJ Allaire for
filename
extension - Andrie de Vries for
reveal-auto-agenda
extension
Moreover:
- Christophe Dervieux for precious advises and his precious time
- Mickaël Canouil for maintaining the awesome Quarto
- Add tests.
- callout-tip in yellow for PDF output
- Remove the
unilur-solution: true
option from chunks when displayed (visible inecho: fenced
).- Idea from Christophe Dervieux: treat
div
attribute - Get
el
content and iterate withwalk()
- Add a filter
CodeBlock
which remove theunilur
options
- Idea from Christophe Dervieux: treat
This helped me developing this extension.
Described here in the docs
format: native
Which returns something like this:
pandoc AST
Pandoc
Meta
{ unMeta =
fromList
[ ( "biblio-config" , MetaBool True )
, ( "labels"
, MetaMap
(fromList
[ ( "abstract" , MetaInlines [ Str "Abstract" ] )
, ( "affiliations"
, MetaInlines [ Str "Affiliations" ]
)
, ( "authors" , MetaInlines [ Str "Authors" ] )
, ( "description"
, MetaInlines [ Str "Description" ]
)
, ( "doi" , MetaInlines [ Str "Doi" ] )
, ( "modified" , MetaInlines [ Str "Modified" ] )
, ( "published" , MetaInlines [ Str "Published" ] )
])
)
, ( "solution" , MetaBool True )
, ( "title"
, MetaInlines [ Str "Unilur" , Space , Str "Example" ]
)
]
}
[ Header 2 ( "usage" , [] , [] ) [ Str "Usage" ]
, BulletList
[ [ Plain
[ Strong [ Str "Activate" ]
, Space
, Str "the"
, Space
, Str "extension"
, Space
, Str "by"
, Space
, Str "adding"
, Space
, Str "the"
, Space
, Str "following"
, Space
, Str "lines"
, Space
, Str "to"
, Space
, Str "your"
, Space
, Str "YAML"
, Space
, Str "header:"
]
]
]
, CodeBlock
( "" , [ "yaml" ] , [] ) "filters:\n - unilur\n"
, BulletList
[ [ Plain
[ Strong [ Str "Solution" ]
, Space
, Str "code"
, Space
, Str "blocks"
, Space
, Str "are"
, Space
[...]
, BulletList
[ [ Plain
[ Str "Solution"
, Space
, Str "with"
, Space
, Code ( "" , [] , [] ) "collapse: true"
]
]
]
, Div
( "" , [ "cell" ] , [ ( "solution" , "true" ) ] )
[ CodeBlock
( "" , [ "r" , "cell-code" ] , [] ) "1 + 2\n## [1] 3"
]
]
quarto render example.qmd -M keep-md:true
/usr/lib/rstudio/resources/app/bin/quarto/bin/tools/pandoc -f markdown -t json -o ast.json example.md
Then visualize the Abstract Syntax Tree (AST) using this code
pandoc AST
xfun:::tree(
jsonlite::fromJSON('ast.json', simplifyVector = FALSE)
)
List of 3
|-pandoc-api-version:List of 3
| |-: int 1
| |-: int 22
| |-: int 2
|-meta :List of 5
| |-execute:List of 2
| | |-t: chr "MetaMap"
| | |-c:List of 1
| | |-keep-md:List of 2
| | |-t: chr "MetaBool"
| | |-c: logi TRUE
| |-filters:List of 2
| | |-t: chr "MetaList"
| | |-c:List of 1
| | |-:List of 2
| | |-t: chr "MetaInlines"
| | |-c:List of 1
| | |-:List of 2
| | |-t: chr "Str"
| | |-c: chr "unilur"
| |-format :List of 2
| | |-t: chr "MetaMap"
| | |-c:List of 1
| | |-html:List of 2
| | |-t: chr "MetaMap"
| | |-c:List of 1
| | |-theme:List of 2
| | |-t: chr "MetaInlines"
| | |-c:List of 1
| | |-:List of 2
| | |-t: chr "Str"
| | |-c: chr "cosmo"
| |-title :List of 2
| | |-t: chr "MetaInlines"
| | |-c:List of 3
| | |-:List of 2
| | | |-t: chr "Str"
| | | |-c: chr "Unilur"
| | |-:List of 1
| | | |-t: chr "Space"
| | |-:List of 2
| | |-t: chr "Str"
| | |-c: chr "Example"
| |-unilur :List of 2
| |-t: chr "MetaMap"
| |-c:List of 1
| |-solution:List of 2
| |-t: chr "MetaInlines"
| |-c:List of 1
| |-:List of 2
| |-t: chr "Str"
| |-c: chr "true"
|-blocks :List of 5
|-:List of 2
| |-t: chr "Div"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-:List of 1
| | | |-: chr "cell"
| | |-:List of 1
| | |-:List of 2
| | |-: chr "solution"
| | |-: chr "true"
| |-:List of 2
| |-:List of 2
| | |-t: chr "CodeBlock"
| | |-c:List of 2
| | |-:List of 3
| | | |-: chr ""
| | | |-:List of 1
| | | | |-: chr "cell-code"
| | | |-: list()
| | |-: chr "```{r}\n#| solution: true\n\n1 + 1\n```"
| |-:List of 2
| |-t: chr "Div"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-:List of 2
| | | |-: chr "cell-output"
| | | |-: chr "cell-output-stdout"
| | |-: list()
| |-:List of 1
| |-:List of 2
| |-t: chr "CodeBlock"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-: list()
| | |-: list()
| |-: chr "[1] 2"
|-:List of 2
| |-t: chr "Para"
| |-c:List of 1
| |-:List of 2
| |-t: chr "Str"
| |-c: chr "Classic"
|-:List of 2
| |-t: chr "Div"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-:List of 1
| | | |-: chr "cell"
| | |-: list()
| |-:List of 2
| |-:List of 2
| | |-t: chr "CodeBlock"
| | |-c:List of 2
| | |-:List of 3
| | | |-: chr ""
| | | |-:List of 1
| | | | |-: chr "cell-code"
| | | |-: list()
| | |-: chr "```{r}\n1 + 1\n```"
| |-:List of 2
| |-t: chr "Div"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-:List of 2
| | | |-: chr "cell-output"
| | | |-: chr "cell-output-stdout"
| | |-: list()
| |-:List of 1
| |-:List of 2
| |-t: chr "CodeBlock"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-: list()
| | |-: list()
| |-: chr "[1] 2"
|-:List of 2
| |-t: chr "Para"
| |-c:List of 1
| |-:List of 2
| |-t: chr "Str"
| |-c: chr "Solution"
|-:List of 2
|-t: chr "Div"
|-c:List of 2
|-:List of 3
| |-: chr ""
| |-:List of 1
| | |-: chr "cell"
| |-:List of 1
| |-:List of 2
| |-: chr "solution"
| |-: chr "true"
|-:List of 2
|-:List of 2
| |-t: chr "CodeBlock"
| |-c:List of 2
| |-:List of 3
| | |-: chr ""
| | |-:List of 2
| | | |-: chr "r"
| | | |-: chr "cell-code"
| | |-: list()
| |-: chr "1 + 2"
|-:List of 2
|-t: chr "Div"
|-c:List of 2
|-:List of 3
| |-: chr ""
| |-:List of 2
| | |-: chr "cell-output"
| | |-: chr "cell-output-stdout"
| |-: list()
|-:List of 1
|-:List of 2
|-t: chr "CodeBlock"
|-c:List of 2
|-:List of 3
| |-: chr ""
| |-: list()
| |-: list()
|-: chr "[1] 3"
MIT License