Remote pair programming in R using Visual Studio Code and Live Share

- The Problem
- State of the Code Editors
- Installation
- Configuration
- Writing an R Package Using VS Code
- Live Share Tutorial
- Final Thoughts
The problem
Way back in the Before Time, my older brother and I worked together on an R package called {wizehiver}. To collaborate, we used many tools. We had an email thread (of over 35 emails!) that eventually became two email threads. We tried GitHub Issues, but we were in such close communication that the back-and-forth on issues was ineffectual. We also tried pair programming but since we lived in separate cities, we did it while one of us would share our screen on Skype. We wished there was a better, more hands-on, and immediate way to collaborate in a source code editor in real-time, similar to how seamless it is to work on Google Docs.
State of the code editors
The RStudio IDE is in our opinion the best IDE for R out there; however, live collaboration using RStudio’s Project Sharing feature is limited to those with a paid RStudio Server Pro license as of this writing. There are many source code editors out there, and notably Atom and Visual Studio (VS) Code both provide extensions for free, collaborative real-time editing.
We have been following, with increasing interest, the growing community of developers who have been focused on tools for R in VS Code. There are now several R packages, VS Code extensions, and a command-line R console available, as well as several tutorials dedicated to R in VS Code. Here we set out to see if VS Code could fill the particular gap we identified in our previous work together — the need for seamless remote pair programming. A few of our use cases are:
- We wanted to collaborate on this blog post in a shared - .Rmdfile which we could edit and knit as we wrote. Ultimately we wrote most of this post on Google Docs before transferring it to a versioned- .Rmdon GitHub for finishing touches.
- We wanted to start collaborating on an open-source R package {mutagen} which will (someday) provide useful extensions to {dplyr}’s - mutate():
 
So far, we only have a hex sticker — #hexdrivendevelopment in action!
Embarrassingly, our last commit to the package was in December 2019. While it would be convenient to blame the pandemic, it was a mix of being busy and other ‘hobby’ projects. However, having a synchronous way of collaborating—where we could see the package being built in action—would enable us to truly get the project underway. Before we begin the tutorial, first we have a public service announcement: if you would like to see Microsoft devote additional resources to support R in VS Code, please upvote R in this vscode-jupyter issue!
Installation
We’re going to use Homebrew to facilitate installation steps on macOS. We only provide instructions for macOS here, but we do provide links for macOS users who prefer to install applications using the point-and-click method, and for Linux and Windows users to find the correct binaries. We also indicate which steps are optional.
- Open Applications > Utilities > Terminal. 
- Install Homebrew using the terminal command below, also provided on the Homebrew landing page. Paste this code into your terminal: 
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"- (Optional) For our favorite free and open-source terminal on macOS, install iTerm2 by pasting this into your terminal:
brew install --cask iterm2- If you don’t have them already, you’ll need R and RStudio Desktop. We’re partial to the preview version of RStudio Desktop which has all the latest features. You can install (and update) them easily from your terminal:
brew install --cask r
brew tap homebrew/cask-versions
brew install --cask rstudio-preview- Install radian, a ‘21st century R console’ and the recommended R console for VS Code.
Update 2021-02-11: Thanks to the efforts of @jdblischak and @randy3k in this closed issue, radian can now be installed with conda-forge instead of only with pip. Most data science tutorials recommend using Python with conda environments, so we suspect that our readers will be more familiar with using conda than pip, as we are. If you do choose to use pip (or python -m pip), beware that pip should be used carefully inside conda environments.
The steps below first install Miniforge, which we prefer to Miniconda since it sets conda-forge as the default channel, then create an empty conda environment named r-console into which we install radian and jedi. jedi is an optional package that enables Python autocompletion using the {reticulate} R package. Paste this into your terminal:
brew install miniforge
conda create --name r-console
conda activate r-console
conda install radian
conda install jedi # for {reticulate} python autocompletion- In RStudio, install the required R packages for VS Code, namely {languageserver} from CRAN and the latest GitHub release of {vscDebugger}:
install.packages("languageserver")
remotes::install_github("ManuelHentschel/vscDebugger", ref = remotes::github_release())For the tutorial, make sure that you have the following R packages installed, if you don’t already:
install.packages("devtools")
install.packages("dplyr")
install.packages("purrr")
install.packages("tibble")
install.packages("usethis")
install.packages("vctrs")- Install VS Code by pasting this into your terminal:
brew install --cask visual-studio-code- Open VS Code and install the following extensions from the Extensions gallery (Shift-Command-X):
Configuration
- Make sure the r-consoleenvironment is still active in your terminal. If it is, your terminal prompt will look like this, or similar:
(r-console) ~ %If not, then reactivate the r-console environment:
conda activate r-console- Type which radianin your terminal to display the path to theradianexecutable. Below is what it is on our local machines. Copy the path to your clipboard.
/usr/local/Caskroom/miniforge/base/envs/r-console/bin/radian- Determine whether bashorzshis your default shell. If you don’t know, type this into your terminal:
echo $SHELLOlder Macs may still use bash, while newer Macs or those with older Macs who have created new user accounts since upgrading to macOS Catalina will likely run zsh, the new default macOS shell.
- Let’s take VS Code for a spin! An useful feature to know about is that typing code <path/file.ext>in your terminal will open a new or existing file in VS Code at the path you specify. Many more details are available in the help pagecode -h. Depending on whether your default shell isbashorzsh, typecode ~/.bashrcorcode ~/.zshrcin your terminal to open your shell configuration file, and paste the path you copied in step 2. above to add an alias toradianand bind it to lowercaser:
alias r="/usr/local/Caskroom/miniforge/base/envs/r-console/bin/radian"You can paste the alias anywhere in the file, but it is probably best to paste it at the very bottom, and avoid inserting it in any preexisting code blocks (e.g., conda initialize blocks) which may be overwritten. Save your configuration file and restart your terminal for the settings to take effect. Now all you need to open radian is to type r in any terminal (Terminal, iTerm2, RStudio, or VS Code)! Useful radian commands to know are:
q() # to exit R, same as with vanilla R and RStudio
;   # to enter shell mode, exit by pressing backspace on an empty line
~   # to enter {reticulate} python mode, exit by pressing backspace on an empty line- To configure your .Rprofile, typecode ~/.Rprofilein your terminal, or if you are already set up with {usethis} in RStudio, run the R commandusethis::edit_r_profile(). At a minimum, you will want to enable {rstudioapi} emulation in VS Code:
options(vsc.rstudioapi = TRUE)- To configure radian, typecode ~/.radian_profilein your terminal which will open up a new blank editor and create a new file named.radian_profilein the home directory. This is our.radian_profile:
options(
    radian.insert_new_line = FALSE,
    radian.escape_key_map = list(
        list(key = "-", value = " <- "),
        list(key = "m", value = " %>% ")
    )
)Save ~/.radian_profile and restart your terminal for the settings to take effect.
- Now we’ll configure VS Code settings. Open VS Code, and navigate to settings.jsonby using the Command Palette (Shift-Command-P) and navigating toPreferences: Open Settings (JSON). This is oursettings.json:
{
    // Liveshare: Prompt when receiving focus requests
    "liveshare.focusBehavior": "prompt",
    // R: Treat`names.like.this` as one word for selection
    "[r]": {
        "editor.wordSeparators": "`~!@#%$^&*()-=+[{]}\\|;:'\",<>/?"
    },
    // R: Use active terminal for all commands
    "r.alwaysUseActiveTerminal": true,
    // R: Use bracketed paste mode when sending code to console (radian)
    "r.bracketedPaste": true,
    // R: R or radian path for macOS
    "r.rterm.mac": "/usr/local/Caskroom/miniforge/base/envs/r-console/bin/radian",
    // R: Enable R session watcher (experimental)
    "r.sessionWatcher": true,
    // R: Remove hidden items when clearing R workspace
    "r.workspaceViewer.removeHiddenItems": true,
    // Telemetry: Disable Microsoft crash reporter
    "telemetry.enableCrashReporter": false,
    // Telemetry: Disable Microsoft telemetry
    "telemetry.enableTelemetry": false,
    // Terminal: Path to integrated shell on macOS
    "terminal.integrated.shell.osx": "/bin/zsh"
}The r.rterm.mac field above should be the path to radian if you followed the radian installation instructions above, otherwise it should be the path to your R executable (if you don’t know it, type which R in your terminal). Since we use Homebrew to install the latest zsh using brew install zsh, the path to our zsh is /usr/local/bin/zsh, but we have put /bin/zsh above since that is the default zsh location for most macOS users. You should run which r and which zsh to confirm your local settings are correct.
- Below are some useful keyboard shortcuts for keybindings.json, found by using the Command Palette (Shift-Command-P) in VS Code and navigating toPreferences: Open Keyboard Shortcuts (JSON). This is ourkeybindings.json:
[
    {
        "description": "View: Show R Workspace",
        "key": "alt+r",
        "command": "workbench.view.extension.workspaceViewer"
    },
    {
        "description": "R: Create R Terminal",
        "key": "alt+`",
        "command": "r.createRTerm"
    },
    {
        "description": "R: Insert Assignment Operator",
        "key": "alt+-",
        "command": "type",
        "when": "editorLangId == r || editorLangId == rmd && editorTextFocus",
        "args": { "text": " <- " }
    },
    {
        "description": "R: Insert Pipe Operator",
        "key": "shift+cmd+m",
        "command": "type",
        "when": "editorLangId == r || editorLangId == rmd && editorTextFocus",
        "args": { "text": " %>% " }
    },
    {
        "description": "R: Insert Assignment Pipe Operator",
        "key": "shift+cmd+,",
        "command": "type",
        "when": "editorLangId == r || editorLangId == rmd && editorTextFocus",
        "args": { "text": " %<>% " }
    },
    {
        "description": "R: Insert Tee Pipe Operator",
        "key": "shift+cmd+.",
        "command": "type",
        "when": "editorLangId == r || editorLangId == rmd && editorTextFocus",
        "args": { "text": " %T>% " }
    },
    {
        "description": "R: Test Package",
        "key": "shift+cmd+8",
        "command": "r.test"
    },
    {
        "description": "R: Document",
        "key": "shift+cmd+9",
        "command": "r.document"
    },
    {
        "description": "R: Load All",
        "key": "shift+cmd+0",
        "command": "r.loadAll",
    }
]Writing an R Package using VS Code
In this section we’re going to set up a toy R package in VS Code, and in the next section we will enable Live Share.
- Open VS Code and use the Command Palette ( - Shift-Command-P) to navigate to- R: Create R Terminal, or use the suggested keyboard shortcut above (- Option-`). Note that if you have an editor open and the focus is on the editor, for the shortcut to work you may first need to use- Control-`for- View: Toggle Integrated Terminalfollowed by- Option-`for- R: Create R Terminal. If our configuration above worked for you, these commands should open a terminal instance with the- radianconsole, and the title of the terminal should be- 1: R Interactive(or- 2: R Interactiveif it’s the second active terminal).
- In the VS Code R console, create a {mutagen} package folder on your Desktop, declare dependencies, and start an R script for a new function - cast_integers():
library(usethis)
create_package("~/Desktop/mutagen")
deps <- c("dplyr", "purrr", "tibble", "vctrs")
purrr::walk(deps, use_package)
use_r("cast_integers")- In VS Code, open the {mutagen} folder using File > Open… ( - Command-O) and selecting the- mutagenfolder in the Desktop. This will open a new VS Code instance and the title bar will read- Welcome — mutagen. The R extension icon will be visible on the sidebar since VS Code will detect the- .Rfile in the folder.
- Use the Explorer icon in the sidebar ( - Shift-Command-E) and open the- cast_integers.Rfile. Paste the following code into the editor and save the file:
#' Safely cast numeric columns to integers
#'
#' `cast_integers()` casts all eligible numeric columns in a data frame to integers, without data loss, using `vctrs::vec_cast()` for coercion.
#' @param .data A data frame
#' @return A tibble. If the input data frame has rownames, these will be preserved in a new rowname column.
#' @examples (mtcars_integerized <- cast_integers(mtcars))
#' @export
cast_integers <- function(.data) {
    stopifnot(is.data.frame(.data))
    .data <- tibble::rownames_to_column(.data)
    .data <- tibble::as_tibble(.data)
    int_index <- purrr::map_lgl(
        .data,
        ~ !inherits(try(vctrs::vec_cast(.x, to = integer()), silent = TRUE), "try-error")
    )
    .data <- dplyr::mutate(
        .data,
        dplyr::across(
            .cols = any_of(names(which(int_index))),
            .fns = ~ vctrs::vec_cast(.x, to = integer())
        )
    )
    return(.data)
}- Now create a new R console in VS Code using either the keyboard shortcuts (Control-`to toggle the terminal andOption-`to create an R console) or by opening the Command Palette (Shift-Command-P) and navigating toR: Create R Terminal. Focus your view on the R extension by clicking R the sidebar (Option-R), and now test out the package. Below are a series of R console commands to familiarize you with the package development workflow in VS Code. We will load the package, document it, and create a new object in the R workspace that uses the new function we just loaded onto the package environment. To get familiar with the VS Code user interface, we will also print the object in the console, view it with the data viewer, and check out the help file for our new function.
library(dplyr)
devtools::load_all() # or Shift-Command-0 using keyboard shortcuts above
devtools::document() # or Shift-Command-9 using keyboard shortcuts above
mtcars_integerized <- mtcars %>% cast_integers()
mtcars_integerized
View(mtcars_integerized)
?cast_integersFinal thoughts
We’re excited for the future of R programming in VS Code. Live Share is an outstanding innovation for collaborative real-time editing, and is only one of the many amazing features in VS Code. Here we have only scratched the surface of use cases for Live Share. Microsoft keeps a running list of many other Live Share use cases.
We are also huge fans of RStudio and the RStudio IDE. On our wish list for RStudio is that a live collaboration feature be supported in future versions of RStudio Desktop (not only the Pro version) and RStudio Cloud. Having many excellent options is a good thing! In the meantime, it is clear that VS Code is maturing into a capable IDE for R. Live Share is an attractive and free feature that enables real-time collaboration for the masses and that we hope others will enjoy as much as we have.
Liked this post? I’d love for you to retweet!
🎉📢🎉 Collaborating in #rstats? Git got you down? Want to code with others remotely, in real-time, and for free (à la Google Docs)? Check out how to set up and use @code (#vscode) and #vsliveshare for remote #pairprogramming 🤝 in R! 🤯. Tutorial here: https://t.co/Qbrw71V77Z pic.twitter.com/3sy9hAJea7
— Isabella Velásquez (@ivelasq3) February 4, 2021