Interacting with Terminals

The rstudioapi package provides a collection of functions that can be used to interact with the RStudio terminal tab.

There are two primary approaches to using these functions.

  1. Use terminalExecute() to run a specific process with the output shown in a new terminal buffer, without blocking the current R session.

  2. Create, query, and manipulate interactive terminals. This might be used to develop custom terminal behavior via an RStudio addin.

TerminalExecute Scenario

# Start a command with results displayed in a terminal buffer
termId <- rstudioapi::terminalExecute("ping rstudio.com")

# If viewing the result in the terminal buffer is sufficient,
# then no need to do anything else. The command will continue
# running and displaying its results without blocking the R session.

# To obtain the results programmatically, wait for it to finish.
while (is.null(rstudioapi::terminalExitCode(termId))) {
  Sys.sleep(0.1)
}

result <- rstudioapi::terminalBuffer(termId)

# Delete the buffer and close the session in the IDE
rstudioapi::terminalKill(termId)

Interative Terminal Scenario

Several concepts are important to understand to make full use of these functions.

Terminal Identifier

Each terminal session has a unique terminal identifier, a required argument for most of the functions. A terminal identifier is generated and returned when a terminal is created via terminalCreate() or terminalExecute(), and identifiers of existing terminals can be obtained via terminalList() or terminalVisible().

Terminal Session

A terminal session is an instance of a terminal that can be displayed in the RStudio terminal tab. A terminal session consists of:

Busy Terminal

A terminal session with child processes running (excluding the shell), is considered busy and this is reflected in the IDE UI and can be queried with terminalBusy().

Terminal States

In the most common situation, a terminal session has all the above features; however, it is possible for terminals to be in other states.

No shell process or child processes: This happens if the associated R session has been closed (or suspended in the case of an inactive RStudio Server session).

The terminalRunning() function returns TRUE if a terminal is in this state.

If a terminal is not running, it can be started via interacting with it in the RStudio IDE, or via terminalActivate().

# start an interactive terminal using the shell selected in 
# RStudio global options
myTerm <- rstudioapi::terminalCreate()

# ....
# sometime later
# ....
if (!rstudioapi::terminalRunning(myTerm)) {
  # start the terminal shell back up, but don't bring to front
  rstudioapi::terminalActivate(myTerm, show = FALSE)
  
  # wait for it to start
  while (!rstudioapi::terminalRunning(myTerm)) {
    Sys.sleep(0.1)
  }
 
  # send a new command 
  rstudioapi::terminalSend(myTerm, "echo Hello\n") 
}

Running but not loaded in the IDE: On RStudio Server, the web browser can be closed but the R session and any associated terminal sessions keep running. If the web browser is reconnected, each terminal will be redisplayed in the IDE when it is selected. The rstudioapi functions may be used on a terminal in this state; for example, the buffer may still be fetched with terminalBuffer() even if the terminal isn’t loaded in the IDE (so long as the R session is still alive).

Terminated but still visible: Normally the terminal emulator for a given terminal session will close when the shell exits. If the option Close Terminal When Shell Exits is turned off, then the terminal buffer will remain loaded in the RStudio IDE until closed by the user or terminalKill(). Terminals started with terminalExecute() will always remain loaded when they finish running. To test a terminal for this state, terminalExitCode() will return a non-NULL value.