Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ More examples please refer:
2. Book document (HTML and PDF): [examples/book](examples/book).
3. Beamer document (PDF): [examples/beamer](examples/beamer).
4. Cross reference example (HTML and PDF): [examples/cross-reference](examples/cross-reference).
5. Presentation document (revealjs): [examples/revealjs](examples/revealjs).

## License

Expand Down
90 changes: 72 additions & 18 deletions _extensions/pseudocode/pseudocode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,7 @@ local function ensure_html_deps()
[[
<script type="text/javascript">
(function(d) {
d.querySelectorAll(".pseudocode-container").forEach(function(el) {
let pseudocodeOptions = {
indentSize: el.dataset.indentSize,
commentDelimiter: " " + el.dataset.commentDelimiter + " ",
lineNumber: el.dataset.lineNumber.toLowerCase() === "true",
lineNumberPunc: el.dataset.lineNumberPunc,
noEnd: el.dataset.noEnd.toLowerCase() === "true",
scopeLines: el.dataset.indentLines.toLowerCase() === "true",
titlePrefix: el.dataset.captionPrefix,
};
pseudocode.renderElement(el.querySelector(".pseudocode"), pseudocodeOptions);
});
})(document);
(function(d) {
d.querySelectorAll(".pseudocode-container").forEach(function(el) {
function fixCaption(el) {
let captionSpan = el.querySelector(".ps-root > .ps-algorithm > .ps-line > .ps-keyword")
if (captionSpan !== null) {
let captionPrefix = el.dataset.captionPrefix + " ";
Expand All @@ -51,7 +37,68 @@ local function ensure_html_deps()
}
captionSpan.innerHTML = captionPrefix + captionNumber;
}
});
}
function mathBackendReady() {
return (typeof window.katex !== "undefined") || (typeof window.MathJax !== "undefined");
}
function renderAll() {
d.querySelectorAll(".pseudocode-container").forEach(function(el) {
if (el.dataset.pseudocodeRendered === "true") {
return;
}
let pseudocodeOptions = {
indentSize: el.dataset.indentSize,
commentDelimiter: " " + el.dataset.commentDelimiter + " ",
lineNumber: el.dataset.lineNumber.toLowerCase() === "true",
lineNumberPunc: el.dataset.lineNumberPunc,
noEnd: el.dataset.noEnd.toLowerCase() === "true",
scopeLines: el.dataset.indentLines.toLowerCase() === "true",
titlePrefix: el.dataset.captionPrefix,
};
try {
pseudocode.renderElement(el.querySelector(".pseudocode"), pseudocodeOptions);
el.dataset.pseudocodeRendered = "true";
fixCaption(el);
} catch (e) {
let errDiv = d.createElement("div");
errDiv.style.color = "red";
errDiv.style.whiteSpace = "pre-wrap";
errDiv.style.fontFamily = "monospace";
errDiv.style.fontSize = "0.5em";
errDiv.style.textAlign = "left";
errDiv.textContent = "pseudocode.js render error: " + (e && e.message ? e.message : e);
el.appendChild(errDiv);
}
});
}
// pseudocode.js resolves its math backend (KaTeX or MathJax) by
// checking for the global `katex`/`MathJax` identifiers at the exact
// moment pseudocode.renderElement() runs (see the Renderer
// constructor in pseudocode.min.js). In a revealjs presentation,
// KaTeX/MathJax is loaded asynchronously by reveal.js's own math
// plugin (often from a CDN), so rendering immediately can race that
// load and fail with:
// "No math backend found. Please setup KaTeX or MathJax."
// Poll briefly for a backend to appear before rendering, so this
// reliably runs after the backend finishes loading instead of
// racing it. If a math backend genuinely never loads (e.g. none is
// configured), give up after ~15s and render anyway so any real
// error is still surfaced above.
function renderAllWhenReady(attemptsLeft) {
if (attemptsLeft === undefined) attemptsLeft = 100;
if (!mathBackendReady() && attemptsLeft > 0) {
setTimeout(function() {
renderAllWhenReady(attemptsLeft - 1);
}, 150);
return;
}
renderAll();
}
renderAllWhenReady();
if (window.Reveal && typeof window.Reveal.on === "function") {
window.Reveal.on("ready", renderAllWhenReady);
window.Reveal.on("slidechanged", renderAllWhenReady);
}
})(document);
</script>
]]
Expand Down Expand Up @@ -124,6 +171,13 @@ local function extract_source_code_options(source_code, render_type)
return options, table.concat(source_codes, "\n")
end

local function html_escape(s)
s = string.gsub(s, "&", "&amp;")
s = string.gsub(s, "<", "&lt;")
s = string.gsub(s, ">", "&gt;")
return s
end

local function render_pseudocode_block_html(global_options)
ensure_html_deps()

Expand Down Expand Up @@ -174,8 +228,8 @@ local function render_pseudocode_block_html(global_options)
data_options[data_k] = v
end
end

local inner_el = pandoc.Div(source_code)
local inner_el = pandoc.Div(pandoc.RawBlock("html", html_escape(source_code)))
inner_el.attr.classes = pandoc.List()
inner_el.attr.classes:insert("pseudocode")

Expand Down
1 change: 1 addition & 0 deletions examples/revealjs/_extensions
44 changes: 44 additions & 0 deletions examples/revealjs/revealjs.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "Quarto Pseudocode Extension - revealjs Example"
filters:
- pseudocode
format: revealjs
---

## Introduction

This slide comes before the algorithm slide, so the pseudocode block
below is not on the first slide of the deck when the presentation loads.

## Quicksort

@algo-quicksort shows the classic in-place Quicksort algorithm.

```pseudocode
#| label: algo-quicksort

\begin{algorithm}
\caption{Quicksort}
\begin{algorithmic}
\Procedure{Quicksort}{$A, p, r$}
\If{$p < r$}
\State $q = $ \Call{Partition}{$A, p, r$}
\State \Call{Quicksort}{$A, p, q - 1$}
\State \Call{Quicksort}{$A, q + 1, r$}
\EndIf
\EndProcedure
\Procedure{Partition}{$A, p, r$}
\State $x = A[r]$
\State $i = p - 1$
\For{$j = p$ \To $r - 1$}
\If{$A[j] < x$}
\State $i = i + 1$
\State exchange $A[i]$ with $A[j]$
\EndIf
\EndFor
\State exchange $A[i + 1]$ with $A[r]$
\Return $i + 1$
\EndProcedure
\end{algorithmic}
\end{algorithm}
```