diff --git a/NEWS.md b/NEWS.md index fdde48e..e80ef21 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,10 +1,10 @@ # felp 0.3.0.9999 - Support `fuzzyhelp` to run Shiny App in background without blocking user terminal. - The new behavior is enabled by default and can be disabled by passing `FALSE` to the `background` argument or to the `fuzzyhelp.background` option. + The new behavior is enabled by default and can be disabled by passing `FALSE` to the `background` argument or to the `fuzzyhelp.background` option (#18, #20). - Fixed wrong behaviors of anchors in the HTML help in the UI of the `fuzzyhelp` function. A click on a anchor should not cause nesting of the UI when href of the anchor is an ID. - Instead, the click should scroll the window to show the element with the corresponding ID. + Instead, the click should scroll the window to show the element with the corresponding ID (#17). # felp 0.3.0 diff --git a/R/fuzzyhelp.R b/R/fuzzyhelp.R index d68fd58..6a4de2a 100644 --- a/R/fuzzyhelp.R +++ b/R/fuzzyhelp.R @@ -379,6 +379,7 @@ create_server <- function(method = c("fzf", "lv")) { #' @param background Whether to run a shiny gadget in a background process. #' The default value is `TRUE` and can be changed by #' `option(fuzzyhelp.background = FALSE)`. +#' @inheritParams shiny::runGadget #' #' @note #' The default fuzzy match algorithm is a simplified version of @@ -386,7 +387,9 @@ create_server <- function(method = c("fzf", "lv")) { #' excludes bonuses from relationship with matched characters and their #' previous characters. #' -#' @return NULL +#' @return +#' If the `background` argument is `TRUE`, then the return value inherits from +#' `callr::r_bg()`. Otherwise, `NULL` is returned. #' #' @examples #' if (FALSE) { @@ -397,13 +400,14 @@ create_server <- function(method = c("fzf", "lv")) { fuzzyhelp <- function( query = "", method = getOption("fuzzyhelp.method", "fzf"), - background = getOption("fuzzyhelp.background", TRUE)) { + background = getOption("fuzzyhelp.background", TRUE), + viewer = shiny::paneViewer()) { app <- create_ui(query) server <- create_server(method) # Create new gadget on foreground if (!background) { - shiny::runGadget(app, server) + shiny::runGadget(app, server, viewer = viewer) return(invisible(NULL)) } @@ -412,7 +416,40 @@ fuzzyhelp <- function( .env$fuzzyhelp_url <- tempfile() } - # Re-use existing gadget + # View existing gadget + if (fuzzyhelp_bg_view(viewer)) { + return(.env$fuzzyhelp) + } + + # Create new gadget on background + if (rstudioapi::isAvailable()) { + # Just start the UI without viewer because RStudio's viewer + # is not available fro the background process. + .env$fuzzyhelp <- fuzzyhelp_bg_start(app, server, identity) + + # Wait and view UI in the main process. + min_seed <- 1L + for (i in c(rep(min_seed, 10L), seq(min_seed + 1, 10))) { + if (fuzzyhelp_bg_view(viewer)) { + return(.env$fuzzyhelp) + } else { + # Wait with exponential backoff + t <- max((i**2) / 10, 0.5) + if (i > min_seed) { + # Don't be too noisy + message("Failed to open fuzzyhelp UI. Will retry in ", t, " seconds") + } + Sys.sleep(t) + } + } + stop("Failed to open fuzzyhelp UI. Try using fuzzyhelp(background = FALSE)") + } + + .env$fuzzyhelp <- fuzzyhelp_bg_start(app, server, viewer) + return(.env$fuzzyhelp) +} + +fuzzyhelp_bg_view <- function(viewer) { if ( !is.null(.env$fuzzyhelp) && is.null(.env$fuzzyhelp$get_exit_status()) && @@ -420,24 +457,36 @@ fuzzyhelp <- function( ) { url <- readLines(.env$fuzzyhelp_url)[1L] if (url != "") { - shiny::paneViewer()(url) - return(.env$fuzzyhelp) + viewer(url) + return(TRUE) } } + return(FALSE) +} - # Create new gadget on background - .env$fuzzyhelp <- callr::r_bg( - function(..., .env) { +fuzzyhelp_bg_start <- function(app, server, viewer) { + writeLines("", .env$fuzzyhelp_url) # Ensure content is empty + callr::r_bg( + function(..., .env, base_viewer, base_options) { + do.call(options, base_options) viewer <- function(url) { writeLines(url, .env$fuzzyhelp_url) - shiny::paneViewer()(url) + base_viewer(url) } shiny::runGadget(..., viewer = viewer) }, - args = list(app = app, server = server, .env = .env), + args = list( + app = app, + server = server, + .env = .env, + base_viewer = viewer, + base_options = options() + ), env = Sys.getenv(), package = TRUE ) +} - return(.env$fuzzyhelp) +fuzzyhelp_addin <- function() { + fuzzyhelp(background = TRUE) } diff --git a/docs/articles/felp.html b/docs/articles/felp.html index 6062172..456f5ba 100644 --- a/docs/articles/felp.html +++ b/docs/articles/felp.html @@ -323,7 +323,7 @@
fuzzyhelp
to run Shiny App in background without blocking user terminal. The new behavior is enabled by default and can be disabled by passing FALSE
to the background
argument or to the fuzzyhelp.background
option.fuzzyhelp
function. A click on a anchor should not cause nesting of the UI when href of the anchor is an ID. Instead, the click should scroll the window to show the element with the corresponding ID.fuzzyhelp
to run Shiny App in background without blocking user terminal. The new behavior is enabled by default and can be disabled by passing FALSE
to the background
argument or to the fuzzyhelp.background
option (#18, #20).fuzzyhelp
function. A click on a anchor should not cause nesting of the UI when href of the anchor is an ID. Instead, the click should scroll the window to show the element with the corresponding ID (#17).fuzzyhelp(
query = "",
method = getOption("fuzzyhelp.method", "fzf"),
- background = getOption("fuzzyhelp.background", TRUE)
+ background = getOption("fuzzyhelp.background", TRUE),
+ viewer = shiny::paneViewer()
)
TRUE
and can be changed by
option(fuzzyhelp.background = FALSE)
.
+
+Specify where the gadget should be displayed--viewer pane,
+dialog window, or external browser--by passing in a call to one of the
+viewer()
functions.
If the background
argument is TRUE
, then the return value inherits from
+callr::r_bg()
. Otherwise, NULL
is returned.
The default fuzzy match algorithm is a simplified version of diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf index 07e5654..010349f 100644 --- a/inst/rstudio/addins.dcf +++ b/inst/rstudio/addins.dcf @@ -1,4 +1,4 @@ Name: Fuzzy Search on R Help Description: Search and view help files with fuzzy queries. -Binding: fuzzyhelp +Binding: fuzzyhelp_addin Interactive: true diff --git a/man/fuzzyhelp.Rd b/man/fuzzyhelp.Rd index 37fcf87..0f21c8d 100644 --- a/man/fuzzyhelp.Rd +++ b/man/fuzzyhelp.Rd @@ -7,7 +7,8 @@ fuzzyhelp( query = "", method = getOption("fuzzyhelp.method", "fzf"), - background = getOption("fuzzyhelp.background", TRUE) + background = getOption("fuzzyhelp.background", TRUE), + viewer = shiny::paneViewer() ) } \arguments{ @@ -20,6 +21,14 @@ default value can be tweaked by \code{options(fuzzyhelp.method = "lv")}.} \item{background}{Whether to run a shiny gadget in a background process. The default value is \code{TRUE} and can be changed by \code{option(fuzzyhelp.background = FALSE)}.} + +\item{viewer}{Specify where the gadget should be displayed--viewer pane, +dialog window, or external browser--by passing in a call to one of the +\code{\link[shiny:viewer]{viewer()}} functions.} +} +\value{ +If the \code{background} argument is \code{TRUE}, then the return value inherits from +\code{callr::r_bg()}. Otherwise, \code{NULL} is returned. } \description{ Users no more have to afraid of exact name of the object they need help.