Add in an RStudio Addin to add in backticks

Gif of RStudio script pane. An RStudio addin called backtick is being used to insert a single backtick, surround selected text with bacticks, surround selected text with backticks as inline R code, and surround selected text with an R code chunk.

tl;dr

I wrote a tiny R package called {backtick}, which contains an RStudio Addin with a handful of functions for inserting backticks into your R scripts and R Markdown documents (yes, really).

Plus one

RStudio Addins let you select an R function from a dropdown menu in the RStudio IDE. They’re often functions that you don’t need in your executed script, but can make your life easier by performing some kind of supportive action.

For example, you can use the RStudio Addin in the {remedy} package from ThinkR to add Markdown formatting to your text. RStudio’s {reprex} package has a built-in RStudio Addin to create a reproducible example from highlighted code. Or how about Miles McBain’s {datapasta} Addin for pasting conveniently into R scripts from external sources?

You can find many more examples in Dean Attali’s {addinslist} package, which itself contains an Addin for… adding more Addins.

In addition

I’ve written about RStudio Addins before.

I have a GitHub-hosted package called {blogsnip} with an Addin to help me insert code into these blogposts.1 For example, to insert the session-information block at the end of each post, or to insert HTML to create more accessible images.

{blogsnip} also hosts a concept function to add a comment to each closing bracket with the name of the function being closed. I’ve found it useful for keeping on top of deeply-nested Shiny apps.

A while back I also wrote an Addin for the {r2eng} package to let your computer speak R code aloud as an English sentence.

I also recently created the {snorkel} R package, which contains an Addin to help you insert {roxygen2} formatting to your function documentation. Turns out Jozef wrote a detailed series about how you can do something similar.

Gif of RStudio Addin being used to add roxygen2 tags to selected text in the documentation for a function. Addins used are: format as bold, link to function in another package, and make hyperlink.

You put a snorkel in your mouth to help you breathe oxygen; you put a {snorkel} in your addins to help you write with {roxygen2}.

I wanted to write something about how to quickly set up a package to insert or replace text, which I think is probably the most common (simple) use of RStudio Addins.

Eventually I was nerdsniped (unintentionally) on Twitter by Calum to do something about it.

The problem

Problem: Calum’s backtick key, `, is being used to activate additional software that’s awkward to toggle on and off every time they wanted to use the backtick for R coding.2

To solve Calum’s problem (and Italy’s?3), you could try to use a custom keyboard shortcut, or maybe a snippet. And RStudio already has a button and shortcut in its IDE for inserting R Markdown code chunks, which require triple backticks to demarcate the start and end of the chunk.

But an RStudio Addin is another viable method that means you can bundle up a set of functions that insert each of the backtick ‘constructions’, from a single backtick to an R Markdown chunk.

As a bonus, you can also set the functions of an Addin to custom keyboard shortcuts and quickly access them from the RStudio command palette (just hit Shift + Cmd + P, or Shift + Ctrl + P, then type the word ‘backtick’).

A solution

So, the (very specific!) user need was clear and I created the {backtick} package with functions to:

  • insert a single backtick (i.e. `)
  • surround selected text with single backticks (i.e. selection becomes `selection`)
  • surround selected text with backticks for execution as inline R code in an R Markdown document (as above, but inserts an r and space after the first backtick)
  • surround selected text with backticks for execution as an R code chunk in an R Markdown document (selection is surrounded by ```{r} above and ``` below)

That last one is especially neat because the in-built RStudio function doesn’t appear to put selected text inside an R Markdown chunk; it simply inserts the skeleton of a chunk.

Calum notes that this solution worked, and that they were able to set the insert backtick Addin to the keyboard shortcut Alt + `, lol.

Add your own

I wanted to record for posterity how you (and me) can create this sort of thing.

  1. First, create a new package—I like to use usethis::create_package()—and complete basic things like the DESCRIPTION file (I wrote about this before)
  2. Write functions in an R script—I like to use usethis::use_r() to create this script in the package—that insert code or replace selected text using the {rstudioapi} package)
  3. Add an inst/rstudio/addins.dcf file4 that declares each of your Addins

Points 2 and 3 are in scope for this quick post.

Use {rstudioapi}

What do I mean by ‘write functions that insert or replace’ text?

Well, insertion is straightforward. Here’s the function definition from {backtick} to insert a single backtick:

bt_backtick <- function() {
  rstudioapi::insertText("`")
}

In other words, it’s as simple as a function that contains rstudioapi::insertText(). This fetches information from the IDE to know where the cursor is placed in your script, which is where a supplied text string (a single backtick in this case) will be inserted.

And what about text replacement? A similar story: the {rstudioapi} package is used to detect the selected text, which can then be pasted together with other strings to produce and insert a new compound string. Here’s an example from {backtick} for surrounding selected text with backticks:

bt_backticks <- function() {

  active_doc <- rstudioapi::getSourceEditorContext()

  if (!is.null(active_doc)) {

    selected_text <- active_doc$selection[[1]]$text

    text_replace <- paste0("`", selected_text, "`")

    rstudioapi::modifyRange(
      active_doc$selection[[1]]$range,
      text_replace
    )

  }

}

So, in short, rstudioapi::getSourceEditorContext() fetches information about the script pane, including the current selection. That selection can be pasted with other strings, such as a backtick character at the start and end, and then inserted back into the script pane with rstudioapi::modifyRange() to replace the original selection.

And, well… that’s it for functions. All you need to do now is create a special text file so that the functions can be interpreted as Addins.

Create a dcf

So, for example, the bt_bactick() function can be exposed as an Addin function by adding the following to the inst/rstudio/addins.dcf file:

Name: Insert Backtick
Description: Insert a single backtick. In R Markdown file, one backtick will be
    inserted. RStudio automatically adds a second backtick when this function is
    used in an R script.
Binding: bt_backtick
Interactive: false

This is pretty straightforward: you provide a name (which will be the name you see in the RStudio Addins dropdown menu) and a description (I just copied the description I wrote for the function documentation), along with the binding (just the function name). There’s also ‘interactive’, which tells RStudio if it needs to wait for the user to do something (no, or false in our example).

Addintional resources

This was a quick roundup to help you (and me) remember quickly how to create this kind of simple insert/replace type of RStudio Addin.

I recommend you check out a number of more in-depth resources:

Let me know about other useful Addins or tutorials for making them.

And perhaps begin lobbying the Italian government to a backtick key on their keyboards as a gesture of solidarity with developers.


Session info
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.1.0 (2021-05-18)
##  os       macOS Big Sur 10.16         
##  system   x86_64, darwin17.0          
##  ui       X11                         
##  language (EN)                        
##  collate  en_GB.UTF-8                 
##  ctype    en_GB.UTF-8                 
##  tz       Europe/London               
##  date     2022-03-07                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  blogdown      1.4     2021-07-23 [1] CRAN (R 4.1.0)
##  bookdown      0.23    2021-08-13 [1] CRAN (R 4.1.0)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.1.0)
##  cli           3.1.0   2021-10-27 [1] CRAN (R 4.1.0)
##  digest        0.6.29  2021-12-01 [1] CRAN (R 4.1.0)
##  evaluate      0.14    2019-05-28 [1] CRAN (R 4.1.0)
##  fastmap       1.1.0   2021-01-25 [1] CRAN (R 4.1.0)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.0)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.1.0)
##  jsonlite      1.7.3   2022-01-17 [1] CRAN (R 4.1.2)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.1.0)
##  magrittr      2.0.2   2022-01-26 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.1.0)
##  rlang         1.0.1   2022-02-03 [1] CRAN (R 4.1.2)
##  rmarkdown     2.10    2021-08-06 [1] CRAN (R 4.1.0)
##  rstudioapi    0.13    2020-11-12 [1] CRAN (R 4.1.0)
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.1.0)
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.1.0)
##  stringi       1.7.6   2021-11-29 [1] CRAN (R 4.1.0)
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 4.1.0)
##  withr         2.4.3   2021-11-30 [1] CRAN (R 4.1.0)
##  xfun          0.29    2021-12-14 [1] CRAN (R 4.1.0)
##  yaml          2.2.2   2022-01-25 [1] CRAN (R 4.1.2)
## 
## [1] /Library/Frameworks/R.framework/Versions/4.1/Resources/library

  1. Shout-out to Serdar, who has contributed functions to {blogsnip}!↩︎

  2. Ideally this would be fixed upstream. Re-map the other software to another key? Easier said than done if it’s a work computer you’re using. Turn off the other software when you’re not using it? But what if you forget to switch it back on? Etc, etc. Relax, this is just a silly blog post. There must be a relevant xkcd though: why fix the real problem when you can write more software to paper the cracks?↩︎

  3. Confirmed by a real-life Italian (as far as I can tell)!↩︎

  4. ‘Debian Control File’ if you must know, but it doesn’t really matter. A package DESCRIPTION file is also a type of dcf file, I believe.↩︎