-
-
Notifications
You must be signed in to change notification settings - Fork 878
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve support for knitr::spin(format = 'qmd') #2320
Conversation
The approach taken here had the goal of not touching the original spin code, so that this only impa cts `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 s olution.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much! I don't have time to review this PR at the moment, but I feel the for
loops might be unnecessary if you take advantage of rle()
. Here is a short function (ninja code) that I just wrote for your reference:
# find the position of the starting `#|` in a consecutive block of `#|` comments
comment_start = function(x) {
i = startsWith(x, '#| ')
r = rle(i)
l = r$lengths
j = cumsum(l) - l + 1
j[r$values]
}
Test:
block = c(
"# %% ",
"#| echo: false",
"#| message: false",
"#| include: false",
"1+1 ",
"#| eval: false",
"1+1",
"",
"#' # Header",
"#' Text",
"#| include: false",
"1+1"
)
comment_start(block)
#> [1] 2 6 11
Then you look back one line and see if that line starts with the rc
pattern (such as # %%
). If not, add # %%
.
Correct on both points @yihui! The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just finished revising this PR. Thanks!
R/spin.R
Outdated
j = cumsum(l) - l + 1 | ||
j[r$values] | ||
} | ||
process_block_for_qmd <- function(block) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is too complicated. Essentially what we need is add # %%\n
to the lines comment_start(block)
(excluding the lines opt + 1
) in block
. Like this:
i = setdiff(comment_start(block), opt + 1)
block[i] = paste0('# %%\n', block[i])
There is no need to use loops.
I forgot to mention that I remove the limitation to 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
```
```{r}
#| eval: false
1+1
```
# Header
Text
```{r}
#| include: false
1+1
``` 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} |
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