Commit 2c54a5d6 authored by Andreas Tille's avatar Andreas Tille

Rebuild for stretch-backports

parents 4057b315 92f3d9de
Package: knitr
Type: Package
Title: A General-Purpose Package for Dynamic Report Generation in R
Version: 1.20
Version: 1.21
Authors@R: c(
person("Yihui", "Xie", role = c("aut", "cre"), email = "xie@yihui.name", comment = c(ORCID = "0000-0003-0645-5666")),
person("Adam", "Vogt", role = "ctb"),
......@@ -13,6 +13,7 @@ Authors@R: c(
person("Ashley", "Manton", role = "ctb"),
person("Ben", "Baumer", role = "ctb"),
person("Brian", "Diggs", role = "ctb"),
person("Brian", "Zhang", role = "ctb"),
person("Cassio", "Pereira", role = "ctb"),
person("Christophe", "Dervieux", role = "ctb"),
person("David", "Hugh-Jones", role = "ctb"),
......@@ -28,6 +29,7 @@ Authors@R: c(
person("Garrick", "Aden-Buie", role = "ctb"),
person("Gregoire", "Detrez", role = "ctb"),
person("Hadley", "Wickham", role = "ctb"),
person("Hao", "Zhu", role = "ctb"),
person("Heewon", "Jeon", role = "ctb"),
person("Henrik", "Bengtsson", role = "ctb"),
person("Hiroaki", "Yutani", role = "ctb"),
......@@ -59,6 +61,8 @@ Authors@R: c(
person(c("Kevin", "K."), "Smith", role = "ctb"),
person("Kirill", "Mueller", role = "ctb"),
person("Kohske", "Takahashi", role = "ctb"),
person("Lorenz", "Walthert", role = "ctb"),
person("Lucas", "Gallindo", role = "ctb"),
person("Martin", "Modrák", role = "ctb"),
person("Michael", "Chirico", role = "ctb"),
person("Michael", "Friendly", role = "ctb"),
......@@ -83,6 +87,7 @@ Authors@R: c(
person("Thibaut", "Assus", role = "ctb"),
person("Thibaut", "Lamadon", role = "ctb"),
person("Thomas", "Leeper", role = "ctb"),
person("Tim", "Mastny", role = "ctb"),
person("Tom", "Torsney-Weir", role = "ctb"),
person("Trevor", "Davis", role = "ctb"),
person("Viktoras", "Veitas", role = "ctb"),
......@@ -94,12 +99,13 @@ Maintainer: Yihui Xie <xie@yihui.name>
Description: Provides a general-purpose tool for dynamic report generation in R
using Literate Programming techniques.
Depends: R (>= 3.1.0)
Imports: evaluate (>= 0.10), highr, markdown, stringr (>= 0.6), yaml,
methods, tools
Imports: evaluate (>= 0.10), highr, markdown, stringr (>= 0.6), yaml
(>= 2.1.19), methods, xfun, tools
Suggests: formatR, testit, digest, rgl (>= 0.95.1201), codetools,
rmarkdown, htmlwidgets (>= 0.7), webshot, tikzDevice (>= 0.10),
tinytex, xfun, reticulate (>= 1.4), JuliaCall (>= 0.11.1), png,
jpeg, xml2, httr, DBI (>= 0.4-1), showtext, tibble
tinytex, reticulate (>= 1.4), JuliaCall (>= 0.11.1), png, jpeg,
gifski, xml2 (>= 1.2.0), httr, DBI (>= 0.4-1), showtext,
tibble, styler
License: GPL
URL: https://yihui.name/knitr/
BugReports: https://github.com/yihui/knitr/issues
......@@ -118,9 +124,9 @@ Collate: 'block.R' 'cache.R' 'utils.R' 'citation.R' 'hooks-html.R'
'template.R' 'utils-base64.R' 'utils-conversion.R'
'utils-rd2html.R' 'utils-sweave.R' 'utils-upload.R'
'utils-vignettes.R' 'zzz.R'
RoxygenNote: 6.0.1
RoxygenNote: 6.1.1
NeedsCompilation: no
Packaged: 2018-02-19 20:23:59 UTC; yihui
Packaged: 2018-12-10 22:10:14 UTC; yihui
Author: Yihui Xie [aut, cre] (<https://orcid.org/0000-0003-0645-5666>),
Adam Vogt [ctb],
Alastair Andrew [ctb],
......@@ -132,6 +138,7 @@ Author: Yihui Xie [aut, cre] (<https://orcid.org/0000-0003-0645-5666>),
Ashley Manton [ctb],
Ben Baumer [ctb],
Brian Diggs [ctb],
Brian Zhang [ctb],
Cassio Pereira [ctb],
Christophe Dervieux [ctb],
David Hugh-Jones [ctb],
......@@ -147,6 +154,7 @@ Author: Yihui Xie [aut, cre] (<https://orcid.org/0000-0003-0645-5666>),
Garrick Aden-Buie [ctb],
Gregoire Detrez [ctb],
Hadley Wickham [ctb],
Hao Zhu [ctb],
Heewon Jeon [ctb],
Henrik Bengtsson [ctb],
Hiroaki Yutani [ctb],
......@@ -179,6 +187,8 @@ Author: Yihui Xie [aut, cre] (<https://orcid.org/0000-0003-0645-5666>),
Kevin K. Smith [ctb],
Kirill Mueller [ctb],
Kohske Takahashi [ctb],
Lorenz Walthert [ctb],
Lucas Gallindo [ctb],
Martin Modrák [ctb],
Michael Chirico [ctb],
Michael Friendly [ctb],
......@@ -203,6 +213,7 @@ Author: Yihui Xie [aut, cre] (<https://orcid.org/0000-0003-0645-5666>),
Thibaut Assus [ctb],
Thibaut Lamadon [ctb],
Thomas Leeper [ctb],
Tim Mastny [ctb],
Tom Torsney-Weir [ctb],
Trevor Davis [ctb],
Viktoras Veitas [ctb],
......@@ -210,4 +221,4 @@ Author: Yihui Xie [aut, cre] (<https://orcid.org/0000-0003-0645-5666>),
Wush Wu [ctb],
Zachary Foster [ctb]
Repository: CRAN
Date/Publication: 2018-02-20 10:11:46 UTC
Date/Publication: 2018-12-10 23:00:03 UTC
This diff is collapsed.
......@@ -26,6 +26,7 @@ export(all_labels)
export(all_patterns)
export(all_rcpp_labels)
export(asis_output)
export(cache_engines)
export(clean_cache)
export(combine_words)
export(current_input)
......@@ -36,6 +37,7 @@ export(extract_raw_output)
export(fig_chunk)
export(fig_path)
export(hook_ffmpeg_html)
export(hook_gifski)
export(hook_movecode)
export(hook_optipng)
export(hook_pdfcrop)
......@@ -100,6 +102,9 @@ export(pat_textile)
export(plot_crop)
export(purl)
export(rand_seed)
export(raw_block)
export(raw_html)
export(raw_latex)
export(raw_output)
export(read_chunk)
export(read_demo)
......@@ -131,3 +136,12 @@ import(graphics)
import(methods)
import(stats)
import(utils)
importFrom(xfun,attr)
importFrom(xfun,file_ext)
importFrom(xfun,isFALSE)
importFrom(xfun,is_windows)
importFrom(xfun,loadable)
importFrom(xfun,parse_only)
importFrom(xfun,sans_ext)
importFrom(xfun,try_silent)
importFrom(xfun,with_ext)
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -72,6 +72,7 @@ call_block = function(block) {
params$engine != 'Rcpp') {
if (opts_knit$get('verbose')) message(' loading cache from ', hash)
cache$load(hash, lazy = params$cache.lazy)
cache_engine(params)
if (!params$include) return('')
if (params$cache == 3) return(cache$output(hash))
}
......@@ -108,10 +109,10 @@ block_exec = function(options) {
res.after = run_hooks(before = FALSE, options)
output = paste(c(res.before, output, res.after), collapse = '')
output = knit_hooks$get('chunk')(output, options)
if (options$cache) block_cache(
options, output,
if (options$engine == 'stan') options$engine.opts$x else character(0)
)
if (options$cache) block_cache(options, output, switch(
options$engine,
'stan' = options$output.var, 'sql' = options$output.var, character(0)
))
return(if (options$include) output else '')
}
......@@ -144,19 +145,23 @@ block_exec = function(options) {
code = options$code
echo = options$echo # tidy code if echo
if (!isFALSE(echo) && options$tidy && length(code)) {
res = try_silent(do.call(
formatR::tidy_source, c(list(text = code, output = FALSE), options$tidy.opts)
))
if (!inherits(res, 'try-error')) {
code = res$text.tidy
} else warning('failed to tidy R code in chunk <', options$label, '>\n',
'reason: ', res)
if (!isFALSE(echo) && !isFALSE(options$tidy) && length(code)) {
tidy.method = if (isTRUE(options$tidy)) 'formatR' else options$tidy
if (is.character(tidy.method)) tidy.method = switch(
tidy.method,
formatR = function(code, ...) formatR::tidy_source(text = code, output = FALSE, ...)$text.tidy,
styler = function(code, ...) unclass(styler::style_text(text = code, ...))
)
res = try_silent(do.call(tidy.method, c(list(code), options$tidy.opts)))
if (!inherits(res, 'try-error')) code = res else warning(
"Failed to tidy R code in chunk '", options$label, "'. Reason:\n", res
)
}
# only evaluate certain lines
if (is.numeric(ev <- options$eval)) {
# group source code into syntactically complete expressions
if (!options$tidy) code = sapply(highr:::group_src(code), paste, collapse = '\n')
if (isFALSE(options$tidy)) code = sapply(highr:::group_src(code), paste, collapse = '\n')
iss = seq_along(code)
code = comment_out(code, '##', setdiff(iss, iss[ev]), newline = FALSE)
}
......@@ -452,8 +457,11 @@ process_tangle = function(x) {
#' @export
process_tangle.block = function(x) {
params = opts_chunk$merge(x$params)
for (o in c('purl', 'eval', 'child'))
try(params[o] <- list(eval_lang(params[[o]])))
for (o in c('purl', 'eval', 'child')) {
if (inherits(try(params[o] <- list(eval_lang(params[[o]]))), 'try-error')) {
params[['purl']] = FALSE # if any of these options cannot be determined, don't purl
}
}
if (isFALSE(params$purl)) return('')
label = params$label; ev = params$eval
if (params$engine != 'R') return(comment_out(knit_code$get(label)))
......@@ -462,7 +470,7 @@ process_tangle.block = function(x) {
paste(unlist(cmds), collapse = '\n')
} else knit_code$get(label)
# read external code if exists
if (!isFALSE(ev) && length(code) && grepl('read_chunk\\(.+\\)', code)) {
if (!isFALSE(ev) && length(code) && any(grepl('read_chunk\\(.+\\)', code))) {
eval(parse_only(unlist(stringr::str_extract_all(code, 'read_chunk\\(([^)]+)\\)'))))
}
code = parse_chunk(code)
......
......@@ -94,7 +94,7 @@ write_bib = function(
})
}
bib = bib[sort(x)]
if (!is.null(file) && length(x)) writeUTF8(unlist(bib), file)
if (!is.null(file) && length(x)) xfun::write_utf8(unlist(bib), file)
invisible(bib)
}
......
......@@ -108,8 +108,10 @@ opts_chunk_attr = local({
opts$external = opts$sanitize = NULL # hide these two rare options
opts$fig.process = 'function'
opts$fig.asp = 'numeric'
opts$fig.dim = 'list'
opts$R.options = 'list'
opts$cache.comments = 'logical'
opts$animation.hook = list('ffmpeg', 'gifski')
opts
})
......@@ -157,8 +159,7 @@ set_alias = function(...) {
opts_knit = new_defaults(list(
progress = TRUE, verbose = FALSE, width = 75L, eval.after = 'fig.cap',
base.dir = NULL, base.url = NULL, root.dir = NULL, child.path = '',
upload.fun = identity, animation.fun = hook_ffmpeg_html,
global.device = FALSE, global.par = FALSE,
upload.fun = identity, global.device = FALSE, global.par = FALSE,
concordance = FALSE, documentation = 1L, self.contained = TRUE,
unnamed.chunk.label = 'unnamed-chunk', highr.opts = NULL,
......
......@@ -31,6 +31,26 @@
#' names(knit_engines$get())
knit_engines = new_defaults()
#' Cache engines of other languages
#'
#' This object controls how to load cached environments from languages other
#' than R (when the chunk option \code{engine} is not \code{'R'}). Each
#' component in this object is a function that takes the current path to the
#' chunk cache and loads it into the language environment.
#'
#' The cache engine function has one argument \code{options}, a list containing
#' all chunk options. Note that \code{options$hash} is the path to the current
#' chunk cache with the chunk's hash, but without any file extension, and the
#' language engine may write a cache database to this path (with an extension).
#'
#' The cache engine function should load the cache environment and should know
#' the extension appropriate for the language.
#' @references See \url{https://github.com/rstudio/reticulate/pull/167} for an
#' implementation of a cache engine for Python.
#' @export
cache_engines = new_defaults()
#' An output wrapper for language engine output
#'
#' If you have designed a language engine, you may call this function in the end
......@@ -110,10 +130,13 @@ eng_interpreted = function(options) {
stata = {
logf = sub('[.]do$', '.log', f)
on.exit(unlink(c(logf)), add = TRUE)
paste(switch(
Sys.info()[['sysname']], Windows = '/q /e do', Darwin = '-q -e do',
Linux = '-q -b do', '-q -b do'
), shQuote(normalizePath(f)))
sprintf(switch(
Sys.info()[['sysname']],
Windows = '/q /e do %s',
Darwin = paste('-q < %s >', shQuote(xfun::normalize_path(logf))),
Linux = '-q -e do %s',
'-q -b do %s'
), shQuote(normalizePath(f)))
},
f
)
......@@ -123,9 +146,10 @@ eng_interpreted = function(options) {
python = '-c', ruby = '-e', scala = '-e', sh = '-c', zsh = '-c', NULL
), shQuote(paste(options$code, collapse = '\n')))
opts = get_engine_opts(options$engine.opts, engine)
# FIXME: for these engines, the correct order is options + code + file
code = if (engine %in% c('awk', 'gawk', 'sed', 'sas'))
paste(code, options$engine.opts) else paste(options$engine.opts, code)
paste(code, opts) else paste(opts, code)
cmd = get_engine_path(options$engine.path, engine)
out = if (options$eval) {
message('running: ', cmd, ' ', code)
......@@ -145,18 +169,21 @@ eng_interpreted = function(options) {
engine_output(options, options$code, out)
}
# options$engine.path can be list(name1 = path1, name2 = path2, ...)
get_engine_path = function(path, engine) {
if (is.list(path)) path = path[[engine]]
path %n% engine
# options$engine.path can be list(name1 = path1, name2 = path2, ...); similarly,
# options$engine.opts can be list(name1 = opts1, ...)
get_engine_opts = function(opts, engine, fallback = '') {
if (is.list(opts)) opts = opts[[engine]]
opts %n% fallback
}
get_engine_path = function(path, engine) get_engine_opts(path, engine, engine)
## C and Fortran (via R CMD SHLIB)
eng_shlib = function(options) {
n = switch(options$engine, c = 'c', fortran = 'f', fortran95 = 'f95')
f = basename(tempfile(n, '.', paste0('.', n)))
writeLines(options$code, f)
on.exit(unlink(c(f, sub_ext(f, c('o', 'so', 'dll')))), add = TRUE)
on.exit(unlink(c(f, with_ext(f, c('o', 'so', 'dll')))), add = TRUE)
if (options$eval) {
out = system(paste('R CMD SHLIB', f), intern = TRUE)
dyn.load(sub(sprintf('[.]%s$', n), .Platform$dynlib.ext, f))
......@@ -178,6 +205,15 @@ eng_python = function(options) {
}
}
cache_eng_python = function(options) {
if (isFALSE(options$python.reticulate)) return()
# TODO: change this hack to reticulate::cache_eng_python(options) after
# https://github.com/rstudio/reticulate/pull/167 is merged and released
if (!'cache_eng_python' %in% ls(asNamespace('reticulate'))) return()
fun = getFromNamespace('cache_eng_python', 'reticulate')
fun(options)
}
## Java
# e.g. see http://cran.rstudio.com/package=jvmr
......@@ -265,7 +301,7 @@ eng_tikz = function(options) {
dir.create(dirname(fig), recursive = TRUE, showWarnings = FALSE)
file.rename(outf, fig)
fig2 = sub_ext(fig, ext)
fig2 = with_ext(fig, ext)
if (to_svg) {
# dvisvgm needs to be on the path
# dvisvgm for windows needs ghostscript bin dir on the path also
......@@ -276,7 +312,7 @@ eng_tikz = function(options) {
# convert to the desired output-format, calling `convert`
conv = 0
if (ext != 'pdf') {
conv = system2(options$engine.opts$convert %n% 'convert', c(
conv = system2(options$engine.opts[['convert']] %n% 'convert', c(
options$engine.opts$convert.opts, sprintf('%s %s', fig, fig2)
))
}
......@@ -308,9 +344,11 @@ eng_dot = function(options) {
}
# prepare system command
cmd = sprintf(command_string, shQuote(options$engine %n% options$engine.path),
shQuote(f), ext <- options$fig.ext %n% dev2ext(options$dev),
shQuote(paste0(fig <- fig_path(), '.', ext)))
cmd = sprintf(
command_string, shQuote(get_engine_path(options$engine.path, options$engine)),
shQuote(f), ext <- options$fig.ext %n% dev2ext(options$dev),
shQuote(paste0(fig <- fig_path(), '.', ext))
)
# generate output
dir.create(dirname(fig), recursive = TRUE, showWarnings = FALSE)
......@@ -455,7 +493,7 @@ is_sql_update_query = function(query) {
query = gsub('^\\s*--.*\n', '', query)
# remove multi-line comments
if (grepl('^\\s*\\/\\*.*', query)) query = gsub('.*\\*\\/', '', query)
grepl('^\\s*(INSERT|UPDATE|DELETE|CREATE).*', query, ignore.case = TRUE)
grepl('^\\s*(INSERT|UPDATE|DELETE|CREATE|DROP).*', query, ignore.case = TRUE)
}
# sql engine
......@@ -509,9 +547,12 @@ eng_sql = function(options) {
query = interpolate_from_env(conn, sql)
if (isFALSE(options$eval)) return(engine_output(options, query, ''))
# execute query -- when we are printing with an enforced max.print we
# use dbFetch so as to only pull down the required number of records
if (is.null(varname) && max.print > 0 && !is_sql_update_query(query)) {
if (is_sql_update_query(query)) {
DBI::dbExecute(conn, query)
data = NULL
} else if (is.null(varname) && max.print > 0) {
# execute query -- when we are printing with an enforced max.print we
# use dbFetch so as to only pull down the required number of records
res = DBI::dbSendQuery(conn, query)
data = DBI::dbFetch(res, n = max.print)
DBI::dbClearResult(res)
......@@ -520,7 +561,7 @@ eng_sql = function(options) {
}
# create output if needed (we have data and we aren't assigning it to a variable)
output = if (!is.null(data) && ncol(data) > 0 && is.null(varname)) capture.output({
output = if (length(dim(data)) == 2 && ncol(data) > 0 && is.null(varname)) capture.output({
# apply max.print to data
display_data = if (max.print == -1) data else head(data, n = max.print)
......@@ -635,6 +676,8 @@ knit_engines$set(
python = eng_python, julia = eng_julia
)
cache_engines$set(python = cache_eng_python)
get_engine = function(name) {
fun = knit_engines$get(name)
if (is.function(fun)) return(fun)
......@@ -647,6 +690,12 @@ get_engine = function(name) {
}
}
cache_engine = function(options) {
cache_fun = cache_engines$get(options$engine)
if (!is.function(cache_fun)) return()
cache_fun(options)
}
# possible values for engines (for auto-completion in RStudio)
opts_chunk_attr$engine = as.list(sort(c('R', names(knit_engines$get()))))
opts_chunk_attr[c('engine.path', 'engine.opts')] = list('character', 'character')
......@@ -18,7 +18,7 @@ hilight_source = function(x, format, options) {
} else if (options$prompt) {
# if you did not reformat or evaluate the code, I have to figure out which
# lines belong to one complete expression first (#779)
if (options$engine == 'R' && !options$tidy && isFALSE(options$eval))
if (options$engine == 'R' && isFALSE(options$tidy) && isFALSE(options$eval))
x = vapply(highr:::group_src(x), paste, character(1), collapse = '\n')
line_prompt(x)
} else x
......
......@@ -7,7 +7,7 @@ hook_plot_html = function(x, options) {
if (options$fig.show == 'animate') {
# Don't print out intermediate plots if we're animating
return(if (fig.cur < fig.num) '' else opts_knit$get('animation.fun')(x, options))
return(if (fig.cur < fig.num) '' else hook_animation(options)(x, options))
}
ai = options$fig.show == 'asis'
plot1 = ai || fig.cur <= 1L; plot2 = ai || fig.cur == fig.num
......@@ -22,6 +22,17 @@ hook_plot_html = function(x, options) {
)
}
hook_animation = function(options) {
if (is.function(fun <- options$animation.hook)) return(fun)
if (is.character(fun)) return(switch(
fun, ffmpeg = hook_ffmpeg_html, gifski = hook_gifski,
scianimator = hook_scianimator, r2swf = hook_r2swf,
stop2('Invalid value for the chunk option animation.hook: ', fun)
))
if (is.function(fun <- opts_knit$get('animation.fun'))) return(fun)
hook_ffmpeg_html
}
.img.attr = function(w, h, extra) {
paste(c(sprintf('width="%s"', w), sprintf('height="%s"', h), extra), collapse = ' ')
}
......@@ -72,8 +83,9 @@ hook_plot_html = function(x, options) {
#' Hooks to create animations in HTML output
#'
#' \code{hook_ffmpeg_html()} uses FFmpeg to convert images to a video;
#' \code{hook_scianimator()} uses the JavaScript library SciAnimator to create
#' animations; \code{hook_r2swf()} uses the \pkg{R2SWF} package.
#' \code{hook_gifski()} uses the \pkg{gifski} to convert images to a GIF
#' animation; \code{hook_scianimator()} uses the JavaScript library SciAnimator
#' to create animations; \code{hook_r2swf()} uses the \pkg{R2SWF} package.
#'
#' These hooks are mainly for the package option \code{animation.fun}, e.g. you
#' can set \code{opts_knit$set(animation.fun = hook_scianimator)}.
......@@ -93,9 +105,11 @@ hook_ffmpeg = function(x, options, format = 'webm') {
fig.fname = paste0(base, '%d', '.', x[2])
mov.fname = paste0(sub('-$', '', base), '.', format)
extra = if (format == 'webm') {
paste('-b:v', options$ffmpeg.bitrate %n% '1M', '-crf 10')
}
extra = switch(
format,
webm = paste('-b:v', options$ffmpeg.bitrate %n% '1M', '-crf 10'),
mp4 = '-pix_fmt yuv420p' # enables Safari support of .mp4
)
ffmpeg.cmd = paste(
'ffmpeg', '-y', '-r', 1 / options$interval, '-i', fig.fname, extra, mov.fname
)
......@@ -127,6 +141,31 @@ hook_ffmpeg = function(x, options, format = 'webm') {
)
}
# use gifski to create gif's
#' @rdname hook_animation
#' @export
hook_gifski = function(x, options) {
x = c(sans_ext(x), file_ext(x))
if (tolower(x[2]) != 'png') stop(
"To use hook_gifski(), the code chunk must generate 'png' images instead of '", x[2], "'."
)
fig.num = options$fig.num
base = sub(paste0(fig.num, '$'), '', x[1])
frames = paste0(base, format(seq_len(fig.num), trim = TRUE), '.', x[2])
gif = paste0(base, '.gif')
dpi = options$dpi
gifski::gifski(
frames, gif, width = options$fig.width * dpi, height = options$fig.height * dpi,
delay = options$interval, loop = isTRUE(grepl('\\bloop\\b', options$aniopts)),
progress = opts_knit$get('progress')
)
unlink(frames)
# pretend it is a single image (gif) generated from the code chunk
options$fig.show = 'asis'; options$fig.cur = 1; options$fig.num = 1
knit_hooks$get('plot')(gif, options)
}
# use SciAnimator to create animations
#' @rdname hook_animation
#' @export
......
......@@ -160,7 +160,10 @@ hook_plot_tex = function(x, options) {
sub(sprintf('%d$', fig.num), '', sans_ext(x)), 1L, fig.num)
} else {
if (nzchar(size)) size = sprintf('[%s]', size)
res = sprintf('\\includegraphics%s{%s} ', size, sans_ext(x))
res = sprintf(
'\\includegraphics%s{%s} ', size,
if (getOption('knitr.include_graphics.ext', FALSE)) x else sans_ext(x)
)
lnk = options$fig.link
if (is.null(lnk) || is.na(lnk)) res else sprintf('\\href{%s}{%s}', lnk, res)
},
......
......@@ -4,23 +4,26 @@ hook_plot_md = function(x, options) {
# if not using R Markdown v2 or output is HTML, just return v1 output
if (is.null(to <- pandoc_to()) || is_html_output(to))
return(hook_plot_md_base(x, options))
if (options$fig.show == 'animate' && is_latex_output())
return(hook_plot_tex(x, options))
office_output = to %in% c('docx', 'pptx', 'rtf', 'odt')
if (!is.null(options$out.width) || !is.null(options$out.height) ||
!is.null(options$out.extra) || options$fig.align != 'default' ||
!is.null(options$fig.subcap)) {
if (to %in% c('beamer', 'latex')) {
!is.null(options$fig.subcap) || options$fig.env != 'figure') {
if (is_latex_output()) {
# Pandoc < 1.13 does not support \caption[]{} so suppress short caption
if (is.null(options$fig.scap)) options$fig.scap = NA
return(hook_plot_tex(x, options))
}
if (to == 'docx') {
if (office_output) {
warning('Chunk options fig.align, out.width, out.height, out.extra ',
'are not supported for Word output')
'are not supported for ', to, ' output')
options$out.width = options$out.height = options$out.extra = NULL
options$fig.align = 'default'
}
}
if (options$fig.show == 'hold' && to == 'docx') {
warning('The chunk option fig.show="hold" is not supported for Word output')
if (options$fig.show == 'hold' && office_output) {
warning('The chunk option fig.show="hold" is not supported for ', to, ' output')
options$fig.show = 'asis'
}
hook_plot_md_base(x, options)
......
......@@ -181,8 +181,8 @@ knit = function(input, output = NULL, tangle = FALSE, text = NULL, quiet = FALSE
# do not run purl() when the output is newer than input (the output might
# have been generated by hook_purl)
if (is.character(output) && !child_mode()) {
out.purl = sub_ext(input, 'R')
if (same_file(output, out.purl) && tangle && file_test('-nt', out.purl, input))
out.purl = with_ext(input, 'R')
if (xfun::same_path(output, out.purl) && tangle && file_test('-nt', out.purl, input))
return(out.purl)
otangle = .knitEnv$tangle.file # the tangled R script
.knitEnv$tangle.file = normalizePath(out.purl, mustWork = FALSE)
......@@ -488,6 +488,7 @@ wrap.knit_asis = function(x, options, inline = FALSE) {
#' @export
wrap.source = function(x, options) {
if (isFALSE(options$echo)) return()
src = sub('\n$', '', x$src)
if (!options$collapse && options$strip.white) src = strip_white(src)
if (is_blank(src)) return() # an empty chunk
......@@ -650,8 +651,10 @@ add_html_caption = function(options, code) {
#' res = paste(c('', '', kable(x, output = FALSE)), collapse = '\n')
#' asis_output(res)
#' }
#' # after you defined the above method, data frames will be printed as tables in knitr,
#' # which is different with the default print() behavior
#' # register the method
#' registerS3method("knit_print", "data.frame", knit_print.data.frame)
#' # after you define and register the above method, data frames will be printed
#' # as tables in knitr, which is different with the default print() behavior
knit_print = function(x, ...) {
if (need_screenshot(x, ...)) {
html_screenshot(x)
......
#' A general-purpose tool for dynamic report generation in R
#'
#' This is an alternative tool to Sweave with a more flexible design and new
#' features like caching and finer control of graphics. It is not limited to LaTeX
#' and is ready to be customized to process other file formats. See the package
#' website in the references for more information and examples.
#' features like caching and finer control of graphics. It is not limited to
#' LaTeX and is ready to be customized to process other file formats. See the
#' package website in the references for more information and examples.
#' @docType package
#' @name knitr-package
#' @aliases knitr
......@@ -17,7 +17,9 @@
#' The name comes from \code{knit} + \code{R} (while \code{Sweave} = \code{S}
#' + \code{weave}).
#' @references Full documentation and demos: \url{https://yihui.name/knitr/};
#' FAQ's: \url{http://bit.ly/knitr-faq}
#' FAQ's: \url{https://yihui.name/knitr/faq/}
#' @importFrom xfun attr file_ext isFALSE is_windows loadable parse_only
#' sans_ext try_silent with_ext
NULL
.knitEnv = new.env()
......@@ -33,3 +35,7 @@ as.strict_list = function(x) {
class(x) = 'knitr_strict_list'
x
}
# TODO: remove this after the next release of spelling:
# https://github.com/ropensci/spelling/issues/12
file_ext = function(...) xfun::file_ext(...)
......@@ -47,7 +47,7 @@ pandoc = function(input, format, config = getOption('config.pandoc'), ext = NA,
encoding = getOption('encoding')) {
if (Sys.which('pandoc') == '')
stop('Please install pandoc first: http://pandoc.org')
cfg = if (is.null(config)) sub_ext(input[1L], 'pandoc') else config
cfg = if (is.null(config)) with_ext(input[1L], 'pandoc') else config
con = file(input[1L], encoding = encoding)
tryCatch(txt <- pandoc_cfg(readLines(con, warn = FALSE)), finally = close(con))
if (file.exists(cfg)) txt = c(txt, '', readLines(cfg, warn = FALSE))
......@@ -94,7 +94,7 @@ pandoc_one = function(input, input_utf8, format, ext, cfg) {
}
out = unname(if (!is.na(cfg['o'])) cfg['o'] else {
if (!is.na(cfg['output'])) cfg['output'] else {
sub_ext(input, if (is.na(ext)) pandoc_ext(format) else ext)
with_ext(input, if (is.na(ext)) pandoc_ext(format) else ext)
}
})
cfg = cfg[setdiff(names(cfg), c('o', 'output', 't'))]
......
......@@ -103,7 +103,9 @@ knit_params = function(text, evaluate = TRUE) {
#' @export
knit_params_yaml = function(yaml, evaluate = TRUE) {
# parse the yaml using our handlers
parsed_yaml = yaml::yaml.load(yaml, handlers = knit_params_handlers(evaluate = evaluate))
parsed_yaml = yaml::yaml.load(
yaml, handlers = knit_params_handlers(evaluate = evaluate), eval.expr = TRUE
)
# if we found paramters then resolve and return them
if (is.list(parsed_yaml) && !is.null(parsed_yaml$params)) {
......
......@@ -375,7 +375,7 @@ include_graphics = function(
path, auto_pdf = getOption('knitr.graphics.auto_pdf', FALSE), dpi = NULL
) {
if (auto_pdf && is_latex_output()) {
path2 = sub_ext(path, 'pdf')
path2 = with_ext(path, 'pdf')
i = file.exists(path2)
path[i] = path2[i]
}
......
......@@ -8,13 +8,13 @@
#'
#' Obviously the goat's hair is the original R script, and the wool is the
#' literate programming document (ready to be knitted).
#' @param hair Path to the R script.
#' @param hair Path to the R script. The script must be encoded in UTF-8 if it
#' contains multibyte characters.
#' @param knit Logical; whether to compile the document after conversion.
#' @param report Logical; whether to generate a report for \file{Rmd}, \file{Rnw}
#' and \file{Rtex} output. Ignored if \code{knit = FALSE}.
#' @param text A character vector of code, as an alternative way to
#' provide the R source. If \code{text} is not \code{NULL}, \code{hair} will
#' be ignored.
#' @param report Logical; whether to generate a report for \file{Rmd},
#' \file{Rnw} and \file{Rtex} output. Ignored if \code{knit = FALSE}.
#' @param text A character vector of code, as an alternative way to provide the
#' R source. If \code{text} is not \code{NULL}, \code{hair} will be ignored.
#' @param envir Environment for \code{\link{knit}()} to evaluate the code.
#' @param format Character; the output format. The default is R Markdown.
#' @param doc A regular expression to identify the documentation lines; by
......@@ -22,12 +22,12 @@
#' if you want to use \code{##} to denote documentation, you can use