Skip to content

Commit 46014f2

Browse files
committed
Update version of {quarto-panelize} and {quarto-webr} extensions
1 parent 0d1f80f commit 46014f2

14 files changed

+887
-173
lines changed

altdoc/_extensions/coatless-quarto/panelize/_extension.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: panelize
22
title: Panelize code cells
3-
author: Carlos Scheidegger and James Joseph Balamuta
4-
version: 0.0.0-dev.1
3+
author: James Joseph Balamuta
4+
version: 0.0.2
55
quarto-required: ">=1.4.554"
66
contributes:
77
filters:
Lines changed: 179 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,197 @@
1-
-- Function to process code blocks
2-
local function clean_code_block(el, language)
3-
4-
-- Check if the code block contains R code
5-
if el.text:match("^```{{"..language) then
6-
-- Remove the ```{{<language>}} and ``` lines
7-
local cleaned_text = el.text:gsub("```{{".. language .."}}\n", ""):gsub("\n```", "")
8-
9-
-- Remove lines starting with #| (options)
10-
cleaned_text = cleaned_text:gsub("#|.-\n", "")
1+
-- Define helper types for clarity
2+
---@class Block
3+
---@field t string The type of the block
4+
---@field attr table Block attributes
5+
---@field content? table Block content
6+
---@field classes table List of classes
7+
---@field text? string Block text if CodeBlock
8+
9+
---@class Cell
10+
---@field code_blocks Block[] List of code blocks
11+
---@field outputs Block[] List of output blocks
12+
---@field language string Programming language
13+
14+
---@class DocumentMetadata
15+
---@field panelize table<string, any> Configuration options
16+
---@field handler_added boolean Flag for handler addition
17+
18+
-- Store metadata at module level
19+
---@type DocumentMetadata
20+
local document_metadata = {
21+
panelize = {},
22+
handler_added = false
23+
}
24+
25+
-- Helper function to detect language from a code block
26+
---@param block Block The code block to analyze
27+
---@return string|nil language The detected language
28+
local function detect_language(block)
29+
if block.attr.classes:includes("r") then
30+
return "r"
31+
elseif block.attr.classes:includes("python") then
32+
return "python"
33+
elseif block.text:match("^```{{r") then
34+
return "r"
35+
elseif block.text:match("^```{{python") then
36+
return "python"
37+
end
38+
return nil
39+
end
1140

12-
-- Add 'language' to the class list if not already present
13-
if not el.attr.classes:includes(language) then
14-
table.insert(el.attr.classes, 1, language)
15-
end
41+
-- Helper function to clean code block text
42+
---@param block Block The code block to clean
43+
---@param language string The programming language
44+
---@return string cleaned_text The processed text
45+
local function clean_code_text(block, language)
46+
local text = block.text
47+
if text:match("^```{{" .. language .. "}") then
48+
text = text:gsub("```{{" .. language .. "}}\n", ""):gsub("\n```", "")
49+
end
50+
return text:gsub("#|.-\n", "")
51+
end
1652

17-
-- Return the modified code block
18-
return pandoc.CodeBlock(cleaned_text, el.attr)
53+
-- Helper function to extract cell content
54+
---@param cell_div Block The cell div block
55+
---@return Cell cell The processed cell content
56+
local function extract_cell_content(cell_div)
57+
local cell = {
58+
code_blocks = {},
59+
outputs = {},
60+
language = nil
61+
}
62+
63+
-- Process blocks in order to maintain sequence
64+
for _, block in ipairs(cell_div.content) do
65+
if block.t == "CodeBlock" and block.classes:includes("cell-code") then
66+
table.insert(cell.code_blocks, block)
67+
-- Detect language from first code block if not already set
68+
if not cell.language then
69+
cell.language = detect_language(block)
70+
end
71+
elseif block.t == "Div" and (
72+
block.classes:includes("cell-output") or
73+
block.classes:includes("cell-output-stdout") or
74+
block.classes:includes("cell-output-display")
75+
) then
76+
table.insert(cell.outputs, block)
77+
end
1978
end
79+
80+
return cell
81+
end
2082

21-
-- If not an R code block, return unchanged
22-
return el
83+
-- Helper function to create tab content
84+
---@param cell Cell The cell content
85+
---@param interactive boolean Whether this is an interactive tab
86+
---@return pandoc.List content The tab content
87+
local function create_tab_content(cell, interactive)
88+
local content = pandoc.List()
89+
90+
if interactive then
91+
-- For interactive tab, combine all code blocks into one
92+
local combined_code = table.concat(
93+
pandoc.List(cell.code_blocks):map(function(block)
94+
return clean_code_text(block, cell.language)
95+
end),
96+
"\n"
97+
)
98+
99+
-- Create single code block with appropriate classes
100+
local classes = cell.language == "r" and {"{webr-r}", "cell-code"} or {"{pyodide-python}", "cell-code"}
101+
local attr = pandoc.Attr("", classes, {})
102+
content:insert(pandoc.CodeBlock(combined_code, attr))
103+
else
104+
-- For result tab, keep original structure
105+
for i, code_block in ipairs(cell.code_blocks) do
106+
content:insert(code_block)
107+
-- Add corresponding output if it exists
108+
if cell.outputs[i] then
109+
content:insert(cell.outputs[i])
110+
end
111+
end
112+
end
113+
114+
return content
23115
end
24116

25-
-- Helper function to clone and update code block attributes
26-
local function clone_and_update_code_block(code_block, new_classes)
27-
local new_attr = code_block.attr:clone()
28-
new_attr.classes = pandoc.List(new_classes)
29-
return pandoc.CodeBlock(code_block.text, new_attr)
117+
-- Process metadata
118+
function Meta(meta)
119+
if meta and meta.panelize then
120+
for key, value in pairs(meta.panelize) do
121+
document_metadata.panelize[key] = pandoc.utils.stringify(value)
122+
end
123+
end
124+
return meta
30125
end
31126

127+
-- Main processing function for divs
32128
function Div(div)
129+
-- Check for required classes
33130
local to_webr = div.classes:includes("to-webr")
34131
local to_pyodide = div.classes:includes("to-pyodide")
35-
36-
-- Check if the `div` has the class "to-source"/"to-webr"/"to-pyodide"
37-
if not (div.classes:includes("to-source") or to_webr or to_pyodide) then
38-
return
132+
local to_source = div.classes:includes("to-source")
133+
134+
if not (to_source or to_webr or to_pyodide) then
135+
return div
39136
end
40137

41-
-- Initialize local variables for code block, cell output, and language
42-
local code_block = nil
43-
local cell_output = nil
44-
local language = nil
45-
46-
-- Walk through the content of the `div` to find `CodeBlock` and `Div` elements
47-
div:walk({
48-
CodeBlock = function(code)
49-
-- If a `CodeBlock` with the class "cell-code" is found, assign it to `code_block`
50-
if code.classes:includes("cell-code") then
51-
code_block = code
52-
-- Determine the language of the code block
53-
if code.classes:includes("r") or code.text:match("^```{{r") then
54-
language = "r"
55-
elseif code.classes:includes("python") or code.text:match("^```{{python") then
56-
language = "python"
57-
else
58-
quarto.log.error("Please only specify either R or Python code cells inside of the `to-panel` div.")
59-
end
60-
end
61-
end,
62-
Div = function(div)
63-
-- If a `Div` with the class "cell-output" is found, assign it to `cell_output`
64-
if div.classes:includes("cell-output") then
65-
cell_output = div
138+
-- Find cell div
139+
local cell_div = nil
140+
for _, block in ipairs(div.content) do
141+
if block.t == "Div" and block.classes:includes("cell") then
142+
cell_div = block
143+
break
66144
end
67-
end
68-
})
69-
70-
local cleaned_code_cell = clean_code_block(code_block, language)
71-
72-
-- Determine the type of Tab to use
73-
local tabs = nil
74-
75-
-- Check if the language matches the required condition
145+
end
146+
147+
if not cell_div then
148+
return div
149+
end
150+
151+
-- Extract cell content
152+
local cell = extract_cell_content(cell_div)
153+
154+
if not cell.language then
155+
quarto.log.error("Please specify either R or Python code cells inside of the .to-* div.")
156+
return div
157+
end
158+
159+
-- Create tabs
160+
local tabs = pandoc.List()
161+
76162
if to_webr or to_pyodide then
77-
-- Create a tab for the Result
78-
local result_tab = quarto.Tab({ title = "Result", content = pandoc.List({code_block, cell_output}) })
79-
80-
-- Pick attribute classes
81-
local code_block_attr_classes = to_webr and {"{webr-r}", "cell-code"} or {"{pyodide-python}", "cell-code"}
82-
83-
-- Create a tab for the Source
84-
local interactive_tab = quarto.Tab({ title = "Interactive", content = clone_and_update_code_block(code_block, code_block_attr_classes) })
85-
86-
-- Combine the tabs into a list
87-
tabs = pandoc.List({ result_tab, interactive_tab })
88-
else
89-
-- Create a tab for the Rendered
90-
local rendered_tab = quarto.Tab({ title = "Result", content = pandoc.List({cleaned_code_cell, cell_output}) })
91-
92-
-- Create a tab for the Source
93-
local source_tab = quarto.Tab({ title = "Source", content = clone_and_update_code_block(code_block, {"md", "cell-code"}) })
94-
95-
-- Combine the tabs into a list
96-
tabs = pandoc.List({ rendered_tab, source_tab })
163+
-- Interactive environment tabs
164+
tabs:insert(quarto.Tab({
165+
title = "Result",
166+
content = pandoc.Blocks(create_tab_content(cell, false))
167+
}))
168+
tabs:insert(quarto.Tab({
169+
title = "Interactive",
170+
content = pandoc.Blocks(create_tab_content(cell, true))
171+
}))
172+
else
173+
-- Source code tabs
174+
tabs:insert(quarto.Tab({
175+
title = "Result",
176+
content = pandoc.Blocks(create_tab_content(cell, false))
177+
}))
178+
-- For source tab, show original code without execution
179+
tabs:insert(quarto.Tab({
180+
title = "Source",
181+
content = pandoc.Blocks(pandoc.List(cell.code_blocks))
182+
}))
97183
end
98-
99-
-- Return a `quarto.Tabset` with the created tabs and specific attributes
184+
185+
-- Return just the tabset, replacing the original div
100186
return quarto.Tabset({
101-
level = 3,
102-
tabs = tabs,
103-
attr = pandoc.Attr("", {"panel-tabset"}) -- This attribute assignment shouldn't be necessary but addresses a known issue. Remove when using Quarto 1.5 or greater as required version.
187+
level = 3,
188+
tabs = tabs,
189+
attr = pandoc.Attr("", {"panel-tabset"}, {})
104190
})
105-
end
191+
end
192+
193+
-- Return the list of functions to register
194+
return {
195+
{Meta = Meta},
196+
{Div = Div}
197+
}

altdoc/_extensions/coatless/webr/_extension.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: webr
22
title: Embedded webr code cells
33
author: James Joseph Balamuta
4-
version: 0.4.2-dev.6
4+
version: 0.4.3-dev.2
55
quarto-required: ">=1.4.554"
66
contributes:
77
filters:

altdoc/_extensions/coatless/webr/qwebr-cell-initialization.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ qwebrInstance.then(
7878
break;
7979
case 'setup':
8080
const activeDiv = document.getElementById(`qwebr-noninteractive-setup-area-${qwebrCounter}`);
81+
82+
// Store code in history
83+
qwebrLogCodeToHistory(cellCode, entry.options);
84+
8185
// Run the code in a non-interactive state with all output thrown away
8286
await mainWebR.evalRVoid(`${cellCode}`);
8387
break;

0 commit comments

Comments
 (0)