posit-dev / positron

Positron, a next-generation data science IDE
https://positron.posit.co
Other
2.79k stars 85 forks source link

`library(devtools)` makes `shiny.tag`/`shiny.tag.lists` always open in Viewer pane #5338

Open maxheld83 opened 3 days ago

maxheld83 commented 3 days ago

System details:

Positron and OS details:

Positron Version: 2024.11.0 (Universal) build 116 Code - OSS Version: 1.93.0 Commit: 8b1688ababfa228db515a739050c466f3bb3089f Date: 2024-10-28T02:50:56.075Z Electron: 30.4.0 Chromium: 124.0.6367.243 Node.js: 20.15.1 V8: 12.4.254.20-electron.0 OS: Darwin arm64 24.1.0

Interpreter details:

R 4.4.2

Describe the issue:

positron will always open an object with class shiny.tag in the Viewer, ignoring options. This can be quite problematic when running a shiny app which (for whatever) ever returns a shiny.tag class; in which case the shiny app gets hidden, and the shiny.tag is shown in the viewer instead.

I was able to nail this down (only?) with print.shiny.tag(), but guessing this is an upstream issue not isolated to shiny.tag.

Steps to reproduce the issue:

  1. print(htmltools::p(), browse = FALSE)

Expected or desired behavior:

On RStudio (or wherever), this will return:

<p></p>

Inside Positron, the Viewer Pane will open (looks empty, because it's just a p<>) and the console will have:

NULL
maxheld83 commented 3 days ago

Upon further inspection, I can confirm that this is not limited to shiny.tag's print method, but appears rooted in Positron ignoring the viewer option.

Consider this reprex:

withr::with_options(new = list(viewer = NULL), print(htmltools::p(), browse = TRUE))

On RStudio, this will open the (blank) page in a web browser. On Positron, it opens the same blank page in the viewer (and returns, again NULL).

Opening in a web browser is expected behavior as per the htmltools source:

https://github.com/rstudio/htmltools/blob/487aa0bed7313d7597b6edd5810e53cab0061198/R/html_print.R#L41-L58,

I also disabled this setting in Positron, to be sure, but to no effect: the blank page was still opened in the viewer pane:

"positron.viewer.openLocalhostUrls": false

So I'm assuming something inside Positron just ignores the set viewer option.

The R session knows, however:

withr::with_options(new = list(viewer = NULL), getOption("viewer"))
NULL
juliasilge commented 2 days ago

I want to check in on this example:

withr::with_options(new = list(viewer = NULL), print(htmltools::p(), browse = TRUE))

When I run this in the R console in Positron, this opens in a browser for me, not the Viewer pane. Also, when run in the R console, print(htmltools::p(), browse = FALSE) prints out in the R console and does not open the Viewer pane.

You are saying both of these open in the Viewer for you? Can you say more about how you are running this code?

maxheld83 commented 2 days ago

You are saying both of these open in the Viewer for you?

correct, when running inside R 4.4.2 Console inside Positron. (Not, naturally, when I bring up another R console via the Terminal, as in R).

Can you say more about how you are running this code?

You mean the context? I ran into this problem when writing some shiny modules inside a package. The modules would return objects classed shiny.tag and friends, and these objects, whenever returned (inside the shiny process!) would jump to the forefront and take over the viewer. For the first couple of hours I thought my shiny app was broken 😅

maxheld83 commented 2 days ago

Is there any other config I could provide to help reproduce this behavior? (Other than above version etc.).

juliasilge commented 1 day ago

Image

maxheld83 commented 1 day ago
  • What happens if you run utils::browseURL("https://www.r-project.org") in the R console?
  1. In the R Console (i.e. R from the system shell, Terminal.app in my case): Opens the website in the system browser, nothing on the R console.
  2. In the R console inside VSCode (R from the Terminal pane):

    VSCode WebView only supports showing local http content.
    Opening in external browser...
    Browsing https://www.r-project.org

    No window opening.

  3. In the Positron R Console: Opens website in system browser.
  • I don't suppose you have set anything for the workbench.externalBrowser setting, have you?

nope, that field is empty.

  • Do you have any code that runs in your .Rprofile?

A bunch, but I hope nothing relevant:

```r options( # live with older variant when no binary is available install.packages.check.source = "no", pkgType = "binary", # don't take focus browser = "/usr/bin/open -g", # UI stuff digits = 3, max.print = 50, gargle_oauth_email = "maximilian.held83@gmail.com", usethis.full_name = "Maximilian Held", usethis.protocol = "https", usethis.description = list( `Authors@R` = 'person( given = "Maximilian", family = "Held", email = "info@maxheld.de", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-4703-5388") )' ), reprex.advertise = FALSE, reprex.style = TRUE, # set up multicore future.plan = "multicore", # be defensive about globals future.globals.onReference = "error", # prevent r processes from saturating the CPU parallelly.availableCores.omit = 1L, # show all steps in backtrace shiny.fullstacktrace = TRUE, # enables rstudio addin support vsc.rstudioapi = TRUE, # best view of shiny gadgets vsc.viewer = "Beside", # watch global env symbols to provide hover info vsc.globalenv = TRUE, vsc.use_httpgd = TRUE ) # can only run when progressr is installed, so needs separate call if (require("progressr", quietly = TRUE)) { progressr::handlers("progress") progressr::handlers(global = TRUE) } if (interactive()) { require(pak, quietly = TRUE) require(devtools, quietly = TRUE) require(reprex, quietly = TRUE) if (Sys.getenv("TERM_PROGRAM") == "vscode") { # this will attach an rsession when inside vscode source(file.path(Sys.getenv("HOME"), ".vscode-R", "init.R")) } message("Loaded dotfile .Rprofile...") if (suppressMessages(require("rprojroot", quietly = TRUE))) { if (rprojroot::is_r_package$testfun[[1]](".")) { message("Package development detected ...") devtools::load_all() } } } ```
  • What do you get for getOption("browser") in the R console?
  1. R Console inside system shell (Terminal.app): [1] "/usr/bin/open -g"
  2. R Console inside Positron Terminal: function defs.

    ``` function(url, title = url, ..., viewer = getOption("vsc.browser", "Active")) { proxy_uri <- Sys.getenv("VSCODE_PROXY_URI") if (nzchar(proxy_uri)) { is_base_path <- grepl("\\:\\d+$", url) url <- sub("^https?\\://(127\\.0\\.0\\.1|localhost)(\\:)?", sub("\\{\\{?port\\}\\}?/?", "", proxy_uri), url ) if (is_base_path) { url <- paste0(url, "/") } } if (grepl("^https?\\://(127\\.0\\.0\\.1|localhost)(\\:\\d+)?", url)) { request_browser(url = url, title = title, ..., viewer = viewer) } else if (grepl("^https?\\://", url)) { message( if (nzchar(proxy_uri)) { "VSCode is not running on localhost but on a remote server.\n" } else { "VSCode WebView only supports showing local http content.\n" }, "Opening in external browser..." ) request_browser(url = url, title = title, ..., viewer = FALSE) } else { path <- sub("^file\\://", "", url) if (file.exists(path)) { path <- normalizePath(path, "/", mustWork = TRUE) if (grepl("\\.html?$", path, ignore.case = TRUE)) { message( "VSCode WebView has restricted access to local file.\n", "Opening in external browser..." ) request_browser(url = path_to_uri(path), title = title, ..., viewer = FALSE ) } else { request("dataview", source = "object", type = "txt", title = title, file = path, viewer = viewer ) } } else { stop("File not exists") } } } ```

  1. In the Positron Console: [1] "/usr/bin/open -g"
  • Does executing htmltools::HTML(as.character(htmltools::p())) also go to the Viewer?

No it does not. AFAIK this affects objects with class shiny.tag and shiny.tag.list, but not html.

Hope this helps.

maxheld83 commented 1 day ago

I do also have VSCode installed, with the R packages for that -- but since neither config nor binary are shared, I'm assuming that's unrelated. (With the exception of the .Rprofile, of course).

maxheld83 commented 1 day ago

Uh-oh, I think I might have the culprit inside my .Rprofile:

 if (Sys.getenv("TERM_PROGRAM") == "vscode") {
    # this will attach an rsession when inside vscode
    source(file.path(Sys.getenv("HOME"), ".vscode-R", "init.R"))
  }

Sys.getenv("TERM_PROGRAM") is still [1] "vscode" inside Positron, this init.R could cause havoc. --> https://github.com/posit-dev/positron/issues/5373

Will check.

So what happened here is what you predicted in https://github.com/posit-dev/positron/issues/1494 @juliasilge 😔.

maxheld83 commented 1 day ago

Apologies for not checking my .Rprofile first.

I found the culprit in my .Rprofile, indeed 😨:

vsc.use_httpgd = TRUE

This causes the problem (inside Positron). Incidentally, VSCode itself (R inside it) does not have this problem.

maxheld83 commented 1 day ago

spoke too soon.

The only combination of my .Rprofile which could reproduce the problem is this 🤯:

if (interactive()) {
  require(devtools, quietly = TRUE)
}

Without it, everything works fine, and htmltools::p() prints <p></p>. With it, the Viewer pane opens.

I have no idea how this could possibly be related.

This also works just interactively::

# open a blank session in positron, without any `.Rprofile`.
htmltools::p()
# prints to console
library(devtools)
htmltools::p()
# now opens the viewer pane

Can someone confirm this behavior or am I loosing my mind?

juliasilge commented 1 day ago

You are not losing your mind, no, and I can reproduce that behavior in Positron. The behavior in RStudio is different, where I see htmltools::p() printing out to the console as expected both before/after library(devtools).

@jennybc do you mind taking a look at this, to understand what might be going on?

jennybc commented 1 day ago

Attaching devtools causes the htmlwidgets namespace to be loaded, which then triggers this from ark:

https://github.com/posit-dev/ark/blob/6e40decac54049b7aaed1e1ddbd1a7dec6d6f721/crates/ark/src/modules/positron/html_widgets.R#L54-L58

which puts these overrides into force:

https://github.com/posit-dev/ark/blob/6e40decac54049b7aaed1e1ddbd1a7dec6d6f721/crates/ark/src/modules/positron/html_widgets.R#L41-L45

And that explains the behaviour. Not exactly sure what to do about it, but maybe others with more knowledge of these overrides and their motivations will have some insight.

juliasilge commented 1 day ago

Yes, I'm not sure what to do about it either at a first glance. I will send to triage! 🚀

These overrides were added in https://github.com/posit-dev/ark/pull/146 to send htmlwidgets to our Plots pane.