Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Added
* knitr engines now print compile errors if chunk option `error = TRUE` ([#546](https://github.com/extendr/rextendr/pull/546))
* knitr engines now return early rather than compiling when `eval = FALSE` ([#548](https://github.com/extendr/rextendr/pull/548))

## Fixed
* The `libgcc_eh` mock in the `Makevars.win.in` template moved from the cargo
Expand Down
43 changes: 21 additions & 22 deletions R/knitr_engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,40 @@ eng_extendrsrc <- function(options) {
eng_impl(options, rust_source)
}


eng_impl <- function(options, extendr_engine) {
if (!requireNamespace("knitr", quietly = TRUE)) {
cli::cli_abort(
"The {.pkg knitr} package is required to run the extendr chunk engine.",
class = "rextendr_error"
)
rlang::check_installed("knitr")

# code to output to html
code_out <- glue_collapse(options$code, sep = "\n")

# wrap up source code in rust syntax
options$engine <- "rust"

# default chunk output
out <- ""
# skip compilation when eval is false
if (isFALSE(options$eval)) {
return(knitr::engine_output(options, code_out, out))
}

if (!is.null(options$preamble)) {
code <- c(
lapply(options$preamble, function(x) knitr::knit_code$get(x)),
recursive = TRUE
)
code <- c(code, options$code)
# code to compile
if (!rlang::is_null(options$preamble)) {
code <- c(unlist(knitr::knit_code$get(options$preamble)), options$code)
} else {
code <- options$code
}

code <- glue_collapse(code, sep = "\n") # code to compile
code_out <- glue_collapse(options$code, sep = "\n") # code to output to html
code <- glue_collapse(code, sep = "\n")

# engine.opts is a list of arguments to be passed to rust_eval, e.g.
# engine.opts = list(dependencies = list(`pulldown-cmark` = "0.8"))
opts <- options$engine.opts

if (!is.environment(opts$env)) {
# default env is knit_global()
# default env is knit_global()
if (!rlang::is_environment(opts$env)) {
opts$env <- knitr::knit_global()
}

# try to compile
cli::cli_alert_success("Compiling Rust extendr code chunk...")
compiled_code <- rlang::try_fetch(
do.call(extendr_engine, c(list(code = code), opts)),
Expand All @@ -58,12 +61,9 @@ eng_impl <- function(options, extendr_engine) {
}
)

out <- ""

# if compilation succeeded (and code should be evaluated)
if (isTRUE(options$eval) && rlang::is_function(compiled_code)) {
if (rlang::is_function(compiled_code)) {
cli::cli_alert_success("Evaluating Rust extendr code chunk...")

out <- utils::capture.output({
result <- withVisible(
compiled_code()
Expand All @@ -79,6 +79,5 @@ eng_impl <- function(options, extendr_engine) {
out <- cli::ansi_strip(compiled_code$stderr)
}

options$engine <- "rust" # wrap up source code in rust syntax
knitr::engine_output(options, code_out, out)
}
12 changes: 12 additions & 0 deletions tests/testthat/test-knitr-engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,15 @@ test_that("knitr-engine surfaces cargo errors", {
options$error <- FALSE
expect_error(eng_extendrsrc(options), class = "system_command_status_error")
})

test_that("knitr-engine does not compile when eval = FALSE", {
skip_if_not_installed("knitr")

options <- knitr::opts_chunk$merge(list(
code = "not valid rust",
eval = FALSE
))

expect_equal(eng_extendr(options), "not valid rust")
expect_equal(eng_extendrsrc(options), "not valid rust")
})
Loading