RStudio Addins

RStudio addins provide a mechanism for executing R functions interactively from within RStudio; either through keyboard shortcuts, through the Command Palette or through the Addins menu.

An addin can be as simple as a function that inserts a commonly used snippet of text, and as complex as a Shiny application that accepts input from the user, and later mutates a document open in RStudio.

Using addins

The following documentation covers:

  • Basics of installing addins
  • Binding keyboard shortcuts to them
  • Developing new addins

Installation

RStudio addins are distributed as R packages. Once you’ve installed an R package that contains addins, they’ll be immediately become available within RStudio.

Let’s start by playing around with a couple of the example addins provided by the addinexamples package. Within RStudio, install this package (plus its requisite dependencies) with:

# if necessary: install.packages("devtools")
devtools::install_github("rstudio/addinexamples", type = "source")

Running addins

After installing this package, you should see the Addins toolbar menu populated with the addins exported by this package:

A screenshot of the addinexamples dropdown - displaying the insert, find and replace, reformat R code, and Subset a data frame add-ins.

Try pressing the Insert %in% addin – the text %in% will be inserted at the cursor position.

The Addins menu displays all available addins, along with a search bar for searching by package name or by addin name:

Keyboard shortcuts

Addins can be assigned a keyboard shortcut through the Tools > Modify Keyboard Shortcuts menu.

A screenshot of the Customize Keyboard shortcuts menu

Developing addins

Addin basics

The Insert %in% addin is implemented entirely with R code. In fact, the R function that made this happen is located here, and its definition is show below:

insertInAddin <- function() {
  rstudioapi::insertText(" %in% ")
}

Executing addinexamples::insertInAddin() directly at the console will insert %in%. RStudio is executing that R script behind the scenes, the addin is providing a user interface element and potentially a shortcut rather than manually writing and executing the function each time.

There are two major types of addins:

  1. Text macros, which insert text into the console or source pane and in some cases transform text within the source pane. The insertInAddin addin defined above is an example of a text macro.

  2. Shiny Gadgets, which are fully interactive Shiny applications. Gadgets may also perform text transformations but they are capable of much more.

More details on Shiny Gadgets are provided below, but first we’ll take a look at using the rstudioapi package (which allows us to interact with RStudio from R code) and then what it takes to install and register an addin.

RStudio API

The rstudioapi package allows interacting with RStudio directly with R code.

install.packages("rstudioapi")

For addins in particular, a number of methods were added that allow R code to introspect and mutate the contents of a document open in RStudio. These methods are outlined below briefly, but see documentation within the rstudioapi package for more details.

getActiveDocumentContext() Returns information about the currently active RStudio document. See below for more details.
insertText(location, text, id = NULL) Insert text at a specific location within a document.
setDocumentContext(text, id = NULL) Set the contents of a document open in RStudio.

The list returned from getActiveDocumentContext() provides the following information about the active RStudio document:

  • id — The unique document id.

  • path — The path to the document on disk.

  • contents — The contents of the document.

  • selection — A list of selections.

The id can be passed to other functions within the API to address a specific document instance rather than the currently active document. Even though it’s optional, it’s highly recommended that you use the id parameter to ensure that you modify the document that was active when your addin was invoked.

The location argument to several of the API functions specifies a position or range to operate on. See the rstudioapi manual for more details on specifying locations.

Registering addins

Addins are just R functions, distributed via R packages. The registration file located at inst/rstudio/addins.dcf lets RStudio know which addins are available. Each addin should have the following four fields:

  • Name: The name of the addin.

  • Description: A description of the addin.

  • Binding: The R function this addin is associated with.

  • Interactive: Whether this addin is interactive (e.g. runs a Shiny application).

For example:

Name: Insert %in%
Description: Inserts `%in%` at the cursor position.
Binding: insertInAddin
Interactive: false

To create your own RStudio addins:

  1. Create an R package

  2. Create some R functions

  3. Create a file at inst/rstudio/addins.dcf

RStudio will automatically discover and register these addins when your package is installed. Any number of addins can be added with a single addins.dcf file, but a blank line must be between each addin that is registered.

Execution Modes

The Interactive field within the addin registration describes whether the addin is interactive or non-interactive. It’s important to understand when an addin should be declared as interactive versus non-interactive, as this affects how RStudio will attempt to execute the addin:

  • Interactive addins are invoked by emitting a call to their function directly into the R console. For addins that display user-interface (e.g. using a Shiny application) this enables users to stop/interrupt them.

  • Non-interactive addins are run in the background and can not be interrupted, so it’s imperative that these addins complete execution quickly. Otherwise, it’s possible that the addin could freeze the user’s R session.

The use case for non-interactive addins is typically simple text insertion or transformation, in which case users would be annoyed if each invocation resulted in code being inserted into the console.

Shiny Gadgets

Shiny gadgets are Shiny applications which can be registered and run as addins. Typically, a Shiny Gadget provides a mechanism for interactively generating code, or modifying a document, but within this realm the possibilities are endless. This article demonstrates how you might create a simple Shiny Gadget, for more complete documentation see the following articles on the Shiny Developer Center:

Shiny Gadgets are similar to regular Shiny applications. You will need to develop a ui and a server for your gadget, and then use the runGadget() function to launch your gadget.

Shiny Gadgets require the shiny and miniUI packages:

install.packages(c("shiny", "miniUI"))

Gadget UI

The UI for a Shiny Gadget can be generated using functions from the miniUI package. Typically, the UI definition of a Shiny Gadget will have the following form:

ui <- miniPage(
  gadgetTitleBar("My Gadget"),
  miniContentPanel(
    ## Your UI items go here.
  )
)

If you’re unfamiliar with how the UI for a Shiny application can be generated, please read the Shiny UI Lesson to get further acquainted with how the UI for a Shiny application might be developed.

Gadget Server

The server function used for a Shiny Gadget is similar to one as provided for a regular Shiny application, except with the requirement that your application must respond to the done event. For example,

server <- function(input, output, session) {
  
  ## Your reactive logic goes here.
  
  # Listen for the 'done' event. This event will be fired when a user
  # is finished interacting with your application, and clicks the 'done'
  # button.
  observeEvent(input$done, {
    
    # Here is where your Shiny application might now go and affect the
    # contents of a document open in RStudio, using the `rstudioapi` package.
    #
    # At the end, your application should call 'stopApp()' here, to ensure that
    # the gadget is closed after 'done' is clicked.
    stopApp()
  })
}

Gadget Viewer

After defining the ui and server for your Shiny gadget, choose what kind of viewer the application should run in. Currently, there are three options available:

  • paneViewer(): Launch the Shiny Gadget within the RStudio Viewer pane. This is useful for gadgets that want to run without obscuring other windows in the RStudio, but such applications should require only a minimal amount of space (as the viewer may be small on the user’s computer).

  • dialogViewer(): Launch the Shiny Gadget as a modal dialog within the RStudio. Use this when your gadget requires a large amount of screen real estate, but is not heavy-weight enough to require a separate window.

  • browserViewer(): Launch the Shiny gadget in a separate window. Use this for large Shiny gadgets that require a large amount of real estate, and perhaps are more complex than applications that could fit comfortably within an RStudio modal dialog.

Putting It Together

Let’s combine the above components into a simple ‘Hello Shiny’ gadget. We’ll create a clock that updates its display every second. Try running the following code in RStudio – you should see a clock displayed in the viewer pane. When you click Done, the current time will be inserted at the cursor position.

library(shiny)
library(miniUI)

# We'll wrap our Shiny Gadget in an addin.
# Let's call it 'clockAddin()'.
clockAddin <- function() {
  
  # Our ui will be a simple gadget page, which
  # simply displays the time in a 'UI' output.
  ui <- miniPage(
    gadgetTitleBar("Clock"),
    miniContentPanel(
      uiOutput("time")
    )
  )
  
  server <- function(input, output, session) {
    
    # Set some CSS styles for our clock.
    clockStyles <- paste(
      "border: 1px solid #DADADA",
      "background-color: #EFEFEF",
      "border-radius: 5px",
      "font-size: 6em",
      "margin-top: 60px",
      "text-align: center",
      sep = "; "
    )
    
    # We'll use a 'reactiveTimer()' to force Shiny
    # to update and show the clock every second.
    invalidatePeriodically <- reactiveTimer(intervalMs = 1000)
    observe({
      
      # Call our reactive timer in an 'observe' function
      # to ensure it's repeatedly fired.
      invalidatePeriodically()
      
      # Get the time, and render it as a large paragraph element.
      time <- Sys.time()
      output$time <- renderUI({
        p(style = clockStyles, time)
      })
    })
    
    # Listen for 'done' events. When we're finished, we'll
    # insert the current time, and then stop the gadget.
    observeEvent(input$done, {
      timeText <- paste0("\"", as.character(Sys.time()), "\"")
      rstudioapi::insertText(timeText)
      stopApp()
    })
    
  }
  
  # We'll use a pane viwer, and set the minimum height at
  # 300px to ensure we get enough screen space to display the clock.
  viewer <- paneViewer(300)
  runGadget(ui, server, viewer = viewer)
  
}

# Try running the clock!
clockAddin()

# Now all that's left is sharing this addin -- put this function
# in an R package, provide the registration metadata at
# 'inst/rstudio/addins.dcf', and you're ready to go!

That example provides a fully functional Shiny gadgets. Additional documentation on creating Gadgets is available at the Shiny Developer Center:

Installation

Creating addins with Shiny Gadgets requires shiny, miniUI, and rstudioapi packages from CRAN. To create an addin package, add these packages to the package DESCRIPTION file as follows:

Imports:
  shiny,
  miniUI,
  rstudioapi

More Examples

The addinexamples package contains several additional examples of Shiny Gadget based addins: