I use it a lot on Rmarkdow for referring to code, so I created an Addin, but wanted to know if there's a shortcut. If it isn't the case, how could I do to configure the addin so when calling it, the position of the caret or cursor stands between both symbols, exactly as it happens when using "" or () in RStudio.
insertInAddin <- function() { rstudioapi::insertText("``") } is the code I used for the Add-in
I'm looking help understanding how to setup
rstudioapi::setCursorPosition()
and document_position() inside the location argument of insertText.
You can use the shrtcts package for this task. It lets you assign Keyboard Shortcuts to arbitrary R Code.
Create a new R Markdown Snippet which can also be used on its own by typing e.g. in (for inline code font) and press Shift+Tab:
snippet in
`${1}`$0
Use the command shrtcts::edit_shortcuts() in the RStudio Console to open the file where you define your custom shortcuts.
Paste the following code inside that file (set your preferred keybinding in the #shortcut line). Note that the inserted text in the second line of the function must match the new Snippet from Step 1:
#' Code Font
#'
#' #description
#' If Editor has selection, transform current selection to code font.
#' If Editor has no selection, write between backticks.
#' #interactive
#' #shortcut Cmd+E
function() {
if (rstudioapi::selectionGet()$value == "") {
rstudioapi::insertText("in")
rstudioapi::executeCommand("insertSnippet") |>
capture.output() |>
invisible()
} else {
# Gets The Active Document
ctx <- rstudioapi::getActiveDocumentContext()
# Checks that a document is active
if (!is.null(ctx)) {
# Extracts selection as a string
selected_text <- ctx$selection[[1]]$text
# modify string
selected_text <- stringr::str_glue("`{selected_text}`")
# replaces selection with string
rstudioapi::modifyRange(ctx$selection[[1]]$range, selected_text)
}
}
}
This solution uses the native pipe |> and thus requires R 4.1.
You can of course just define separate variables in each line or use the magrittr pipe if you use earlier versions of R.
Further the stringr::str_glue() command can be easily replaced with a base R solution to avoid dependencies.
Use the command shrtcts::add_rstudio_shortcuts(set_keyboard_shortcuts = TRUE) in the RStudio Console to add the new shortcut with its assigned keybinding. Then restart RStudio.
Now you can use e.g. cmd+e without selection to place your cursor within backticks and press Tab to continue writing after the second backtick.
Or you can select text and then press cmd+e to surround the selected text by backticks.
The solution above can be easily generalized for bold and italic text in RMarkdown documents or to write within Dollar signs to add Inline Latex Math.
You can check RMarkdown Code Chunks and RStudio Shortcuts.
The shortcut you're looking for is: Ctrl+Alt+I.
Or you can create your own Code Snippet. To do this, follow the instructions on this page: Code Snippets in the RStudio IDE.
Related
I am looking to create a custom function in R that will allow the user to call the function and then it will produce an auto complete pipeline ready for them to edit, this way they can jump into quickly customizing the standard pipeline instead of copy pasting from an old script or retyping. How can I go about setting up this sort of autocomplete:
#pseudo code what I type---
seq.Date(1,2,by = "days") %>%
pblapply(function(x){
read.fst(list.files(as.character(x), as.data.table = T) %>%
group_by(x) %>%
count()
}) %>% rbindlist()
#how can I write a function so that when I call that function, it ouputs an autocomplete
#of the above so that I can go ahead and start just customizing the code? Something like this
my_autocomplete_function = function(x) {
print(
"
seq.Date(as.Date(Sys.Date()),as.Date(Sys.Date()+1),by = 'days') %>%
pbapply::pblapply(function(x){
fst::read.fst(list.files(as.character(x), as.data.table = T)) %>%
#begin filtering and grouping by below custom
group_by()
}) %>% rbindlist()
")
}
#I can just print the function and copy paste the text from the output in my console to my script
my_autocomplete_function()
#but I rather it just autocomplete and appear in the script if possible?
Putting text into the command line will probably be a function of the interface you are using to run R - is it plain R, Rstudio, etc?
One possibility might be to use the clipr package and put the code into the clipboard, then prompt the user to hit their "paste" button to get it on the command line. For example this function which creates a little code string:
> writecode = function(x){
code = paste0("print(",x,")")
clipr::write_clip(code)
message("Code ready to paste")}
Use it like this:
> writecode("foo")
Code ready to paste
Then when I hit Ctrl-V to paste, I see this:
> print(foo)
I can then edit that line. Any string will do:
> writecode("bar")
Code ready to paste
[ctrl-V]
> print(bar)
Its one extra key for your user to press, but having a chunk of code appear on the command line with no prompting might be quite surprising for a user.
I spend my day reading the source code for utils auto completion. The linebuffer only contains the code for ... one line, so that can't do fully what your looking for here, but it is quite customizable. Maybe the rstudio source code for autocompletion has more answers. Here is an example to write and activate your own custom auto completer. It is not well suited for packages as any new pacakge could overwrite the settings.
Below a
#load this function into custom.completer setting to activate
rc.options("custom.completer" = function(x) {
#perhaps debug it, it will kill your rsession sometimes
#browser()
###default completion###
##activating custom deactivates anything else
#however you can run utils auto completer also like this
#rstudio auto completation is not entirely the same as utils
f = rc.getOption("custom.completer")
rc.options("custom.completer" = NULL)
#function running base auto complete.
#It will dump suggestion into mutable .CompletionEnv$comps
utils:::.completeToken() #inspect this function to learn more about completion
rc.options("custom.completer" = f)
###your custom part###
##pull this environment holding all input/output needed
.CompletionEnv = utils:::.CompletionEnv
#perhaps read the 'token'. Also 'linebuffer', 'start' & 'end' are also useful
token = .CompletionEnv$token
#generate a new completion or multiple...
your_comps = paste0(token,c("$with_tomato_sauce","$with_apple_sauce"))
#append your suggestions to the vanilla suggestions/completions
.CompletionEnv$comps = c(your_comps,.CompletionEnv$comps)
print(.CompletionEnv$comps)
#no return used
NULL
})
xxx<tab>
NB! currently rstudio IDE will backtick quote any suggestion which is not generated by them. I want to raise an issue on that someday.
Bonus info: A .DollarNames.mys3class-method can be very useful and works with both rstudio and utils out of the box e.g.
#' #export
.DollarNames.mys3class = function(x, pattern = "") {
#x is the .CompletionEnv
c("apple","tomato")
}
In RStudio, [Ctrl] + [Enter] runs the currently highlighted code part, but with echo. [Ctrl] [Shift] + [S] sources the whole file without echo.
Is it possible to run the highlighted/selected code part without having the input clutter the console? Or is this an implicit requirement when running code instead of sourcing? (There seem to be subtle differences mentioned in other SO posts)
In conclusion: Is there a Hotkey to press to get exactly what [Ctrl]+[Enter] does, but without cluttering the console with my script code?
I don't believe there is a built-in way to do that. However, you can create an Addin that will source() the code and sink() results to a text file, which can be openend automatically.
In RStudio, create a New Project > R Package.
Create a new R script called runSelected:
#' runSelected
#'
#' RStudio addin to run selected code and show results in
#' default text editor.
#'
#' #export
runSelection <- function() {
context <- rstudioapi::getActiveDocumentContext()
selection <- rstudioapi::primary_selection(context)
tmp_code <- tempfile()
f <- file(tmp_code)
writeChar(object = selection$text, con = f)
close(f)
tmp_results <- tempfile()
sink(tmp_results)
source(tmp_code)
sink()
shell.exec(tmp_results)
}
In the package's directory, create file inst/rstudio/addins.dcf:
Name: Run Selection
Description: Run selected text and see results in text editor
Binding: runSelection
Interactive: false
Generate documentation with roxygen2, build and voilĂ !
Currently in RStudio keybinding CTRL/CMD + SHIFT + B perform the following job
devtools::install().
How can I change it to have this behaviour:
devtools::install(build_vignettes = TRUE)
If not, is it possible to create the entirely new keybinding for it?
You can execute anything by using an add-in. See https://rstudio.github.io/rstudioaddins/ for details. In summary, you create a small R package containing a function like
installWithVignettes <- function() devtools::install(build_vignettes = TRUE)
then set up a special file in the package inst/rstudio/addins.dcf that names this as an add-in. After that you can assign a shortcut to it.
Clarification
Solving this problem with a function was not possible, which #IInspectable kindly confirmed in the comments under the old, deleted, question. Long story short: backslashes need to be escaped in string literals, i.e. a 'C:\\Marketing' needs to be passed instead of 'C:\Marketing'. I am fully aware of this and this question and my answer below is not about the error thrown, manual solutions or using other software (e.g. AutoHotkey) as given in other related questions.
Please note the question is a follow up of another one, thank you #IInspectable for your valuable comments.
"Windows" paths...
I do work with Windows formatted paths (like C:\Marketing) quite often by pasting them into R code. Changing the backslashes every time is highly annoying, thus I have attempted to write a parsing function for them. The desired usage was to use this function in the code with the copied path as a parameter, i.e. path_parse('C:\Marketing'). My first approach, based on #Tyler Rinker answer from here, was as following:
path_parse <- function(path = 'clipboard') {
path <- if (path == 'clipboard') readClipboard() else path
return(chartr('\\', '/', path))
}
and it was working nicely with the path copied to the clipboard, but unfortunately was throwing an error message an unrecognized escape in character string, as in e.g. this question, when used with pasted string literals:
> path_parse('C:\Marketing')
Error: '\M' is an unrecognized escape in character string starting "'C:\M"
Of course manually changing all the input string literals (as in passing 'C:\\Marketing' or 'C:/Marketing' instead of 'C:\Marketing') is not an option here, as this is exactly why I want to automate it somehow.
One closely related question to this one is here, but it is based on Tinn-R GUI and AutoHotkey software, which I do not want to install.
Addins to the rescue
The solution was closer than I thought, an RStudio addin (see e.g. here how to use them) parsing the selected text (i.e. the pasted "Windows" path) by changing all backslashes into forward slashes and inserting it back into the code. Code and screenshots in the answer below.
A working solution (or rather a workaround, as initially I wanted to solve this with a function)
As I wrote in the question above, solving this problem with a function was not possible, so I tried a different solution, which is doing exactly what I wanted, and might be useful for others as well. I have built an addin package (a nice article by RStudio) with the following function:
#' Parse selected "Windows" path to an "R-usable" one
#'
#' #return
#' #export
#' #importFrom rstudioapi getActiveDocumentContext
#' #importFrom magrittr '%>%'
#'
#' #examples
path_parse <- function() {
getActiveDocumentContext()[['selection']][[1]][['text']] %>%
{ gsub('\\\\', '/', .) } %>%
{ gsub('//', '/', .) } %>% # To remove double f. slashes
{ ifelse(check_for_quotes(.), insertText(.), insertText(paste0('\'', ., '\''))) }
}
### Old function:
# path_parse <- function() {
# getActiveDocumentContext()[['selection']][[1]][['text']] %>%
# { chartr('\\', '/', .) } %>% { insertText(paste0('\'', ., '\'')) }
# }
and assigned a Ctrl+Alt+P shortcut to it.
What it does is, basically, parsing the selected text (i.e. the pasted "Windows" path) by changing all backslashes into forward slashes and inserting it back into the code:
Using pure dot inside a knitr chunk with engine = "dot" is straightforward, but you have to write the dot code yourself.
<<r dot-ex, engine = "dot", echo=FALSE>>=
digraph test123 {
A -> B
}
#
I want a function to do it for me.
dotFun <- function() {
dotCode <- 'digraph test123 {
A -> B
}'
return(dotCode)
}
and then call this inside a knit chunk similar to a function that returns LaTeX code and knit with result = 'as.is'
<<r dot-ex, engine = "dot">>=
cat(dotFun())
#
but this results in :Error in (knit_engines$get(options$engine))(options):
setting chunk option results = 'asis' yields the same error message.
Is there a way to do this?
It is not possible with the current version of knitr (v1.5), but will be possible in the next version (v1.6), which has not been released yet. If you use the development version on Github, you can actually assign the source code to a code chunk via the code option, e.g.
<<dot-ex, engine = "dot", code = dotFun()>>=
#
More on this in the news for v1.6.
Any particular reason this has to be evaluated within a knitr chunk with that engine? Why not do it directly from R with some system calls? You can write the command to a file, and use system to call dot on that file, and read the results back into R.
This is, in fact, what knitr does. You can probably pretty easily take the knitr dot engine and wrap it into a function of your own -- see
https://github.com/yihui/knitr/blob/master/R/engine.R#L144.