Skip to content

Commit

Permalink
Disallow unbalanced chunk delimiters (#2306)
Browse files Browse the repository at this point in the history
notice has been given for two years: https://yihui.org/en/2021/10/unbalanced-delimiters/
  • Loading branch information
yihui authored Nov 10, 2023
1 parent c520211 commit 0d1ad21
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 9 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- The `family` argument was not passed to the `pdf` device (thanks, @sebkopf, rstudio/rmarkdown#2526).

## MAJOR CHANGES

- Unbalanced chunk delimiters (fences) in R Markdown documents are no longer allowed, as announced two years ago at <https://yihui.org/en/2021/10/unbalanced-delimiters/> (#2306). This means the opening delimiter must strictly match the closing delimiter, e.g., if a code chunk starts with four backticks, it must also end with four; or if a chunk header is indented by two spaces, the closing fence must be indented by exactly two spaces. For authors who cannot update their R Markdown documents for any reason at the moment, setting `options(knitr.unbalanced.chunk = TRUE)` (e.g., in `.Rprofile`) can temporarily prevent **knitr** from throwing an error, but it is strongly recommended that you fix the problems as soon as possible, because this workaround will be removed in future.

# CHANGES IN knitr VERSION 1.45

## NEW FEATURES
Expand Down
28 changes: 19 additions & 9 deletions R/parser.R
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,6 @@ group_indices = function(chunk.begin, chunk.end, lines = NA, is.md = FALSE) {
in.chunk = FALSE # whether inside a chunk now
pattern.end = NA # the expected chunk end pattern (derived from header)
b = NA # the last found chunk header
# TODO: for now we only disallow unmatched delimiters during R CMD check
# that's not running on CRAN; we will fully disallow it in the future (#2057)
signal = if (is_R_CMD_check() && !(is_cran() || is_bioc())) stop2 else warning2
g = NA # group index: odd - text; even - chunk
fun = function(is.begin, is.end, line, i) {
if (i == 1) {
Expand All @@ -583,7 +580,7 @@ group_indices = function(chunk.begin, chunk.end, lines = NA, is.md = FALSE) {
} # otherwise ignore the chunk header
return(g)
}
if (in.chunk && is.end && match_chunk_end(pattern.end, line, i, b, lines, signal)) {
if (in.chunk && is.end && match_chunk_end(pattern.end, line, i, b, lines)) {
in.chunk <<- FALSE
g <<- g + 1
return(g - 1) # don't use incremented g yet; use it in the next step
Expand All @@ -605,7 +602,7 @@ match_chunk_begin = function(pattern.end, x, pattern = '^\\1\\\\{') {
grepl(gsub('^([^`]*`+).*', pattern, pattern.end), x)
}

match_chunk_end = function(pattern, line, i, b, lines, signal = stop) {
match_chunk_end = function(pattern, line, i, b, lines) {
if (is.na(pattern) || grepl(pattern, line)) return(TRUE)
n = length(lines)
# if the exact match was not found, look ahead to see if there is another
Expand All @@ -617,16 +614,29 @@ match_chunk_end = function(pattern, line, i, b, lines, signal = stop) {
if (!any(match_chunk_begin(pattern, lines[i + 1:(k - 1)], '^\\1`*\\\\{')))
return(FALSE)
}
# TODO: clean up the exceptions here (although perhaps some may never update again)
signal = if (getOption('knitr.unbalanced.chunk', check_old(
c('ensembleR', 'FSinR', 'funmediation', 'liger', 'loo', 'microsamplingDesign', 'mmpf', 'rSEA', 'StructFDR', 'TRMF'),
c('0.1.0', '2.0.5', '1.0.1', '2.0.1', '2.6.0', '1.0.8', '0.0.5', '2.1.1', '1.3', '0.1.5')
))) warning2 else stop2
signal(
'The closing backticks on line ', i, ' ("', line, '") in ', current_input(),
' do not match the opening backticks "',
'The closing fence on line ', i, ' ("', line, '") in ', current_input(),
' does not match the opening fence "',
gsub('\\^(\\s*`+).*', '\\1', pattern), '" on line ', b, '. You are recommended to ',
'fix either the opening or closing delimiter of the code chunk to use exactly ',
'the same numbers of backticks and same level of indentation (or blockquote).'
'fix either the opening or closing fence of the code chunk to use exactly ',
'the same numbers of backticks and same level of indentation (or blockquote). ',
'See https://yihui.org/en/2021/10/unbalanced-delimiters/ for more info.'
)
TRUE
}

# TODO: just use check_old_package() in xfun >= 0.42
check_old = function(name, version) {
for (i in seq_along(name))
if (xfun::check_old_package(name[i], version[i])) return(TRUE)
FALSE
}

#' Get all chunk labels in a document
#'
#' The function \code{all_labels()} returns all chunk labels as a character
Expand Down

0 comments on commit 0d1ad21

Please sign in to comment.