Skip to content

Commit

Permalink
Use cli (#1956)
Browse files Browse the repository at this point in the history
* Init article on the conversion task

* Build up the cli-based UI in one place

* Introduce ui_cli_bullets()

* author.R

* Factor out the path-processing logic into ui_path_impl()

* addin.R

* ui_bullets() is better because shorter

* badge.R

* ui_abort() feels more consistent with everything else

* Introduce ui_code_snippet()

* block.R

* Some testing improvements

* Test ui_code_snippet()

* Replace all calls to ui_code_block()

* Typo

* Update conversion article

* browse.R

* Eliminate usage of ui_warn()

* ci.R

* code_of_conduct.R

* course.R

* coverage.R

* cpp11.R

* Single quote inline .field if no color

* create.R

* data.R

* description.R

* directory.R

* edit.R

* git-default-branch.R

* git.R

* Test bulletize() and usethis_map_cli()

* github-actions.R

* .val seems like a better default for usethis

* github-labels.R

* github-pages.R

* github.R + check_current_branch()

* github_token.R

* Remove hd_line() which is not used anywhere at this point

* Notes

* Modernize kv_line() + other changes to improve git_sitrep()

* github_token.R

* helpers.R

* issue.R

* license.R

* lifecycle.R

* logo.R

* news.R

* package.R

* pkgdown.R

* Provide default bullets in ui_abort()

* pr.R

* proj-desc.R

* proj.R

* rcpp.R

* readme.R

* release.R

* rename-files.R

* revdep.R

* roxygen.R

* rprofile.R

* rstudio.R

* sitrep.R

* spelling.R

* template.R

* test.R

* tibble.R

* tidyverse.R

* upkeep.R

* use_github_file.R

* use_import_fun.R

* usethis-defunct.R

* Rename to ui_legacy_bullet(); catch up on note-taking

* utils-git.R

* utils.R

* version.R

* vignette.R

* write.R

* utils-github.R

* Add snapshot tests for remote GitHub configurations

* Finish converting UI around GitHub remote configurations

* Refactor flaky test

* Better organization

* Catch up on note-taking

* Work on making the article actually render the way I want

* Mark ui_*() functions as superseded

* Mark ui_yeah() and ui_no() as superseded

* Work on kv_line()

* Use ui_yep() and ui_nah() everywhere

* Re-align filenames re: legacy ui

* OMG I don't want people to depend on usethis for ui functions

* Switch to ui_nah() , for real

* Make sure I don't call into the legacy file

* Deal with stragglers that are not TODOs

* Update principles.md

* NEWS bullet

* Yet another straggler

* Deal with utils::menu() prep and other unusual stuff

* Make test less sensitive to local conditions

* Article needs asciicast

* Increase width to forcibly prevent snapshot diff due to linebreaks

I guess temp paths vary in length, even across separate runs on the same platform?

* Organize the articles

* Update README

* Make the width even larger???

* Apply suggestions from code review

Co-authored-by: olivroy <52606734+olivroy@users.noreply.github.com>

* Update snapshot

* How about cli.width?????

* YOLO

* `.run` fixups

* These run afoul of the `.run` rules, so why bother

* Better captures the intent

---------

Co-authored-by: olivroy <52606734+olivroy@users.noreply.github.com>
  • Loading branch information
jennybc and olivroy committed Mar 4, 2024
1 parent ce6ed46 commit fc8472c
Show file tree
Hide file tree
Showing 111 changed files with 3,631 additions and 1,485 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Expand Up @@ -53,7 +53,7 @@ Suggests:
spelling (>= 1.2),
styler (>= 1.2.0),
testthat (>= 3.1.8)
Config/Needs/website: tidyverse/tidytemplate, xml2
Config/Needs/website: r-lib/asciicast, tidyverse/tidytemplate, xml2
Config/testthat/edition: 3
Config/testthat/parallel: TRUE
Config/testthat/start-first: github-actions, release
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Expand Up @@ -3,6 +3,9 @@
S3method(format,github_remote_config)
S3method(print,github_remote_config)
S3method(print,sitrep)
S3method(usethis_map_cli,"NULL")
S3method(usethis_map_cli,character)
S3method(usethis_map_cli,default)
export(browse_circleci)
export(browse_cran)
export(browse_github)
Expand Down
13 changes: 13 additions & 0 deletions NEWS.md
@@ -1,5 +1,18 @@
# usethis (development version)

* The `ui_*()` functions have been marked as
[superseded](https://lifecycle.r-lib.org/articles/stages.html#superseded).
External users of these functions are encouraged to use the
[cli package](https://cli.r-lib.org/) instead.
The cli package did not have the required functionality when the
`usethis::ui_*()` functions were first created, but it does now and it's the
superior option.
There is a cli vignette about how to make this transition:
`vignette("usethis-ui", package = "cli")`.

usethis no longer uses the `ui_*()` functions internally, in favor of new
cli-based helpers that are not exported.

# usethis 2.2.3

* Patch release with changes to `.Rd` files requested by CRAN.
Expand Down
6 changes: 4 additions & 2 deletions R/addin.R
Expand Up @@ -15,13 +15,15 @@ use_addin <- function(addin = "new_addin", open = rlang::is_interactive()) {
if (!file_exists(addin_dcf_path)) {
create_directory(proj_path("inst", "rstudio"))
file_create(addin_dcf_path)
ui_done("Creating {ui_path(addin_dcf_path)}")
ui_bullets(c("v" = "Creating {.path {pth(addin_dcf_path)}}"))
}

addin_info <- render_template("addins.dcf", data = list(addin = addin))
addin_info[length(addin_info) + 1] <- ""
write_utf8(addin_dcf_path, addin_info, append = TRUE)
ui_done("Adding binding to {ui_code(addin)} to addins.dcf.")
ui_bullets(c(
"v" = "Adding binding to {.fun {addin}} to {.path addins.dcf}"
))

if (open) {
edit_file(addin_dcf_path)
Expand Down
53 changes: 28 additions & 25 deletions R/author.R
Expand Up @@ -60,13 +60,15 @@ use_author <- function(given = NULL, family = NULL, ..., role = "ctb") {
author <- utils::person(given = given, family = family, role = role, ...)
aut_fmt <- format(author, style = 'text')
if (authors_at_r_already) {
ui_done("
Adding to {ui_field('Authors@R')} in DESCRIPTION:
{aut_fmt}")
ui_bullets(c(
"v" = "Adding to {.field Authors@R} in DESCRIPTION:",
" " = "{aut_fmt}"
))
} else {
ui_done("
Creating {ui_field('Authors@R')} field in DESCRIPTION and adding:
{aut_fmt}")
ui_bullets(c(
"v" = "Creating {.field Authors@R} field in DESCRIPTION and adding:",
" " = "{aut_fmt}"
))
}
d$add_author(given = given, family = family, role = role, ...)

Expand All @@ -84,17 +86,17 @@ challenge_legacy_author_fields <- function(d = proj_desc()) {
return(invisible())
}

ui_oops("
Found legacy {ui_field('Author')} and/or {ui_field('Maintainer')} field \\
in DESCRIPTION.
usethis only supports modification of the {ui_field('Authors@R')} field.")
ui_info("
We recommend one of these paths forward:
* Delete these fields and rebuild with {ui_code('use_author()')}.
* Convert to {ui_field('Authors@R')} with {ui_code('desc::desc_coerce_authors_at_r()')},
then delete the legacy fields.")
if (ui_yeah("Do you want to cancel this operation and sort that out first?")) {
ui_stop("Cancelling.")
ui_bullets(c(
"x" = "Found legacy {.field Author} and/or {.field Maintainer} field in
DESCRIPTION.",
" " = "usethis only supports modification of the {.field Authors@R} field.",
"i" = "We recommend one of these paths forward:",
"_" = "Delete the legacy fields and rebuild with {.fun use_author}; or",
"_" = "Convert to {.field Authors@R} with
{.fun desc::desc_coerce_authors_at_r}, then delete the legacy fields."
))
if (ui_yep("Do you want to cancel this operation and sort that out first?")) {
ui_abort("Cancelling.")
}
invisible()
}
Expand All @@ -108,10 +110,10 @@ check_author_is_novel <- function(given = NULL, family = NULL, d = proj_desc())
})
if (any(m)) {
aut_name <- glue("{given %||% ''} {family %||% ''}")
usethis_abort(c(
"{.val {aut_name}} already appears in {.val Authors@R}.",
"Please make the desired change directly in DESCRIPTION or call the \\
desc package directly."
ui_abort(c(
"x" = "{.val {aut_name}} already appears in {.field Authors@R}.",
" " = "Please make the desired change directly in DESCRIPTION or call the
{.pkg desc} package directly."
))
}
invisible()
Expand All @@ -129,10 +131,11 @@ challenge_default_author <- function(d = proj_desc()) {
)

if (any(m)) {
ui_info("
{ui_field('Authors@R')} appears to include a placeholder author:
{format(default_author, style = 'text')}")
if(is_interactive() && ui_yeah("Would you like to remove it?")) {
ui_bullets(c(
"i" = "{.field Authors@R} appears to include a placeholder author:",
" " = "{format(default_author, style = 'text')}"
))
if(is_interactive() && ui_yep("Would you like to remove it?")) {
# TODO: Do I want to suppress this output?
# Authors removed: First Last, NULL NULL.
do.call(d$del_author, unclass(default_author)[[1]])
Expand Down
24 changes: 13 additions & 11 deletions R/badge.R
Expand Up @@ -43,23 +43,25 @@ NULL
use_badge <- function(badge_name, href, src) {
path <- find_readme()
if (is.null(path)) {
ui_oops("
Can't find a README for the current project.
See {ui_code('usethis::use_readme_rmd()')} for help creating this file.
Badge link can only be printed to screen.
")
ui_bullets(c(
"!" = "Can't find a README for the current project.",
"i" = "See {.fun usethis::use_readme_rmd} for help creating this file.",
"i" = "Badge link will only be printed to screen."
))
path <- "README"
}
changed <- block_append(
glue("{ui_field(badge_name)} badge"),
glue("{badge_name} badge"),
glue("[![{badge_name}]({src})]({href})"),
path = path,
block_start = badge_start,
block_end = badge_end
)

if (changed && path_ext(path) == "Rmd") {
ui_todo("Re-knit {ui_path(path)} with {ui_code('devtools::build_readme()')}")
ui_bullets(c(
"_" = "Re-knit {.path {pth(path)}} with {.fun devtools::build_readme}."
))
}
invisible(changed)
}
Expand Down Expand Up @@ -153,10 +155,10 @@ use_posit_cloud_badge <- function(url) {
img <- "https://img.shields.io/badge/launch-posit%20cloud-447099?style=flat"
use_badge("Launch Posit Cloud", url, img)
} else {
usethis_abort("
{.fun usethis::use_posit_cloud_badge} requires a link to an \\
existing Posit Cloud project of the form \\
{.val https://posit.cloud/content/<project-id>} or \\
ui_abort("
{.fun usethis::use_posit_cloud_badge} requires a link to an
existing Posit Cloud project of the form
{.val https://posit.cloud/content/<project-id>} or
{.val https://posit.cloud/spaces/<space-id>/content/<project-id>}.")
}

Expand Down
26 changes: 15 additions & 11 deletions R/block.R
Expand Up @@ -16,13 +16,14 @@ block_append <- function(desc, value, path,
}

if (is.null(block_lines)) {
ui_todo("
Copy and paste the following lines into {ui_path(path)}:")
ui_code_block(c(block_prefix, block_start, value, block_end, block_suffix))
ui_bullets(c(
"_" = "Copy and paste the following lines into {.path {pth(path)}}:"
))
ui_code_snippet(c(block_prefix, block_start, value, block_end, block_suffix))
return(FALSE)
}

ui_done("Adding {desc} to {ui_path(path)}")
ui_bullets(c("v" = "Adding {.val {desc}} to {.path {pth(path)}}."))

start <- block_lines[[1]]
end <- block_lines[[2]]
Expand Down Expand Up @@ -54,8 +55,10 @@ block_replace <- function(desc, value, path,
}

if (is.null(block_lines)) {
ui_todo("Copy and paste the following lines into {ui_value(path)}:")
ui_code_block(c(block_start, value, block_end))
ui_bullets(c(
"_" = "Copy and paste the following lines into {.path {pth(path)}}:"
))
ui_code_snippet(c(block_start, value, block_end))
return(invisible(FALSE))
}

Expand All @@ -67,7 +70,7 @@ block_replace <- function(desc, value, path,
return(invisible(FALSE))
}

ui_done("Replacing {desc} in {ui_path(path)}")
ui_bullets(c("v" = "Replacing {desc} in {.path {pth(path)}}."))

lines <- c(
lines[seq2(1, start - 1L)],
Expand Down Expand Up @@ -99,10 +102,11 @@ block_find <- function(lines, block_start = "# <<<", block_end = "# >>>") {
}

if (!(length(start) == 1 && length(end) == 1 && start < end)) {
ui_stop(
"Invalid block specification.
Must start with {ui_code(block_start)} and end with {ui_code(block_end)}"
)
ui_abort(c(
"Invalid block specification.",
"Must start with {.code {block_start}} and end with
{.code {block_end}}."
))
}

c(start + 1L, end - 1L)
Expand Down
39 changes: 22 additions & 17 deletions R/browse.R
Expand Up @@ -77,7 +77,10 @@ browse_package <- function(package = NULL) {
grl <- set_names(grl$url, nm = grl$remote)
parsed <- parse_github_remotes(grl)
urls <- c(urls, glue_data(parsed, "https://{host}/{repo_owner}/{repo_name}"))
details <- c(details, map(parsed$name, ~ glue("{ui_value(.x)} remote")))
details <- c(
details,
map(parsed$name, ~ cli::cli_fmt(cli::cli_text("{.val {.x}} remote")))
)
}

desc_urls_dat <- desc_urls(package, include_cran = TRUE)
Expand All @@ -86,11 +89,11 @@ browse_package <- function(package = NULL) {
details,
map(
desc_urls_dat$desc_field,
~ if (is.na(.x)) "CRAN" else glue("{ui_field(.x)} field in DESCRIPTION")
~ if (is.na(.x)) "CRAN" else cli::cli_fmt(cli::cli_text("{.field {.x}} field in DESCRIPTION"))
)
)
if (length(urls) == 0) {
ui_oops("Can't find any URLs")
ui_bullets(c(x = "Can't find any URLs."))
return(invisible(character()))
}

Expand Down Expand Up @@ -171,15 +174,17 @@ github_url <- function(package = NULL) {

if (is.null(desc_urls_dat)) {
if (is.null(package)) {
ui_stop("
Project {ui_value(project_name())} has no DESCRIPTION file and \\
has no GitHub remotes configured
No way to discover URLs")
ui_abort(c(
"Project {.val {project_name()}} has no DESCRIPTION file and
has no GitHub remotes configured.",
"No way to discover URLs."
))
} else {
ui_stop("
Can't find DESCRIPTION for package {ui_value(package)} locally \\
or on CRAN
No way to discover URLs")
ui_abort(c(
"Can't find DESCRIPTION for package {.pkg {package}} locally
or on CRAN.",
"No way to discover URLs."
))
}
}

Expand All @@ -191,13 +196,13 @@ github_url <- function(package = NULL) {
}

if (is.null(package)) {
ui_stop("
Project {ui_value(project_name())} has no GitHub remotes configured \\
and has no GitHub URLs in DESCRIPTION")
ui_abort("
Project {.val {project_name()}} has no GitHub remotes configured
and has no GitHub URLs in DESCRIPTION.")
}
ui_warn("
Package {ui_value(package)} has no GitHub URLs in DESCRIPTION
Trying the GitHub CRAN mirror")
cli::cli_warn(c(
"!" = "Package {.val {package}} has no GitHub URLs in DESCRIPTION.",
" " = "Trying the GitHub CRAN mirror."))
glue_chr("https://github.com/cran/{package}")
}

Expand Down
4 changes: 3 additions & 1 deletion R/ci.R
Expand Up @@ -82,7 +82,9 @@ use_circleci_badge <- function(repo_spec = NULL) {

circleci_activate <- function(owner, browse = is_interactive()) {
url <- glue("https://circleci.com/add-projects/gh/{owner}")
ui_todo("Turn on CircleCI for your repo at {url}")
ui_bullets(c(
"_" = "Turn on CircleCI for your repo at {.url {url}}."
))
if (browse) {
utils::browseURL(url)
}
Expand Down
14 changes: 8 additions & 6 deletions R/code-of-conduct.R
Expand Up @@ -23,9 +23,8 @@
#' @export
use_code_of_conduct <- function(contact, path = NULL) {
if (missing(contact)) {
ui_stop("
{ui_code('use_code_of_conduct()')} requires contact details in \\
first argument")
ui_abort("
{.fun use_code_of_conduct} requires contact details in first argument.")
}

new <- use_coc(contact = contact, path = path)
Expand All @@ -35,13 +34,16 @@ use_code_of_conduct <- function(contact, path = NULL) {
href <- sub("/$", "", href)
href <- paste0(href, "/CODE_OF_CONDUCT.html")

ui_todo("You may also want to describe the code of conduct in your README:")
ui_code_block("
ui_bullets(c(
"_" = "You may also want to describe the code of conduct in your README:"
))
ui_code_snippet("
## Code of Conduct
Please note that the {project_name()} project is released with a \\
[Contributor Code of Conduct]({href}). By contributing to this project, \\
you agree to abide by its terms."
you agree to abide by its terms.",
language = ""
)

invisible(new)
Expand Down

0 comments on commit fc8472c

Please sign in to comment.