diff --git a/NEWS.md b/NEWS.md index 827ef6beda..2b4badc11c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,8 @@ rmarkdown 2.7 - Automatically exclude renv directory for `render_site()` (thanks, @jmbuhr, #1996) +- Number offset for section headers can be set via the `number_offset` top-level option of the YAML front matter. This feature supports variety of formats including those without native `--number-sections` option (e.g., `md_document`) (thanks, @atusy, #1999). + rmarkdown 2.6 ================================================================================ diff --git a/R/render.R b/R/render.R index e743d9bb0c..b854ee8307 100644 --- a/R/render.R +++ b/R/render.R @@ -875,6 +875,13 @@ render <- function(input, pandoc_args <- output_format$pandoc$args + # let number_offset in metadata be an alternative of --number-offset option + if (("--number-sections" %in% pandoc_args) && !is.null(env$metadata$number_offset)) { + pandoc_args <- c( + pandoc_args, paste0("--number-offset=", env$metadata$number_offset) + ) + } + # if Lua filters are provided, add the command line switch if (!is.null(lua_filters <- output_format$pandoc$lua_filters)) { lua_filters <- pandoc_lua_filter_args(lua_filters) diff --git a/inst/rmarkdown/lua/number-sections.lua b/inst/rmarkdown/lua/number-sections.lua index 50596b5a9e..eb65382cf1 100644 --- a/inst/rmarkdown/lua/number-sections.lua +++ b/inst/rmarkdown/lua/number-sections.lua @@ -21,6 +21,18 @@ if FORMAT == "docx" then -- to be consistent with Pandoc >= 2.10.1 separator = pandoc.Str("\t") end +function Meta(meta) + local offset = meta.number_offset + if offset then + offset = (type(offset) == "table") and (pandoc.utils.stringify(offset)) or offset + local i = 0 + for int in string.gmatch(offset, "[0-9]+") do + i = i + 1 + section_number_table[i] = tonumber(int) + end + end +end + function Header(elem) -- If unnumbered if (elem.classes:find("unnumbered")) then @@ -51,3 +63,8 @@ function Header(elem) return elem end + +return { + {Meta = Meta}, + {Header = Header} +} diff --git a/tests/testthat/test-lua-filters.R b/tests/testthat/test-lua-filters.R index ad45c652fb..8392518d61 100644 --- a/tests/testthat/test-lua-filters.R +++ b/tests/testthat/test-lua-filters.R @@ -27,14 +27,28 @@ test_that("pagebreak Lua filters works", { }) test_that("number_sections Lua filter works", { - numbers <- c("1", "1.1", "2", "2.1") - headers <- c("#", "##", "#", "##") - rmd <- paste0(headers, " ", numbers, "\n\n") - result <- .generate_md_and_convert(rmd, md_document(number_sections = TRUE)) - expected <- paste(numbers, numbers) - # pandoc 2.11.2 default to atx headers - if (pandoc_available("2.11.2")) expected <- paste(headers, expected) - expect_identical(result[result %in% expected], expected) + test_number_sections <- function(number_offset = 0L) { + numbers <- paste0( + c(1L, 1L, 2L, 2L) + number_offset, + c("", ".1", "", ".1") + ) + headers <- c("#", "##", "#", "##") + result <- .generate_md_and_convert( + paste0(headers, " ", numbers, "\n\n"), + md_document( + number_sections = TRUE, + pandoc_args = if (number_offset > 0) { + sprintf("--metadata=number_offset:%s", number_offset) + } + ) + ) + expected <- paste(numbers, numbers) + # pandoc 2.11.2 default to atx headers + if (pandoc_available("2.11.2")) expected <- paste(headers, expected) + expect_identical(result[result %in% expected], expected) + } + test_number_sections(1L) + test_number_sections(2L) }) test_that("formats have the expected Lua filter", {