File: vignette.R

package info (click to toggle)
r-cran-usethis 3.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,228 kB
  • sloc: sh: 26; makefile: 17; cpp: 6; ansic: 3
file content (179 lines) | stat: -rw-r--r-- 5,554 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#' Create a vignette or article
#'
#' Creates a new vignette or article in `vignettes/`. Articles are a special
#' type of vignette that appear on pkgdown websites, but are not included
#' in the package itself (because they are added to `.Rbuildignore`
#' automatically).
#'
#' @section General setup:
#' * Adds needed packages to `DESCRIPTION`.
#' * Adds `inst/doc` to `.gitignore` so built vignettes aren't tracked.
#' * Adds `vignettes/*.html` and `vignettes/*.R` to `.gitignore` so
#'   you never accidentally track rendered vignettes.
#' * For `*.qmd`, adds Quarto-related patterns to `.gitignore` and
#'   `.Rbuildignore`.
#' @param name File name to use for new vignette. Should consist only of
#'   numbers, letters, `_` and `-`. Lower case is recommended. Can include the
#'   `".Rmd"` or `".qmd"` file extension, which also dictates whether to place
#'   an R Markdown or Quarto vignette. R Markdown (`".Rmd"`) is the current
#'   default, but it is anticipated that Quarto (`".qmd"`) will become the
#'   default in the future.
#' @param title The title of the vignette. If not provided, a title is generated
#'   from `name`.
#' @seealso
#' * The [vignettes chapter](https://r-pkgs.org/vignettes.html) of
#'   [R Packages](https://r-pkgs.org)
#' * The pkgdown vignette on Quarto:
#'   `vignette("quarto", package = "pkgdown")`
#' * The quarto (as in the R package) vignette on HTML vignettes:
#'   `vignette("hello", package = "quarto")`
#' @export
#' @examples
#' \dontrun{
#' use_vignette("how-to-do-stuff", "How to do stuff")
#' use_vignette("r-markdown-is-classic.Rmd", "R Markdown is classic")
#' use_vignette("quarto-is-cool.qmd", "Quarto is cool")
#' }
use_vignette <- function(name, title = NULL) {
  check_is_package("use_vignette()")
  check_required(name)
  maybe_name(title)

  ext <- get_vignette_extension(name)
  if (ext == "qmd") {
    check_installed("quarto")
    check_installed("pkgdown", version = "2.1.0")
  }

  name <- path_ext_remove(name)
  check_vignette_name(name)
  title <- title %||% name

  use_dependency("knitr", "Suggests")
  use_git_ignore("inst/doc")

  if (tolower(ext) == "rmd") {
    use_dependency("rmarkdown", "Suggests")
    proj_desc_field_update("VignetteBuilder", "knitr", overwrite = TRUE, append = TRUE)
    use_vignette_template("vignette.Rmd", name, title)
  } else {
    use_dependency("quarto", "Suggests")
    proj_desc_field_update("VignetteBuilder", "quarto", overwrite = TRUE, append = TRUE)
    use_vignette_template("vignette.qmd", name, title)
  }

  invisible()
}

#' @export
#' @rdname use_vignette
use_article <- function(name, title = NULL) {
  check_is_package("use_article()")
  check_required(name)
  maybe_name(title)

  ext <- get_vignette_extension(name)
  if (ext == "qmd") {
    check_installed("quarto")
    check_installed("pkgdown", version = "2.1.0")
  }

  name <- path_ext_remove(name)
  title <- title %||% name

  if (tolower(ext) == "rmd") {
    proj_desc_field_update("Config/Needs/website", "rmarkdown", overwrite = TRUE, append = TRUE)
    use_vignette_template("article.Rmd", name, title, subdir = "articles")
  } else {
    use_dependency("quarto", "Suggests")
    proj_desc_field_update("Config/Needs/website", "quarto", overwrite = TRUE, append = TRUE)
    use_vignette_template("article.qmd", name, title, subdir = "articles")
  }
  use_build_ignore("vignettes/articles")

  invisible()
}

use_vignette_template <- function(template, name, title, subdir = NULL) {
  check_name(template)
  check_name(name)
  check_name(title)
  maybe_name(subdir)

  ext <- get_vignette_extension(template)

  if (is.null(subdir)) {
    target_dir <- "vignettes"
  } else {
    target_dir <- path("vignettes", subdir)
  }

  use_directory(target_dir)

  use_git_ignore(c("*.html", "*.R"), directory = target_dir)
  if (ext == "qmd") {
    use_git_ignore("**/.quarto/")
    use_git_ignore("*_files", target_dir)
    use_build_ignore(path(target_dir, ".quarto"))
    use_build_ignore(path(target_dir, "*_files"))
  }

  path <- path(target_dir, asciify(name), ext = ext)

  data <- list(
    Package = project_name(),
    vignette_title = title,
    braced_vignette_title = glue("{{{title}}}")
  )

  use_template(template,
    save_as = path,
    data = data,
    open = TRUE
  )

  path
}

check_vignette_name <- function(name) {
  if (!valid_vignette_name(name)) {
    ui_abort(c(
      "{.val {name}} is not a valid filename for a vignette. It must:",
      "Start with a letter.",
      "Contain only letters, numbers, '_', and '-'."
    ))
  }
}

# https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Writing-package-vignettes
# "To ensure that they can be accessed from a browser (as an HTML index is
# provided), the file names should start with an ASCII letter and be comprised
# entirely of ASCII letters or digits or hyphen or underscore."
valid_vignette_name <- function(x) {
  grepl("^[[:alpha:]][[:alnum:]_-]*$", x)
}

check_vignette_extension <- function(ext) {
  # Quietly accept "rmd" here, tho we'll always write ".Rmd" in such a filepath
  if (! ext %in% c("Rmd", "rmd", "qmd")) {
    valid_exts_cli <- cli::cli_vec(
      c("Rmd", "qmd"),
      style = list("vec-sep2" = " or ")
    )
    ui_abort(c(
      "Unsupported file extension: {.val {ext}}",
      "usethis can only create a vignette or article with one of these
       extensions: {.val {valid_exts_cli}}."
    ))
  }
}

get_vignette_extension <- function(name) {
  ext <- path_ext(name)
  if (nzchar(ext)) {
    check_vignette_extension(ext)
  } else {
    ext <- "Rmd"
  }
  ext
}