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

New upstream version 1.14

parent d1820ff2
Package: knitr
Type: Package
Title: A General-Purpose Package for Dynamic Report Generation in R
Version: 1.12.3
Date: 2016-01-22
Version: 1.14
Date: 2016-08-11
Authors@R: c(
person("Yihui", "Xie", email = "xie@yihui.name", role = c("aut", "cre")),
person("Adam", "Vogt", role = "ctb"),
......@@ -77,11 +77,12 @@ Authors@R: c(
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.0.2)
Depends: R (> 3.0.2)
Imports: evaluate (>= 0.8), digest, formatR, highr, markdown, stringr
(>= 0.6), yaml (>= 2.1.5), methods, tools
Suggests: testit, rgl (>= 0.95.1201), codetools, rmarkdown, tikzDevice
(>= 0.9), XML, RCurl
Suggests: testit, rgl (>= 0.95.1201), codetools, rmarkdown,
htmlwidgets, webshot, tikzDevice (>= 0.10), png, jpeg, XML,
RCurl, DBI (>= 0.4-1), tibble
License: GPL
URL: http://yihui.name/knitr/
BugReports: https://github.com/yihui/knitr/issues
......@@ -96,12 +97,12 @@ Collate: 'block.R' 'cache.R' 'utils.R' 'citation.R' 'hooks-html.R'
'hooks-extra.R' 'hooks-latex.R' 'hooks-md.R' 'hooks-rst.R'
'hooks-textile.R' 'hooks.R' 'output.R' 'package.R' 'pandoc.R'
'params.R' 'parser.R' 'pattern.R' 'rocco.R' 'spin.R' 'table.R'
'template.R' 'themes-eclipse.R' 'utils-base64.R'
'utils-conversion.R' 'utils-rd2html.R' 'utils-sweave.R'
'utils-upload.R' 'utils-vignettes.R' 'zzz.R'
'template.R' 'utils-base64.R' 'utils-conversion.R'
'utils-rd2html.R' 'utils-sweave.R' 'utils-upload.R'
'utils-vignettes.R' 'zzz.R'
RoxygenNote: 5.0.1
NeedsCompilation: no
Packaged: 2016-01-21 22:54:26 UTC; yihui
Packaged: 2016-08-11 21:15:37 UTC; yihui
Author: Yihui Xie [aut, cre],
Adam Vogt [ctb],
Alastair Andrew [ctb],
......@@ -174,4 +175,4 @@ Author: Yihui Xie [aut, cre],
Wush Wu [ctb],
Zachary Foster [ctb]
Repository: CRAN
Date/Publication: 2016-01-22 10:26:48
Date/Publication: 2016-08-13 11:33:17
This diff is collapsed.
......@@ -9,8 +9,9 @@ S3method(process_tangle,inline)
S3method(wrap,character)
S3method(wrap,default)
S3method(wrap,error)
S3method(wrap,html_screenshot)
S3method(wrap,knit_asis)
S3method(wrap,knit_asis_list)
S3method(wrap,knit_embed_url)
S3method(wrap,knit_image_paths)
S3method(wrap,list)
S3method(wrap,message)
......@@ -20,12 +21,13 @@ S3method(wrap,warning)
export(Sweave2knitr)
export(all_labels)
export(all_patterns)
export(all_rcpp_labels)
export(asis_output)
export(clean_cache)
export(combine_words)
export(current_input)
export(dep_auto)
export(dep_prev)
export(eclipse_theme)
export(engine_output)
export(fig_chunk)
export(fig_path)
......@@ -45,7 +47,9 @@ export(hook_r2swf)
export(hook_scianimator)
export(image_uri)
export(imgur_upload)
export(include_app)
export(include_graphics)
export(include_url)
export(inline_expr)
export(kable)
export(knit)
......@@ -60,6 +64,7 @@ export(knit_filter)
export(knit_global)
export(knit_hooks)
export(knit_meta)
export(knit_meta_add)
export(knit_params)
export(knit_params_yaml)
export(knit_patterns)
......
......@@ -18,7 +18,7 @@ call_block = function(block) {
# expand parameters defined via template
if (!is.null(block$params$opts.label)) {
block$params <- merge_list(opts_template$get(block$params$opts.label), block$params)
block$params = merge_list(opts_template$get(block$params$opts.label), block$params)
}
params = opts_chunk$merge(block$params)
......@@ -67,7 +67,9 @@ call_block = function(block) {
}
hash = paste(valid_path(params$cache.path, label), digest::digest(content), sep = '_')
params$hash = hash
if (cache$exists(hash, params$cache.lazy) && isFALSE(params$cache.rebuild)) {
if (cache$exists(hash, params$cache.lazy) &&
isFALSE(params$cache.rebuild) &&
params$engine != 'Rcpp') {
if (opts_knit$get('verbose')) message(' loading cache from ', hash)
cache$load(hash, lazy = params$cache.lazy)
if (!params$include) return('')
......@@ -76,8 +78,7 @@ call_block = function(block) {
if (params$engine == 'R')
cache$library(params$cache.path, save = FALSE) # load packages
} else if (label %in% names(dep_list$get()) && !isFALSE(opts_knit$get('warn.uncached.dep')))
warning('code chunks must not depend on the uncached chunk "', label, '"',
call. = FALSE)
warning2('code chunks must not depend on the uncached chunk "', label, '"')
params$params.src = block$params.src
opts_current$restore(params) # save current options
......@@ -105,7 +106,7 @@ block_exec = function(options) {
output = in_dir(opts_knit$get('root.dir') %n% input_dir(), engine(options))
res.after = run_hooks(before = FALSE, options)
output = paste(c(res.before, output, res.after), collapse = '')
output = if (is_blank(output)) '' else knit_hooks$get('chunk')(output, options)
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)
......@@ -118,12 +119,17 @@ block_exec = function(options) {
obj.before = ls(globalenv(), all.names = TRUE) # global objects before chunk
keep = options$fig.keep
keep.idx = NULL
if (is.numeric(keep)) {
keep.idx = keep
keep = "index"
}
# open a device to record plots
if (chunk_device(options$fig.width[1L], options$fig.height[1L], keep != 'none',
options$dev, options$dev.args, options$dpi, options)) {
# preserve par() settings from the last code chunk
if (keep.pars <- opts_knit$get('global.par'))
par(opts_knit$get('global.pars'))
par2(opts_knit$get('global.pars'))
showtext(options$fig.showtext) # showtext support
dv = dev.cur()
on.exit({
......@@ -162,6 +168,7 @@ block_exec = function(options) {
options$error = err.code != 2L
}
cache.exists = cache$exists(options$hash, options$cache.lazy)
evaluate = knit_hooks$get('evaluate')
# return code with class 'source' if not eval chunks
res = if (is_blank(code)) list() else if (isFALSE(ev)) {
as.source(code)
......@@ -169,7 +176,7 @@ block_exec = function(options) {
fix_evaluate(cache$output(options$hash, 'list'), options$cache == 1)
} else in_dir(
opts_knit$get('root.dir') %n% input_dir(),
evaluate::evaluate(
evaluate(
code, envir = env, new_device = FALSE,
keep_warning = !isFALSE(options$warning),
keep_message = !isFALSE(options$message),
......@@ -218,6 +225,8 @@ block_exec = function(options) {
if (keep %in% c('first', 'last')) {
res = res[-(if (keep == 'last') head else tail)(which(figs), -1L)]
} else {
# keep only selected
if (keep == 'index') res = res[which(figs)[keep.idx]]
# merge low-level plotting changes
if (keep == 'high') res = merge_low_plot(res, figs)
}
......@@ -233,16 +242,16 @@ block_exec = function(options) {
if (isTRUE(options$fig.beforecode)) res = fig_before_code(res)
on.exit(plot_counter(reset = TRUE), add = TRUE) # restore plot number
if (options$fig.show != 'animate' && options$fig.num > 1) {
options = recycle_plot_opts(options)
}
on.exit({
plot_counter(reset = TRUE)
shot_counter(reset = TRUE)
}, add = TRUE) # restore plot number
output = unlist(wrap(res, options)) # wrap all results together
res.after = run_hooks(before = FALSE, options, env) # run 'after' hooks
output = paste(c(res.before, output, res.after), collapse = '') # insert hook results
output = if (is_blank(output)) '' else knit_hooks$get('chunk')(output, options)
output = knit_hooks$get('chunk')(output, options)
if (options$cache > 0) {
obj.new = setdiff(ls(globalenv(), all.names = TRUE), obj.before)
......@@ -256,16 +265,16 @@ block_exec = function(options) {
dep_auto()
}
if (options$cache < 3) {
if (!cache.exists) block_cache(options, res.orig, objs)
if (options$cache.rebuild || !cache.exists) block_cache(options, res.orig, objs)
} else block_cache(options, output, objs)
}
if (options$include) output else ''
if (options$include) output else if (is.null(s <- options$indent)) '' else s
}
block_cache = function(options, output, objects) {
hash = options$hash
outname = sprintf('.%s', hash)
outname = cache_output_name(hash)
assign(outname, output, envir = knit_global())
purge_cache(options)
cache$library(options$cache.path, save = TRUE)
......@@ -283,19 +292,25 @@ purge_cache = function(options) {
# not need to close the device on exit
chunk_device = function(width, height, record = TRUE, dev, dev.args, dpi, options) {
dev_new = function() {
# actually I should adjust the recording device according to dev, but here
# I have only considered the png and tikz devices (because the measurement
# results can be very different especially with the latter, see #1066)
# actually I should adjust the recording device according to dev, but here I
# have only considered the png and tikz devices (because the measurement
# results can be very different especially with the latter, see #1066), and
# also the cairo_pdf device (#1235)
if (identical(dev, 'png')) {
do.call(grDevices::png, c(list(
filename = tempfile(), width = width, height = height, units = 'in', res = dpi
), get_dargs(dev.args, 'png')))
} else if (identical(dev, 'tikz')) {
do.call(tikz_dev, c(list(
dargs = c(list(
file = paste0(tempfile(), ".tex"), width = width, height = height
), get_dargs(dev.args, 'tikz'), list(
sanitize = options$sanitize, standAlone = options$external
)))
), get_dargs(dev.args, 'tikz'))
dargs$sanitize = options$sanitize; dargs$standAlone = options$external
if (is.null(dargs$verbose)) dargs$verbose = FALSE
do.call(tikz_dev, dargs)
} else if (identical(dev, 'cairo_pdf')) {
do.call(grDevices::cairo_pdf, c(list(
filename = tempfile(), width = width, height = height
), get_dargs(dev.args, 'cairo_pdf')))
} else if (identical(getOption('device'), pdf_null)) {
if (!is.null(dev.args)) {
dev.args = get_dargs(dev.args, 'pdf')
......@@ -389,7 +404,7 @@ inline_exec = function(block, envir = knit_global(), hook = knit_hooks$get('inli
for (i in 1:n) {
v = withVisible(eval(parse_only(code[i]), envir = envir))
res = if (v$visible) knit_print(v$value, inline = TRUE, options = opts_chunk$get())
if (inherits(res, c('knit_asis', 'knit_asis_list'))) res = wrap(res, inline = TRUE)
if (inherits(res, 'knit_asis')) res = wrap(res, inline = TRUE)
d = nchar(input)
# replace with evaluated results
stringr::str_sub(input, loc[i, 1], loc[i, 2]) = if (length(res)) {
......
......@@ -15,6 +15,10 @@ new_cache = function() {
}
cache_save = function(keys, outname, hash, lazy = TRUE) {
meta_name = cache_meta_name(hash)
if (exists(meta_name, envir = knit_global())) outname = c(outname, meta_name)
out0 = outname
on.exit(rm(list = out0, envir = knit_global()), add = TRUE)
# keys are new variables created; outname is the text output of a chunk
path = cache_path(hash)
# add random seed to cache if exists
......@@ -59,6 +63,13 @@ new_cache = function() {
load(path2, envir = knit_global())
if (exists('.Random.seed', envir = knit_global(), inherits = FALSE))
copy_env(knit_global(), globalenv(), '.Random.seed')
name = cache_meta_name(hash)
if (exists(name, envir = knit_global())) {
.knitEnv$meta = c(
.knitEnv$meta, get(name, envir = knit_global(), inherits = FALSE)
)
rm(list = name, envir = knit_global())
}
}
}
......@@ -86,7 +97,11 @@ new_cache = function() {
# when cache=3, code output is stored in .[hash], so cache=TRUE won't lose
# output as cacheSweave does; for cache=1,2, output is the evaluate() list
cache_output = function(hash, mode = 'character') {
get(sprintf('.%s', hash), envir = knit_global(), mode = mode, inherits = FALSE)
name = cache_output_name(hash)
res = get(name, envir = knit_global(), mode = mode, inherits = FALSE)
# clean up this hidden variable after we obtain its value
if (mode == mode(res)) rm(list = name, envir = knit_global())
res
}
list(purge = cache_purge, save = cache_save, load = cache_load, objects = cache_objects,
......@@ -101,6 +116,11 @@ known_globals = c(
'{', '[', '(', ':', '<-', '=', '+', '-', '*', '/', '%%', '%/%', '%*%', '%o%', '%in%'
)
# a variable name to store the metadata object from code chunks
cache_meta_name = function(hash) sprintf('.%s_meta', hash)
# a variable name to store the text output of code chunks
cache_output_name = function(hash) sprintf('.%s', hash)
cache = new_cache()
# a regex for cache files
......
......@@ -47,6 +47,9 @@ new_defaults = function(value = list()) {
#'
#' A list of available options:
#' \url{http://yihui.name/knitr/options#chunk_options}
#' @note \code{opts_current} is read-only in the sense that it does nothing if
#' you call \code{opts_current$set()}; you can only query the options via
#' \code{opts_current$get()}.
#' @export
#' @examples opts_chunk$get('prompt'); opts_chunk$get('fig.keep')
opts_chunk = new_defaults(list(
......@@ -148,7 +151,7 @@ set_alias = function(...) {
#' }
#' @include hooks-html.R
opts_knit = new_defaults(list(
progress = TRUE, verbose = FALSE, width = 75L, eval.after = NULL,
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,
......@@ -187,9 +190,9 @@ adjust_opts_knit = function() {
i = intersect(i, which(nms[i] %in% paste('knitr', opts_knit_names, sep = '.')))
if (length(i)) {
nms.pkg = sub('^knitr.', 'knitr.package.', nms[i])
warning(
warning2(
'These options must be renamed (from left to right):\n',
formatUL(sprintf('%s => %s', nms[i], nms.pkg)), call. = FALSE, immediate. = TRUE
formatUL(sprintf('%s => %s', nms[i], nms.pkg)), immediate. = TRUE
)
Sys.sleep(10)
names(opts)[i] = nms[i] = nms.pkg
......
......@@ -25,6 +25,8 @@
#'
#' \Sexpr[results=verbatim]{str(knitr::knit_engines$get())}
#' @export
#' @note The Leiningen engine \code{lein} requires lein-exec plugin; see
#' \url{https://github.com/yihui/knitr/issues/1176} for details.
#' @references Usage: \url{http://yihui.name/knitr/objects}; examples:
#' \url{http://yihui.name/knitr/demo/engines/}
#' @examples knit_engines$get('python'); knit_engines$get('awk')
......@@ -55,7 +57,7 @@ engine_output = function(options, code, out, extra = NULL) {
out = sub('([^\n]+)$', '\\1\n', out)
# replace the engine names for markup later, e.g. ```Rscript should be ```r
options$engine = switch(
options$engine, 'Rscript' = 'r', node = 'javascript',
options$engine, mysql = 'sql', node = 'javascript', psql = 'sql', Rscript = 'r',
options$engine
)
if (options$engine == 'stata') {
......@@ -149,14 +151,24 @@ eng_shlib = function(options) {
## Rcpp
eng_Rcpp = function(options) {
sourceCpp = getFromNamespace('sourceCpp', 'Rcpp')
code = paste(options$code, collapse = '\n')
# engine.opts is a list of arguments to be passed to Rcpp function, e.g.
# engine.opts=list(plugin='RcppArmadillo')
opts = options$engine.opts
# use custom cacheDir for sourceCpp if it's supported
cache = options$cache && ('cacheDir' %in% names(formals(sourceCpp)))
if (cache) {
opts$cacheDir = paste(valid_path(options$cache.path, options$label), 'sourceCpp', sep = '_')
opts$cleanupCacheDir = TRUE
}
if (!is.environment(opts$env)) opts$env = knit_global() # default env is knit_global()
if (options$eval) {
message('Building shared library for Rcpp code chunk...')
do.call(getFromNamespace('sourceCpp', 'Rcpp'), c(list(code = code), opts))
do.call(sourceCpp, c(list(code = code), opts))
}
options$engine = 'cpp' # wrap up source code in cpp syntax instead of Rcpp
......@@ -170,10 +182,13 @@ eng_stan = function(options) {
code = paste(options$code, collapse = '\n')
opts = options$engine.opts
## name of the modelfit object returned by stan_model
x = opts$x
if (is.null(x <- options$output.var)) {
warning("the option engine.opts$x is deprecated; use the chunk option output.var instead")
x = opts$x
}
if (!is.character(x) || length(x) != 1L) stop(
"engine.opts$x must be a character string; ",
"provide a name for the returned `stanmodel` object."
"the chunk option output.var must be a character string ",
"providing a name for the returned `stanmodel` object."
)
opts$x = NULL
if (options$eval) {
......@@ -200,24 +215,39 @@ eng_tikz = function(options) {
s = append(lines, options$code, i) # insert tikz into tex-template
writeLines(s, texf <- paste0(f <- tempfile('tikz', '.'), '.tex'))
on.exit(unlink(texf), add = TRUE)
unlink(outf <- paste0(f, '.pdf'))
tools::texi2pdf(texf, clean = TRUE)
if (!file.exists(outf)) stop('failed to compile tikz; check the template: ', tmpl)
fig = fig_path('', options)
dir.create(dirname(fig), recursive = TRUE, showWarnings = FALSE)
file.rename(outf, paste0(fig, '.pdf'))
# convert to the desired output-format, calling `convert`
ext = tolower(options$fig.ext %n% dev2ext(options$dev))
if (ext != 'pdf') {
conv = system2(options$engine.opts$convert %n% 'convert', c(
options$engine.opts$convert.opts, sprintf('%s.pdf %s.%s', fig, fig, ext)
))
if (conv != 0 && !options$error)
stop('problems with `convert`; probably not installed?')
to_svg = ext == 'svg'
unlink(outf <- paste0(f, if (to_svg) '.dvi' else '.pdf'))
tools::texi2dvi(texf, pdf = !to_svg, clean = TRUE)
if (!file.exists(outf)) stop('Failed to compile tikz; check the template: ', tmpl)
fig = fig_path(if (to_svg) '.dvi' else '.pdf', options)
dir.create(dirname(fig), recursive = TRUE, showWarnings = FALSE)
file.rename(outf, fig)
fig2 = sub_ext(fig, ext)
if (to_svg) {
# dvisvgm needs to be on the path
# dvisvgm for windows needs ghostscript bin dir on the path also
conv = system2('dvisvgm', fig)
# copy the svg to figure subdir
file.rename(basename(fig2), fig2)
} else {
# convert to the desired output-format, calling `convert`
conv = 0
if (ext != 'pdf') {
conv = system2(options$engine.opts$convert %n% 'convert', c(
options$engine.opts$convert.opts, sprintf('%s %s', fig, fig2)
))
}
}
if (conv != 0 && !options$error) stop('Failed to compile ', fig, ' to ', fig2)
fig = fig2
options$fig.num = 1L; options$fig.cur = 1L
extra = knit_hooks$get('plot')(paste(fig, ext, sep = '.'), options)
extra = knit_hooks$get('plot')(fig, options)
options$engine = 'tex' # for output hooks to use the correct language class
engine_output(options, options$code, '', extra)
}
......@@ -333,6 +363,136 @@ eng_block = function(options) {
)
}
# helper to create engines the wrap embedded html assets (e.g. css,js)
eng_html_asset = function(prefix, postfix) {
function(options) {
if (options$eval && is_html_output(excludes = 'markdown')) {
code = c(prefix, options$code, postfix)
paste(code, collapse = '\n')
}
}
}
# include js in a script tag (ignore if not html output)
eng_js = eng_html_asset('<script type="text/javascript">', '</script>')
# include css in a style tag (ignore if not html output)
eng_css = eng_html_asset('<style type="text/css">', '</style>')
# sql engine
eng_sql = function(options) {
# Return char vector of sql interpolation param names
varnames_from_sql = function(conn, sql) {
varPos = DBI::sqlParseVariables(conn, sql)
if (length(varPos$start) > 0) {
varNames = substring(sql, varPos$start, varPos$end)
sub("^\\?", "", varNames)
}
}
# Vectorized version of exists
mexists = function(x, env = knit_global(), inherits = TRUE) {
vapply(x, exists, logical(1), where = env, inherits = inherits)
}
# Interpolate a sql query based on the variables in an environment
interpolate_from_env = function(conn, sql, env = knit_global(), inherits = TRUE) {
names = unique(varnames_from_sql(conn, sql))
names_missing = names[!mexists(names, env, inherits)]
if (length(names_missing) > 0) {
stop("Object(s) not found: ", paste('"', names_missing, '"', collapse = ", "))
}
args = if (length(names) > 0) setNames(
mget(names, envir = env, inherits = inherits), names
)
do.call(DBI::sqlInterpolate, c(list(conn, sql), args))
}
# extract options
conn = options$connection
if (is.null(conn)) stop2(
"The 'connection' option (DBI connection) is required for sql chunks."
)
varname = options$output.var
max.print = options$max.print %n% (opts_knit$get('sql.max.print') %n% 10)
if (is.na(max.print) || is.null(max.print))
max.print = -1
sql = paste(options$code, collapse = '\n')
# 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
query = interpolate_from_env(conn, sql)
if (is.null(varname) && max.print > 0) {
res = DBI::dbSendQuery(conn, query)
data = if (!DBI::dbHasCompleted(res) || (DBI::dbGetRowCount(res) > 0))
DBI::dbFetch(res, n = max.print)
DBI::dbClearResult(res)
} else {
data = DBI::dbGetQuery(conn, query)
}
# 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({
# apply max.print to data
display_data = if (max.print == -1) data else head(data, n = max.print)
# get custom sql print function
sql.print = opts_knit$get('sql.print')
# use kable for markdown
if (!is.null(sql.print)) {
options$results = 'asis'
cat(sql.print(data))
} else if (out_format('markdown')) {
# we are going to output raw markdown so set results = 'asis'
options$results = 'asis'
# force left alignment if the first column is an incremental id column
first_column = display_data[[1]]
if (is.numeric(first_column) && all(diff(first_column) == 1))
display_data[[1]] = as.character(first_column)
# wrap html output in a div so special styling can be applied
if (is_html_output()) cat('<div class="knitsql-table">\n')
# determine records caption
caption = options$tab.cap
if (is.null(caption)) {
rows = nrow(data)
rows_formatted = formatC(rows, format = "d", big.mark = ',')
caption = if (max.print == -1 || rows < max.print) {
paste(rows_formatted, "records")
} else {
paste("Displaying records 1 -", rows_formatted)
}
}
# disable caption
if (identical(caption, NA)) caption = NULL
# print using kable
print(kable(display_data, caption = caption))
# terminate div
if (is_html_output()) cat("\n</div>\n")
# otherwise use tibble if it's available
} else if (loadable('tibble')) {
print(tibble::as_tibble(display_data), n = max.print)
} else print(display_data) # fallback to standard print
})
# assign varname if requested
if (!is.null(varname)) assign(varname, data, envir = knit_global())
# return output
engine_output(options, options$code, output)
}
# set engines for interpreted languages
local({
for (i in c(
......@@ -346,7 +506,8 @@ local({
knit_engines$set(
highlight = eng_highlight, Rcpp = eng_Rcpp, tikz = eng_tikz, dot = eng_dot,
c = eng_shlib, fortran = eng_shlib, asy = eng_dot, cat = eng_cat,
asis = eng_asis, stan = eng_stan, block = eng_block
asis = eng_asis, stan = eng_stan, block = eng_block, js = eng_js, css = eng_css,
sql = eng_sql
)
get_engine = function(name) {
......
......@@ -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$tidy && isFALSE(options$eval))
if (options$engine == 'R' && !options$tidy && isFALSE(options$eval))
x = vapply(highr:::group_src(x), paste, character(1), collapse = '\n')
line_prompt(x)
} else x
......@@ -135,7 +135,8 @@ styler_assistant_latex = function(x) {
}
sprintf('%s#1%s', start, end)
})
sprintf('\\newcommand{\\hl%s}[1]{%s}%%', names(x), styles)
res = sprintf('\\newcommand{\\hl%s}[1]{%s}%%', names(x), styles)
c(res, '\\let\\hlipl\\hlkwb')
}
col2latexrgb = function(hex) {
......
......@@ -19,8 +19,7 @@
#' The function \code{hook_optipng()} calls the program \command{optipng} to
#' optimize PNG images. Note the chunk option \code{optipng} can be used to
#' provide additional parameters to the program \command{optipng}, e.g.
#' \code{optipng = '-o7'}. See \url{http://optipng.sourceforge.net/} for
#' details.
#' \code{optipng = '-o7'}.
#'
#' When the plots are not recordable via \code{\link[grDevices]{recordPlot}} and
#' we save the plots to files manually via other functions (e.g. \pkg{rgl}
......
......@@ -27,18 +27,21 @@ hook_plot_html = function(x, options) {
}
.img.tag = function(src, w, h, caption, extra) {
caption = if (length(caption) == 1 && caption != '') {
paste0('title="', caption, '" alt="', caption, '" ')
}
paste0(
'<img src="', opts_knit$get('base.url'), src, '" title="', caption,
'" alt="', caption, '" ', .img.attr(w, h, extra), ' />'
'<img src="', opts_knit$get('base.url'), src, '" ', caption,
.img.attr(w, h, extra), ' />'
)
}
.img.cap = function(options) {
.img.cap = function(options, alt = FALSE) {
cap = options$fig.cap %n% {
if (is.null(pandoc_to())) sprintf('plot of chunk %s', options$label) else ''
}
if (length(cap) == 0) cap = ''
if (cap == '') return(cap)
if (is_blank(cap) || alt) return(cap)
paste0(create_label(options$fig.lp, options$label), cap)
}
......@@ -91,9 +94,9 @@ hook_ffmpeg = function(x, options, format = 'webm') {
'ffmpeg', '-y', '-r', 1 / options$interval, '-i', fig.fname, extra, mov.fname
)
if (Sys.which('ffmpeg') == '') stop(
if (Sys.which('ffmpeg') == '') stop2(
'Could not find ffmpeg command. You should either change the animation.fun ',
'hook option or install ffmpeg with libvpx enabled.', call. = FALSE
'hook option or install ffmpeg with libvpx enabled.'
)
message('executing: ', ffmpeg.cmd)
system(ffmpeg.cmd, ignore.stdout = TRUE)
......
......@@ -117,7 +117,7 @@ hook_plot_tex = function(x, options) {
# * close figure environment
if (plot2) {
if (is.null(scap) && !grepl('[{].*?[:.;].*?[}]', cap)) {
scap = strsplit(cap, '[$:.;]')[[1L]][1L]
scap = strsplit(cap, '[:.;]( |\\\\|$)')[[1L]][1L]
}
scap = if (is.null(scap) || is.na(scap)) '' else sprintf('[%s]', scap)
cap = if (cap == '') '' else sprintf(
......@@ -153,7 +153,9 @@ hook_plot_tex = function(x, options) {