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}{