--- title: "Publishing runnable R chunks with CarmaR" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Publishing runnable R chunks with CarmaR} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = FALSE) ``` A 'Quarto' site rendered with the `carmar` filter keeps every page exactly as rendered, and gives each visible R chunk a Run button that evaluates the chunk on the reader's own computer, in the reader's own R. No server runs the code; the page talks to a small local process - a CarmaR kernel - over a loopback socket. This vignette is the author's story, then the reader's. ## The author Enable publishing in the project once: ```{r} carmar::use_publishing("path/to/project") # or "." from inside the project ``` This copies the extension into `_extensions/carmar`, puts `- carmar` under `filters:` in `_quarto.yml` (appended after any filters already there), and writes the two options you may want to change when the file has none: Prefer a folder to a command? Download `carmar-quarto.zip` from and unzip it inside the project: it creates the same `_extensions/carmar/` folder. Then add `- carmar` under `filters:` in `_quarto.yml` yourself (`quarto add https://lacarm.com/carmar/carmar-quarto.zip` does the copy too). ```yaml carmar: port: 4747 label: Run on my computer ``` The port is the loopback port a reader's kernel will listen on; leave it at 4747 unless something else on readers' machines owns that port. The label is the text of the Run button. A `_quarto.yml` that `use_publishing()` cannot edit safely (an inline `filters: [...]` list) is left as it was and the lines to add are printed. Render and publish as you always do: ```sh quarto render quarto publish ``` Before publishing, or after, check the rendered output: ```{r} carmar::check_publishing("_site") # a book renders to "_book" ``` One row per page: `port` is `NA` for a page rendered without the filter, and `assets` is `FALSE` when the page references the runtime script and stylesheet but they are not beside it - which is what happens when a site is uploaded without its `site_libs` directory. A chunk that should be shown but never offered to run goes in a div with the class `carmar-no-run`: ````markdown ::: {.carmar-no-run} ```{r} unlink("~", recursive = TRUE) # example only ``` ::: ```` If the site sets its own Content Security Policy, allow the loopback socket the page dials, on the port you chose: ``` connect-src ws://127.0.0.1:4747 ``` ## Pages that are already rendered A report rendered years ago by R Markdown, a bookdown `_book/`, a pkgdown article: none of them needs rendering again. One tag before `` loads the runtime, which gives every R block a Run button and the strip at the top: ```{r} carmar::make_runnable("report.html") # one file carmar::make_runnable("_book") # every .html under a folder, once ``` By default the page loads the runtime from CarmaR's published copy; pass `assets = "local"` to copy the two files beside the pages instead. The tag is inserted once; calling it again changes nothing. ## Any page at all A reader can make a page runnable that its author never touched: a bookmark whose address is the one-line script at injects the runtime on click. The kernel treats the site like any other — approved once per session in the consent tab, code run only on Run — so no author cooperation is needed, only a site whose Content-Security-Policy allows the script. ## The reader The reader needs R and this package: ```{r} install.packages("carmar") carmar::listen("https://book.example") ``` `listen()` starts a headless kernel on the page's port and approves that one site - scheme and host, nothing more - for the kernel's lifetime. It prints one line: ``` CarmaR is listening on port 4747 for https://book.example - open the page and press Run. ``` Then the reader opens the page and presses Run. The chunk's output appears under the chunk, from their own R, with their own packages and files. If `listen()` is called without a site, the page's first Run opens a local consent page naming the site, and the reader approves it there. Either way a site is never trusted because it asked: approval is per exact origin, per kernel, and ends when the kernel stops. The browser may also ask, once, for permission for the site to reach the local network; that is the browser's own question, and answering yes lets the page reach `127.0.0.1` and nothing else. This is execution, not a sandbox. What a reader runs has the same access as their own R console, so authors keep the code visible and readers read a chunk before running it. To see and stop what is running: ```{r} carmar::sessions() carmar::stop_kernel(4747) ```