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.
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.
- 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) - 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) - 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:
- Sharon’s excellent video ‘Write your own RStudio addins’
- Jozef’s in-depth blog series
- RStudio’s very own introduction
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
Shout-out to Serdar, who has contributed functions to {blogsnip}!↩︎
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?↩︎
‘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.↩︎