diff --git a/NEWS.md b/NEWS.md index a71218b68..f628a5bf2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # pkgdown (development version) +* `build_reference()` adds anchors to arguments making it possible to link directly to an argument, if desired. A subtle visual treatment makes it easy to see which argument is targeted (#2228). * `as.pkgdown()` will no longer prompt you to install a missing template package from CRAN, since these are almost always found in GitHub (#2076). * `init_site()` once again describes one copy per line, and now uses a better prefix when copying assets from pkgdown itself (#2445). * Very wide words are now automatically broken across lines and hyphenated (when possible) when they'd otherwise create a horizontal scrollbar on mobile (#1888). diff --git a/R/rd-data.R b/R/rd-data.R index 55c325124..56c7550af 100644 --- a/R/rd-data.R +++ b/R/rd-data.R @@ -65,7 +65,7 @@ as_data.tag_section <- function(x, ...) { as_data.tag_arguments <- function(x, ...) { list( title = tr_("Arguments"), - contents = describe_contents(x, ...) + contents = describe_contents(x, ..., id_prefix = "arg-") ) } @@ -77,7 +77,7 @@ as_data.tag_value <- function(x, ...) { ) } -describe_contents <- function(x, ...) { +describe_contents <- function(x, ..., id_prefix = NULL) { # Drop pure whitespace nodes between items is_ws <- purrr::map_lgl(x, is_whitespace) @@ -90,7 +90,7 @@ describe_contents <- function(x, ...) { if (length(x) == 0) { NULL } else if (any(purrr::map_lgl(x, inherits, "tag_item"))) { - paste0("
\n", parse_descriptions(x, ...), "
") + paste0("
\n", parse_descriptions(x, ..., id_prefix = id_prefix), "
") } else { flatten_para(x, ...) } diff --git a/R/rd-html.R b/R/rd-html.R index b99557d14..958e40c27 100644 --- a/R/rd-html.R +++ b/R/rd-html.R @@ -366,16 +366,27 @@ parse_items <- function(rd, ...) { paste(collapse = "") } -parse_descriptions <- function(rd, ...) { +parse_descriptions <- function(rd, ..., id_prefix = NULL) { if (length(rd) == 0) { return(character()) } parse_item <- function(x) { if (inherits(x, "tag_item")) { + term <- flatten_text(x[[1]], ...) + def <- flatten_para(x[[2]], ...) + + if (!is.null(id_prefix)) { + id <- paste0(id_prefix, make_slug(term)) + id_attr <- paste0(" id='", id, "'") + anchor <- anchor_html(id) + } else { + id_attr <- "" + anchor <- "" + } paste0( - "
", flatten_text(x[[1]], ...), "
\n", - "
", flatten_para(x[[2]], ...), "
\n" + "", term, anchor, "\n", + "
", def , "
\n" ) } else { flatten_text(x, ...) diff --git a/R/tweak-tags.R b/R/tweak-tags.R index b61698ecd..d9ae8eed6 100644 --- a/R/tweak-tags.R +++ b/R/tweak-tags.R @@ -22,9 +22,7 @@ tweak_anchors <- function(html) { xml2::xml_attr(headings, "id") <- new_id # Insert anchors - anchor <- paste0( - "" - ) + anchor <- anchor_html(id) for (i in seq_along(headings)) { heading <- headings[[i]] if (length(xml2::xml_contents(heading)) == 0) { @@ -37,6 +35,10 @@ tweak_anchors <- function(html) { invisible() } +anchor_html <- function(id) { + paste0("") +} + tweak_link_md <- function(html) { links <- xml2::xml_find_all(html, ".//a") if (length(links) == 0) diff --git a/inst/BS5/assets/pkgdown.scss b/inst/BS5/assets/pkgdown.scss index 5b97fce38..d44997238 100644 --- a/inst/BS5/assets/pkgdown.scss +++ b/inst/BS5/assets/pkgdown.scss @@ -236,8 +236,9 @@ body { // spacing tweaks dd { - margin-left: 1.5rem; + padding-left: 1.5rem } + summary { margin-bottom: 0.5rem; } @@ -261,10 +262,23 @@ a.anchor { background-size: Min(0.9em, 20px) Min(0.9em, 20px); background-position: center center; } -h2, h3, h4, h5, h6 { +h2, h3, h4, h5, h6, dt { &:hover .anchor {display: inline-block;} } +// Give targetted arguments some visual distinction +dt:target, dt:target + dd { + border-left: 0.5rem solid $info; + margin-left: -0.75rem; +} +dt:target { + padding-left: 0.25rem; +} +dt:target + dd { + padding-left: 1.75rem; +} + + // orcid badge .orcid { color: #A6CE39; diff --git a/tests/testthat/assets/reference/R/funs.R b/tests/testthat/assets/reference/R/funs.R index b3cd42500..a1f3b814d 100644 --- a/tests/testthat/assets/reference/R/funs.R +++ b/tests/testthat/assets/reference/R/funs.R @@ -1,7 +1,10 @@ #' A #' @export #' @keywords foo -a <- function() {} +#' @param a a letter +#' @param b a a number +#' @param c a logical +a <- function(a, b, c) {} #' B #' @export diff --git a/tests/testthat/assets/reference/man/a.Rd b/tests/testthat/assets/reference/man/a.Rd index c71c4950d..0a4c25842 100644 --- a/tests/testthat/assets/reference/man/a.Rd +++ b/tests/testthat/assets/reference/man/a.Rd @@ -4,7 +4,14 @@ \alias{a} \title{A} \usage{ -a() +a(a, b, c) +} +\arguments{ +\item{a}{a letter} + +\item{b}{a a number} + +\item{c}{a logical} } \description{ A diff --git a/tests/testthat/test-build-reference.R b/tests/testthat/test-build-reference.R index 273fc0cb7..da6b49626 100644 --- a/tests/testthat/test-build-reference.R +++ b/tests/testthat/test-build-reference.R @@ -104,6 +104,15 @@ test_that("examples are reproducible by default, i.e. 'seed' is respected", { expect_snapshot(cat(examples)) }) +test_that("arguments get individual ids", { + pkg <- local_pkgdown_site(test_path("assets/reference")) + suppressMessages(build_reference(pkg, topics = "a")) + + html <- xml2::read_html(file.path(pkg$dst_path, "reference", "a.html")) + expect_equal(xpath_attr(html, "//dt", "id"), c("arg-a", "arg-b", "arg-c")) + +}) + test_that("title and page title escapes html", { pkg <- local_pkgdown_site(test_path("assets/reference")) suppressMessages(build_reference(pkg, topics = "g")) diff --git a/tests/testthat/test-rd-html.R b/tests/testthat/test-rd-html.R index 1d77e8545..8584b84ff 100644 --- a/tests/testthat/test-rd-html.R +++ b/tests/testthat/test-rd-html.R @@ -355,6 +355,14 @@ test_that("\\describe items can contain multiple paragraphs", { expect_snapshot_output(cat(out, sep = "\n")) }) +test_that("can add ids to descriptions", { + out <- rd2html("\\describe{ + \\item{abc}{Contents 1} + \\item{xyz}{Contents 2} + }", id_prefix = "foo") + expect_snapshot_output(cat(out, sep = "\n")) +}) + test_that("\\describe items can contain multiple paragraphs", { out <- rd2html("\\describe{ \\item{Label}{