2

I’ve written an RStudio addin that launches a Shiny gadget in the RStudio Viewer. However, once the gadget is running, my R console is locked until I close the gadget. Here’s a minimal example of my code:

library(rstudioapi)
library(shiny)

# Simplified function to fetch history
get_r_history <- function() {
  # Simulates fetching history (real function fetches R or terminal history)
  return(c("plot(1:10)", "summary(mtcars)", "lm(y ~ x, data = df)"))
}

# Simplified addin UI and server
run_addin <- function() {
  history <- get_r_history()

  ui <- fluidPage(
    titlePanel("History Selector"),
    selectInput("selected_line", "Select a line:", choices = history),
    actionButton("insert", "Insert into Script")
  )

  server <- function(input, output, session) {
    observeEvent(input$insert, {
      selected_line <- input$selected_line
      if (!is.null(selected_line)) {
        context <- rstudioapi::getActiveDocumentContext()
        if (!is.null(context)) {
          rstudioapi::insertText(location = context$selection[[1]]$range, text = selected_line)
        }
      }
    })
  }

  shiny::runGadget(ui, server, viewer = shiny::paneViewer())
}

run_addin()

When the gadget is displayed in the RStudio Viewer, I cannot execute code in the console simultaneously. Is there a way to keep the gadget in the RStudio Viewer but still have access to the console? I have seen that by using browserViewer() to open it externally might work, but I specifically want to display it in the RStudio Viewer.

Any suggestions or workarounds would be greatly appreciated.

3
  • 2
    Maybe you want a background job: docs.posit.co/ide/user/ide/guide/tools/jobs.html Commented Jan 13 at 16:25
  • I have tried to use a background job, but the main problem lies in the fact that when I run the app it cannot access the history and it says that RStudio is not running. Commented Jan 14 at 15:26
  • It's tricky. Once you are running the shiny app in a background process (e.g. using callr::r_bg or library(future) to unblock the console you will need to pass the information provided by {rstudioapi} from the main process to the sub process. You might want to check library(ipc). Commented Jan 16 at 11:57

1 Answer 1

3

Please check the below workaround using my earlier answer here.

The shiny app is started in a backgound R process via callr::r_bg.

Once the user clicks the Insert button a txt file is filled with the selected line.

The main process checks this text file continuously for new content without blocking itself by using a recursive call to later::later:

library(rstudioapi)
library(shiny)
library(callr)
library(later)

# Simplified function to fetch history
get_r_history <- function() {
  # Simulates fetching history (real function fetches R or terminal history)
  return(c("plot(1:10)", "summary(mtcars)", "lm(y ~ x, data = df)"))
}

history <- get_r_history()

ui <- fluidPage(
  titlePanel("History Selector"),
  selectInput("selected_line", "Select a line:", choices = history),
  actionButton("insert", "Insert into Script")
)

server <- function(input, output, session) {
  observeEvent(input$insert, {
    selected_line <- input$selected_line
    if (length(selected_line) > 0L && !selected_line == "") {
      writeLines(selected_line, con = "selected_line.txt")
    }
  })
}

app <- shinyApp(ui, server)

viewer("http://localhost:8080")
shiny_bg_process <- callr::r_bg(function(app, viewer){shiny::runGadget(app, viewer, port = 8080)}, args = list(app, viewer))
# shiny_bg_process$is_alive()
# shiny_bg_process$kill()

recursive_check = function(interval = 1L) {
  if(file.exists("selected_line.txt")){
    selected_line <- readLines(con = "selected_line.txt")
    writeLines("", con = "selected_line.txt") # reset
  } else {
    selected_line <- NULL
  }
  if(length(selected_line) > 0L && !selected_line == ""){
    context <- rstudioapi::getActiveDocumentContext()
    if (!is.null(context)) {
      rstudioapi::insertText(location = context$selection[[1]]$range, text = selected_line)
    } 
  }
  later::later(recursive_check, interval)
}

recursive_check()

PS: as mentioned in my above comment you might be able to realize a similar behaviour via library(ipc). Ideally, polling the selected_line should be avoided (signal the main process from the sub process).

PPS: Apart from some predefined options runGadget and runApp more or less do the same thing: starting a shiny app.

Sign up to request clarification or add additional context in comments.

3 Comments

I was not able to replicate your example. The r history is not accessible with the error "Error accessing R history: savehistory can be used in Rgui and Rterm. And if i try to write something on the active document through the addin I get: Error: cannot find the function "POST". I call the httr::POST function in distinct occasion as: response <- POST(url, add_headers(`Content-Type` = "application/json", Authorization = paste("Bearer", api_key)), encode = "json", body = body)
@Leone as shown in your crosspost my provided example works fine (please see the gif). Unfortunately you fail to explain which changes you have made, so I don't know how to further assist.
I was able to make it work. Thank you. I am facing other problems but now it does run in background leaving the console active

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.