Skip to content

Commit

Permalink
More options (#143)
Browse files Browse the repository at this point in the history
* Add support for `output`, `comment`, `label`, `classes`, and `fig-cap`.

* Update docs; fix spacing in new style.

* Add release note
  • Loading branch information
coatless authored Jan 31, 2024
1 parent 25ec63e commit 0d4651c
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 34 deletions.
45 changes: 35 additions & 10 deletions _extensions/webr/qwebr-cell-elements.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ globalThis.qwebrCreateHTMLElement = function (
let qwebrElement;
switch ( evalType ) {
case EvalTypes.Interactive:
qwebrElement = qwebrCreateInteractiveElement(qwebrCounter);
qwebrElement = qwebrCreateInteractiveElement(qwebrCounter, cellData.options);
break;
case EvalTypes.Output:
qwebrElement = qwebrCreateNonInteractiveOutputElement(qwebrCounter);
qwebrElement = qwebrCreateNonInteractiveOutputElement(qwebrCounter, cellData.options);
break;
case EvalTypes.Setup:
qwebrElement = qwebrCreateNonInteractiveSetupElement(qwebrCounter);
qwebrElement = qwebrCreateNonInteractiveSetupElement(qwebrCounter, cellData.options);
break;
default:
qwebrElement = document.createElement('div');
Expand All @@ -40,12 +40,20 @@ globalThis.qwebrCreateHTMLElement = function (
};

// Function that setups the interactive element creation
globalThis.qwebrCreateInteractiveElement = function (qwebrCounter) {
globalThis.qwebrCreateInteractiveElement = function (qwebrCounter, qwebrOptions) {

// Create main div element
var mainDiv = document.createElement('div');
mainDiv.id = 'qwebr-interactive-area-' + qwebrCounter;
mainDiv.className = 'qwebr-interactive-area';
mainDiv.className = `qwebr-interactive-area`;
if (qwebrOptions.classes) {
mainDiv.className += " " + qwebrOptions.classes
}

// Add a unique cell identifier that users can customize
if (qwebrOptions.label) {
mainDiv.setAttribute('data-id', qwebrOptions.label);
}

// Create toolbar div
var toolbarDiv = document.createElement('div');
Expand Down Expand Up @@ -133,12 +141,20 @@ globalThis.qwebrCreateInteractiveElement = function (qwebrCounter) {
}

// Function that adds output structure for non-interactive output
globalThis.qwebrCreateNonInteractiveOutputElement = function(qwebrCounter) {
globalThis.qwebrCreateNonInteractiveOutputElement = function(qwebrCounter, qwebrOptions) {
// Create main div element
var mainDiv = document.createElement('div');
mainDiv.id = 'qwebr-noninteractive-area-' + qwebrCounter;
mainDiv.className = 'qwebr-noninteractive-area';

mainDiv.className = `qwebr-noninteractive-area`;
if (qwebrOptions.classes) {
mainDiv.className += " " + qwebrOptions.classes
}

// Add a unique cell identifier that users can customize
if (qwebrOptions.label) {
mainDiv.setAttribute('data-id', qwebrOptions.label);
}

// Create a status container div
var statusContainer = createLoadingContainer(qwebrCounter);

Expand Down Expand Up @@ -167,11 +183,20 @@ globalThis.qwebrCreateNonInteractiveOutputElement = function(qwebrCounter) {
};

// Function that adds a stub in the page to indicate a setup cell was used.
globalThis.qwebrCreateNonInteractiveSetupElement = function(qwebrCounter) {
globalThis.qwebrCreateNonInteractiveSetupElement = function(qwebrCounter, qwebrOptions) {
// Create main div element
var mainDiv = document.createElement('div');
mainDiv.id = `qwebr-noninteractive-setup-area-${qwebrCounter}`;
mainDiv.className = 'qwebr-noninteractive-setup-area';
mainDiv.className = `qwebr-noninteractive-setup-area`;
if (qwebrOptions.classes) {
mainDiv.className += " " + qwebrOptions.classes
}


// Add a unique cell identifier that users can customize
if (qwebrOptions.label) {
mainDiv.setAttribute('data-id', qwebrOptions.label);
}

// Create a status container div
var statusContainer = createLoadingContainer(qwebrCounter);
Expand Down
29 changes: 25 additions & 4 deletions _extensions/webr/qwebr-compute-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ globalThis.qwebrIdentity = function(x) {
return x;
};

// Append a comment
globalThis.qwebrPrefixComment = function(x, comment) {
return `${comment}${x}`;
};

// Function to parse the pager results
globalThis.qwebrParseTypePager = async function (msg) {

Expand Down Expand Up @@ -68,9 +73,10 @@ globalThis.qwebrComputeEngine = async function(
let pager = [];

// Handle how output is processed
let showMarkup = options.results === "markup" && options.output !== "asis";
let processOutput;

if (options.results == "markup") {
if (showMarkup) {
processOutput = qwebrEscapeHTMLCharacters;
} else {
processOutput = qwebrIdentity;
Expand Down Expand Up @@ -104,7 +110,7 @@ globalThis.qwebrComputeEngine = async function(
await mainWebR.evalRVoid("dev.off()");

// Avoid running through output processing
if (options.results === "hide") {
if (options.results === "hide" || options.output === "false") {
break processResultOutput;
}

Expand All @@ -117,7 +123,8 @@ globalThis.qwebrComputeEngine = async function(
)
.map((evt, index) => {
const className = `qwebr-output-code-${evt.type}`;
return `<code id="${className}-editor-${elements.id}-result-${index + 1}" class="${className}">${processOutput(evt.data)}</code>`;
const outputResult = qwebrPrefixComment(processOutput(evt.data), options.comment);
return `<code id="${className}-editor-${elements.id}-result-${index + 1}" class="${className}">${outputResult}</code>`;
})
.join("\n");

Expand Down Expand Up @@ -180,7 +187,21 @@ globalThis.qwebrComputeEngine = async function(

// Place the graphics on the canvas
if (canvas) {
elements.outputGraphDiv.appendChild(canvas);
// Create figure element
const figureElement = document.createElement('figure');

// Append canvas to figure
figureElement.appendChild(canvas);

if (options['fig-cap']) {
// Create figcaption element
const figcaptionElement = document.createElement('figcaption');
figcaptionElement.innerText = options['fig-cap'];
// Append figcaption to figure
figureElement.appendChild(figcaptionElement);
}

elements.outputGraphDiv.appendChild(figureElement);
}

// Display the pager data
Expand Down
10 changes: 10 additions & 0 deletions _extensions/webr/webr.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ local qwebRDefaultCellOptions = {
["warning"] = "true",
["message"] = "true",
["results"] = "markup",
["output"] = "true",
["comment"] = "",
["label"] = "",
["classes"] = "",
["dpi"] = 72,
["fig-cap"] = "",
["fig-width"] = 7,
["fig-height"] = 5,
["out-width"] = "700px",
Expand Down Expand Up @@ -559,6 +564,11 @@ local function enableWebRCodeCell(el)
-- Convert webr-specific option commands into attributes
cellCode, cellOptions = extractCodeBlockOptions(el)

-- Ensure we have a label representation
if cellOptions["label"] == '' then
cellOptions["label"] = "unnamed-chunk-" .. qwebrCounter
end

-- Remove space left between options and code contents
cellCode = removeEmptyLinesUntilContent(cellCode)

Expand Down
35 changes: 22 additions & 13 deletions docs/qwebr-cell-options.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,35 @@ These options can be customized to tailor the behavior of the code block based o


:::{.callout-important}
The `{quarto-webr}` extension does not support all of the cell options from [Quarto](https://quarto.org/docs/reference/cells/cells-knitr.html) or [Knitr](https://yihui.org/knitr/options/). Please consult below for details on what is available.
The `{quarto-webr}` extension does not support all of the cell options from [Quarto](https://quarto.org/docs/reference/cells/cells-knitr.html) or [Knitr](https://yihui.org/knitr/options/). Please consult the tables below for details on what is available.
:::

## webR

| Option | Default Value | Description |
|-----------|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `context` | `"interactive"` | Describe how the cell should operate on the page through either `"interactive"` (Runnable code editor), `"output"` (Output only of executed at runtime), or `"setup"` (execute code without seeing output at runtime). |
| Option | Default Value | Description |
|-----------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `context` | `interactive` | Describe how the cell should operate on the page through either `interactive` (Runnable code editor), `output` (Output only of executed at runtime), or `setup` (execute code without seeing output at runtime). |


:::{.callout-note}
The `context` option is unique to the `{quarto-webr}` extension. For more details, please see [Hiding and Executing Code](qwebr-internal-cell.qmd).
:::

## Attributes

| Option | Default Value | Description |
|-----------|---------------|---------------------------------------------------|
| `label` | `''` | Unique label for code cell. Useful for debugging. |
| `classes` | `''` | Classes to apply to cell container |

## Cell Output

| Option | Default Value | Description |
|-----------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `results` | `'markup'` | Controls how to display the text results through either: `'markup'` (Mark up text output with appropriate environments), `'asis'` (Write text output as-is, raw text results directly into the output document), or `'hide'` (Hide text output). |
| `warning` | `true` | Preserve standard error output (`warning()`, `message()`, or `stop()`) in the output. |
| `message` | `true` | See prior entry. |
| Option | Default Value | Description |
|-----------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `results` | `markup` | Controls how to display the text results through either: `markup` (Mark up text output with appropriate environments), `asis` (Write text output as-is, raw text results directly into the output document), or `hide` (Hide text output). |
| `output` | `true` | Controls inclusion of results: `true` (all results), `false` (no results), or `'asis'` (output as-is, raw text results directly into the output document). |
| `warning` | `true` | Preserve standard error output (`warning()`, `message()`, or `stop()`) in the output. |
| `message` | `true` | See prior entry. |


:::{.callout-important}
Expand All @@ -59,8 +67,9 @@ At the present time, we cannot differentiate between the type of condition being

| Option | Default Value | Description |
|--------------|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| `dpi` | 72 | Dots per inch to use in calculating pixel values for `fig-height` and `fig-width`, e.g. `dpi * inches = pixels`. |
| `fig-width` | 7 | Width of the plot (in inches) |
| `fig-height` | 5 | Height of the plot (in inches) |
| `out-width` | `"700px"` | Width of the plot in the output document, which can be different from its physical `fig-width` such as `"100%"` or `"250px"`. |
| `fig-cap` | `""` | Figure caption that should appear under the canvas |
| `dpi` | `72` | Dots per inch to use in calculating pixel values for `fig-height` and `fig-width`, e.g. `dpi * inches = pixels`. |
| `fig-width` | `7` | Width of the plot (in inches) |
| `fig-height` | `5` | Height of the plot (in inches) |
| `out-width` | `700px` | Width of the plot in the output document, which can be different from its physical `fig-width` such as `"100%"` or `"250px"`. |
| `out-height` | `""` | Height of the plot in the output document, similar to `out-width`. |
9 changes: 7 additions & 2 deletions docs/qwebr-release-notes.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ format:
toc: true
---

# 0.4.0: ???? (??-??-????) [DEV]
# 0.4.0: Ball of Yarn (??-??-????) [DEV]

## Breaking changes

Expand All @@ -20,7 +20,10 @@ format:
- Implemented a custom JSON format for code cell data and option sharing between Quarto and webR. ([#120](https://github.com/coatless/quarto-webr/pull/120))
- Redesigned non-interactive cells to provide improved reliability and visual cues. ([#120](https://github.com/coatless/quarto-webr/pull/120))
- Interactive cells now have a toolbar above them that provides three actions: Run Code, Start Over, and Copy. ([#91](https://github.com/coatless/quarto-webr/issues/91))
- Initial code cell option support for changing figure width and height (`dpi`, `fig-width`, `fig-height`, `out-width`, & `out-height`), suppressing standard error messages generated by `warning()`, `message()`, and `stop()` (`warning: false` or `message: false`), and allowing content to appear as-is (`results: 'asis'`). ([#104](https://github.com/coatless/quarto-webr/issues/104), [#125](https://github.com/coatless/quarto-webr/issues/125))
- Initial [code cell option](https://quarto-webr.thecoatlessprofessor.com/qwebr-cell-options.html) support ([#104](https://github.com/coatless/quarto-webr/issues/104), [#117](https://github.com/coatless/quarto-webr/issues/117), [#125](https://github.com/coatless/quarto-webr/issues/125)):
- Attributes: `label` and `classes`.
- Figures: `fig-cap`, `dpi`, `fig-width`, `fig-height`, `out-width`, & `out-height`.
- Cell output: `warning`/`message`, `results`, and `output`
- Added `repos` document meta option key to specify custom package repositories containing compiled R WASM Packages not found in the main [webR repository](https://repo.r-wasm.org/) ([#124](https://github.com/coatless/quarto-webr/issues/124), [#132](https://github.com/coatless/quarto-webr/pull/132)).

## Changes
Expand All @@ -40,9 +43,11 @@ format:

## Documentation

- New section discussing [code cell options in `{webr-r}` cells](https://quarto-webr.thecoatlessprofessor.com/qwebr-cell-options.html).
- New section with [demos of the Quarto extension's features](https://quarto-webr.thecoatlessprofessor.com/demos/qwebr-feature-demos.html). ([#128](https://github.com/coatless/quarto-webr/pull/128))
- Added a demo on [non-interactive code cells](https://quarto-webr.thecoatlessprofessor.com/demos/qwebr-non-interactive-areas.html). ([#128](https://github.com/coatless/quarto-webr/pull/128))
- Added a demo on [using custom repositories to install R WASM package binaries](https://quarto-webr.thecoatlessprofessor.com/demos/qwebr-custom-repository.html). ([#128](https://github.com/coatless/quarto-webr/pull/132))
- Added a demo for showing [initial code cell option support](https://quarto-webr.thecoatlessprofessor.com/demos/qwebr-code-cell-options.html). ([#141](https://github.com/coatless/quarto-webr/pull/141))
- Modified the RevealJS presentation YAML to include an option to disable the webR status message header ([#110](https://github.com/coatless/quarto-webr/issues/110))
- Updated [blog posts](https://quarto-webr.thecoatlessprofessor.com/qwebr-community-examples.html#blog-posts) on [community examples](https://quarto-webr.thecoatlessprofessor.com/qwebr-community-examples.html) page ([#135](https://github.com/coatless/quarto-webr/pull/135))
- Minor documentation tweaks.
Expand Down
22 changes: 19 additions & 3 deletions tests/qwebr-test-escape-html-output-characters.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ filters:
- webr
---

Ensure HTML output is escaped.
Ensure HTML output is escaped or passed t hrough

## Interactive

### results: markup
```{webr-r}
# This function converts a markdown link into HTML
"[Posit](https://posit.co)" |> (\(.) {
Expand All @@ -22,7 +23,7 @@ Ensure HTML output is escaped.

## Non-interactive

### Escape HTML Characters
### results: markup

```{webr-r}
#| context: output
Expand All @@ -35,7 +36,7 @@ Ensure HTML output is escaped.
})()
```

### Leave characters asis
### results: asis

```{webr-r}
#| context: output
Expand All @@ -49,3 +50,18 @@ Ensure HTML output is escaped.
})()
```


### output: asis

```{webr-r}
#| context: output
#| output: asis
# This function converts a markdown link into HTML
"[Posit](https://posit.co)" |> (\(.) {
text <- sub("\\].*", "", sub(".*\\[", "", .))
url <- sub("\\).*", "", sub(".*\\(", "", .))
writeLines(noquote(paste0('<a href="', url, '" target = "_blank">', text, '</a>')))
})()
```

41 changes: 40 additions & 1 deletion tests/qwebr-test-output-classes.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ filters:
- webr
---

Test output classes for standard output and standard error.
Test output classes for standard output, standard error, and custom `classes` attributes.

## Interactive

Expand All @@ -21,6 +21,7 @@ stop("This is a hard error message!")

## Non-interactive

### No Comment
```{webr-r}
#| context: output
cat("Display letters: ")
Expand All @@ -30,3 +31,41 @@ warning("This is a warning message!")
stop("This is a hard error message!")
```

### With comment

```{webr-r}
#| context: output
#| comment: "## "
cat("Display letters: ")
print(letters[1:5])
warning("This is a warning message!")
stop("This is a hard error message!")
```

### With output class custom

```{=html}
<style>
.green {
background-color: green;
}
.toad {
color: orange;
}
</style>
```

```{webr-r}
#| context: output
#| classes: toad green
cat("Display letters: ")
print(letters[1:5])
warning("This is a warning message!")
stop("This is a hard error message!")
```
1 change: 1 addition & 0 deletions tests/qwebr-test-output-graph.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ plot(pressure)
### Default options
```{webr-r}
#| context: output
#| fig-cap: Testing out figure captions
plot(pressure)
```

Expand Down
Loading

0 comments on commit 0d4651c

Please sign in to comment.