1#' Convert a document with pandoc 2#' 3#' Convert documents to and from various formats using the pandoc utility. 4#' 5#' Supported input and output formats are described in the 6#' \href{https://pandoc.org/MANUAL.html}{pandoc user guide}. 7#' 8#' The system path as well as the version of pandoc shipped with RStudio (if 9#' running under RStudio) are scanned for pandoc and the highest version 10#' available is used. 11#' @param input Character vector containing paths to input files 12#' (files must be UTF-8 encoded) 13#' @param to Format to convert to (if not specified, you must specify 14#' \code{output}) 15#' @param from Format to convert from (if not specified then the format is 16#' determined based on the file extension of \code{input}). 17#' @param output Output file (if not specified then determined based on format 18#' being converted to). 19#' @param citeproc \code{TRUE} to run the pandoc-citeproc filter (for processing 20#' citations) as part of the conversion. 21#' @param options Character vector of command line options to pass to pandoc. 22#' @param verbose \code{TRUE} to show the pandoc command line which was executed 23#' @param wd Working directory in which code will be executed. If not 24#' supplied, defaults to the common base directory of \code{input}. 25#' @examples 26#' \dontrun{ 27#' library(rmarkdown) 28#' 29#' # convert markdown to various formats 30#' pandoc_convert("input.md", to = "html") 31#' pandoc_convert("input.md", to = "latex") 32#' 33#' # process citations 34#' pandoc_convert("input.md", to = "html", citeproc = TRUE) 35#' 36#' # add some pandoc options 37#' pandoc_convert("input.md", to = "latex", options = c("--listings")) 38#' } 39#' @export 40pandoc_convert <- function(input, 41 to = NULL, 42 from = NULL, 43 output = NULL, 44 citeproc = FALSE, 45 options = NULL, 46 verbose = FALSE, 47 wd = NULL) { 48 49 # ensure we've scanned for pandoc 50 find_pandoc() 51 52 # evaluate path arguments before changing working directory 53 force(output) 54 55 # execute in specified working directory 56 if (is.null(wd)) { 57 wd <- base_dir(input) 58 } 59 60 oldwd <- setwd(wd) 61 on.exit(setwd(oldwd), add = TRUE) 62 63 # input file and formats 64 args <- c(input) 65 if (!is.null(to)) { 66 if (to == 'html') to <- 'html4' 67 if (to == 'pdf') to <- 'latex' 68 args <- c(args, "--to", to) 69 } 70 if (!is.null(from)) 71 args <- c(args, "--from", from) 72 73 # output file 74 if (!is.null(output)) 75 args <- c(args, "--output", output) 76 77 # set pandoc stack size 78 args <- prepend_pandoc_stack_size(args) 79 80 # additional command line options 81 args <- c(args, options) 82 83 # citeproc filter if requested 84 if (citeproc) { 85 # --natbib/--biblatex conflicts with pandoc own citation processing, 86 # '--filter pandoc-citeproc' or '--citeproc' 87 args <- c(args[!args %in% c("--natbib", "--biblatex")], 88 pandoc_citeproc_args()) 89 } 90 91 # build the conversion command 92 command <- paste(quoted(pandoc()), paste(quoted(args), collapse = " ")) 93 94 # show it in verbose mode 95 if (verbose) 96 cat(command, "\n") 97 98 # run the conversion 99 with_pandoc_safe_environment({ 100 result <- system(command) 101 }) 102 if (result != 0) 103 stop2("pandoc document conversion failed with error ", result) 104 105 invisible(NULL) 106} 107 108 109#' Convert a bibliograpy file 110#' 111#' Convert a bibliography file (e.g. a BibTeX file) to an R list, JSON text, 112#' or YAML text 113#' 114#' @param file Bibliography file 115#' @param type Conversion type 116#' 117#' @return For `type = "list"`, and R list. For `type = "json"` or `type = "yaml"`, 118#' a character vector with the specified format. 119#' 120#' @export 121pandoc_citeproc_convert <- function(file, type = c("list", "json", "yaml")) { 122 123 # ensure we've scanned for pandoc 124 find_pandoc() 125 126 # resolve type 127 type <- match.arg(type) 128 129 if (pandoc_available("2.11")) { 130 bin <- pandoc() 131 to <- switch(type, 132 list = "csljson", 133 json = "csljson", 134 yaml = "markdown" 135 ) 136 args <- c(file, "-s", "-t", to) 137 } else { 138 bin <- pandoc_citeproc() 139 conversion <- switch(type, 140 list = "--bib2json", 141 json = "--bib2json", 142 yaml = "--bib2yaml" 143 ) 144 args <- c(conversion, file) 145 } 146 147 # build the conversion command 148 command <- paste(quoted(bin), paste(quoted(args), collapse = " ")) 149 150 # run the conversion 151 with_pandoc_safe_environment({ 152 result <- system(command, intern = TRUE) 153 }) 154 status <- attr(result, "status") 155 if (!is.null(status)) { 156 cat(result, sep = "\n") 157 stop("Error ", status, " occurred building shared library.") 158 } 159 160 Encoding(result) <- "UTF-8" 161 162 # convert the output if requested 163 if (type == "list") { 164 jsonlite::fromJSON(result, simplifyVector = FALSE) 165 } else { 166 result 167 } 168} 169 170#' Check pandoc availability and version 171#' 172#' Determine whether pandoc is currently available on the system (optionally 173#' checking for a specific version or greater). Determine the specific version 174#' of pandoc available. 175#' 176#' The system environment variable \samp{PATH} as well as the version of pandoc 177#' shipped with RStudio (its location is set via the environment variable 178#' \samp{RSTUDIO_PANDOC} by RStudio products like the RStudio IDE, RStudio 179#' Server, Shiny Server, and RStudio Connect, etc) are scanned for pandoc and 180#' the highest version available is used. Please do not modify the environment 181#' variable \samp{RSTUDIO_PANDOC} unless you know what it means. 182#' @param version Required version of pandoc 183#' @param error Whether to signal an error if pandoc with the required version 184#' is not found 185#' @return \code{pandoc_available} returns a logical indicating whether the 186#' required version of pandoc is available. \code{pandoc_version} returns a 187#' \code{\link[base]{numeric_version}} with the version of pandoc found. 188#' @examples 189#' \dontrun{ 190#' library(rmarkdown) 191#' 192#' if (pandoc_available()) 193#' cat("pandoc", as.character(pandoc_version()), "is available!\n") 194#' 195#' if (pandoc_available("1.12.3")) 196#' cat("required version of pandoc is available!\n") 197#' } 198#' @export 199pandoc_available <- function(version = NULL, 200 error = FALSE) { 201 202 # ensure we've scanned for pandoc 203 find_pandoc() 204 205 # check availability 206 found <- !is.null(.pandoc$dir) && (is.null(version) || .pandoc$version >= version) 207 208 msg <- c( 209 "pandoc", if (!is.null(version)) c("version", version, "or higher"), 210 "is required and was not found (see the help page ?rmarkdown::pandoc_available)." 211 ) 212 if (error && !found) stop2(paste(msg, collapse = " ")) 213 214 found 215} 216 217 218#' @rdname pandoc_available 219#' @export 220pandoc_version <- function() { 221 find_pandoc() 222 .pandoc$version 223} 224 225#' Functions for generating pandoc command line arguments 226#' 227#' Functions that assist in creating various types of pandoc command line 228#' arguments (e.g. for templates, table of contents, highlighting, and content 229#' includes). 230#' 231#' Non-absolute paths for resources referenced from the 232#' \code{in_header}, \code{before_body}, and \code{after_body} 233#' parameters are resolved relative to the directory of the input document. 234#' @inheritParams includes 235#' @param name Name of template variable to set. 236#' @param value Value of template variable (defaults to \code{true} if missing). 237#' @param toc \code{TRUE} to include a table of contents in the output. 238#' @param toc_depth Depth of headers to include in table of contents. 239#' @param highlight The name of a pandoc syntax highlighting theme. 240#' @param latex_engine LaTeX engine for producing PDF output. Options are 241#' "pdflatex", "lualatex", "xelatex", and "tectonic". 242#' @param default The highlighting theme to use if "default" 243#' is specified. 244#' @return A character vector with pandoc command line arguments. 245#' @examples 246#' \dontrun{ 247#' library(rmarkdown) 248#' 249#' pandoc_include_args(before_body = "header.htm") 250#' pandoc_include_args(before_body = "header.tex") 251#' 252#' pandoc_highlight_args("kate") 253#' 254#' pandoc_latex_engine_args("pdflatex") 255#' 256#' pandoc_toc_args(toc = TRUE, toc_depth = 2) 257#' } 258#' @name pandoc_args 259NULL 260 261#' @rdname pandoc_args 262#' @export 263pandoc_variable_arg <- function(name, 264 value) { 265 266 c("--variable", if (missing(value)) name else paste(name, "=", value, sep = "")) 267} 268 269#' @rdname pandoc_args 270#' @export 271pandoc_metadata_arg <- function(name, 272 value) { 273 274 c("--metadata", if (missing(value)) name else paste(name, "=", value, sep = "")) 275} 276 277 278#' @rdname pandoc_args 279#' @export 280pandoc_include_args <- function(in_header = NULL, 281 before_body = NULL, 282 after_body = NULL) { 283 args <- c() 284 285 for (file in in_header) 286 args <- c(args, "--include-in-header", pandoc_path_arg(file)) 287 288 for (file in before_body) 289 args <- c(args, "--include-before-body", pandoc_path_arg(file)) 290 291 for (file in after_body) 292 args <- c(args, "--include-after-body", pandoc_path_arg(file)) 293 294 args 295} 296 297#' @rdname pandoc_args 298#' @export 299pandoc_highlight_args <- function(highlight, 300 default = "tango") { 301 302 args <- c() 303 304 if (is.null(highlight)) 305 args <- c(args, "--no-highlight") 306 else { 307 if (identical(highlight, "default")) 308 highlight <- default 309 args <- c(args, "--highlight-style", highlight) 310 } 311 312 args 313} 314 315#' @rdname pandoc_args 316#' @export 317pandoc_latex_engine_args <- function(latex_engine) { 318 319 c(if (pandoc2.0()) "--pdf-engine" else "--latex-engine", 320 find_latex_engine(latex_engine)) 321} 322 323# For macOS, use a full path to the latex engine since the stripping 324# of the PATH environment variable by OSX 10.10 Yosemite prevents 325# pandoc from finding the engine in e.g. /usr/texbin 326find_latex_engine <- function(latex_engine) { 327 328 # do not need full path if latex_engine is available from PATH 329 if (!is_osx() || nzchar(Sys.which(latex_engine))) return(latex_engine) 330 # resolve path if it's not already an absolute path 331 if (!grepl("/", latex_engine) && nzchar(path <- find_program(latex_engine))) 332 latex_engine <- path 333 latex_engine 334} 335 336#' @rdname pandoc_args 337#' @export 338pandoc_toc_args <- function(toc, 339 toc_depth = 3) { 340 341 args <- c() 342 343 if (toc) { 344 args <- c(args, "--table-of-contents") 345 args <- c(args, "--toc-depth", toc_depth) 346 } 347 348 args 349} 350 351#' @section About Pandoc citeproc: 352#' For Pandoc version before 2.11, a pandoc filter \samp{pandoc-citeproc} is 353#' used. Since Pandoc 2.11, the feature is built-in and activated using 354#' \samp{--citeproc} flag. \samp{pandoc_citeproc_arg} will return the correct 355#' switches depending on the Pandoc version in use. 356#' @rdname pandoc_args 357#' @export 358pandoc_citeproc_args <- function() { 359 if (pandoc_available("2.11")) 360 "--citeproc" 361 else 362 c("--filter", pandoc_citeproc()) 363} 364 365 366#' Transform path for passing to pandoc 367#' 368#' Transform a path for passing to pandoc on the command line. Calls 369#' \code{\link[base:path.expand]{path.expand}} on all platforms. On Windows, 370#' transform it to a short path name if it contains spaces, and then convert 371#' forward slashes to back slashes (as required by pandoc for some path 372#' references). 373#' @param path Path to transform 374#' @param backslash Whether to replace forward slashes in \code{path} with 375#' backslashes on Windows. 376#' @return Transformed path that can be passed to pandoc on the command line. 377#' @export 378pandoc_path_arg <- function(path, backslash = TRUE) { 379 380 path <- path.expand(path) 381 382 # remove redundant ./ prefix if present 383 path <- sub('^[.]/', '', path) 384 385 if (is_windows()) { 386 i <- grep(' ', path) 387 if (length(i)) 388 path[i] <- utils::shortPathName(path[i]) 389 if (backslash) path <- gsub('/', '\\\\', path) 390 } 391 392 path 393} 394 395 396#' Render a pandoc template. 397#' 398#' Use the pandoc templating engine to render a text file. Substitutions are 399#' done using the \code{metadata} list passed to the function. 400#' @param metadata A named list containing metadata to pass to template. 401#' @param template Path to a pandoc template. 402#' @param output Path to save output. 403#' @param verbose \code{TRUE} to show the pandoc command line which was 404#' executed. 405#' @return (Invisibly) The path of the generated file. 406#' @export 407pandoc_template <- function(metadata, template, output, verbose = FALSE) { 408 409 tmp <- tempfile(fileext = ".md") 410 on.exit(unlink(tmp)) 411 412 cat("---\n", file = tmp) 413 cat(yaml::as.yaml(metadata), file = tmp, append = TRUE) 414 cat("---\n", file = tmp, append = TRUE) 415 cat("\n", file = tmp, append = TRUE) 416 417 pandoc_convert(tmp, "markdown", output = output, 418 options = paste0("--template=", template), 419 verbose = verbose) 420 421 invisible(output) 422} 423 424#' Create a self-contained HTML document using pandoc. 425#' 426#' Create a self-contained HTML document by base64 encoding images, 427#' scripts, and stylesheets referred by the input document. 428#' @param input Input html file to create self-contained version of. 429#' @param output Path to save output. 430#' @return (Invisibly) The path of the generated file. 431#' @export 432pandoc_self_contained_html <- function(input, output) { 433 434 # make input file path absolute 435 input <- normalizePath(input) 436 437 # ensure output file exists and make it's path absolute 438 if (!file.exists(output)) 439 file.create(output) 440 output <- normalizePath(output) 441 442 # create a simple body-only template 443 template <- tempfile(fileext = ".html") 444 on.exit(unlink(template), add = TRUE) 445 write_utf8("$body$", template) 446 447 # convert from markdown to html to get base64 encoding 448 # (note there is no markdown in the source document but 449 # we still need to do this "conversion" to get the 450 # base64 encoding) 451 452 # determine from (there are bugs in pandoc < 1.17 that 453 # cause markdown_strict to hang on very large script 454 # elements) 455 from <- if (pandoc_available("1.17")) 456 "markdown_strict" 457 else 458 "markdown" 459 460 # do the conversion 461 pandoc_convert( 462 input = input, 463 from = from, 464 output = output, 465 options = c( 466 "--self-contained", 467 "--template", template 468 ) 469 ) 470 471 invisible(output) 472} 473 474 475validate_self_contained <- function(mathjax) { 476 477 if (identical(mathjax, "local")) 478 stop2("Local MathJax isn't compatible with self_contained\n", 479 "(you should set self_contained to FALSE)") 480} 481 482pandoc_mathjax_args <- function(mathjax, 483 template, 484 self_contained, 485 files_dir, 486 output_dir) { 487 args <- c() 488 489 if (!is.null(mathjax)) { 490 491 if (identical(mathjax, "default")) { 492 if (identical(template, "default")) 493 mathjax <- default_mathjax() 494 else 495 mathjax <- NULL 496 } 497 else if (identical(mathjax, "local")) { 498 mathjax_path <- pandoc_mathjax_local_path() 499 mathjax_path <- render_supporting_files(mathjax_path, 500 files_dir, 501 "mathjax-local") 502 mathjax <- paste(normalized_relative_to(output_dir, mathjax_path), "/", 503 mathjax_config(), sep = "") 504 } 505 506 if (identical(template, "default")) { 507 args <- c(args, "--mathjax") 508 args <- c(args, "--variable", paste0("mathjax-url:", mathjax)) 509 } else if (!self_contained) { 510 args <- c(args, paste(c("--mathjax", mathjax), collapse = "=")) 511 } else { 512 warning("MathJax doesn't work with self_contained when not ", 513 "using the rmarkdown \"default\" template.", call. = FALSE) 514 } 515 516 } 517 518 args 519} 520 521 522pandoc_mathjax_local_path <- function() { 523 524 local_path <- Sys.getenv("RMARKDOWN_MATHJAX_PATH", unset = NA) 525 if (is.na(local_path)) { 526 local_path <- unix_mathjax_path() 527 if (is.na(local_path)) { 528 stop("For mathjax = \"local\", please set the RMARKDOWN_MATHJAX_PATH ", 529 "environment variable to the location of MathJax. ", 530 "On Linux systems you can also install MathJax using your ", 531 "system package manager.") 532 } else { 533 local_path 534 } 535 } else { 536 local_path 537 } 538} 539 540 541unix_mathjax_path <- function() { 542 543 if (identical(.Platform$OS.type, "unix")) { 544 mathjax_path <- "/usr/share/javascript/mathjax" 545 if (file.exists(file.path(mathjax_path, "MathJax.js"))) 546 mathjax_path 547 else 548 NA 549 } else { 550 NA 551 } 552} 553 554 555pandoc_html_highlight_args <- function(template, 556 highlight) { 557 558 args <- c() 559 560 if (is.null(highlight)) { 561 args <- c(args, "--no-highlight") 562 } 563 else if (!identical(template, "default")) { 564 if (identical(highlight, "default")) 565 highlight <- "pygments" 566 args <- c(args, "--highlight-style", highlight) 567 } 568 else { 569 highlight <- match.arg(highlight, html_highlighters()) 570 if (is_highlightjs(highlight)) { 571 args <- c(args, "--no-highlight") 572 args <- c(args, "--variable", "highlightjs=1") 573 } 574 else { 575 args <- c(args, "--highlight-style", highlight) 576 } 577 } 578 579 args 580} 581 582is_highlightjs <- function(highlight) { 583 !is.null(highlight) && (highlight %in% c("default", "textmate")) 584} 585 586#' Find the \command{pandoc} executable 587#' 588#' Searches for the \command{pandoc} executable in a few places and use the 589#' highest version found, unless a specific version is requested. 590#' @param cache Whether to search for \command{pandoc} again if a Pandoc 591#' directory containing the \command{pandoc} executable of the expected 592#' version (if provided) has been found previously. Search again if 593#' \code{cache = FALSE}. 594#' @param dir A character vector of potential directory paths under which 595#' \command{pandoc} may be found. If not provided, this function searches for 596#' \command{pandoc} from the environment variable \var{RSTUDIO_PANDOC} (the 597#' RStudio IDE will set this variable to the directory of Pandoc bundled with 598#' the IDE), the environment variable \var{PATH}, and the directory 599#' \file{~/opt/pandoc/}. 600#' @param version The version of Pandoc to look for (e.g., \code{"2.9.2.1"}). If 601#' not provided, this function searches for the highest version under the 602#' potential directories. 603#' @note Usually you do not need to install Pandoc if you use the RStudio IDE, 604#' because the IDE has bundled a version of Pandoc. If you have installed a 605#' version of Pandoc by yourself and want to use this version instead, you may 606#' use the \code{dir} argument of this function. 607#' @return A list containing the directory and version of Pandoc (if found). 608#' @export 609#' @examples rmarkdown::find_pandoc() 610#' rmarkdown::find_pandoc(dir = '~/Downloads/Pandoc') 611#' rmarkdown::find_pandoc(version = '2.7.3') 612find_pandoc <- function(cache = TRUE, dir = NULL, version = NULL) { 613 614 if (!cache) set_pandoc_info(NULL) # clear previously found pandoc path 615 if (!is.null(.pandoc$dir) && (is.null(version) || version == .pandoc$version)) 616 return(as.list(.pandoc)) 617 618 # look up pandoc in potential sources unless user has supplied `dir` 619 sources <- if (length(dir) == 0) c( 620 Sys.getenv("RSTUDIO_PANDOC"), 621 dirname(find_program("pandoc")), 622 "~/opt/pandoc" 623 ) else dir 624 sources <- path.expand(sources) 625 626 # determine the versions of the sources 627 versions <- lapply(sources, function(src) { 628 if (dir_exists(src)) get_pandoc_version(src) else numeric_version("0") 629 }) 630 631 # find the maximum version 632 found_src <- NULL 633 found_ver <- numeric_version("0") 634 for (i in seq_along(sources)) { 635 ver <- versions[[i]] 636 if ((!is.null(version) && ver == version) || (is.null(version) && ver > found_ver)) { 637 found_ver <- ver 638 found_src <- sources[[i]] 639 } 640 } 641 642 set_pandoc_info(found_src, found_ver) 643 as.list(.pandoc) 644} 645 646# Get an S3 numeric_version for the pandoc utility at the specified path 647get_pandoc_version <- function(pandoc_dir) { 648 path <- file.path(pandoc_dir, "pandoc") 649 if (is_windows()) path <- paste0(path, ".exe") 650 if (!utils::file_test("-x", path)) return(numeric_version("0")) 651 info <- with_pandoc_safe_environment( 652 system(paste(shQuote(path), "--version"), intern = TRUE) 653 ) 654 version <- strsplit(info, "\n")[[1]][1] 655 version <- strsplit(version, " ")[[1]][2] 656 numeric_version(version) 657} 658 659set_pandoc_info <- function(dir, version = if (!is.null(dir)) get_pandoc_version(dir)) { 660 .pandoc$dir <- dir 661 .pandoc$version <- version 662} 663 664# prepend pandoc stack size arguments 665prepend_pandoc_stack_size <- function(args) { 666 stack_size <- getOption("pandoc.stack.size", default = "512m") 667 c(c("+RTS", paste0("-K", stack_size), "-RTS"), args) 668} 669 670# wrap a system call to pandoc so that LC_ALL is not set 671# see: https://github.com/rstudio/rmarkdown/issues/31 672# see: https://ghc.haskell.org/trac/ghc/ticket/7344 673with_pandoc_safe_environment <- function(code) { 674 675 lc_all <- Sys.getenv("LC_ALL", unset = NA) 676 677 if (!is.na(lc_all)) { 678 Sys.unsetenv("LC_ALL") 679 on.exit(Sys.setenv(LC_ALL = lc_all), add = TRUE) 680 } 681 682 lc_ctype <- Sys.getenv("LC_CTYPE", unset = NA) 683 684 if (!is.na(lc_ctype)) { 685 Sys.unsetenv("LC_CTYPE") 686 on.exit(Sys.setenv(LC_CTYPE = lc_ctype), add = TRUE) 687 } 688 689 if (Sys.info()['sysname'] == "Linux" && 690 is.na(Sys.getenv("HOME", unset = NA))) { 691 stop("The 'HOME' environment variable must be set before running Pandoc.") 692 } 693 694 if (Sys.info()['sysname'] == "Linux" && 695 is.na(Sys.getenv("LANG", unset = NA))) { 696 # fill in a the LANG environment variable if it doesn't exist 697 Sys.setenv(LANG = detect_generic_lang()) 698 on.exit(Sys.unsetenv("LANG"), add = TRUE) 699 } 700 701 if (Sys.info()['sysname'] == "Linux" && 702 identical(Sys.getenv("LANG"), "en_US")) { 703 Sys.setenv(LANG = "en_US.UTF-8") 704 on.exit(Sys.setenv(LANG = "en_US"), add = TRUE) 705 } 706 707 force(code) 708} 709 710# if there is no LANG environment variable set pandoc is going to hang so 711# we need to specify a "generic" lang setting. With glibc >= 2.13 you can 712# specify C.UTF-8 so we prefer that. If we can't find that then we fall back 713# to en_US.UTF-8. 714detect_generic_lang <- function() { 715 716 locale_util <- Sys.which("locale") 717 718 if (nzchar(locale_util)) { 719 locales <- system(paste(locale_util, "-a"), intern = TRUE) 720 locales <- suppressWarnings( 721 strsplit(locales, split = "\n", fixed = TRUE) 722 ) 723 if ("C.UTF-8" %in% locales) 724 return("C.UTF-8") 725 } 726 727 # default to en_US.UTF-8 728 "en_US.UTF-8" 729} 730 731 732# get the path to the pandoc binary 733pandoc <- function() { 734 find_pandoc() 735 file.path(.pandoc$dir, "pandoc") 736} 737 738 739# get the path to the pandoc-citeproc binary 740pandoc_citeproc <- function() { 741 find_pandoc() 742 bin <- "pandoc-citeproc" 743 p <- file.path(.pandoc$dir, bin) 744 if (xfun::is_windows()) p <- xfun::with_ext(p, "exe") 745 if (file.exists(p)) p else bin 746} 747 748#' @rdname pandoc_args 749#' @param lua_files Character vector of file paths to Lua filter files. Paths 750#' will be transformed by \code{\link{pandoc_path_arg}}. 751#' @export 752pandoc_lua_filter_args <- function(lua_files) { 753 # Lua filters was introduced in pandoc 2.0 754 if (pandoc2.0()) c(rbind("--lua-filter", pandoc_path_arg(lua_files))) 755} 756 757 758# quote args if they need it 759quoted <- function(args) { 760 761 # some characters are legal in filenames but without quoting are likely to be 762 # interpreted by the shell (e.g. redirection, wildcard expansion, etc.) -- 763 # wrap arguments containing these characters in quotes. 764 shell_chars <- grepl(.shell_chars_regex, args) 765 args[shell_chars] <- shQuote(args[shell_chars]) 766 args 767} 768 769find_pandoc_theme_variable <- function(args) { 770 771 range <- length(args) - 1 772 773 for (i in 1:range) { 774 if (args[[i]] == "--variable" && grepl("^theme:", args[[i + 1]])) { 775 return(substring(args[[i + 1]], nchar("theme:") + 1)) 776 } 777 } 778 779 # none found, return NULL 780 NULL 781} 782 783 784# Environment used to cache the current pandoc directory and version 785.pandoc <- new.env() 786.pandoc$dir <- NULL 787.pandoc$version <- NULL 788 789pandoc2.0 <- function() { 790 pandoc_available("2.0") 791} 792 793#' Get the path of the pandoc executable 794#' 795#' Returns the path of the pandoc executable used by functions in the the 796#' \pkg{rmarkdown} package. This is the most recent version of pandoc found in 797#' either the system path or shipped with RStudio. 798#' 799#' See the 800#' \href{https://pandoc.org/MANUAL.html}{pandoc manual} 801#' for pandoc commands. 802#' 803#' @export 804pandoc_exec <- pandoc 805