yihui / knitr

A general-purpose tool for dynamic report generation in R
https://yihui.org/knitr/
2.36k stars 873 forks source link

Improve support for knitr::spin(format = 'qmd') #2320

Closed kylebutts closed 3 months ago

kylebutts commented 5 months ago

The approach taken here had the goal of not touching the original spin code, so that this only impacts format = 'qmd' and did so as simply as possible.

To do this, I find the any code chunk that starts with #| and prepend a # %% for the previous line. This prevents converting each option passed with #| from creating a new chunk.

Perhaps this could be integrated more deeply with how knitr::spin works, but this is the simplest solution.

@cderv

kylebutts commented 5 months ago

Example:

library(devtools)
load_all()

spin_w_tempfile = function(..., format = "Rmd") {
  tmp = tempfile(fileext = ".R")
  writeLines(c(...), tmp)
  spinned = spin(tmp, knit = FALSE, format = format)
  result = readLines(spinned)
  file.remove(c(tmp, spinned))
  result
}

print_result = function(s) {
  cat(paste0(s, collapse = "\n"))
}

block = c(
  "# %% ",
  "#| echo: false",
  "#| message: false",
  "#| include: false",
  "1+1 ",
  "#| eval: false",
  "1+1",
  "",
  "#' # Header",
  "#' Text",
  "#| include: false",
  "1+1"
)

block |> process_block_for_qmd() |> print_result()
#> # %% 
#> #| echo: false
#> #| message: false
#> #| include: false
#> 1+1 
#> # %%
#> #| eval: false
#> 1+1
#> 
#> #' # Header
#> #' Text
#> # %%
#> #| include: false
#> 1+1
kylebutts commented 5 months ago

Correct on both points @yihui! The rle solution is nice, thank you.

yihui commented 3 months ago

I forgot to mention that I remove the limitation to qmd, i.e., this idea should work for any formats (Rnw, Rhtml, etc.). That's because the #| comments are not special to qmd. They work for all knitr document formats.

block = c(
  "# %% ",
  "#| echo: false",
  "#| message: false",
  "#| include: false",
  "1+1 ",
  "#| eval: false",
  "1+1",
  "",
  "#' # Header",
  "#' Text",
  "#| include: false",
  "1+1"
)

cat(spin(text = block, knit = FALSE), sep = '\n')
```{r}
#| echo: false
#| message: false
#| include: false
1+1 
#| eval: false
1+1

Header

Text

#| include: false
1+1

```r
cat(spin(text = block, knit = FALSE, format = 'Rnw'), sep = '\n')
\documentclass{article}
\begin{document}

<<>>=
#| echo: false
#| message: false
#| include: false
1+1 
@
<<>>=
#| eval: false
1+1
@

# Header
Text

<<>>=
#| include: false
1+1
@

\end{document}