diff --git a/NEWS.md b/NEWS.md index 215d21e0f..37d7ede9f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # usethis (development version) +* `pr_resume()` (without a specific `branch`) and `pr_fetch()` (without a specific `number`) no longer error when a branch name contains curly braces (#2107, @jonthegeek). + # usethis 3.2.1 * `create_quarto_project()` exits early if the Quarto CLI does not appear to be diff --git a/R/pr.R b/R/pr.R index 6b1c20dad..650dbe2b5 100644 --- a/R/pr.R +++ b/R/pr.R @@ -944,7 +944,7 @@ choose_branch <- function(exclude = character()) { ) at_user <- glue("@{pr_user}") template <- ui_pre_glue( - "{pretty_name} {cli::symbol$arrow_right} <> ({.field <>}): {.val <>}" + "{pretty_name} {cli::symbol$arrow_right} <> ({.field <>}): {.val <>}" ) cli::format_inline(template) } @@ -988,14 +988,15 @@ choose_pr <- function(tr = NULL, pr_dat = NULL) { function(pr_number, pr_html_url, pr_user, pr_state, pr_title) { href_number <- ui_pre_glue("{.href [PR #<>](<>)}") at_user <- glue("@{pr_user}") + pr_title_escaped <- ui_escape_glue(pr_title) if (some_closed) { template <- ui_pre_glue( - "<> ({.field <>}, {pr_state}): {.val <>}" + "<> ({.field <>}, {pr_state}): {.val <>}" ) cli::format_inline(template) } else { template <- ui_pre_glue( - "<> ({.field <>}): {.val <>}" + "<> ({.field <>}): {.val <>}" ) cli::format_inline(template) } diff --git a/R/utils-ui.R b/R/utils-ui.R index 98e3c86e3..125e064cc 100644 --- a/R/utils-ui.R +++ b/R/utils-ui.R @@ -162,6 +162,11 @@ ui_pre_glue <- function(..., .envir = parent.frame()) { glue(..., .open = "<<", .close = ">>", .envir = .envir) } +ui_escape_glue <- function(x) { + gsub("([{}])", "\\1\\1", x) +} + + bulletize <- function(x, bullet = "*", n_show = 5, n_fudge = 2) { n <- length(x) n_show_actual <- compute_n_show(n, n_show, n_fudge) diff --git a/tests/testthat/test-utils-ui.R b/tests/testthat/test-utils-ui.R index 6d1381e6a..26774ace2 100644 --- a/tests/testthat/test-utils-ui.R +++ b/tests/testthat/test-utils-ui.R @@ -267,3 +267,17 @@ cli::test_that_cli( }, configs = c("plain", "fancy") ) + +test_that("ui_escape_glue() doubles curly braces", { + expect_equal(ui_escape_glue("no braces"), "no braces") + expect_equal(ui_escape_glue("one { brace"), "one {{ brace") + expect_equal(ui_escape_glue("one } brace"), "one }} brace") + expect_equal( + ui_escape_glue("A {brace_set} in text"), + "A {{brace_set}} in text" + ) + expect_equal( + ui_escape_glue("{multiple} {brace} {sets}"), + "{{multiple}} {{brace}} {{sets}}" + ) +})