1#' Define an R Markdown output format 2#' 3#' Define an R Markdown output format based on a combination of knitr and pandoc 4#' options. 5#' 6#' @param knitr Knitr options for an output format (see 7#' \code{\link{knitr_options}}) 8#' @param pandoc Pandoc options for an output format (see 9#' \code{\link{pandoc_options}}) 10#' @param keep_md Keep the markdown file generated by knitting. Note that 11#' if this is \code{TRUE} then \code{clean_supporting} will always be 12#' \code{FALSE}. 13#' @param clean_supporting Cleanup any supporting files after conversion see 14#' \code{\link{render_supporting_files}} 15#' @param df_print Method to be used for printing data frames. Valid values 16#' include "default", "kable", "tibble", and "paged". The "default" method uses 17#' \code{print.data.frame}. The "kable" method uses the 18#' \code{\link[knitr:kable]{knitr::kable}} function. The "tibble" method uses 19#' the \pkg{tibble} package to print a summary of the data frame. The "paged" 20#' method creates a paginated HTML table (note that this method is only valid 21#' for formats that produce HTML). In addition 22#' to the named methods you can also pass an arbitrary function to be used 23#' for printing data frames. You can disable the df_print behavior entirely 24#' by setting the option \code{rmarkdown.df_print} to \code{FALSE}. 25#' @param pre_knit An optional function that runs before kniting which 26#' receives the \code{input} (input filename passed to \code{render}) and 27#' \code{...} (for future expansion) arguments. 28#' @param post_knit An optional function that runs after kniting which 29#' receives the \code{metadata}, \code{input_file}, \code{runtime}, and \code{...} 30#' (for future expansion) arguments. This function can return additional 31#' arguments to pass to pandoc and can call \code{knitr::knit_meta_add} 32#' to add additional dependencies based on the contents of the input_file or on other 33#' assets side by side with it that may be used to produce html with dependencies 34#' during subsequent processing. 35#' @param pre_processor An optional pre-processor function that receives the 36#' \code{metadata}, \code{input_file}, \code{runtime}, \code{knit_meta}, 37#' \code{files_dir}, and \code{output_dir} and can return additional arguments 38#' to pass to pandoc. 39#' @param intermediates_generator An optional function that receives the 40#' original \code{input_file}, its \code{encoding}, and the intermediates 41#' directory (i.e. the \code{intermediates_dir} argument to 42#' \code{\link{render}}). The function should generate and return the names of 43#' any intermediate files required to render the \code{input_file}. 44#' @param post_processor An optional post-processor function that receives the 45#' \code{metadata}, \code{input_file}, \code{output_file}, \code{clean}, 46#' and \code{verbose} parameters, and can return an alternative 47#' \code{output_file}. 48#' @param on_exit A function to call when \code{rmarkdown::render()} finishes 49#' execution (as registered with a \code{\link{on.exit}} handler). 50#' @param base_format An optional format to extend. 51#' 52#' @return An R Markdown output format definition that can be passed to 53#' \code{\link{render}}. 54#' 55#' @seealso \link{render}, \link{knitr_options}, \link{pandoc_options} 56#' 57#' @examples 58#' \dontrun{ 59#' output_format(knitr = knitr_options(opts_chunk = list(dev = 'png')), 60#' pandoc = pandoc_options(to = "html")) 61#' } 62#' 63#' @export 64output_format <- function(knitr, 65 pandoc, 66 keep_md = FALSE, 67 clean_supporting = TRUE, 68 df_print = NULL, 69 pre_knit = NULL, 70 post_knit = NULL, 71 pre_processor = NULL, 72 intermediates_generator = NULL, 73 post_processor = NULL, 74 on_exit = NULL, 75 base_format = NULL) { 76 77 format <- list( 78 knitr = knitr, 79 pandoc = pandoc, 80 keep_md = keep_md, 81 clean_supporting = clean_supporting && !keep_md, 82 df_print = df_print, 83 pre_knit = pre_knit, 84 post_knit = post_knit, 85 pre_processor = pre_processor, 86 intermediates_generator = intermediates_generator, 87 post_processor = post_processor, 88 on_exit = on_exit 89 ) 90 91 class(format) <- "rmarkdown_output_format" 92 93 # if a base format was supplied, merge it with the format we just created 94 if (!is.null(base_format)) 95 merge_output_formats(base_format, format) 96 else 97 format 98} 99 100# merges two scalar values; picks the overlay if non-NULL and then the base 101merge_scalar <- function(base, overlay) { 102 if (is.null(base) && is.null(overlay)) 103 NULL 104 else if (is.null(overlay)) 105 base 106 else 107 overlay 108} 109 110# merges two functions: if both are non-NULL, produces a new function that 111# invokes each and then uses the supplied operation to combine their outputs 112merge_function_outputs <- function(base, overlay, op) { 113 if (!is.null(base) && !is.null(overlay)) { 114 function(...) { 115 op(base(...), overlay(...)) 116 } 117 } else { 118 merge_scalar(base, overlay) 119 } 120} 121 122# merges two post-processors; if both are non-NULL, produces a new function that 123# calls the overlay post-processor and then the base post-processor. 124merge_post_processors <- function(base, overlay) { 125 if (!is.null(base) && !is.null(overlay)) { 126 function(metadata, input_file, output_file, ...) { 127 output_file <- overlay(metadata, input_file, output_file, ...) 128 base(metadata, input_file, output_file, ...) 129 } 130 } 131 else { 132 merge_scalar(base, overlay) 133 } 134} 135 136# merges two output formats 137merge_output_formats <- function(base, overlay) { 138 structure(list( 139 knitr = merge_lists(base$knitr, overlay$knitr), 140 pandoc = merge_pandoc_options(base$pandoc, overlay$pandoc), 141 keep_md = 142 merge_scalar(base$keep_md, overlay$keep_md), 143 clean_supporting = 144 merge_scalar(base$clean_supporting, overlay$clean_supporting), 145 df_print = 146 merge_scalar(base$df_print, overlay$df_print), 147 pre_knit = 148 merge_function_outputs(base$pre_knit, overlay$pre_knit, c), 149 post_knit = 150 merge_function_outputs(base$post_knit, overlay$post_knit, c), 151 pre_processor = 152 merge_function_outputs(base$pre_processor, overlay$pre_processor, c), 153 intermediates_generator = 154 merge_function_outputs(base$intermediates_generator, 155 overlay$intermediates_generator, c), 156 post_processor = 157 merge_post_processors(base$post_processor, overlay$post_processor), 158 on_exit = 159 merge_on_exit(base$on_exit, overlay$on_exit) 160 ), class = "rmarkdown_output_format") 161} 162 163merge_on_exit <- function(base, overlay) { 164 function() { 165 if (is.function(base)) base() 166 if (is.function(overlay)) overlay() 167 } 168} 169 170merge_pandoc_options <- function(base, overlay) { 171 res <- merge_lists(base, overlay, recursive = FALSE) 172 res$args <- c(base$args, overlay$args) 173 res 174} 175 176#' Knitr options for an output format 177#' 178#' Define the knitr options for an R Markdown output format. 179#' 180#' @param opts_knit List of package level knitr options (see 181#' \code{\link[knitr:opts_knit]{opts_knit}}) 182#' @param opts_chunk List of chunk level knitr options (see 183#' \code{\link[knitr:opts_chunk]{opts_chunk}}) 184#' @param knit_hooks List of hooks for R code chunks, inline R code, and output 185#' (see \code{\link[knitr:knit_hooks]{knit_hooks}}) 186#' @param opts_hooks List of hooks for code chunk options 187#' (see \code{\link[knitr:opts_hooks]{opts_hooks}}) 188#' @param opts_template List of templates for chunk level knitr options (see 189#' \code{\link[knitr:opts_template]{opts_template}}) 190#' 191#' @return An list that can be passed as the \code{knitr} argument of the 192#' \code{\link{output_format}} function. 193#' 194#' @seealso \link{output_format} 195#' 196#' @export 197knitr_options <- function(opts_knit = NULL, 198 opts_chunk = NULL, 199 knit_hooks = NULL, 200 opts_hooks = NULL, 201 opts_template = NULL) { 202 list(opts_knit = opts_knit, 203 opts_chunk = opts_chunk, 204 knit_hooks = knit_hooks, 205 opts_hooks = opts_hooks, 206 opts_template = opts_template) 207} 208 209#' Knitr options for a PDF output format 210#' 211#' Define knitr options for an R Markdown output format that creates PDF output. 212#' 213#' @inheritParams html_document 214#' @inheritParams pdf_document 215#' 216#' @return An list that can be passed as the \code{knitr} argument of the 217#' \code{\link{output_format}} function. 218#' 219#' @seealso \link{knitr_options}, \link{output_format} 220#' 221#' @export 222knitr_options_pdf <- function(fig_width, fig_height, fig_crop, dev = 'pdf') { 223 224 # default options 225 opts_knit <- NULL 226 opts_chunk <- list(dev = dev, 227 fig.width = fig_width, 228 fig.height = fig_height) 229 230 # set the dingbats option for the pdf device if requried 231 if (dev == 'pdf') 232 opts_chunk$dev.args <- list(pdf = list(useDingbats = FALSE)) 233 234 knit_hooks <- NULL 235 236 # apply cropping if requested and we have pdfcrop 237 crop <- fig_crop && !is_windows() && nzchar(find_program("pdfcrop")) 238 if (crop) { 239 knit_hooks = list(crop = knitr::hook_pdfcrop) 240 opts_chunk$crop = TRUE 241 } 242 243 # return options 244 knitr_options(opts_knit = opts_knit, 245 opts_chunk = opts_chunk, 246 knit_hooks = knit_hooks) 247} 248 249 250#' Pandoc options for an output format 251#' 252#' Define the pandoc options for an R Markdown output format. 253#' 254#' @param to Pandoc format to convert to 255#' @param from Pandoc format to convert from 256#' @param args Character vector of command line arguments to pass to pandoc 257#' @param keep_tex Keep the intermediate tex file used in the conversion to PDF 258#' (applies only to 'latex' and 'beamer' target formats) 259#' @param latex_engine LaTeX engine to producing PDF output (applies only to 260#' 'latex' and 'beamer' target formats) 261#' @param ext File extension (e.g. ".tex") for output file (if \code{NULL} 262#' chooses default based on \code{to}). This is typically used to force 263#' the final output of a latex or beamer converstion to be \code{.tex} 264#' rather than \code{.pdf}. 265#' 266#' @return An list that can be passed as the \code{pandoc} argument of the 267#' \code{\link{output_format}} function. 268#' 269#' @details The \code{from} argument should be used very cautiously as it's 270#' important for users to be able to rely on a stable definition of supported 271#' markdown extensions. 272#' 273#' @seealso \link{output_format}, \link{rmarkdown_format} 274#' 275#' @export 276pandoc_options <- function(to, 277 from = rmarkdown_format(), 278 args = NULL, 279 keep_tex = FALSE, 280 latex_engine = c("pdflatex", "lualatex", "xelatex"), 281 ext = NULL) { 282 list(to = to, 283 from = from, 284 args = args, 285 keep_tex = keep_tex, 286 latex_engine = match.arg(latex_engine), 287 ext = ext) 288} 289 290#' R Markdown input format definition 291#' 292#' Compose a pandoc markdown input definition for R Markdown that can be 293#' passed as the \code{from} argument of \link{pandoc_options}. 294#' 295#' 296#' @param implicit_figures Automatically make figures from images (defaults to \code{TRUE}). 297#' @param extensions Markdown extensions to be added or removed from the 298#' default definition of R Markdown. 299#' 300#' @return Pandoc markdown format specification 301#' 302#' @details 303#' 304#' By default R Markdown is defined as all pandoc markdown extensions with 305#' the following tweaks for backward compatibility with the markdown package 306#' (+ features are added, - features are removed): 307#' 308#' \tabular{l}{ 309#' \code{+autolink_bare_uris} \cr 310#' \code{+ascii_identifier} \cr 311#' \code{+tex_math_single_backslash} \cr 312#' } 313#' 314#' 315#' For more on pandoc markdown see the \href{http://pandoc.org/README.html}{pandoc online documentation}. 316#' 317#' @examples 318#' \dontrun{ 319#' rmarkdown_format("-implicit_figures") 320#' } 321#' 322#' @seealso \link{output_format}, \link{pandoc_options} 323#' 324#' @export 325rmarkdown_format <- function(extensions = NULL) { 326 327 format <- c("markdown") 328 329 # only add extensions if the user hasn't already specified 330 # a manual override for them 331 addExtension <- function(extension) { 332 if (length(grep(extension, extensions)) == 0) 333 format <<- c(format, paste0("+", extension)) 334 } 335 336 addExtension("autolink_bare_uris") 337 addExtension("ascii_identifiers") 338 addExtension("tex_math_single_backslash") 339 340 format <- c(format, extensions, recursive = TRUE) 341 342 paste(format, collapse = "") 343} 344 345# Add the +smart extension for Pandoc >= 2.0 346smart_extension <- function(smart, extension) { 347 c(extension, if (smart && pandoc2.0()) "+smart") 348} 349 350#' Determine the default output format for an R Markdown document 351#' 352#' Read the YAML metadata (and any common _output.yml file) for the 353#' document and return the output format that will be generated by 354#' a call to \code{\link{render}}. 355#' 356#' @param input Input file (Rmd or plain markdown) 357#' @param encoding The encoding of the input file; see \code{\link{file}} 358#' 359#' @return A named list with a \code{name} value containing the format 360#' name and an \code{options} value that is a list containing all the options 361#' for the format and their values. An option's default value will be returned 362#' if the option isn't set explicitly in the document. 363#' 364#' @details 365#' 366#' This function is useful for front-end tools that require additional 367#' knowledge of the output to be produced by \code{\link{render}} (e.g. to 368#' customize the preview experience). 369#' 370#' @export 371default_output_format <- function(input, encoding = getOption("encoding")) { 372 373 # execute within the input file's directory (this emulates the way 374 # yaml front matter discovery is done within render) 375 oldwd <- setwd(dirname(tools::file_path_as_absolute(input))) 376 on.exit(setwd(oldwd), add = TRUE) 377 378 # because we're now within the same directory as the input file, 379 # we just need its basename 380 input <- basename(input) 381 382 # parse the YAML and front matter and get the explicitly set options 383 input_lines <- read_lines_utf8(input, encoding) 384 format <- output_format_from_yaml_front_matter(input_lines, encoding = encoding) 385 386 # look up the formals of the output function to get the full option list and 387 # merge against the explicitly set list 388 format_function <- eval(parse(text = format$name)) 389 format$options <- merge_lists(as.list(formals(format_function)), 390 format$options, 391 recursive = FALSE) 392 format 393} 394 395#' Resolve the output format for an R Markdown document 396#' 397#' Read the YAML metadata (and any common _output.yml file) for the 398#' document and return an output format object that can be 399#' passed to the \code{\link{render}} function. 400#' 401#' @param input Input file (Rmd or plain markdown) 402#' @param output_format Name of output format (or \code{NULL} to use 403#' the default format for the input file). 404#' @param output_options List of output options that should override the 405#' options specified in metadata. 406#' @param encoding The encoding of the input file; see \code{\link{file}} 407#' 408#' @return An R Markdown output format definition that can be passed to 409#' \code{\link{render}}. 410#' 411#' @details 412#' 413#' This function is useful for front-end tools that need to modify 414#' the default behavior of an output format. 415#' 416#' @export 417resolve_output_format <- function(input, 418 output_format = NULL, 419 output_options = NULL, 420 encoding = getOption("encoding")) { 421 422 # read the input file 423 input_lines <- read_lines_utf8(input, encoding) 424 425 # validate that the output format is either NULL or a character vector 426 if (!is.null(output_format) && !is.character(output_format)) 427 stop("output_format must be a character vector") 428 429 # resolve the output format by looking at the yaml 430 output_format <- output_format_from_yaml_front_matter(input_lines, 431 output_options, 432 output_format, 433 encoding = encoding) 434 435 # return it 436 create_output_format(output_format$name, output_format$options) 437} 438 439 440#' Determine all output formats for an R Markdown document 441#' 442#' Read the YAML metadata (and any common _output.yml file) for the 443#' document and return the output formats that will be generated by 444#' a call to \code{\link{render}}. 445#' 446#' @param input Input file (Rmd or plain markdown) 447#' @param encoding The encoding of the input file; see \code{\link{file}} 448#' 449#' @return A character vector with the names of all output formats. 450#' 451#' @details 452#' 453#' This function is useful for front-end tools that require additional 454#' knowledge of the output to be produced by \code{\link{render}} (e.g. to 455#' customize the preview experience). 456#' 457#' @export 458all_output_formats <- function(input, encoding = getOption("encoding")) { 459 enumerate_output_formats(input = input, 460 envir = parent.frame(), 461 encoding = encoding) 462 463} 464 465 466# Synthesize the output format for a document from it's YAML. If we can't 467# find an output format then we just return html_document 468output_format_from_yaml_front_matter <- function(input_lines, 469 output_options = NULL, 470 output_format_name = NULL, 471 encoding = getOption("encoding")) { 472 473 format_name <- output_format_name 474 # ensure input is the correct data type 475 if (!is_null_or_string(format_name)) { 476 stop("Unrecognized output format specified", call. = FALSE) 477 } 478 479 # parse the yaml 480 yaml_input <- parse_yaml_front_matter(input_lines) 481 482 # default to no options 483 format_options <- list() 484 485 # parse _site.yml output format if we have it 486 config <- site_config(".", encoding = encoding) 487 yaml_site <- config[["output"]] 488 489 # parse common _output.yml if we have it 490 yaml_common <- if (file.exists("_output.yml")) { 491 yaml_load_file_utf8("_output.yml") 492 } else if (file.exists("_output.yaml")) { 493 yaml_load_file_utf8("_output.yaml") 494 } 495 496 # merge _site.yml and _output.yml 497 yaml_common <- merge_output_options(yaml_site, yaml_common) 498 499 # parse output format from front-matter if we have it 500 if (length(yaml_common) || length(yaml_input[["output"]])) { 501 502 # alias the output format yaml 503 yaml_output <- yaml_input[["output"]] 504 505 # merge against common _output.yml 506 yaml_output <- merge_output_options(yaml_common, yaml_output) 507 508 # if a named format was provided then try to find it 509 if (!is.null(format_name)) { 510 511 # if this is a named element of the list then use that 512 if (format_name %in% names(yaml_output)) { 513 514 format_options <- yaml_output[[format_name]] 515 516 # otherwise this could be a heterogeneous list of characters and 517 # lists so scan for an embedded list 518 } else { 519 for (format in yaml_output) { 520 if (is.list(format) && !is.null(format[[format_name]])) 521 format_options <- format[[format_name]] 522 } 523 } 524 525 # if the options are just "default" then that's the same as empty list 526 if (identical(format_options, "default")) format_options <- list() 527 528 # no named format passed so take the first element 529 } else { 530 if (is.list(yaml_output[[1]])) { 531 # check for named list 532 if (nzchar(format_name <- names(yaml_output)[[1]])) { 533 format_options <- yaml_output[[1]] 534 # nested named list 535 } else { 536 format_name <- names(yaml_output[[1]])[[1]] 537 format_options <- yaml_output[[1]][[format_name]] 538 } 539 } else if (is.list(yaml_output) && 540 (is.null(yaml_output[[1]]) || 541 identical(yaml_output[[1]], "default"))) { 542 format_name <- names(yaml_output)[[1]] 543 544 } else { 545 format_name <- yaml_output[[1]] 546 } 547 } 548 549 # no output formats defined in the file, just take the passed format 550 # by name (or default to html_document if no named format was specified) 551 } else { 552 if (is.null(format_name)) format_name <- "html_document" 553 } 554 555 # merge any output_options passed in the call to render 556 if (!is.null(output_options)) { 557 format_options <- merge_output_options(format_options, output_options) 558 } 559 560 # return the format name and options 561 list(name = format_name, options = format_options) 562} 563 564create_output_format <- function(name, options) { 565 566 # validate the name 567 if (is.null(name)) 568 stop("The output format name must not be NULL", call. = FALSE) 569 if (name == "revealjs_presentation") 570 stop("reveal.js presentations are now located in a separate package: ", 571 "https://github.com/jjallaire/revealjs") 572 573 # lookup the function 574 output_format_func <- eval(parse(text = name)) 575 if (!is.function(output_format_func)) 576 stop("YAML output format must evaluate to a function", call. = FALSE) 577 578 # call the function 579 output_format <- do.call(output_format_func, options) 580 if (!is_output_format(output_format)) 581 stop("Format is not of class rmarkdown_output_format", call. = FALSE) 582 583 # return the format 584 output_format 585} 586 587is_output_format <- function(x) { 588 inherits(x, "rmarkdown_output_format") 589} 590 591enumerate_output_formats <- function(input, envir, encoding) { 592 593 # read the input 594 input_lines <- read_lines_utf8(input, encoding) 595 596 # if this is an R file then spin it 597 if (identical(tolower(tools::file_ext(input)), "r")) 598 input_lines <- knitr::spin(text = input_lines, knit = FALSE, envir = envir) 599 600 # parse _site.yml output format if we have it 601 config <- site_config(input, encoding = encoding) 602 if (!is.null(config) && !is.null(config[["output"]])) { 603 site_output_format_yaml <- config[["output"]] 604 } else { 605 site_output_format_yaml <- list() 606 } 607 608 # read the ymal front matter 609 yaml_front_matter <- parse_yaml_front_matter(input_lines) 610 611 # read any _output.yml 612 output_yml <- file.path(dirname(input), "_output.yml") 613 output_yaml <- file.path(dirname(input), "_output.yaml") 614 if (file.exists(output_yml)) 615 common_output_format_yaml <- yaml_load_file_utf8(output_yml) 616 else if (file.exists(output_yaml)) 617 common_output_format_yaml <- yaml_load_file_utf8(output_yaml) 618 else 619 common_output_format_yaml <- list() 620 621 # merge site and common 622 common_output_format_yaml <- merge_output_options(site_output_format_yaml, 623 common_output_format_yaml) 624 625 # parse output formats from front-matter if we have it 626 if (length(common_output_format_yaml) > 0 || 627 length(yaml_front_matter[["output"]]) > 0) { 628 629 # alias the output format yaml 630 output_format_yaml <- yaml_front_matter[["output"]] 631 632 # merge against common _output.yml 633 output_format_yaml <- merge_output_options(common_output_format_yaml, 634 output_format_yaml) 635 } 636 else { 637 output_format_yaml <- NULL 638 } 639 640 # return them by name 641 if (is.character(output_format_yaml)) { 642 output_format_yaml 643 } else if (is.list(output_format_yaml)) { 644 names(output_format_yaml) 645 } else { 646 NULL 647 } 648} 649 650#' Parse the YAML front matter from a file 651#' 652#' @inheritParams default_output_format 653#' 654#' @keywords internal 655#' @export 656yaml_front_matter <- function(input, encoding = getOption("encoding")) { 657 658 # read the input file 659 input_lines <- read_lines_utf8(input, encoding) 660 661 # parse the yaml front matter 662 parse_yaml_front_matter(input_lines) 663} 664 665parse_yaml_front_matter <- function(input_lines) { 666 667 partitions <- partition_yaml_front_matter(input_lines) 668 if (!is.null(partitions$front_matter)) { 669 front_matter <- partitions$front_matter 670 if (length(front_matter) > 2) { 671 front_matter <- front_matter[2:(length(front_matter) - 1)] 672 front_matter <- paste(front_matter, collapse = "\n") 673 validate_front_matter(front_matter) 674 parsed_yaml <- yaml_load_utf8(front_matter) 675 if (is.list(parsed_yaml)) 676 parsed_yaml 677 else 678 list() 679 } 680 else 681 list() 682 } 683 else 684 list() 685} 686 687validate_front_matter <- function(front_matter) { 688 front_matter <- trim_trailing_ws(front_matter) 689 if (grepl(":$", front_matter)) 690 stop("Invalid YAML front matter (ends with ':')", call. = FALSE) 691} 692 693 694 695partition_yaml_front_matter <- function(input_lines) { 696 697 validate_front_matter <- function(delimiters) { 698 if (length(delimiters) >= 2 && 699 (delimiters[2] - delimiters[1] > 1) && 700 grepl("^---\\s*$", input_lines[delimiters[1]])) { 701 # verify that it's truly front matter (not preceded by other content) 702 if (delimiters[1] == 1) 703 TRUE 704 else 705 is_blank(input_lines[1:delimiters[1] - 1]) 706 } else { 707 FALSE 708 } 709 } 710 711 # is there yaml front matter? 712 delimiters <- grep("^(---|\\.\\.\\.)\\s*$", input_lines) 713 if (validate_front_matter(delimiters)) { 714 715 front_matter <- input_lines[(delimiters[1]):(delimiters[2])] 716 717 input_body <- c() 718 719 if (delimiters[1] > 1) 720 input_body <- c(input_body, 721 input_lines[1:delimiters[1] - 1]) 722 723 if (delimiters[2] < length(input_lines)) 724 input_body <- c(input_body, 725 input_lines[-(1:delimiters[2])]) 726 727 list(front_matter = front_matter, 728 body = input_body) 729 } 730 else { 731 list(front_matter = NULL, 732 body = input_lines) 733 } 734} 735 736merge_output_options <- function(base_options, overlay_options) { 737 738 # if either one of these is a character vector then normalize to a named list 739 normalize_list <- function(target) { 740 if (is.null(target)) { 741 list() 742 } else if (is.character(target)) { 743 setNames(lapply(target, function(x) list()), target) 744 } else { 745 target[names(target) != "..."] # remove symbols (...) from list 746 } 747 } 748 749 merge_lists(normalize_list(base_options), normalize_list(overlay_options)) 750} 751 752is_pandoc_to_html <- function(options) { 753 identical(options$to, "html") || identical(options$to, "html5") 754} 755 756citeproc_required <- function(yaml_front_matter, input_lines = NULL) { 757 ( 758 is.null(yaml_front_matter$citeproc) || 759 yaml_front_matter$citeproc 760 ) && ( 761 !is.null(yaml_front_matter$bibliography) || 762 !is.null(yaml_front_matter$references) || 763 length(grep("^references\\:\\s*$", input_lines)) > 0 764 ) 765} 766