From 4e99d8cec798345e0748ce0841d4c0ecc917fe04 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 23 Apr 2026 07:46:10 -0500 Subject: [PATCH] Preserve multi-line content This ensures that we don't change existing behaviour, just give better warnings. Fixes #1867 --- R/rd-r6-external.R | 4 +-- R/tag-parser.R | 22 +++++++--------- tests/testthat/_snaps/tag-parser.md | 40 +++++++---------------------- tests/testthat/test-tag-parser.R | 23 ++++++++--------- 4 files changed, 29 insertions(+), 60 deletions(-) diff --git a/R/rd-r6-external.R b/R/rd-r6-external.R index 87ecea9a..123a7e5b 100644 --- a/R/rd-r6-external.R +++ b/R/rd-r6-external.R @@ -5,9 +5,7 @@ roxy_tag_parse.roxy_tag_R6method <- function(x) { warn_roxy_tag(x, "requires a value like {.code Class$method}") return(NULL) } - if (warn_if_multiline(x, raw)) { - return(NULL) - } + warn_if_multiline(x, raw, multiline = FALSE) pieces <- strsplit(raw, "\\$")[[1]] if (length(pieces) != 2 || pieces[1] == "" || pieces[2] == "") { diff --git a/R/tag-parser.R b/R/tag-parser.R index 0ee91f71..32877c96 100644 --- a/R/tag-parser.R +++ b/R/tag-parser.R @@ -27,9 +27,7 @@ tag_value <- function(x, multiline = FALSE) { return(NULL) } - if (!multiline && warn_if_multiline(x, x$val)) { - return(NULL) - } + warn_if_multiline(x, x$val, multiline) if (!rdComplete(x$raw, is_code = FALSE)) { warn_roxy_tag(x, "has mismatched braces or quotes") @@ -134,12 +132,11 @@ tag_two_part <- function( warn_roxy_tag(x, "requires two parts: {first} and {second}") } NULL - } else if (!multiline && warn_if_multiline(x, trimws(x$raw))) { - NULL } else if (!rdComplete(x$raw, is_code = FALSE)) { warn_roxy_tag(x, "has mismatched braces or quotes") NULL } else { + warn_if_multiline(x, trimws(x$raw), multiline) pieces <- split_two_part(trimws(x$raw)) if (required && pieces[[2]] == "") { @@ -192,9 +189,7 @@ tag_name_description <- function(x) { tag_words <- function(x, min = 0, max = Inf, multiline = FALSE) { val <- trimws(x$raw) - if (!multiline && warn_if_multiline(x, val)) { - return(NULL) - } + warn_if_multiline(x, val, multiline) if (!rdComplete(x$raw, is_code = FALSE)) { warn_roxy_tag(x, "has mismatched braces or quotes") @@ -221,8 +216,11 @@ tag_words_line <- function(x) { tag_words(x) } -# Returns TRUE (and warns) if val contains multiple lines, FALSE otherwise. -warn_if_multiline <- function(x, val) { +# Warns if multiline is FALSE and val contains multiple lines. +warn_if_multiline <- function(x, val, multiline) { + if (multiline) { + return(invisible()) + } n_lines <- re_count(val, "\n") if (n_lines >= 1) { first_line <- re_split_half(val, "\n")[[1]] @@ -233,10 +231,8 @@ warn_if_multiline <- function(x, val) { i = "The first line is {.str {first_line}}" ) ) - TRUE - } else { - FALSE } + invisible() } #' @export diff --git a/tests/testthat/_snaps/tag-parser.md b/tests/testthat/_snaps/tag-parser.md index b5d52f68..3a27601c 100644 --- a/tests/testthat/_snaps/tag-parser.md +++ b/tests/testthat/_snaps/tag-parser.md @@ -163,54 +163,32 @@ Message: x test.R:1: @test must have at most 1 word, not 2. -# tag_words() warns on multi-line content +# tag_words() warns on multi-line content and preserves value Code tag <- roxy_test_tag("a\nb") - expect_parse_failure(tag_words(tag)) - Output - - Message: + out <- tag_words(tag) + Message x test.R:1: @test must be only 1 line long, not 2. i The first line is "a" - Code - tag <- roxy_test_tag("a\nb\nc") - expect_parse_failure(tag_words(tag)) - Output - - Message: - x test.R:1: @test must be only 1 line long, not 3. - i The first line is "a" -# tag_two_part() warns on multi-line content by default +# tag_two_part() warns on multi-line content and preserves value Code tag <- roxy_test_tag("foo bar\nbaz") - expect_parse_failure(tag_two_part(tag, "a name", "a value")) - Output - - Message: + out <- tag_two_part(tag, "a name", "a value") + Message x test.R:1: @test must be only 1 line long, not 2. i The first line is "foo bar" -# tag_value() warns on multi-line content +# tag_value() warns on multi-line content and preserves value Code tag <- roxy_test_tag("a\nb") - expect_parse_failure(tag_value(tag)) - Output - - Message: + out <- tag_value(tag) + Message x test.R:1: @test must be only 1 line long, not 2. i The first line is "a" - Code - tag <- roxy_test_tag("a\nb\nc") - expect_parse_failure(tag_value(tag)) - Output - - Message: - x test.R:1: @test must be only 1 line long, not 3. - i The first line is "a" # tag_words_line() is deprecated diff --git a/tests/testthat/test-tag-parser.R b/tests/testthat/test-tag-parser.R index 4c06ffcc..35ab2dd9 100644 --- a/tests/testthat/test-tag-parser.R +++ b/tests/testthat/test-tag-parser.R @@ -77,35 +77,32 @@ test_that("tag_words() gives useful warnings", { }) }) -test_that("tag_words() warns on multi-line content", { +test_that("tag_words() warns on multi-line content and preserves value", { expect_snapshot({ tag <- roxy_test_tag("a\nb") - expect_parse_failure(tag_words(tag)) - - tag <- roxy_test_tag("a\nb\nc") - expect_parse_failure(tag_words(tag)) + out <- tag_words(tag) }) + expect_equal(out$val, c("a", "b")) }) -test_that("tag_two_part() warns on multi-line content by default", { +test_that("tag_two_part() warns on multi-line content and preserves value", { expect_snapshot({ tag <- roxy_test_tag("foo bar\nbaz") - expect_parse_failure(tag_two_part(tag, "a name", "a value")) + out <- tag_two_part(tag, "a name", "a value") }) + expect_equal(out$val, list(name = "foo", description = "bar\nbaz")) tag <- roxy_test_tag("foo bar\nbaz") - out <- tag_two_part(tag, "a name", "a value", multiline = TRUE) + out <- expect_silent(tag_two_part(tag, "a name", "a value", multiline = TRUE)) expect_equal(out$val, list(name = "foo", description = "bar\nbaz")) }) -test_that("tag_value() warns on multi-line content", { +test_that("tag_value() warns on multi-line content and preserves value", { expect_snapshot({ tag <- roxy_test_tag("a\nb") - expect_parse_failure(tag_value(tag)) - - tag <- roxy_test_tag("a\nb\nc") - expect_parse_failure(tag_value(tag)) + out <- tag_value(tag) }) + expect_equal(out$val, "a\nb") }) test_that("tag_words_line() is deprecated", {