From 0bbd779b6f5b037588deb4192770f950059e0c59 Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 19 Sep 2025 09:52:03 -0400 Subject: [PATCH 1/2] Escape curly braces in pr_title Added a simple helper to escape curly braces for glue (`ui_escape_glue()` in `utils-ui.R`), then applied it in the relevant `pr_*()` functions. I used Positron Assistant and Google Gemini as a test on this, then revised their fixes significantly. Do you want to add a test for this in `manual-pr-functions.R`? Or I could automate this stuff with mocked github API calls if you want to go that far. Fixes #2107 --- R/pr.R | 8 ++++---- R/utils-ui.R | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/R/pr.R b/R/pr.R index 6b1c20dad..c73ab72dd 100644 --- a/R/pr.R +++ b/R/pr.R @@ -322,7 +322,7 @@ pr_fetch <- function(number = NULL, target = c("source", "primary")) { pr_user <- glue("@{pr$pr_user}") ui_bullets(c( "v" = "Checking out PR {.href [{pr$pr_string}]({pr$pr_html_url})} ({.field {pr_user}}): - {.val {pr$pr_title}}." + {.val {ui_escape_glue(pr$pr_title)}}." )) if (pr$pr_from_fork && isFALSE(pr$maintainer_can_modify)) { @@ -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) } @@ -990,12 +990,12 @@ choose_pr <- function(tr = NULL, pr_dat = NULL) { at_user <- glue("@{pr_user}") 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) From 8ce1ebe7b8ae8710ec8e5d50653021e2d969d888 Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 19 Sep 2025 09:57:10 -0400 Subject: [PATCH 2/2] Do the escape once in the sub-function toward the end. --- R/pr.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/pr.R b/R/pr.R index c73ab72dd..e1c2ca493 100644 --- a/R/pr.R +++ b/R/pr.R @@ -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) }