execute <- function(
input,
format,
tempDir,
libDir,
dependencies,
cwd,
params,
resourceDir,
handledLanguages,
markdown
) {
knit_root_dir <- if (!is.null(cwd)) {
tools::file_path_as_absolute(cwd)
} else {
NULL
}
oldwd <- setwd(dirname(rmarkdown:::abs_path(input)))
on.exit(setwd(oldwd), add = TRUE)
input <- basename(input)
rmd_input <- paste0(xfun::sans_ext(input), ".rmarkdown")
xfun::write_utf8(
xfun::read_utf8(textConnection(markdown, encoding = "UTF-8")),
rmd_input
)
input <- rmd_input
rmd_input_path <- rmarkdown:::abs_path(rmd_input)
on.exit(unlink(rmd_input_path), add = TRUE)
knitr::knit_engines$set(ojs = function(options) {
knitr:::one_string(c(
"```{ojs}",
options$yaml.code,
options$code,
"```"
))
})
langs = lapply(
setNames(handledLanguages, handledLanguages),
function(lang) {
function(options) {
knitr:::one_string(c(
paste0("```{", lang, "}"),
options$yaml.code,
options$code,
"```"
))
}
}
)
knitr::knit_engines$set(langs)
r_options <- format$metadata$`r-options`
if (!is.null(r_options)) {
do.call(options, r_options)
}
if (is_dashboard_output(format)) {
if (is.na(getOption("DT.options", NA))) {
options(
DT.options = list(
bPaginate = FALSE,
dom = "ifrt",
language = list(info = "Showing _TOTAL_ entries")
)
)
}
}
knitr <- knitr_options(format, resourceDir, handledLanguages)
knitr <- knitr_options_with_cache(input, format, knitr)
apply_responsive_patch(format)
post_knit <- function(...) {
if (is_shiny_prerendered(knitr::opts_knit$get("rmarkdown.runtime"))) {
code <- readLines(file.path(resourceDir, "rmd", "ojs.R"))
rmarkdown::shiny_prerendered_chunk("server-extras", code, TRUE)
}
if (is_html_prefered(format) || is_pandoc_to_format(format, c("native"))) {
render_env <- parent.env(parent.frame())
render_env$front_matter$always_allow_html <- TRUE
}
NULL
}
df_print <- format$execute$`df-print`
if (
df_print == "paged" &&
!is_pandoc_html_format(format) &&
!is_html_prefered(format)
) {
df_print <- "kable"
}
output_format <- rmarkdown::output_format(
knitr = knitr,
pandoc = pandoc_options(format),
post_knit = post_knit,
keep_md = FALSE,
clean_supporting = TRUE,
df_print = df_print
)
needs_ojs <- grepl("(\n|^)[[:space:]]*```+\\{ojs[^}]*\\}", markdown)
if (
!is_shiny_prerendered(knitr::opts_knit$get("rmarkdown.runtime")) &&
needs_ojs
) {
local({
.quarto_tools_env <- attach(NULL, name = "tools:quarto")
source(file.path(resourceDir, "rmd", "ojs_static.R"), local = TRUE)
assign("ojs_define", ojs_define, envir = .quarto_tools_env)
})
}
env <- globalenv()
env$.QuartoInlineRender <- function(v) {
if (is.null(v)) {
"NULL"
} else if (inherits(v, "AsIs")) {
v
} else if (is.character(v)) {
gsub(
pattern = "(\\[|\\]|[`*_{}()>#+-.!])",
x = v,
replacement = "\\\\\\1"
)
} else {
v
}
}
render_output <- rmarkdown::render(
input = input,
output_format = output_format,
knit_root_dir = knit_root_dir,
params = params,
run_pandoc = FALSE,
envir = env
)
knit_meta <- attr(render_output, "knit_meta")
files_dir <- attr(render_output, "files_dir")
intermediates_dir <- attr(render_output, "intermediates_dir")
output_file <- file.path(dirname(input), render_output)
preserved <- extract_preserve_chunks(output_file, format)
supporting <- if (
!is.null(intermediates_dir) && file_test("-d", intermediates_dir)
) {
rmarkdown:::abs_path(intermediates_dir)
} else {
character()
}
if (df_print == "paged") {
knit_meta <- append(
knit_meta,
list(rmarkdown::html_dependency_pagedtable())
)
}
if (dependencies) {
engineDependencies <- NULL
includes <- pandoc_includes(
input,
format,
output_file,
ifelse(!is.null(libDir), libDir, files_dir),
knit_meta,
tempDir
)
} else {
includes <- NULL
engineDependencies = list(
knitr = I(list(jsonlite::serializeJSON(knit_meta)))
)
}
if (!is.null(preserved)) {
preserve <- split(unname(preserved), names(preserved))
} else {
preserve <- NA
}
postProcess <- !identical(preserve, NA) || isTRUE(format$render$`code-link`)
markdown <- xfun::read_utf8(output_file)
unlink(output_file)
list(
engine = "knitr",
markdown = paste(markdown, collapse = "\n"),
supporting = I(supporting),
filters = I("rmarkdown/pagebreak.lua"),
includes = includes,
engineDependencies = engineDependencies,
preserve = preserve,
postProcess = postProcess
)
}
pandoc_options <- function(format) {
rmarkdown::pandoc_options(
to = format$pandoc$to,
from = format$pandoc$from,
args = c("--to", format$pandoc$to),
keep_tex = isTRUE(format$render$`keep-tex`)
)
}
knitr_options <- function(format, resourceDir, handledLanguages) {
knit_hooks <- list()
to <- format$pandoc$to
if (identical(to, "pdf")) {
to <- "latex"
}
opts_knit <- list(
quarto.version = 1,
rmarkdown.pandoc.from = format$pandoc$from,
rmarkdown.pandoc.to = to,
rmarkdown.version = 3,
rmarkdown.runtime = "static"
)
opts_chunk <- list(
fig.width = format$execute$`fig-width`,
fig.height = format$execute$`fig-height`,
fig.asp = format$execute$`fig-asp`,
dev = format$execute$`fig-format`,
dpi = format$execute$`fig-dpi`,
eval = format$execute[["eval"]],
error = format$execute[["error"]],
echo = !isFALSE(format$execute[["echo"]]),
fenced.echo = identical(format$execute[["echo"]], "fenced"),
warning = isTRUE(format$execute[["warning"]]),
message = isTRUE(format$execute[["warning"]]),
include = isTRUE(format$execute[["include"]]),
comment = NA
)
if (isFALSE(format$execute[["output"]])) {
opts_chunk$results <- "hide"
opts_chunk$fig.show <- "hide"
opts_chunk$warning <- FALSE
opts_chunk$message <- FALSE
} else if (identical(format$execute[["output"]], "asis")) {
opts_chunk$results <- "asis"
}
if (is_html_prefered(format)) {
opts_chunk$screenshot.force <- FALSE
}
if (opts_chunk$dev == "retina") {
opts_chunk$dev <- "png"
opts_chunk$fig.retina = 2
}
if (opts_chunk$dev == 'pdf') {
opts_chunk$dev.args <- list(pdf = list(useDingbats = FALSE))
if (has_crop_tools(FALSE)) {
knit_hooks$crop <- function(before, options, envir) {
if (isTRUE(options$crop)) {
knitr::hook_pdfcrop(before, options, envir)
}
}
opts_chunk$crop <- TRUE
}
}
opts_chunk$ft.shadow <- FALSE
knitr <- list()
if (is.list(format$metadata$knitr)) {
knitr <- format$metadata$knitr
}
hooks <- knitr_hooks(format, resourceDir, handledLanguages)
rmarkdown::knitr_options(
opts_knit = rmarkdown:::merge_lists(opts_knit, knitr$opts_knit),
opts_chunk = rmarkdown:::merge_lists(opts_chunk, knitr$opts_chunk),
opts_hooks = hooks$opts,
knit_hooks = rmarkdown:::merge_lists(knit_hooks, hooks$knit)
)
}
knitr_options_with_cache <- function(input, format, opts) {
cache <- format$execute$`cache`
if (!is.null(cache)) {
if (identical(cache, "refresh")) {
cache_dir <- knitr_cache_dir(input, format)
if (rmarkdown:::dir_exists(cache_dir)) {
unlink(cache_dir, recursive = TRUE)
}
cache <- TRUE
}
opts$opts_chunk$cache <- isTRUE(cache)
if (identical(cache, FALSE)) {
opts$opts_hooks$cache <- function(options) {
options$cache <- FALSE
options
}
}
}
opts
}
knitr_cache_dir <- function(input, format) {
pandoc_to <- format$pandoc$to
base_pandoc_to <- gsub('[-+].*', '', pandoc_to)
if (base_pandoc_to == 'html4') {
base_pandoc_to <- 'html'
}
cache_dir <- rmarkdown:::knitr_cache_dir(input, base_pandoc_to)
cache_dir <- gsub("/$", "", cache_dir)
cache_dir
}
pandoc_includes <- function(
input,
format,
output,
files_dir,
knit_meta,
tempDir
) {
dependencies <- dependencies_from_render(input, files_dir, knit_meta, format)
if (!is.null(dependencies$shiny)) {
rmarkdown:::shiny_prerendered_append_dependencies(
output,
dependencies$shiny,
files_dir,
dirname(input)
)
}
includes <- apply_patches(format, dependencies$includes)
create_pandoc_includes(includes, tempDir)
}
dependencies_from_render <- function(input, files_dir, knit_meta, format) {
front_matter <- rmarkdown::yaml_front_matter(input)
runtime <- front_matter$runtime
server <- front_matter[["server"]]
if (is.null(runtime)) {
if (is_shiny_prerendered(runtime, server)) {
runtime <- "shinyrmd"
} else {
runtime <- "static"
}
}
dependencies <- list()
resolver <- rmarkdown:::html_dependency_resolver
if (is_shiny_prerendered(runtime, server)) {
resolver <- function(deps) {
dependencies$shiny <<- list(
deps = deps,
packages = rmarkdown:::get_loaded_packages()
)
list()
}
}
dependencies$includes <- list()
if (is_pandoc_html_format(format) || is_html_prefered(format)) {
extras <- rmarkdown:::html_extras_for_document(
knit_meta,
runtime,
resolver,
list()
)
filteredDependencies = c("bootstrap")
if (is_dashboard_output(format)) {
bslibDepNames <- c(
"bootstrap",
"bslib-webComponents-js",
"bslib-tag-require",
"bslib-card-js",
"bslib-card-styles",
"htmltools-fill",
"bslib-value_box-styles",
"bs3compat",
"bslib-sidebar-js",
"bslib-sidebar-styles",
"bslib-page_fillable-styles",
"bslib-page_navbar-styles",
"bslib-component-js",
"bslib-component-css"
)
append(filteredDependencies, bslibDepNames)
}
extras$dependencies <- Filter(
function(dependency) !(dependency$name %in% filteredDependencies),
extras$dependencies
)
if (length(extras$dependencies) > 0) {
deps <- html_dependencies_as_string(extras$dependencies, files_dir)
dependencies$includes$in_header <- deps
}
if (is_pandoc_html_format(format)) {
ojs_defines <- rmarkdown:::flatten_dependencies(
knit_meta,
function(dep) inherits(dep, "ojs-define")
)
ojs_define_str <- knitr:::one_string(unlist(ojs_defines))
if (ojs_define_str != "") {
dependencies$includes$in_header <- knitr:::one_string(c(
dependencies$includes$in_header,
ojs_define_str
))
}
}
} else if (
is_pandoc_latex_output(format) &&
rmarkdown:::has_latex_dependencies(knit_meta)
) {
latex_dependencies <- rmarkdown:::flatten_latex_dependencies(knit_meta)
dependencies$includes$in_header <- rmarkdown:::latex_dependencies_as_string(
latex_dependencies
)
}
dependencies
}
html_dependencies_as_string <- function(dependencies, files_dir) {
if (!rmarkdown:::dir_exists(files_dir)) {
dir.create(files_dir, showWarnings = FALSE, recursive = TRUE)
}
dependencies <- lapply(
dependencies,
htmltools::copyDependencyToDir,
files_dir
)
dependencies <- lapply(dependencies, function(dependency) {
dir <- dependency$src$file
if (!is.null(dir)) {
dependency$src$file <- gsub(
"\\\\",
"/",
paste(files_dir, basename(dir), sep = "/")
)
}
dependency
})
return(htmltools::renderDependencies(
dependencies,
"file",
encodeFunc = identity
))
}
is_shiny_prerendered <- function(runtime, server = NULL) {
if (
identical(runtime, "shinyrmd") || identical(runtime, "shiny_prerendered")
) {
TRUE
} else if (identical(server, "shiny")) {
TRUE
} else if (is.list(server) && identical(server[["type"]], "shiny")) {
TRUE
} else {
FALSE
}
}
create_pandoc_includes <- function(includes, tempDir) {
pandoc <- list()
write_includes <- function(from, to) {
content <- includes[[from]]
if (!is.null(content)) {
path <- tempfile(tmpdir = tempDir)
xfun::write_utf8(content, path)
pandoc[[to]] <<- I(path)
}
}
write_includes("in_header", "include-in-header")
write_includes("before_body", "include-before-body")
write_includes("after_body", "include-after-body")
pandoc
}
extract_preserve_chunks <- function(output_file, format) {
if (is_pandoc_html_format(format)) {
extract <- htmltools::extractPreserveChunks
} else if (format$pandoc$to == "rtf") {
extract <- knitr::extract_raw_output
} else {
extract <- NULL
}
if (!is.null(extract)) {
rmarkdown:::extract_preserve_chunks(output_file, extract)
} else {
NULL
}
}
is_pandoc_to_format <- function(format, check_fmts) {
to <- gsub("[-+].*", "", format$pandoc$to)
to %in% check_fmts
}
is_pandoc_html_format <- function(format) {
knitr::is_html_output(
format$pandoc$to,
c("markdown", "epub", "gfm", "commonmark", "commonmark_x", "markua")
)
}
is_pandoc_latex_output <- function(format) {
is_pandoc_to_format(format, c("latex", "beamer", "pdf"))
}
is_pandoc_ipynb_output <- function(format) {
is_pandoc_to_format(format, c("ipynb"))
}
is_pandoc_markdown_output <- function(format) {
markdown_formats <- c(
"markdown",
"markdown_github",
"markdown_mmd",
"markdown_phpextra",
"markdown_strict",
"gfm",
"commonmark",
"commonmark_x",
"markua"
)
is_pandoc_to_format(format, markdown_formats)
}
is_html_prefered <- function(format) {
(is_pandoc_markdown_output(format) &&
isTRUE(format$render$`prefer-html`)) ||
is_pandoc_ipynb_output(format)
}
is_dashboard_output <- function(format) {
identical(format$identifier[["base-format"]], "dashboard")
}
apply_patches <- function(format, includes) {
if (format$pandoc$to %in% c("slidy", "revealjs")) {
includes <- apply_slides_patch(includes)
}
includes
}
apply_slides_patch <- function(includes) {
slides_js <- '
<script>
// htmlwidgets need to know to resize themselves when slides are shown/hidden.
// Fire the "slideenter" event (handled by htmlwidgets.js) when the current
// slide changes (different for each slide format).
(function () {
// dispatch for htmlwidgets
function fireSlideEnter() {
const event = window.document.createEvent("Event");
event.initEvent("slideenter", true, true);
window.document.dispatchEvent(event);
}
function fireSlideChanged(previousSlide, currentSlide) {
fireSlideEnter();
// dispatch for shiny
if (window.jQuery) {
if (previousSlide) {
window.jQuery(previousSlide).trigger("hidden");
}
if (currentSlide) {
window.jQuery(currentSlide).trigger("shown");
}
}
}
// hookup for slidy
if (window.w3c_slidy) {
window.w3c_slidy.add_observer(function (slide_num) {
// slide_num starts at position 1
fireSlideChanged(null, w3c_slidy.slides[slide_num - 1]);
});
}
})();
</script>
'
includes$after_body <- paste0(includes$after_body, slides_js)
includes
}
apply_responsive_patch <- function(format) {
if (isTRUE(format$metadata[["fig-responsive"]])) {
if (requireNamespace("htmlwidgets", quietly = TRUE)) {
htmlwidgets_resolveSizing <- htmlwidgets:::resolveSizing
resolveSizing <- function(x, sp, standalone, knitrOptions = NULL) {
sizing <- htmlwidgets_resolveSizing(x, sp, standalone, knitrOptions)
if (
isTRUE(sp$knitr$figure) &&
is.numeric(sizing$height) &&
is.numeric(sizing$width)
) {
sizing$height <- paste0(
as.integer(sizing$height / sizing$width * 650),
"px"
)
sizing$width <- "100%"
}
sizing
}
assignInNamespace("resolveSizing", resolveSizing, ns = "htmlwidgets")
}
}
}
`%||%` <- function(x, y) {
if (is.null(x)) y else x
}
has_crop_tools <- function(warn = TRUE) {
if (packageVersion("knitr") >= "1.44") {
return(knitr:::has_crop_tools(warn))
}
tools <- c(
pdfcrop = unname(rmarkdown:::find_program("pdfcrop")),
ghostscript = unname(tools::find_gs_cmd())
)
missing <- tools[tools == ""]
if (length(missing) == 0) {
return(TRUE)
}
x <- paste0(names(missing), collapse = ", ")
if (warn) {
warning(
sprintf("\nTool(s) not installed or not in PATH: %s", x),
"\n-> As a result, figure cropping will be disabled."
)
}
FALSE
}