Skip to content

Commit

Permalink
a follow-up on #2331: use xfun::fenced_block() from yihui/xfun@22a97ce
Browse files Browse the repository at this point in the history
  • Loading branch information
yihui committed Mar 25, 2024
1 parent 031e08c commit 5435c52
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 46 deletions.
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -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"),
Expand Down Expand Up @@ -120,7 +120,7 @@ Imports:
highr,
methods,
tools,
xfun (>= 0.42),
xfun (>= 0.42.5),
yaml (>= 2.1.19)
Suggests:
bslib,
Expand Down Expand Up @@ -200,3 +200,4 @@ Collate:
'utils-vignettes.R'
'zzz.R'
RoxygenNote: 7.3.1
Remotes: yihui/xfun
45 changes: 18 additions & 27 deletions R/hooks-md.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/testit/test-hooks-md.R
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
16 changes: 4 additions & 12 deletions tests/testit/test-utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -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('<i>foo</i>') == '\n```{=html}\n<i>foo</i>\n```\n')
(c(raw_latex('\\emph{x}')) %==% '\n```{=latex}\n\\emph{x}\n```\n')
(c(raw_html('<i>foo</i>')) %==% '\n```{=html}\n<i>foo</i>\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')
Expand Down
2 changes: 1 addition & 1 deletion vignettes/knitr-intro.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -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')
```

5 comments on commit 5435c52

@yihui
Copy link
Owner Author

@yihui yihui commented on 5435c52 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cderv Just FYI (in case this could affect Quarto), this change may introduce changes in the number of blank lines or backticks in knitr chunk output like this: yihui/knitr-examples@b26aa39 Such changes are harmless in terms of Markdown syntax, but could cause problems in reverse dependencies. Currently the cloud revdep check throws a lot of errors: https://github.com/yihui/crandalf/actions/runs/8428912903 I'm not sure what's going on (it seems TeX Live is still 2023 there). I need to go to bed now and will check tomorrow.

@cderv
Copy link
Collaborator

@cderv cderv commented on 5435c52 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the heads up on the change;

Not sure why you would get 2023... I ran test on our daily bundle and they seems to be latest... 🤔
If you need help debugging GHA, please tell me.

@yihui
Copy link
Owner Author

@yihui yihui commented on 5435c52 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant 2023 not on GHA, but on our cloud revdep check machine.

@cderv
Copy link
Collaborator

@cderv cderv commented on 5435c52 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I looked at CRANDALF and so 2023 in the results inside the bundle at https://github.com/yihui/crandalf/actions/runs/8428912903 🤔

I'll handle the revdep cloud check environment

@yihui
Copy link
Owner Author

@yihui yihui commented on 5435c52 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I guess you will have to ping Josh Forest directly on Slack. I'm not optimistic about anyone reading issues in the revdep cloud check repo. I really wish they could simplify the work by 1) dropping older R versions (https://github.com/rstudio/revdepcheck-cloud/issues/114), and 2) automatically keeping everything up-to-date (R, TeX Live, etc). There's no point for anyone to waste time on requesting new versions of this and that from time to time. Revdep checks should be done with the latest versions of pretty much everything.

Please sign in to comment.