Skip to content

Commit

Permalink
Work around cmark sourcepos indent bug (#1391)
Browse files Browse the repository at this point in the history
Closes #1353.
  • Loading branch information
gaborcsardi authored Jul 10, 2022
1 parent dd713e7 commit 5ead04a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# roxygen2 (development version)

* Fix bug interpolating the results of indented inline RMarkdown (#1353).

* R6 documentation no longer shows inherited methods if there aren't any
(#1371).

Expand Down
40 changes: 38 additions & 2 deletions R/markdown.R
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,47 @@ markdown_pass1 <- function(text) {
rcode_nodes <- keep(code_nodes, is_markdown_code_node)
if (length(rcode_nodes) == 0) return(text)
rcode_pos <- parse_md_pos(map_chr(rcode_nodes, xml_attr, "sourcepos"))
rcode_pos <- work_around_cmark_sourcepos_bug(text, rcode_pos)
out <- eval_code_nodes(rcode_nodes)
str_set_all_pos(text, rcode_pos, out, rcode_nodes)
}

# Work around commonmark sourcepos bug for inline R code
# https://github.com/r-lib/roxygen2/issues/1353
work_around_cmark_sourcepos_bug <- function(text, rcode_pos) {
if (Sys.getenv("ROXYGEN2_NO_SOURCEPOS_WORKAROUND", "") != "") {
return(rcode_pos)
}

lines <- str_split(text, fixed("\n"))[[1]]

for (l in seq_len(nrow(rcode_pos))) {
# Do not try to fix multi-line code, we error for that (below)
if (rcode_pos$start_line[l] != rcode_pos$end_line[l]) next
line <- lines[rcode_pos$start_line[l]]
start <- rcode_pos$start_column[l]

# Maybe correct? At some point this will be fixed upstream, hopefully.
if (str_sub(line, start - 1, start + 1) == "`r ") next

# Maybe indented and we can shift it?
# It is possible that the shift that we try accidentally matches
# "`r ", but it seems to be extremely unlikely. An example is this:
# #' ``1`r `` `r 22*10`
# (seven spaces after the #', so an indent of six spaces. If we shift
# the real "`r " left by six characters, there happens to be another
# "`r " there.

indent <- nchar(str_extract(line, "^[ ]+"))
if (str_sub(line, start - 1 + indent, start + 1 + indent) == "`r ") {
rcode_pos$start_column[l] <- rcode_pos$start_column[l] + indent
rcode_pos$end_column[l] <- rcode_pos$end_column[l] + indent
}
}

rcode_pos
}

is_markdown_code_node <- function(x) {
info <- str_sub(xml_attr(x, "info"), 1, 3)
str_sub(xml_text(x), 1, 2) == "r " ||
Expand Down Expand Up @@ -124,8 +161,7 @@ knitr_chunk_defaults <- list(
str_set_all_pos <- function(text, pos, value, nodes) {
# Cmark has a bug when reporting source positions for multi-line
# code tags, and it does not count the indenting space in the
# continuation lines. However, the bug might get fixed later, so
# for now we just simply error for multi-line inline code.
# continuation lines: https://github.com/commonmark/cmark/issues/296
types <- xml_name(nodes)
if (any(types == "code" & pos$start_line != pos$end_line)) {
cli::cli_abort("multi-line `r ` markup is not supported", call = NULL)
Expand Down
16 changes: 16 additions & 0 deletions tests/testthat/test-markdown-code.R
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,19 @@ test_that("fragile tags in generated code", {
expect_silent(out2 <- markdown("foo `r '\\\\out{<span></span>}'` bar"))
expect_equal(out2, "foo \\out{<span></span>} bar")
})

test_that("workaround for cmark sourcepos bug (#1353) works", {
out <- roc_proc_text(rd_roclet(), "
#' Title
#'
#' line1
#' pre `r \"1\"` 2 `r 1+2` post
#'
#' no workaround needed `r 'here'`
#' @md
foo <- function() {}
")[[1]]

expect_equal(out$get_section("description")$value, "line1\npre 1 2 3 post")
expect_equal(out$get_section("details")$value, "no workaround needed here")
})

0 comments on commit 5ead04a

Please sign in to comment.