diff --git a/DESCRIPTION b/DESCRIPTION
index e8903d0428..34d1becba0 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,7 +1,7 @@
Package: knitr
Type: Package
Title: A General-Purpose Package for Dynamic Report Generation in R
-Version: 1.45.13
+Version: 1.45.14
Authors@R: c(
person("Yihui", "Xie", role = c("aut", "cre"), email = "xie@yihui.name", comment = c(ORCID = "0000-0003-0645-5666")),
person("Abhraneel", "Sarma", role = "ctb"),
@@ -120,7 +120,7 @@ Imports:
highr,
methods,
tools,
- xfun (>= 0.42),
+ xfun (>= 0.42.5),
yaml (>= 2.1.19)
Suggests:
bslib,
@@ -200,3 +200,4 @@ Collate:
'utils-vignettes.R'
'zzz.R'
RoxygenNote: 7.3.1
+Remotes: yihui/xfun
diff --git a/R/hooks-md.R b/R/hooks-md.R
index 665b157f9f..6e91d060ad 100644
--- a/R/hooks-md.R
+++ b/R/hooks-md.R
@@ -144,19 +144,6 @@ css_text_align = function(align) {
if (align == 'default') '' else sprintf(' style="text-align: %s"', align)
}
-# turn a class string "a b" to c(".a", ".b") for Pandoc fenced code blocks
-block_class = function(x) {
- if (length(x) > 0) gsub('^[.]*', '.', unlist(strsplit(x, '\\s+')))
-}
-
-# concatenate block attributes (including classes) for Pandoc fenced code blocks
-block_attr = function(attr, class = NULL, lang = NULL) {
- x = c(block_class(class), attr)
- if (length(x) == 0) return(lang)
- x = c(sprintf('.%s', lang), x)
- paste0('{', paste0(x, collapse = ' '), '}')
-}
-
#' @rdname output_hooks
#' @export
#' @param strict Boolean; whether to use strict markdown or reST syntax. For markdown, if
@@ -194,12 +181,12 @@ hooks_markdown = function(strict = FALSE, fence_char = '`') {
hook.r = function(x, options) {
lang = tolower(options$lang %n% eng2lang(options$engine))
if (!options$highlight) lang = 'text'
- fenced_block(x, options$attr.source, options$class.source, lang, .char = fence_char)
+ fenced_block(x, options$attr.source, c(lang, options$class.source), .char = fence_char)
}
list(
source = function(x, options) {
x = hilight_source(x, 'markdown', options)
- if (strict) hook.t(x) else hook.r(c(x, ''), options)
+ if (strict) hook.t(x) else hook.r(x, options)
},
inline = function(x) {
if (is_latex_output()) .inline.hook.tex(x) else {
@@ -225,22 +212,26 @@ hooks_markdown = function(strict = FALSE, fence_char = '`') {
)
}
-pandoc_div = function(x, .attr = NULL, .class = NULL) {
- if (is.null(.attr) && is.null(.class)) return(x)
- fenced_block(c(x, ''), .attr, .class, .char = ':', .sep = ' ', .outer = '')
+pandoc_div = function(x, attr = NULL, class = NULL) {
+ if (is.null(attr) && is.null(class)) return(x)
+ x = fenced_block(x, attr, class, .char = ':')
+ x = gsub('^\n\n|\n\n$', '', x)
+ gsub('^(:::+) *', '\\1 ', x) # add a space if necessary
}
-# add a fence around content (either fenced code block ``` or Div :::)
-fenced_block = function(x, ..., .char = '`', .sep = '', .outer = '\n\n') {
- x = one_string(c('', x))
- f = create_fence(x, .char)
- paste0(.outer, paste(f, block_attr(...), sep = .sep), x, f, .outer)
+# turn a class string "a b" to c(".a", ".b") for Pandoc fenced code blocks
+block_class = function(x, attr = NULL) {
+ if (length(x)) x = unlist(strsplit(x, '\\s+'))
+ if (length(x) > 1 || length(attr)) gsub('^[.]*', '.', x) else x
}
-create_fence = function(x, char = '`') {
- r = paste0('\n', char, '{3,}')
- l = max(if (grepl(r, x)) attr(gregexpr(r, x)[[1]], 'match.length'), 3)
- paste(rep(char, l), collapse = '')
+# add a fence around content (either fenced code block ``` or Div :::)
+fenced_block = function(x, attr = NULL, class = NULL, .char = '`') {
+ x = sub('\n$', '', x)
+ x = xfun::fenced_block(x, c(block_class(class, attr), attr), char = .char)
+ x = one_string(c('', x, '', ''))
+ # remove the space between ``` and { for backward-compatibility
+ sub('``` {', '```{', x, fixed = TRUE)
}
# convert some engine names to language names
diff --git a/R/utils.R b/R/utils.R
index 8dcdce4a75..ca99c73aeb 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -1052,8 +1052,9 @@ raw_output = function(x, markers = raw_markers, ...) {
#' knitr::raw_latex('\\emph{some text}')
raw_block = function(x, type = 'latex', ...) {
if (!rmarkdown::pandoc_available('2.0.0')) warning('raw_block() requires Pandoc >= 2.0.0')
- x = c(sprintf('\n```{=%s}', type), x, '```\n')
- asis_output(one_string(x), ...)
+ x = fenced_block(x, attr = paste0('=', type))
+ x = gsub('^\n|\n$', '', x)
+ asis_output(x, ...)
}
#' @rdname raw_block
diff --git a/tests/testit/test-hooks-md.R b/tests/testit/test-hooks-md.R
index 26e46f50f7..96052f9eb4 100644
--- a/tests/testit/test-hooks-md.R
+++ b/tests/testit/test-hooks-md.R
@@ -70,8 +70,8 @@ hook_chunk = knit_hooks$get("chunk")
assert('Chunks are enclosed by fenced divs when needed.', {
(hook_chunk('', list(class.chunk=NULL)) %==% '')
(hook_chunk('', list(class.chunk="")) %==% '::: \n\n:::')
- (hook_chunk('', list(class.chunk="foo")) %==% '::: {.foo}\n\n:::')
- (hook_chunk(':::', list(class.chunk="foo")) %==% ':::: {.foo}\n:::\n::::')
+ (hook_chunk('', list(class.chunk="foo")) %==% '::: foo\n\n:::')
+ (hook_chunk(':::', list(class.chunk="foo")) %==% ':::: foo\n:::\n::::')
})
knit_hooks$restore()
diff --git a/tests/testit/test-utils.R b/tests/testit/test-utils.R
index c99d6abf81..a26cfd8819 100644
--- a/tests/testit/test-utils.R
+++ b/tests/testit/test-utils.R
@@ -168,26 +168,18 @@ assert('restore_raw_output() restores raw output', {
})
assert('raw_block() returns a raw attribute block for Pandoc', {
- (raw_latex('\\emph{x}') == '\n```{=latex}\n\\emph{x}\n```\n')
- (raw_html('foo') == '\n```{=html}\nfoo\n```\n')
+ (c(raw_latex('\\emph{x}')) %==% '\n```{=latex}\n\\emph{x}\n```\n')
+ (c(raw_html('foo')) %==% '\n```{=html}\nfoo\n```\n')
})
assert('block_class() turns a character vector into Pandoc attributes for code block classes', {
(block_class(NULL) %==% NULL)
- (block_class('a') %==% '.a')
+ (block_class('a') %==% 'a')
+ (block_class('a', '.b') %==% '.a')
(block_class('a b') %==% c('.a', '.b'))
(block_class(c('a', 'b')) %==% c('.a', '.b'))
})
-assert('block_attr(x) turns a character vector into Pandoc attributes', {
- (block_attr(NULL) %==% NULL)
- (block_attr(NULL, lang = 'r') %==% 'r')
- (block_attr('.a') %==% '{.a}')
- (block_attr('.a b="11"') %==% '{.a b="11"}')
- (block_attr(c('.a', 'b="11"')) %==% '{.a b="11"}')
-})
-
-
assert('when collapse is TRUE, class.* and attr.* become NULL except for class.source and attr.source', {
keys = unlist(lapply(
c('class.', 'attr.'), paste0, c('source', 'output', 'message', 'warning', 'error')
diff --git a/vignettes/knitr-intro.Rmd b/vignettes/knitr-intro.Rmd
index a2b89b1b20..7ed5dacaaf 100644
--- a/vignettes/knitr-intro.Rmd
+++ b/vignettes/knitr-intro.Rmd
@@ -45,6 +45,6 @@ abline(fit, col = 'red')
## References
-```{r, echo=FALSE, results='asis'}
+```{r, echo=FALSE, results='asis', warning=FALSE}
print(citation('knitr'), style = 'html')
```