From 0d8eabdfc85772d2ceb6e4804a247537c6dff31c Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Fri, 9 Aug 2024 16:02:40 -0500 Subject: [PATCH 1/9] fix #2567: add classes `odd`, `even`, and `header` back to table rows for Pandoc >= 3.2.1 may also close #2566 --- DESCRIPTION | 2 +- NEWS.md | 3 +++ R/html_document_base.R | 5 ++++- inst/rmarkdown/lua/table-classes.lua | 20 ++++++++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 inst/rmarkdown/lua/table-classes.lua diff --git a/DESCRIPTION b/DESCRIPTION index 10098ecadb..19e09cef98 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: rmarkdown Title: Dynamic Documents for R -Version: 2.27.1 +Version: 2.27.2 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut"), person("Yihui", "Xie", , "xie@yihui.name", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0645-5666")), diff --git a/NEWS.md b/NEWS.md index facb43f6e5..84b0bf3d42 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,11 @@ rmarkdown 2.28 ================================================================================ +- Add classes `odd`, `even`, and `header` back to table rows for Pandoc >= 3.2.1, so tables can be styled properly (thanks, @therealgenna, #2567). + - `beamer_presentation` support handling latex dependencies via the new `extra_dependencies` argument and declarations within chunks (e.g., `knitr::asis_output("", meta = list(rmarkdown::latex_dependency("longtable")))`) (thanks, @cderv, @atusy, #2478). + rmarkdown 2.27 ================================================================================ diff --git a/R/html_document_base.R b/R/html_document_base.R index d2dff82b1c..8992aad03a 100644 --- a/R/html_document_base.R +++ b/R/html_document_base.R @@ -237,7 +237,10 @@ html_document_base <- function(theme = NULL, knitr = NULL, pandoc = pandoc_options( to = "html", from = NULL, args = args, - lua_filters = pkg_file_lua(c("pagebreak.lua", "latex-div.lua")) + lua_filters = pkg_file_lua(c( + "pagebreak.lua", "latex-div.lua", + if (pandoc_available("3.2.1")) "table-classes.lua" + )) ), keep_md = FALSE, clean_supporting = FALSE, diff --git a/inst/rmarkdown/lua/table-classes.lua b/inst/rmarkdown/lua/table-classes.lua new file mode 100644 index 0000000000..b4fb23ad36 --- /dev/null +++ b/inst/rmarkdown/lua/table-classes.lua @@ -0,0 +1,20 @@ +--[[ +Add classes 'odd' (or 'header' in table header) / 'even' to table rows +]] + +local function add_odd_even (rows, odd) + odd = odd or 'odd' + for rownum, row in ipairs(rows) do + row.classes:insert((rownum % 2) == 0 and 'even' or odd) + end + return rows +end + +function Table (tbl) + add_odd_even(tbl.head.rows, 'header') + for _, tblbody in ipairs(tbl.bodies) do + add_odd_even(tblbody.body) + end + add_odd_even(tbl.foot.rows) + return tbl +end From c61d0f24ea26ea88f30ba520b000253bf8c54f2e Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Fri, 9 Aug 2024 16:16:34 -0500 Subject: [PATCH 2/9] update tests for lua filters accordingly --- tests/testthat/test-lua-filters.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/testthat/test-lua-filters.R b/tests/testthat/test-lua-filters.R index 4f273dc0fe..9a907392cc 100644 --- a/tests/testthat/test-lua-filters.R +++ b/tests/testthat/test-lua-filters.R @@ -108,14 +108,15 @@ test_that("formats have the expected Lua filter", { } # different lua filter pgb <- "pagebreak"; lxd <- "latex-div" + tbl <- if (pandoc_available("3.2.1")) "table-classes" nbs <- "number-sections"; acs <- "anchor-sections" expect_filters(beamer_presentation(), c(pgb, lxd)) expect_filters(github_document(number_sections = TRUE), md_document(number_sections = TRUE)) - expect_filters(html_document(), c(pgb, lxd)) - expect_filters(html_document(anchor_sections = TRUE), c(pgb, lxd, acs)) - expect_filters(html_document(anchor_sections = list(depth = 3)), c(pgb, lxd, acs)) - expect_filters(html_document_base(), c(pgb, lxd)) + expect_filters(html_document(), c(pgb, lxd, tbl)) + expect_filters(html_document(anchor_sections = TRUE), c(pgb, lxd, tbl, acs)) + expect_filters(html_document(anchor_sections = list(depth = 3)), c(pgb, lxd, tbl, acs)) + expect_filters(html_document_base(), c(pgb, lxd, tbl)) expect_filters(latex_document(), c(pgb, lxd)) expect_filters(context_document(ext = ".tex"), c(pgb)) expect_filters(md_document(number_sections = TRUE), c(nbs)) @@ -123,7 +124,7 @@ test_that("formats have the expected Lua filter", { expect_filters(powerpoint_presentation(number_sections = TRUE), c(nbs)) expect_filters(odt_document(number_sections = TRUE), c(pgb, nbs)) expect_filters(rtf_document(number_sections = TRUE), c(nbs)) - expect_filters(slidy_presentation(number_sections = TRUE), c(pgb, lxd, nbs)) + expect_filters(slidy_presentation(number_sections = TRUE), c(pgb, lxd, tbl, nbs)) expect_filters( word_document(number_sections = TRUE), c(pgb, if (!pandoc_available("2.10.1")) nbs) From 8dca3ac37ddbab762643337edfc60e985903a4b2 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Sat, 17 Aug 2024 10:47:54 -0500 Subject: [PATCH 3/9] CRAN release v2.28 --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 19e09cef98..9c15c5d639 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: rmarkdown Title: Dynamic Documents for R -Version: 2.27.2 +Version: 2.28 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut"), person("Yihui", "Xie", , "xie@yihui.name", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0645-5666")), From 8a5789288632f61c8d9923b63e51018cea472841 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Sat, 17 Aug 2024 10:48:34 -0500 Subject: [PATCH 4/9] start the next version --- DESCRIPTION | 2 +- NEWS.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9c15c5d639..b9cd2569d9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: rmarkdown Title: Dynamic Documents for R -Version: 2.28 +Version: 2.28.1 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut"), person("Yihui", "Xie", , "xie@yihui.name", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0645-5666")), diff --git a/NEWS.md b/NEWS.md index 84b0bf3d42..c0f1361ea6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +rmarkdown 2.29 +================================================================================ + + rmarkdown 2.28 ================================================================================ From cda675af2583e3691ef0bf3558961436dec9a614 Mon Sep 17 00:00:00 2001 From: Tom Palmer Date: Wed, 28 Aug 2024 11:08:39 +0100 Subject: [PATCH 5/9] Update actions/checkout to v4 (#2570) --- .github/workflows/R-CMD-check.yaml | 2 +- .github/workflows/check-pandoc-daily.yaml | 2 +- .github/workflows/pkgdown.yaml | 2 +- .github/workflows/update-citation-cff.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 4df14ebc92..c3dce49234 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -57,7 +57,7 @@ jobs: actions: read steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: diff --git a/.github/workflows/check-pandoc-daily.yaml b/.github/workflows/check-pandoc-daily.yaml index ede043bf14..553769c92a 100644 --- a/.github/workflows/check-pandoc-daily.yaml +++ b/.github/workflows/check-pandoc-daily.yaml @@ -26,7 +26,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 21e25e364b..eb8984c113 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -20,7 +20,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/update-citation-cff.yaml b/.github/workflows/update-citation-cff.yaml index 15ca84acfa..9606bdf108 100644 --- a/.github/workflows/update-citation-cff.yaml +++ b/.github/workflows/update-citation-cff.yaml @@ -17,7 +17,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: From 4e22703b9293552078476d74966ee3cd6307fb1e Mon Sep 17 00:00:00 2001 From: Luis Verde Arregoitia Date: Mon, 9 Sep 2024 16:34:27 -0600 Subject: [PATCH 6/9] consistent dev install instructions (#2571) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ba4dbcb43..f2f2015e69 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ If you want to use the rmarkdown package outside of RStudio, you can install the install.packages("rmarkdown") ``` -If you want to use the development version of the rmarkdown package (either with or without RStudio), you can install the package from GitHub via the [**remotes** package](https://remotes.r-lib.org): +If you want to use the development version of the rmarkdown package (either with or without RStudio), you can install the package from GitHub via the [**pak** package](https://pak.r-lib.org): ```r # install.packages("pak") From da85f8c7a6294cab3447a41ad82e4018a51139c4 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Sep 2024 21:40:09 +0200 Subject: [PATCH 7/9] Support new Pandoc 3.4 behavior with GFM math (#2573) --- DESCRIPTION | 2 +- R/github_document.R | 4 ++-- tests/testthat/test-github_document.R | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b9cd2569d9..e24bba43bf 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: rmarkdown Title: Dynamic Documents for R -Version: 2.28.1 +Version: 2.28.2 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut"), person("Yihui", "Xie", , "xie@yihui.name", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0645-5666")), diff --git a/R/github_document.R b/R/github_document.R index 994496a115..8784c55641 100644 --- a/R/github_document.R +++ b/R/github_document.R @@ -102,8 +102,8 @@ github_document <- function(toc = FALSE, # don't activate math in Pandoc and pass it as is # https://github.blog/changelog/2022-05-19-render-mathematical-expressions-in-markdown/ math <- NULL - # TODO: Check for version - should be the default in Pandoc 2.19+ - variant <- paste0(variant, "+tex_math_dollars") + # Pandoc 3.4 uses +tex_math_gfm by default to write special gfm syntax. We choose to keep $$ and $ which are still supported by Github + variant <- if (pandoc_available("3.4")) paste0(variant, "-tex_math_gfm") else paste0(variant, "+tex_math_dollars") preview_math <- check_math_argument("mathjax") } else { # fallback to webtex diff --git a/tests/testthat/test-github_document.R b/tests/testthat/test-github_document.R index 3e622087ee..cc996513d9 100644 --- a/tests/testthat/test-github_document.R +++ b/tests/testthat/test-github_document.R @@ -13,7 +13,7 @@ test_that("toc has correct identifier", { } else { "before-pandoc-2.18" } - res <- render(tmp_file, github_document(toc = TRUE, html_preview = FALSE)) + res <- render(tmp_file, github_document(toc = TRUE, html_preview = FALSE), quiet = TRUE) expect_snapshot_file(res, "github-toc.md", compare = compare_file_text, variant = pandoc_version) }) @@ -32,7 +32,7 @@ test_that("toc has correct identifier also when sections are numbered ", { } else { "before-pandoc-2.18" } - res <- render(tmp_file, github_document(toc = TRUE, number_sections = TRUE, html_preview = FALSE)) + res <- render(tmp_file, github_document(toc = TRUE, number_sections = TRUE, html_preview = FALSE), quiet = TRUE) expect_snapshot_file(res, "github-toc-numbered.md", compare = compare_file_text, variant = pandoc_version) }) @@ -41,7 +41,7 @@ test_that("github_document produces atx-header", { skip_on_cran() # avoid pandoc issue on CRAN h <- paste0(Reduce(paste0, rep("#", 5), accumulate = TRUE), " title ", 1:5, "\n\n") tmp_file <- local_rmd_file(h) - res <- render(tmp_file, github_document(html_preview = FALSE)) + res <- render(tmp_file, github_document(html_preview = FALSE), quiet = TRUE) expect_snapshot_file(res, "github-atx.md", compare = compare_file_text) }) From 9bf0910ad02c15a1099b860688382481a5c1838d Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Sep 2024 10:01:16 +0200 Subject: [PATCH 8/9] Add support for `child=c("child.Rmd")` in find_external_resources() (#2575) --- NEWS.md | 1 + R/html_resources.R | 2 +- tests/testthat/test-resources.R | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c0f1361ea6..ba8fefa3a5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ rmarkdown 2.29 ================================================================================ +- `find_external_resources()` now correctly detects knitr child document provided with option like `child = c("child.Rmd")` (thanks, @rempsyc, #2574). rmarkdown 2.28 ================================================================================ diff --git a/R/html_resources.R b/R/html_resources.R index c4aa4f68d0..e7005c56e4 100644 --- a/R/html_resources.R +++ b/R/html_resources.R @@ -316,7 +316,7 @@ discover_rmd_resources <- function(rmd_file, discover_single_resource) { rmd_content[idx], chunk_start, chunk_start + attr(chunk_line, "capture.length", exact = TRUE) - 2 ) - for (child_expr in c("\\bchild\\s*=\\s*'([^']+)'", "\\bchild\\s*=\\s*\"([^\"]+)\"")) { + for (child_expr in c("\\bchild\\s*=\\s*(?:c\\()?'([^']+)'\\)?", "\\bchild\\s*=\\s*(?:c\\()?\"([^\"]+)\"\\)?")) { child_match <- gregexpr(child_expr, chunk_text, perl = TRUE)[[1]] if (child_match > 0) { child_start <- attr(child_match, "capture.start", exact = TRUE) diff --git a/tests/testthat/test-resources.R b/tests/testthat/test-resources.R index 65c7891434..50d5beaf44 100644 --- a/tests/testthat/test-resources.R +++ b/tests/testthat/test-resources.R @@ -263,3 +263,24 @@ test_that("multiple resources in the includes option can be discovered", { expect_equal(resources, expected) }) + +test_that("knitr child are correctly discovered as resources from chunk options", { + expect_child_resource_found <- function(child_opts, child) { + dir <- withr::local_tempdir("find-child") + withr::local_dir(dir) + rmd <- "test.Rmd" + xfun::write_utf8( + text = knitr::knit_expand(text = c("```{r,<>}", "```"), delim = c("<<", ">>")), + rmd + ) + xfun::write_utf8(c("Content"), child) + expect_contains(find_external_resources(!!rmd)$path, !!child) + } + child <- "child.Rmd" + expect_child_resource_found('child="child.Rmd"', child) + expect_child_resource_found(' child = "child.Rmd"', child) + expect_child_resource_found('child=c("child.Rmd")', child) + expect_child_resource_found("child='child.Rmd'", child) + expect_child_resource_found(" child = 'child.Rmd'", child) + expect_child_resource_found("child=c('child.Rmd')", child) +}) From c787e8a8c96726b4c3430bc53360be5f806bb114 Mon Sep 17 00:00:00 2001 From: Aron Atkins Date: Fri, 13 Sep 2024 17:06:29 -0400 Subject: [PATCH 9/9] parameters with `choices` and `multiple = TRUE` should use a `select` input (#2576) --- NEWS.md | 21 ++++++++++ R/params.R | 13 +++--- tests/testthat/test-params.R | 80 ++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index ba8fefa3a5..9481647838 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,27 @@ rmarkdown 2.29 - `find_external_resources()` now correctly detects knitr child document provided with option like `child = c("child.Rmd")` (thanks, @rempsyc, #2574). +- `knit_params_ask()` uses a `select` input for parameters which allow multiple selected values. Previously, a `radio` input was incorrectly used when the parameter had a small number of choices. + + ```yaml + params: + primaries: + choices: ["red", "yellow", "blue"] + multiple: true + ``` + + When `multiple` is not enabled, parameter configuration still uses `radio` when there are fewer than five choices. + + The `input` parameter field can still be used to force the configuration control. + + ```yaml + params: + grade: + input: radio + choices: ["A", "B", "C", "D", "F"] + ``` + + rmarkdown 2.28 ================================================================================ diff --git a/R/params.R b/R/params.R index 17b5ddccb1..74ca9d1eca 100644 --- a/R/params.R +++ b/R/params.R @@ -161,11 +161,13 @@ params_get_input <- function(param) { input <- param$input if (is.null(input)) { if (!is.null(param$choices)) { - ## radio buttons for a small number of choices, select otherwise. - if (length(param$choices) <= 4) { - input <- "radio" - } else { + ## select for a large number of choices and multiple choices. + if (isTRUE(param$multiple)) { + input <- "select" + } else if (length(param$choices) > 4) { input <- "select" + } else { + input <- "radio" } } else { ## Not choices. Look at the value type to find what input control we @@ -219,8 +221,7 @@ params_configurable <- function(param) { } # Some inputs (like selectInput) support the selection of # multiple entries through a "multiple" argument. - multiple_ok <- (!is.null(param$multiple) && param$multiple) - if (multiple_ok) { + if (isTRUE(param$multiple)) { return(TRUE) } # sliderInput supports either one or two-value inputs. diff --git a/tests/testthat/test-params.R b/tests/testthat/test-params.R index 04a8678bb4..2d45378704 100644 --- a/tests/testthat/test-params.R +++ b/tests/testthat/test-params.R @@ -105,6 +105,86 @@ test_that("parameters are configurable", { value = c(10, 20, 30)))) }) +test_that("params_get_input", { + # input derived from value type. + expect_equal(params_get_input(list( + value = TRUE + )), "checkbox") + expect_equal(params_get_input(list( + value = as.integer(42) + )), "numeric") + expect_equal(params_get_input(list( + value = 7.5 + )), "numeric") + expect_equal(params_get_input(list( + value = "character" + )), "text") + expect_equal(params_get_input(list( + value = Sys.Date() + )), "date") + expect_equal(params_get_input(list( + value = Sys.time() + )), "datetime") + + # numeric becomes a slider with both min and max + expect_equal(params_get_input(list( + value = as.integer(42), + min = 0 + )), "numeric") + expect_equal(params_get_input(list( + value = as.integer(42), + max = 100 + )), "numeric") + expect_equal(params_get_input(list( + value = as.integer(42), + min = 0, + max = 100 + )), "slider") + expect_equal(params_get_input(list( + value = 7.5, + min = 0 + )), "numeric") + expect_equal(params_get_input(list( + value = 7.5, + max = 10 + )), "numeric") + expect_equal(params_get_input(list( + value = 7.5, + min = 0, + max = 10 + )), "slider") + + # choices implies radio or select + expect_equal(params_get_input(list( + value = "red", + choices = c("red", "green", "blue") + )), "radio") + expect_equal(params_get_input(list( + value = "red", + multiple = TRUE, + choices = c("red", "green", "blue") + )), "select") + expect_equal(params_get_input(list( + value = "red", + choices = c("red", "green", "blue", "yellow", "black", "white") + )), "select") + expect_equal(params_get_input(list( + value = "red", + multiple = TRUE, + choices = c("red", "green", "blue", "yellow", "black", "white") + )), "select") + + # explicit input overrides inference + expect_equal(params_get_input(list( + input = "slider", + value = 42 + )), "slider") + expect_equal(params_get_input(list( + input = "file", + value = "data.csv" + )), "file") +}) + test_that("params hidden w/o show_default", { # file input is always NULL