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")
::install_github("rstudio/addinexamples", type = "source") devtools
Running addins
After installing this package, you should see the Addins toolbar menu populated with the addins exported by this package:
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.
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:
<- function() {
insertInAddin ::insertText(" %in% ")
rstudioapi }
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:
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.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:
Create an R package
Create some R functions
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:
<- miniPage(
ui 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,
<- function(input, output, session) {
server
## 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()'.
<- function() {
clockAddin
# Our ui will be a simple gadget page, which
# simply displays the time in a 'UI' output.
<- miniPage(
ui gadgetTitleBar("Clock"),
miniContentPanel(
uiOutput("time")
)
)
<- function(input, output, session) {
server
# Set some CSS styles for our clock.
<- paste(
clockStyles "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.
<- reactiveTimer(intervalMs = 1000)
invalidatePeriodically 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.
<- Sys.time()
time $time <- renderUI({
outputp(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, {
<- paste0("\"", as.character(Sys.time()), "\"")
timeText ::insertText(timeText)
rstudioapistopApp()
})
}
# We'll use a pane viwer, and set the minimum height at
# 300px to ensure we get enough screen space to display the clock.
<- paneViewer(300)
viewer 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:
Find and Replace — Find and replace words in a document.
Reformat R Code — Reformat R code using
formatR::tidy_source()
.Subset a Data Frame — Interactively subset a data frame.