├── LICENSE ├── .gitignore ├── data ├── KEYS.rda └── rstudio_shortcuts.rda ├── .Rbuildignore ├── .travis.yml ├── NEWS.md ├── R ├── createEnv.R ├── llc_addin.R ├── KEYS-data.R ├── rstudio_shortcuts-data.R ├── utils.R ├── restore_addins.R ├── fetch_keys.R ├── fetch_addins.R ├── create_yml.R ├── rm_shorcut.R ├── toggle_addin.R ├── zzz.R ├── anti_addin.R ├── set_shortcut.R └── rsam.R ├── man ├── fetch_addin_keys.Rd ├── anti_addin.Rd ├── restore_addins.Rd ├── rsam.Rd ├── fetch_addins.Rd ├── KEYS.Rd ├── rm_shortcut.Rd ├── toggle_addin.Rd ├── rstudio_shortcuts.Rd ├── set_shortcut.Rd ├── create_yml.Rd └── grapes-greater-than-grapes.Rd ├── inst └── rstudio │ └── addins.dcf ├── rsam.Rproj ├── cran-comments.md ├── NAMESPACE ├── DESCRIPTION ├── data-raw └── fetch_rstudio_shortcuts.R ├── appveyor.yml ├── README.Rmd └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2018 2 | COPYRIGHT HOLDER: Jonathan Sidi 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /data/KEYS.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonicd/rsam/HEAD/data/KEYS.rda -------------------------------------------------------------------------------- /data/rstudio_shortcuts.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonicd/rsam/HEAD/data/rstudio_shortcuts.rda -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^data-raw$ 4 | README.Rmd 5 | ^\.travis\.yml$ 6 | ^appveyor\.yml$ 7 | ^cran-comments\.md$ 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: false 5 | cache: packages 6 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rsam 0.1.0 2 | 3 | * Added a `NEWS.md` file to track changes to the package. 4 | * Initial commit to CRAN 5 | 6 | # rsam 0.1.3 7 | 8 | * Add permission prompts for rsam to write to disk. 9 | -------------------------------------------------------------------------------- /R/createEnv.R: -------------------------------------------------------------------------------- 1 | .creatEnv <- function() { 2 | .rsamEnv <- new.env() 3 | .rsamEnv$write_json <- FALSE 4 | .rsamEnv$write_dcf <- FALSE 5 | .rsamEnv$set <- TRUE 6 | 7 | assign(".rsamEnv", envir = parent.frame(), value = .rsamEnv) 8 | 9 | return(.rsamEnv) 10 | } 11 | 12 | .creatEnv() 13 | -------------------------------------------------------------------------------- /R/llc_addin.R: -------------------------------------------------------------------------------- 1 | lla1 <- function(){ 2 | 3 | do.call(get('rsam_fn_1',envir = parent.frame(2)),args = list()) 4 | 5 | } 6 | 7 | lla2 <- function(){ 8 | 9 | do.call(get('rsam_fn_2',envir = parent.frame(2)),args = list()) 10 | 11 | } 12 | 13 | 14 | lla3 <- function(){ 15 | 16 | do.call(get('rsam_fn_3',envir = parent.frame(2)),args = list()) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /R/KEYS-data.R: -------------------------------------------------------------------------------- 1 | #' @title Keyboard Validation 2 | #' @description List containing keyboard keys 3 | #' @format A list with 99 elements of class 'key' 4 | #' @details key class has a '.+' method so keys can be appended to each other 5 | #' @examples 6 | #' base_key <- KEYS$`left command/window key` 7 | #' base_key 8 | #' base_key + KEYS$shift + KEYS$i 9 | #' base_key + KEYS[2:9] 10 | #' 11 | "KEYS" 12 | -------------------------------------------------------------------------------- /man/fetch_addin_keys.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fetch_keys.R 3 | \name{fetch_addin_keys} 4 | \alias{fetch_addin_keys} 5 | \title{Current Addins shortcuts} 6 | \usage{ 7 | fetch_addin_keys() 8 | } 9 | \value{ 10 | data.frame 11 | } 12 | \description{ 13 | Retrieve current defined Addin shortcuts 14 | } 15 | \seealso{ 16 | \code{\link[jsonlite]{fromJSON}} 17 | } 18 | -------------------------------------------------------------------------------- /man/anti_addin.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/anti_addin.R 3 | \name{anti_addin} 4 | \alias{anti_addin} 5 | \title{Create duplicate of addins.dcf file in installed packages.} 6 | \usage{ 7 | anti_addin() 8 | } 9 | \value{ 10 | nothing 11 | } 12 | \description{ 13 | Create duplicates of installed addins.dcf of packages with addins 14 | found in libpath that rsam will manipulate 15 | } 16 | -------------------------------------------------------------------------------- /inst/rstudio/addins.dcf: -------------------------------------------------------------------------------- 1 | Name: lla1 2 | Description: Wrap any global objects in rsam_fn_1() and use this addin to run them. 3 | Binding: lla1 4 | Interactive: true 5 | 6 | Name: lla2 7 | Description: Wrap any global objects in rsam_fn_2() and use this addin to run them. 8 | Binding: lla2 9 | Interactive: true 10 | 11 | Name: lla3 12 | Description: Wrap any global objects in rsam_fn_3() and use this addin to run them. 13 | Binding: lla3 14 | Interactive: true 15 | -------------------------------------------------------------------------------- /man/restore_addins.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/restore_addins.R 3 | \name{restore_addins} 4 | \alias{restore_addins} 5 | \title{Restore package addins} 6 | \usage{ 7 | restore_addins(package = NULL) 8 | } 9 | \arguments{ 10 | \item{package}{character, packages to restore default addins, if NULL all packages will 11 | be restored, Default: NULL} 12 | } 13 | \description{ 14 | Restores addins.dcf files of installed package 15 | } 16 | -------------------------------------------------------------------------------- /man/rsam.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rsam.R 3 | \name{rsam} 4 | \alias{rsam} 5 | \title{rsam user interface} 6 | \usage{ 7 | rsam(warn = TRUE) 8 | } 9 | \arguments{ 10 | \item{warn}{boolean, show warning popup message to restart IDE, Default: TRUE} 11 | } 12 | \description{ 13 | Shiny application to use rsam through UI 14 | } 15 | \seealso{ 16 | \code{\link[rhandsontable]{rHandsontableOutput}},\code{\link[rhandsontable]{renderRHandsontable}} 17 | } 18 | -------------------------------------------------------------------------------- /rsam.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageCheckArgs: --as-cran 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /R/rstudio_shortcuts-data.R: -------------------------------------------------------------------------------- 1 | #' @title Rstudio Keyboard Shortcuts 2 | #' @description Keyboard shortcut definitions scrapped from 3 | #' \href{https://support.rstudio.com/hc/en-us/articles/200711853-Keyboard-Shortcuts}{RStudio Homesite} 4 | #' @format A data frame with 276 rows and 3 variables: 5 | #' \describe{ 6 | #' \item{\code{Description}}{character Decription What Shortcut Does} 7 | #' \item{\code{Shortcut}}{character Short Definition} 8 | #' \item{\code{OS}}{character Operating System} 9 | #'} 10 | "rstudio_shortcuts" 11 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | * local OS X install, R 3.3.3 3 | * ubuntu 12.04 (on travis-ci), R 3.3.3 4 | * win-builder (devel and release) 5 | 6 | ## R CMD check results 7 | 8 | 0 errors | 0 warnings | 1 note 9 | 10 | * This is a new release. 11 | 12 | ## Reverse dependencies 13 | 14 | This is a new release, so there are no reverse dependencies. 15 | 16 | --- 17 | 18 | * I have run R CMD check on the NUMBER downstream dependencies. 19 | (Summary at ...). 20 | 21 | * FAILURE SUMMARY 22 | 23 | * All revdep maintainers were notified of the release on RELEASE DATE. 24 | -------------------------------------------------------------------------------- /man/fetch_addins.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fetch_addins.R 3 | \name{fetch_addins} 4 | \alias{fetch_addins} 5 | \title{Current Addins} 6 | \usage{ 7 | fetch_addins(fields = NULL) 8 | } 9 | \arguments{ 10 | \item{fields}{character, fields to return from output data.frame, NULL returns all, 11 | Default: NULL} 12 | } 13 | \value{ 14 | data.frame containing the columns: c('Package', 'Name', 'Description', 15 | 'Binding', 'Interactive', 'libpath', 'Key', 'Shortcut') 16 | } 17 | \description{ 18 | Retrieve current installed Addins 19 | } 20 | -------------------------------------------------------------------------------- /man/KEYS.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/KEYS-data.R 3 | \docType{data} 4 | \name{KEYS} 5 | \alias{KEYS} 6 | \title{Keyboard Validation} 7 | \format{A list with 99 elements of class 'key'} 8 | \usage{ 9 | KEYS 10 | } 11 | \description{ 12 | List containing keyboard keys 13 | } 14 | \details{ 15 | key class has a '.+' method so keys can be appended to each other 16 | } 17 | \examples{ 18 | base_key <- KEYS$`left command/window key` 19 | base_key 20 | base_key + KEYS$shift + KEYS$i 21 | base_key + KEYS[2:9] 22 | 23 | } 24 | \keyword{datasets} 25 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | #' @inherit magrittr::'%>%' 2 | #' @export 3 | `%>%` <- magrittr::'%>%' 4 | 5 | #' @export 6 | `+.key` <- function (e1, e2) 7 | { 8 | sprintf('%s+%s',e1,e2) 9 | } 10 | 11 | #' @importFrom utils menu 12 | yesno <- function(...) { 13 | yeses <- c("Yes", "Definitely", "For sure", "Yup", "Yeah", "I agree", "Absolutely") 14 | nos <- c("No way", "Not yet", "I forget", "No", "Nope", "Uhhhh... Maybe?") 15 | 16 | cat(paste0(..., collapse = "")) 17 | qs <- c(sample(yeses, 1), sample(nos, 2)) 18 | rand <- sample(length(qs)) 19 | 20 | !(utils::menu(qs[rand]) != which(rand == 1)) 21 | } 22 | -------------------------------------------------------------------------------- /man/rm_shortcut.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rm_shorcut.R 3 | \name{rm_shortcut} 4 | \alias{rm_shortcut} 5 | \title{Remove user defined addin keyboard shortcuts} 6 | \usage{ 7 | rm_shortcut(fn, verbose = TRUE) 8 | } 9 | \arguments{ 10 | \item{fn}{character, binding of addin to remove keyboard shortcut} 11 | 12 | \item{verbose}{boolean, print message of actions taken, Default: TRUE} 13 | } 14 | \description{ 15 | Command line function to remove user defined keyboard shortcuts for addins 16 | } 17 | \details{ 18 | fn expecting the form of the addin binding, ie package::function notation. 19 | } 20 | -------------------------------------------------------------------------------- /man/toggle_addin.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toggle_addin.R 3 | \name{toggle_addin} 4 | \alias{toggle_addin} 5 | \title{Toggle RStudio addins} 6 | \usage{ 7 | toggle_addin(key) 8 | } 9 | \arguments{ 10 | \item{key}{character, vector containing package::binding objects that uniquely 11 | identify addins.} 12 | } 13 | \description{ 14 | Toggle Rstudio addins on and off by passing package::binding 15 | } 16 | \details{ 17 | a data.frame containing a summary of installed addins can be fetched through 18 | \code{\link{fetch_addins}}. Each time a Key is passed into the function the toggle will 19 | be activated for it. 20 | } 21 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method("+",key) 4 | export("%>%") 5 | export(anti_addin) 6 | export(create_yml) 7 | export(fetch_addin_keys) 8 | export(fetch_addins) 9 | export(restore_addins) 10 | export(rm_shortcut) 11 | export(rsam) 12 | export(set_shortcut) 13 | export(toggle_addin) 14 | import(rhandsontable) 15 | import(shiny) 16 | importFrom(jsonlite,fromJSON) 17 | importFrom(jsonlite,write_json) 18 | importFrom(miniUI,gadgetTitleBar) 19 | importFrom(miniUI,miniContentPanel) 20 | importFrom(miniUI,miniPage) 21 | importFrom(miniUI,miniTitleBarButton) 22 | importFrom(utils,installed.packages) 23 | importFrom(utils,menu) 24 | importFrom(yaml,read_yaml) 25 | importFrom(yaml,write_yaml) 26 | -------------------------------------------------------------------------------- /man/rstudio_shortcuts.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rstudio_shortcuts-data.R 3 | \docType{data} 4 | \name{rstudio_shortcuts} 5 | \alias{rstudio_shortcuts} 6 | \title{Rstudio Keyboard Shortcuts} 7 | \format{A data frame with 276 rows and 3 variables: 8 | \describe{ 9 | \item{\code{Description}}{character Decription What Shortcut Does} 10 | \item{\code{Shortcut}}{character Short Definition} 11 | \item{\code{OS}}{character Operating System} 12 | }} 13 | \usage{ 14 | rstudio_shortcuts 15 | } 16 | \description{ 17 | Keyboard shortcut definitions scrapped from 18 | \href{https://support.rstudio.com/hc/en-us/articles/200711853-Keyboard-Shortcuts}{RStudio Homesite} 19 | } 20 | \keyword{datasets} 21 | -------------------------------------------------------------------------------- /man/set_shortcut.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/set_shortcut.R 3 | \name{set_shortcut} 4 | \alias{set_shortcut} 5 | \title{Set RStudio Addin Keyboard Shortcuts} 6 | \usage{ 7 | set_shortcut(fn, shortcut, overide = FALSE, verbose = TRUE) 8 | } 9 | \arguments{ 10 | \item{fn}{character, vector of package::function names} 11 | 12 | \item{shortcut}{character, vector the same length of fn with corresponding shortcuts} 13 | 14 | \item{overide}{boolean, set to TRUE to ignore any existing shortcut, Default: FALSE} 15 | 16 | \item{verbose}{boolean, set to TRUE to return a message on actions taken, Default: TRUE} 17 | } 18 | \description{ 19 | Helper function that sets Rstudio addin keyboard shortcuts 20 | } 21 | -------------------------------------------------------------------------------- /R/restore_addins.R: -------------------------------------------------------------------------------- 1 | #' @title Restore package addins 2 | #' @description Restores addins.dcf files of installed package 3 | #' @param package character, packages to restore default addins, if NULL all packages will 4 | #' be restored, Default: NULL 5 | #' @rdname restore_addins 6 | #' @export 7 | restore_addins <- function(package=NULL){ 8 | 9 | current_keys <- fetch_addins(fields = c('Package','libpath')) 10 | 11 | restore_pkg <- current_keys[match(unique(current_keys$Package),current_keys$Package),] 12 | 13 | if(!is.null(package)) 14 | restore_pkg <- restore_pkg[restore_pkg$Key%in%package,] 15 | 16 | sapply(restore_pkg$libpath,function(x){ 17 | file.copy(x,gsub('_addins.dcf$','addins.dcf',x),overwrite = TRUE) 18 | }) 19 | 20 | return(invisible(NULL)) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rsam 2 | Type: Package 3 | Date: 2018-01-29 4 | Title: 'RStudio' Addin Manager 5 | Version: 0.1.3 6 | Authors@R: person("Jonathan", "Sidi", email = 7 | "yonicd@gmail.com", role = c("aut", "cre"),comment = 8 | c(ORCID = "0000-0002-4222-1819")) 9 | Maintainer: Jonathan Sidi 10 | Description: Toggle 'RStudio' addins on and off to hide in 11 | the IDE dropdown list and set/remove keyboard 12 | shortcuts for installed addins. 13 | Depends: R (>= 2.10) 14 | Imports: 15 | utils,yaml,data.table,jsonlite,miniUI,shiny,rhandsontable,magrittr 16 | Encoding: UTF-8 17 | URL: https://github.com/yonicd/rsam 18 | BugReports: https://github.com/yonicd/rsam/issues 19 | LazyData: true 20 | RoxygenNote: 6.0.1.9000 21 | License: MIT + file LICENSE 22 | -------------------------------------------------------------------------------- /data-raw/fetch_rstudio_shortcuts.R: -------------------------------------------------------------------------------- 1 | fetch_rstudio_shortcuts <- function(){ 2 | a <- xml2::read_html('https://support.rstudio.com/hc/en-us/articles/200711853-Keyboard-Shortcuts') 3 | a1 <- rvest::html_nodes(a,xpath = '/html/body/main/div/article/div[1]/table') 4 | a2 <- rvest::html_table(a1,header = TRUE,fill = TRUE,trim=TRUE) 5 | dat <- a2[[1]] 6 | 7 | names(dat) <- dat[1,] 8 | 9 | dat <- dat[-1,] 10 | dat <- dat[nzchar(dat[,1]),] 11 | dat <- dat[apply(dat,1,function(x) length(unique(x))>1),] 12 | 13 | dat_bind <- do.call('rbind',lapply(2:3,function(x){ 14 | y=2 15 | if(x==2) y=3 16 | dat1 <- dat[,-x] 17 | names(dat1)[2] <- 'Shortcut' 18 | dat1$OS <- names(dat)[y] 19 | dat1[nzchar(dat1$Shortcut),] 20 | })) 21 | 22 | dat_bind <- dat_bind[!grepl('Description',dat_bind$Description),] 23 | 24 | dat_bind 25 | } 26 | 27 | -------------------------------------------------------------------------------- /man/create_yml.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/create_yml.R 3 | \name{create_yml} 4 | \alias{create_yml} 5 | \title{Writes _rsam.yml to home directory} 6 | \usage{ 7 | create_yml(overwrite = FALSE) 8 | } 9 | \arguments{ 10 | \item{overwrite}{boolean, if TRUE will set output file to defaults, Default: FALSE} 11 | } 12 | \value{ 13 | NOTHING 14 | } 15 | \description{ 16 | Writes ~/_rsam.yml to bypass rsam onattach/onload prompt menu 17 | } 18 | \details{ 19 | Default Settings: 20 | 21 | \tabular{lll}{ 22 | \strong{field} \tab \strong{description} \tab \strong{setting}\cr 23 | write_json \tab Permission to write ~/.R/rstudio/keybindings/addins.json \tab TRUE\cr 24 | write_dcf \tab Permission to duplicate rstudio/addins.dcf of installed packages with addins \tab TRUE\cr 25 | verbose \tab Permission to run onLoad/onAttach script run with messages to console \tab TRUE 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /R/fetch_keys.R: -------------------------------------------------------------------------------- 1 | #' @title Current Addins shortcuts 2 | #' @description Retrieve current defined Addin shortcuts 3 | #' @return data.frame 4 | #' @seealso 5 | #' \code{\link[jsonlite]{fromJSON}} 6 | #' @rdname fetch_addin_keys 7 | #' @export 8 | #' @importFrom jsonlite fromJSON 9 | fetch_addin_keys <- function(){ 10 | 11 | json_now <- jsonlite::fromJSON("~/.R/rstudio/keybindings/addins.json") 12 | 13 | current_keys <- unlist(json_now) 14 | 15 | current_names <- names(current_keys) 16 | 17 | current_keys <- data.frame(Package=gsub('::(.*?)$','',current_names), 18 | Binding=gsub('^(.*?)::','',current_names), 19 | Shortcut=current_keys, 20 | stringsAsFactors = FALSE, 21 | row.names = NULL) 22 | 23 | current_keys$Shortcut[!nzchar(current_keys$Shortcut)] <- NA 24 | 25 | current_keys$Key <- paste(current_keys$Package,current_keys$Binding,sep = '::') 26 | 27 | return(current_keys) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | # Adapt as necessary starting from here 17 | 18 | build_script: 19 | - travis-tool.sh install_deps 20 | 21 | test_script: 22 | - travis-tool.sh run_tests 23 | 24 | on_failure: 25 | - 7z a failure.zip *.Rcheck\* 26 | - appveyor PushArtifact failure.zip 27 | 28 | artifacts: 29 | - path: '*.Rcheck\**\*.log' 30 | name: Logs 31 | 32 | - path: '*.Rcheck\**\*.out' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.fail' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.Rout' 39 | name: Logs 40 | 41 | - path: '\*_*.tar.gz' 42 | name: Bits 43 | 44 | - path: '\*_*.zip' 45 | name: Bits 46 | -------------------------------------------------------------------------------- /R/fetch_addins.R: -------------------------------------------------------------------------------- 1 | #' @title Current Addins 2 | #' @description Retrieve current installed Addins 3 | #' @param fields character, fields to return from output data.frame, NULL returns all, 4 | #' Default: NULL 5 | #' @return data.frame containing the columns: c('Package', 'Name', 'Description', 6 | #' 'Binding', 'Interactive', 'libpath', 'Key', 'Shortcut') 7 | #' @rdname fetch_addins 8 | #' @export 9 | #' @importFrom utils installed.packages 10 | fetch_addins <- function(fields=NULL){ 11 | 12 | addin_pkgs <- anti_addin() 13 | 14 | if(is.null(addin_pkgs)) invisible(return(NULL)) 15 | 16 | addins <- lapply(addin_pkgs,function(x){ 17 | ret <- read.dcf(x) 18 | s <- strsplit(x,'/')[[1]] 19 | s <- s[length(s)-2] 20 | ret <- cbind(Package=s,ret) 21 | ret <- cbind(ret,libpath=x) 22 | as.data.frame(ret,stringsAsFactors = FALSE) 23 | }) 24 | 25 | addins <- data.table::rbindlist(addins,fill=TRUE) 26 | 27 | if(!'Shortcut'%in%names(addins)) addins$Shortcut <- NA 28 | 29 | if(!is.null(fields)) 30 | addins <- addins[,intersect(fields,colnames(addins))] 31 | 32 | return(addins) 33 | } 34 | -------------------------------------------------------------------------------- /R/create_yml.R: -------------------------------------------------------------------------------- 1 | #' @title Writes _rsam.yml to home directory 2 | #' @description Writes ~/_rsam.yml to bypass rsam onattach/onload prompt menu 3 | #' @param overwrite boolean, if TRUE will set output file to defaults, Default: FALSE 4 | #' @details 5 | #' Default Settings: 6 | #' 7 | #' \tabular{lll}{ 8 | #' \strong{field} \tab \strong{description} \tab \strong{setting}\cr 9 | #' write_json \tab Permission to write ~/.R/rstudio/keybindings/addins.json \tab TRUE\cr 10 | #' write_dcf \tab Permission to duplicate rstudio/addins.dcf of installed packages with addins \tab TRUE\cr 11 | #' verbose \tab Permission to run onLoad/onAttach script run with messages to console \tab TRUE 12 | #'} 13 | #' 14 | #' @return NOTHING 15 | #' @rdname create_yml 16 | #' @export 17 | #' @importFrom yaml write_yaml 18 | create_yml <- function(overwrite=FALSE){ 19 | 20 | this_file <- '~/_rsam.yml' 21 | 22 | x <- data.frame(write_json=TRUE, 23 | write_dcf=TRUE, 24 | verbose=TRUE, 25 | stringsAsFactors = FALSE) 26 | 27 | if(interactive()){ 28 | if(!file.exists(this_file)){ 29 | yaml::write_yaml(x,file = this_file) 30 | }else{ 31 | if(overwrite){ 32 | yaml::write_yaml(x,file = this_file) 33 | } 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /R/rm_shorcut.R: -------------------------------------------------------------------------------- 1 | #' @title Remove user defined addin keyboard shortcuts 2 | #' @description Command line function to remove user defined keyboard shortcuts for addins 3 | #' @param fn character, binding of addin to remove keyboard shortcut 4 | #' @param verbose boolean, print message of actions taken, Default: TRUE 5 | #' @return NULL 6 | #' @details fn expecting the form of the addin binding, ie package::function notation. 7 | #' @rdname rm_shortcut 8 | #' @export 9 | #' @importFrom jsonlite write_json 10 | rm_shortcut <- function(fn, verbose = TRUE){ 11 | 12 | if(!.rsamEnv$write_json){ 13 | message('rsam does not have rights to write to jsons on disk') 14 | invisible(return(NULL)) 15 | } 16 | 17 | current_keys <- fetch_addin_keys() 18 | 19 | rm_idx <- current_keys$Key%in%fn 20 | 21 | miss_keys <- setdiff(fn,current_keys$Key) 22 | rm_keys <- current_keys[rm_idx,] 23 | new_keys <- current_keys[!rm_idx,] 24 | 25 | jsonlite::write_json(split(new_keys[,3],new_keys[,4]), 26 | path="~/.R/rstudio/keybindings/addins.json", 27 | auto_unbox = TRUE, 28 | pretty = TRUE) 29 | 30 | 31 | 32 | if(verbose){ 33 | 34 | if(length(miss_keys)>0){ 35 | message('Not found in current Keyboard Settings: ', paste0(miss_keys,collapse = ',')) 36 | } 37 | 38 | if(nrow(rm_keys)>0){ 39 | for(i in 1:nrow(rm_keys)){ 40 | message("Keyboard shortcut '", 41 | rm_keys$Shortcut[i], 42 | "' removed from '", 43 | rm_keys$Key[i],"'") 44 | } 45 | 46 | message('Restart RStudio to initialize') 47 | } 48 | 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /R/toggle_addin.R: -------------------------------------------------------------------------------- 1 | #' @title Toggle RStudio addins 2 | #' @description Toggle Rstudio addins on and off by passing package::binding 3 | #' @param key character, vector containing package::binding objects that uniquely 4 | #' identify addins. 5 | #' @details a data.frame containing a summary of installed addins can be fetched through 6 | #' \code{\link{fetch_addins}}. Each time a Key is passed into the function the toggle will 7 | #' be activated for it. 8 | #' @rdname toggle_addin 9 | #' @export 10 | toggle_addin <- function(key){ 11 | 12 | if(!.rsamEnv$write_dcf){ 13 | message('rsam does not have rights to write to dcf on disk') 14 | invisible(return(NULL)) 15 | } 16 | 17 | default_addins <- fetch_addins() 18 | 19 | current_toggle <- as.data.frame(do.call('rbind',sapply(unique(gsub('_addins.dcf','_toggle',default_addins$libpath)),read.dcf)),stringsAsFactors = FALSE) 20 | 21 | for(idx in which(current_toggle$Key%in%key)){ 22 | if(current_toggle$Hide[idx]=='true'){ 23 | 24 | current_toggle$Hide[idx] <- 'false' 25 | 26 | }else{ 27 | 28 | current_toggle$Hide[idx] <- 'true' 29 | 30 | } 31 | } 32 | 33 | new_addins <- merge(default_addins,current_toggle,by = 'Key') 34 | 35 | new_toggle <- split(new_addins,new_addins$Package) 36 | 37 | new_dcf <- split(new_addins,new_addins$Package) 38 | 39 | junk <- lapply(new_dcf,function(dat){ 40 | fl <- gsub('_addins.dcf$','addins.dcf',dat$libpath[1]) 41 | 42 | dat <- dat[dat$Hide=='false',] 43 | 44 | if(nrow(dat)==0){ 45 | if(file.exists(fl)) 46 | unlink(fl,force = TRUE) 47 | }else{ 48 | write.dcf(as.matrix(dat[,c('Name','Description','Binding','Interactive')]),file=fl) 49 | } 50 | }) 51 | 52 | junk <- lapply(new_toggle,function(dat){ 53 | write.dcf(as.matrix(dat[,c('Key','Hide')]), 54 | file=gsub('_addins.dcf$','_toggle',dat$libpath[1])) 55 | }) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | #' @importFrom jsonlite write_json 2 | #' @importFrom yaml read_yaml 3 | .onLoad <- function(libname, pkgname) { 4 | 5 | if(file.exists('~/_rsam.yml')){ 6 | this_yml <- yaml::read_yaml('~/_rsam.yml') 7 | 8 | assign("set", envir = .rsamEnv, FALSE) 9 | assign("write_json", envir = .rsamEnv, this_yml$write_json) 10 | assign("write_dcf", envir = .rsamEnv, this_yml$write_dcf) 11 | 12 | } 13 | 14 | if(interactive()&.rsamEnv$set){ 15 | 16 | assign("set", envir = .rsamEnv, FALSE) 17 | 18 | .rsamEnv$write_json <- yesno('Do you agree to let {rsam} manipulate the addins\njsons used to manage RStudio addin keyboard shortcuts?') 19 | .rsamEnv$write_dcf <- yesno('Do you agree to let {rsam} duplicate the dcf files of the installed addins in your .libPaths\nand manipulate them to manage RStudio Addins dropdown list?') 20 | } 21 | 22 | key_dir <- '~/.R/rstudio/keybindings' 23 | 24 | if(!dir.exists(key_dir)&.rsamEnv$write_json){ 25 | 26 | dir.create('~/.R/rstudio/keybindings',showWarnings = FALSE,recursive = TRUE) 27 | 28 | for(this_file in paste0(c('addins','editor_bindings','rstudio_bindings'),'.json')) 29 | jsonlite::write_json(c(), path = file.path(key_dir,this_file)) 30 | } 31 | } 32 | 33 | 34 | #' @importFrom jsonlite write_json 35 | #' @importFrom yaml read_yaml 36 | .onAttach <- function(libname, pkgname) { 37 | 38 | if(file.exists('~/_rsam.yml')){ 39 | this_yml <- yaml::read_yaml('~/_rsam.yml') 40 | 41 | assign("set", envir = .rsamEnv, FALSE) 42 | assign("write_json", envir = .rsamEnv, this_yml$write_json) 43 | assign("write_dcf", envir = .rsamEnv, this_yml$write_dcf) 44 | 45 | if(this_yml$verbose){ 46 | packageStartupMessage('rsam persmissions set by ~/_rsam.yml') 47 | } 48 | 49 | 50 | } 51 | 52 | if(interactive()&.rsamEnv$set){ 53 | 54 | assign("set", envir = .rsamEnv, FALSE) 55 | 56 | .rsamEnv$write_json <- yesno('Do you agree to let {rsam} manipulate the addins\njsons used to manage RStudio addin keyboard shortcuts?') 57 | .rsamEnv$write_dcf <- yesno('Do you agree to let {rsam} duplicate the dcf files of the installed addins in your .libPaths\nand manipulate them to manage RStudio Addins dropdown list?') 58 | 59 | } 60 | 61 | key_dir <- '~/.R/rstudio/keybindings' 62 | 63 | if(!dir.exists(key_dir)&.rsamEnv$write_json){ 64 | 65 | dir.create('~/.R/rstudio/keybindings',showWarnings = FALSE,recursive = TRUE) 66 | 67 | for(this_file in paste0(c('addins','editor_bindings','rstudio_bindings'),'.json')) 68 | jsonlite::write_json(c(), path = file.path(key_dir,this_file)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /R/anti_addin.R: -------------------------------------------------------------------------------- 1 | #' @title Create duplicate of addins.dcf file in installed packages. 2 | #' @description Create duplicates of installed addins.dcf of packages with addins 3 | #' found in libpath that rsam will manipulate 4 | #' @return nothing 5 | #' @rdname anti_addin 6 | #' @export 7 | #' @importFrom utils installed.packages 8 | anti_addin <- function(){ 9 | 10 | if(!.rsamEnv$write_dcf){ 11 | message('rsam does not have rights to write to dcf on disk') 12 | invisible(return(NULL)) 13 | } 14 | 15 | inst_pkgs <- utils::installed.packages()[,c(1,2)] 16 | inst_pkgs1 <- file.path(inst_pkgs[,2],inst_pkgs[,1],'rstudio','addins.dcf') 17 | 18 | addin_pkgs <- inst_pkgs1[which(file.exists(inst_pkgs1))] 19 | addin_pkgs2 <- gsub('addins.dcf$','_addins.dcf', 20 | inst_pkgs1[which(file.exists(gsub('addins.dcf$','_addins.dcf',inst_pkgs1)))]) 21 | 22 | check_addins <- sort(c(addin_pkgs,addin_pkgs2)) 23 | 24 | check_pkgs <- unlist(lapply(strsplit(check_addins,'/'),function(x) x[length(x)-2])) 25 | 26 | check <- data.frame(check_addins,check_pkgs,stringsAsFactors = FALSE) 27 | 28 | check <- split(check,check$check_pkgs) 29 | 30 | addin_pkgs <- sapply(check,function(x){ 31 | x[nrow(x),1] 32 | },USE.NAMES = FALSE,simplify = TRUE) 33 | 34 | names(addin_pkgs) <- NULL 35 | 36 | anti_addins <- gsub('/addins.dcf$','/_addins.dcf',addin_pkgs) 37 | toggle_addins <- gsub('/addins.dcf$','/_toggle',addin_pkgs) 38 | 39 | for(idx in 1:length(addin_pkgs)){ 40 | if(!file.exists(anti_addins[idx])) 41 | file.copy(addin_pkgs[idx],anti_addins[idx],overwrite = FALSE) 42 | } 43 | 44 | pkgs <- sapply(strsplit(anti_addins,'/'),function(x){ 45 | x[length(x)-2] 46 | }) 47 | 48 | current_keys <- fetch_addin_keys() 49 | 50 | for(this_pkg in pkgs){ 51 | this_dcf <- read.dcf(anti_addins[grep(this_pkg,pkgs)]) 52 | 53 | this_key <- paste(this_pkg,this_dcf[,'Binding'],sep='::') 54 | 55 | if(!'Key'%in%colnames(this_dcf)) 56 | this_dcf <- cbind(this_dcf,Key=this_key) 57 | 58 | if(!is.null(current_keys)){ 59 | this_dcf <- cbind(this_dcf,Shortcut=NA) 60 | 61 | for(idx in 1:nrow(this_dcf)){ 62 | this_dcf[idx,'Shortcut'] <- current_keys$Shortcut[match(this_dcf[idx,'Key'],current_keys$Key)] 63 | } 64 | } 65 | 66 | write.dcf(this_dcf,file = anti_addins[grep(this_pkg,pkgs)]) 67 | 68 | if(!file.exists(toggle_addins[grep(this_pkg,pkgs)])){ 69 | write.dcf(cbind(Key=this_key,Hide='false'),file=toggle_addins[grep(this_pkg,pkgs)]) 70 | } 71 | } 72 | 73 | return(invisible(anti_addins)) 74 | } 75 | -------------------------------------------------------------------------------- /R/set_shortcut.R: -------------------------------------------------------------------------------- 1 | #' @title Set RStudio Addin Keyboard Shortcuts 2 | #' @description Helper function that sets Rstudio addin keyboard shortcuts 3 | #' @param fn character, vector of package::function names 4 | #' @param shortcut character, vector the same length of fn with corresponding shortcuts 5 | #' @param overide boolean, set to TRUE to ignore any existing shortcut, Default: FALSE 6 | #' @param verbose boolean, set to TRUE to return a message on actions taken, Default: TRUE 7 | #' @rdname set_shortcut 8 | #' @export 9 | #' @importFrom jsonlite write_json 10 | set_shortcut <- function(fn, shortcut, overide = FALSE, verbose = TRUE) { 11 | 12 | if(!.rsamEnv$write_json){ 13 | message('rsam does not have rights to write to jsons on disk') 14 | invisible(return(NULL)) 15 | } 16 | 17 | if(length(fn)!=length(unique(fn))) 18 | stop('fn values must be unique') 19 | 20 | fn <- unique(fn) 21 | 22 | if(length(shortcut)!=length(unique(shortcut))) 23 | stop('shorcut values must be unique') 24 | 25 | shortcut <- unique(shortcut) 26 | 27 | if(length(fn)!=length(shortcut)) 28 | stop('fn, shortcut must be same length') 29 | 30 | not_found <- FALSE 31 | 32 | current_keys <- fetch_addins() 33 | 34 | if(is.null(current_keys$Shortcut)) 35 | current_keys$Shortcut <- NA 36 | 37 | current_keys$new <- FALSE 38 | 39 | for(fn_idx in 1:length(fn)){ 40 | idx <- grep(sprintf('^%s$',fn[fn_idx]),current_keys$Key) 41 | if(length(idx)>0){ 42 | 43 | if(is.na(current_keys$Shortcut[idx])){ 44 | current_keys$new[idx] <- TRUE 45 | current_keys$Shortcut[grep(shortcut[fn_idx],current_keys$Shortcut)] <- NA 46 | current_keys$Shortcut[idx] <- shortcut[fn_idx] 47 | } 48 | 49 | if(overide&(current_keys$Shortcut[idx]!=shortcut[fn_idx])){ 50 | current_keys$new[idx] <- TRUE 51 | current_keys$Shortcut[grep(shortcut[fn_idx],current_keys$Shortcut)] <- NA 52 | current_keys$Shortcut[idx] <- shortcut[fn_idx] 53 | } 54 | }else{ 55 | 56 | not_found <- TRUE 57 | 58 | if (verbose) { 59 | message('* Addin binding not found: ', fn[fn_idx]) 60 | } 61 | } 62 | } 63 | 64 | new_keys <- current_keys[!is.na(current_keys$Shortcut),c('Shortcut','Key','new')] 65 | 66 | if(sum(new_keys$new)>0){ 67 | 68 | jsonlite::write_json(split(new_keys[,1],new_keys[,2]), 69 | path="~/.R/rstudio/keybindings/addins.json", 70 | auto_unbox = TRUE, 71 | pretty = TRUE) 72 | 73 | msg <- paste0("* The following addin keyboard shorcuts were set, restart RStudio to initialize\n", 74 | paste0(sprintf("%s = %s", 75 | new_keys$Key[new_keys$new], 76 | new_keys$Shortcut[new_keys$new]), 77 | collapse = "\n")) 78 | } else { 79 | msg <- "\n* Addin shortcuts unchanged" 80 | } 81 | 82 | if (verbose) { 83 | 84 | if(not_found) 85 | msg <- sprintf('%s\n\n* For a summary of installed Addin Bindings run rsam::fetch_addins()',msg) 86 | 87 | message(msg) 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /R/rsam.R: -------------------------------------------------------------------------------- 1 | #' @title rsam user interface 2 | #' @description Shiny application to use rsam through UI 3 | #' @param warn boolean, show warning popup message to restart IDE, Default: TRUE 4 | #' @seealso 5 | #' \code{\link[rhandsontable]{rHandsontableOutput}},\code{\link[rhandsontable]{renderRHandsontable}} 6 | #' @rdname rsam 7 | #' @export 8 | #' @import shiny 9 | #' @import rhandsontable 10 | #' @importFrom miniUI miniPage gadgetTitleBar miniTitleBarButton miniContentPanel 11 | rsam <- function(warn=TRUE) { 12 | 13 | default_addins <- fetch_addins() 14 | 15 | current_toggle <- as.data.frame(do.call('rbind',sapply(unique(gsub('_addins.dcf','_toggle',default_addins$libpath)),read.dcf)),stringsAsFactors = FALSE) 16 | 17 | current_toggle$Show <- !as.logical(current_toggle$Hide) 18 | 19 | this <- merge(current_toggle,default_addins,by = 'Key') 20 | 21 | this_warn <- NULL 22 | 23 | if(!.rsamEnv$write_dcf) this_warn <- 'rsam does not have rights to write to jsons on disk' 24 | if(!.rsamEnv$write_json) this_warn <- paste(this_warn,'rsam does not have rights to write to dcf on disk',sep='\n') 25 | 26 | 27 | 28 | 29 | # gadget UI ---- 30 | ui <- miniUI::miniPage( 31 | 32 | miniUI::gadgetTitleBar( 33 | shiny::textOutput("title", inline = TRUE), 34 | left = miniUI::miniTitleBarButton("qt", "Quit"), 35 | right = miniUI::miniTitleBarButton( 36 | inputId = "update", "Update", 37 | primary = TRUE 38 | ) 39 | ), 40 | miniUI::miniContentPanel( 41 | rhandsontable::rHandsontableOutput(outputId = 'hot') 42 | 43 | ) 44 | ) 45 | 46 | # gadget Server ----- 47 | server <- function(input, output, session) { 48 | 49 | output$title <- shiny::renderText({ 50 | paste0("RStudio Addin Manager") 51 | }) 52 | 53 | output$hot <- rhandsontable::renderRHandsontable({ 54 | tbl <- this[,c('Package','Name','Description','Show','Shortcut')] 55 | 56 | tbl$Shortcut[is.na(tbl$Shortcut)] <- '' 57 | 58 | rhandsontable::rhandsontable(tbl, readOnly = TRUE, height = 500) %>% 59 | hot_col(c('Show'), readOnly = FALSE)%>% 60 | hot_col(c('Shortcut'), readOnly = FALSE)%>% 61 | hot_cols(columnSorting = TRUE) 62 | }) 63 | 64 | this_update <- eventReactive(input$hot,{ 65 | 66 | this_new <- this 67 | this_new$Show <- unlist(lapply(input$hot$data,'[[',4)) 68 | this_new$Shortcut <- unlist(lapply(input$hot$data,'[[',5)) 69 | 70 | this_new 71 | }) 72 | 73 | if(!is.null(this_warn)){ 74 | showModal(modalDialog(title = HTML(this_warn),easyClose = TRUE)) 75 | } 76 | 77 | 78 | shiny::observeEvent(input$update, { 79 | 80 | output$title <- shiny::renderText({ 81 | HTML( 82 | "Restart IDE for changes to go into effect" 83 | ) 84 | }) 85 | 86 | if(input$update==1&warn){ 87 | showModal(modalDialog( 88 | title = HTML(paste0( 89 | "Restart IDE for changes to go into effect", 90 | " after closing application!
This warning will show up only once") 91 | ), 92 | easyClose = TRUE 93 | )) 94 | } 95 | 96 | this_now <- this[,c('Key','Show')] 97 | current_toggle_now <- as.data.frame(do.call('rbind',sapply(unique(gsub('_addins.dcf','_toggle',default_addins$libpath)),read.dcf)),stringsAsFactors = FALSE) 98 | this_now$Show <- !as.logical(current_toggle_now$Hide) 99 | 100 | this_toggle <- this_update() 101 | 102 | if(sum(!grepl('NA|^$',this_toggle$Shortcut))>0){ 103 | 104 | this_shortcut <- this_toggle[!grepl('NA|^$',this_toggle$Shortcut),c('Key','Shortcut')] 105 | 106 | set_shortcut(fn = this_shortcut$Key, 107 | shortcut = this_shortcut$Shortcut, 108 | overide = TRUE, 109 | verbose = FALSE) 110 | } 111 | 112 | change <- merge(this_now, 113 | this_toggle[,c('Key','Show')], 114 | by='Key') 115 | 116 | toggle_addin(change$Key[change$Show.x!=change$Show.y]) 117 | }) 118 | 119 | shiny::observeEvent(input$qt, { 120 | shiny::stopApp() 121 | }) 122 | 123 | 124 | } 125 | 126 | # Run Gadget ---- 127 | shiny::runGadget(ui, server, viewer = shiny::paneViewer(minHeight = 450)) 128 | 129 | } 130 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | md_document: 4 | variant: markdown_github 5 | --- 6 | [![Project Status: Active - The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/0.1.0/active.svg)](http://www.repostatus.org/#active) 7 | [![Travis-CI Build Status](https://travis-ci.org/yonicd/rsam.svg?branch=master)](https://travis-ci.org/yonicd/rsam)[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/yonicd/rsam?branch=master&svg=true)](https://ci.appveyor.com/project/yonicd/rsam) 8 | 9 | 10 | ```{r, echo = FALSE, warning=FALSE, message=FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>", 14 | fig.path = "README-" 15 | ) 16 | 17 | library(rsam) 18 | library(dplyr) 19 | x <- fetch_addins(fields = c("Package","Name","Binding","Interactive","Key","Shortcut")) 20 | 21 | x[is.na(x)] <- '' 22 | 23 | 24 | ``` 25 | 26 | # RStudio Addin Manager 27 | 28 | `{rsam}` provides a command line and user interface to manage RStudio addins. 29 | 30 | ## Installation 31 | 32 | Since `{rsam}` manages the rstudio addins it must write to disk. 33 | 34 | ```{r, eval=FALSE} 35 | remotes::install_github('yonicd/rsam') 36 | ``` 37 | 38 | ## Permissions 39 | 40 | {rsam} needs explicit user permissions to write to disk. There are two questions that need to be answered for the package to run as intended. 41 | 42 | - Do you agree to let {rsam} manipulate the addins jsons used to manage RStudio addin keyboard shortcuts? 43 | 44 | - Do you agree to let {rsam} duplicate the dcf files of the installed addins in your `.libPaths()` and manipulate them to manage RStudio Addins dropdown list? 45 | 46 | Answering the affirmative to both will allow {rsam} to manipulate non R related files. Answering only one will allow for a narrow application of {rsam}. 47 | 48 | There are two ways to set answers to the questions: 49 | 50 | 1. On load or attach of the library a prompt is invoked asking the two questions. This is done to set the permissions once a session. 51 | 52 | 2. Use `rsam::create_yml()` to write _rsam.yml to the home directory `(~)`. In this file there are three fields. When loading {rsam} looks for this file and if it exists then uses the field settings instead of asking questions via prompts. 53 | 54 | | Field| Description| Setting| 55 | |--:|--:|--:| 56 | | write_json| Permission to write ~/.R/rstudio/keybindings/addins.json| yes| 57 | | write_dcf | Permission to duplicate and edit rstudio/addins.dcf of installed packages with addins| yes| 58 | | verbose | Permission to run onload/onattach script run with messages to console| yes| 59 | 60 | ## UI 61 | 62 | ```{r,eval=FALSE} 63 | library(rsam) 64 | 65 | rsam() 66 | 67 | ``` 68 | 69 | [![rsam usage](http://img.youtube.com/vi/-XZWv7CJrs8/0.jpg)](https://www.youtube.com/watch?v=-XZWv7CJrs8) 70 | 71 | ## CLI 72 | 73 | ### Retrieve Summary of Installed Addins 74 | 75 | ```{r,eval=FALSE} 76 | fetch_addins() 77 | ``` 78 | 79 | ```{r,echo=FALSE} 80 | knitr::kable(x) 81 | ``` 82 | 83 | ### Building Keyboard Shortcuts 84 | 85 | `rsam` has a validation for keyboard keys through the class `key` 86 | 87 | ```{r} 88 | 89 | KEYS$`left command/window key` 90 | 91 | KEYS$shift 92 | 93 | KEYS$i 94 | 95 | key <- KEYS$`left command/window key` + KEYS$shift + KEYS$i 96 | 97 | key 98 | ``` 99 | 100 | ### Set Keyboard Shortcut for Addins 101 | 102 | ```{r,eval=FALSE} 103 | 104 | set_shortcut(fn = 'blogdown::serve_site',shortcut = key) 105 | 106 | #if the binding already has a shortcut mapped to it `overide` must be TRUE 107 | set_shortcut(fn = 'blogdown::serve_site',shortcut = key, overide = TRUE) 108 | 109 | ``` 110 | 111 | ### Remove Keyboard Shortcut for Addins 112 | 113 | ```{r,eval=FALSE} 114 | rm_shortcut(fn = 'blogdown::serve_site') 115 | ``` 116 | 117 | ### Toggle Addins on/off 118 | 119 | Every time a binding is passed to the `toggle_addin` function it will switch states. 120 | 121 | ```{r,eval=FALSE} 122 | toggle_addin(key = c("blogdown::serve_site","blogdown::new_post_addin","blogdown::update_meta_addin")) 123 | ``` 124 | 125 | ### Limited Liability Addins 126 | 127 | `rsam` gives you 3 empty addins to pass into them whatever you want and run them as your personal addins. You can also set keyboard shortcuts for each one with `set_shortcut`. 128 | 129 | Pass through an expression wrapped the global objects `rsam_fn_1()`, `rsam_fn_2()`, and `rsam_fn_3()` into the Rstudio Addin list. 130 | 131 | 132 | ```{r, eval=FALSE} 133 | 134 | rsam_fn_1 <- function(){ 135 | library(ggplot2) 136 | library(dplyr) 137 | 138 | iris%>%ggplot(aes(x=Sepal.Length,y=Sepal.Width)) + geom_point() 139 | } 140 | 141 | # Change shortcuts to whatever you want 142 | 143 | keys <- KEYS$`left command/window key` + KEYS$shift + KEYS$l 144 | 145 | rsam::set_shortcut(fn = 'rsam::lla1',shortcut = keys + KEYS$`1`) 146 | 147 | rsam::set_shortcut(fn = 'rsam::lla2',shortcut = keys + KEYS$`2`) 148 | 149 | rsam::set_shortcut(fn = 'rsam::lla3',shortcut = keys + KEYS$`3`) 150 | 151 | ``` 152 | 153 | ## Feedbacks and enhancement 154 | 155 | You've found a bug, or have an enhancment idea? Feel free to open an issue : [https://github.com/yonicd/rsam/issues](https://github.com/yonicd/rsam/issues). 156 | -------------------------------------------------------------------------------- /man/grapes-greater-than-grapes.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{magrittr forward-pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \arguments{ 10 | \item{lhs}{A value or the magrittr placeholder.} 11 | 12 | \item{rhs}{A function call using the magrittr semantics.} 13 | } 14 | \description{ 15 | Pipe an object forward into a function or call expression. 16 | } 17 | \details{ 18 | \bold{Using \code{\%>\%} with unary function calls}\cr 19 | When functions require only one argument, \code{x \%>\% f} is equivalent 20 | to \code{f(x)} (not exactly equivalent; see technical note below.) 21 | \cr\cr 22 | \bold{Placing \code{lhs} as the first argument in \code{rhs} call}\cr 23 | The default behavior of \code{\%>\%} when multiple arguments are required 24 | in the \code{rhs} call, is to place \code{lhs} as the first argument, i.e. 25 | \code{x \%>\% f(y)} is equivalent to \code{f(x, y)}. 26 | \cr\cr 27 | \bold{Placing \code{lhs} elsewhere in \code{rhs} call}\cr 28 | Often you will want \code{lhs} to the \code{rhs} call at another position than the first. 29 | For this purpose you can use the dot (\code{.}) as placeholder. For example, 30 | \code{y \%>\% f(x, .)} is equivalent to \code{f(x, y)} and 31 | \code{z \%>\% f(x, y, arg = .)} is equivalent to \code{f(x, y, arg = z)}. 32 | \cr\cr 33 | \bold{Using the dot for secondary purposes}\cr 34 | Often, some attribute or property of \code{lhs} is desired in the \code{rhs} call in 35 | addition to the value of \code{lhs} itself, e.g. the number of rows or columns. 36 | It is perfectly valid to use the dot placeholder several times in the \code{rhs} 37 | call, but by design the behavior is slightly different when using it inside 38 | nested function calls. In particular, if the placeholder is only used 39 | in a nested function call, \code{lhs} will also be placed as the first argument! 40 | The reason for this is that in most use-cases this produces the most readable 41 | code. For example, \code{iris \%>\% subset(1:nrow(.) \%\% 2 == 0)} is 42 | equivalent to \code{iris \%>\% subset(., 1:nrow(.) \%\% 2 == 0)} but 43 | slightly more compact. It is possible to overrule this behavior by enclosing 44 | the \code{rhs} in braces. For example, \code{1:10 \%>\% {c(min(.), max(.))}} is 45 | equivalent to \code{c(min(1:10), max(1:10))}. 46 | \cr\cr 47 | \bold{Using \%>\% with call- or function-producing \code{rhs}}\cr 48 | It is possible to force evaluation of \code{rhs} before the piping of \code{lhs} takes 49 | place. This is useful when \code{rhs} produces the relevant call or function. 50 | To evaluate \code{rhs} first, enclose it in parentheses, i.e. 51 | \code{a \%>\% (function(x) x^2)}, and \code{1:10 \%>\% (call("sum"))}. 52 | Another example where this is relevant is for reference class methods 53 | which are accessed using the \code{$} operator, where one would do 54 | \code{x \%>\% (rc$f)}, and not \code{x \%>\% rc$f}. 55 | \cr\cr 56 | \bold{Using lambda expressions with \code{\%>\%}}\cr 57 | Each \code{rhs} is essentially a one-expression body of a unary function. 58 | Therefore defining lambdas in magrittr is very natural, and as 59 | the definitions of regular functions: if more than a single expression 60 | is needed one encloses the body in a pair of braces, \code{{ rhs }}. 61 | However, note that within braces there are no "first-argument rule": 62 | it will be exactly like writing a unary function where the argument name is 63 | "\code{.}" (the dot). 64 | \cr\cr 65 | \bold{Using the dot-place holder as \code{lhs}}\cr 66 | When the dot is used as \code{lhs}, the result will be a functional sequence, 67 | i.e. a function which applies the entire chain of right-hand sides in turn 68 | to its input. See the examples. 69 | } 70 | \section{Technical notes}{ 71 | 72 | 73 | The magrittr pipe operators use non-standard evaluation. They capture 74 | their inputs and examines them to figure out how to proceed. First a function 75 | is produced from all of the individual right-hand side expressions, and 76 | then the result is obtained by applying this function to the left-hand side. 77 | For most purposes, one can disregard the subtle aspects of magrittr's 78 | evaluation, but some functions may capture their calling environment, 79 | and thus using the operators will not be exactly equivalent to the 80 | "standard call" without pipe-operators. 81 | \cr\cr 82 | Another note is that special attention is advised when using non-magrittr 83 | operators in a pipe-chain (\code{+, -, $,} etc.), as operator precedence will impact how the 84 | chain is evaluated. In general it is advised to use the aliases provided 85 | by magrittr. 86 | 87 | } 88 | 89 | \examples{ 90 | # Basic use: 91 | iris \%>\% head 92 | 93 | # Use with lhs as first argument 94 | iris \%>\% head(10) 95 | 96 | # Using the dot place-holder 97 | "Ceci n'est pas une pipe" \%>\% gsub("une", "un", .) 98 | 99 | # When dot is nested, lhs is still placed first: 100 | sample(1:10) \%>\% paste0(LETTERS[.]) 101 | 102 | # This can be avoided: 103 | rnorm(100) \%>\% {c(min(.), mean(.), max(.))} \%>\% floor 104 | 105 | # Lambda expressions: 106 | iris \%>\% 107 | { 108 | size <- sample(1:10, size = 1) 109 | rbind(head(., size), tail(., size)) 110 | } 111 | 112 | # renaming in lambdas: 113 | iris \%>\% 114 | { 115 | my_data <- . 116 | size <- sample(1:10, size = 1) 117 | rbind(head(my_data, size), tail(my_data, size)) 118 | } 119 | 120 | # Building unary functions with \%>\% 121 | trig_fest <- . \%>\% tan \%>\% cos \%>\% sin 122 | 123 | 1:10 \%>\% trig_fest 124 | trig_fest(1:10) 125 | } 126 | \seealso{ 127 | \code{\link{\%<>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}} 128 | } 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Project Status: Active - The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/0.1.0/active.svg)](http://www.repostatus.org/#active) [![Travis-CI Build Status](https://travis-ci.org/yonicd/rsam.svg?branch=master)](https://travis-ci.org/yonicd/rsam)[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/yonicd/rsam?branch=master&svg=true)](https://ci.appveyor.com/project/yonicd/rsam) 2 | 3 | RStudio Addin Manager 4 | ===================== 5 | 6 | `{rsam}` provides a command line and user interface to manage RStudio addins. 7 | 8 | Installation 9 | ------------ 10 | 11 | Since `{rsam}` manages the rstudio addins it must write to disk. 12 | 13 | ``` r 14 | remotes::install_github('yonicd/rsam') 15 | ``` 16 | 17 | Permissions 18 | ----------- 19 | 20 | {rsam} needs explicit user permissions to write to disk. There are two questions that need to be answered for the package to run as intended. 21 | 22 | - Do you agree to let {rsam} manipulate the addins jsons used to manage RStudio addin keyboard shortcuts? 23 | 24 | - Do you agree to let {rsam} duplicate the dcf files of the installed addins in your `.libPaths()` and manipulate them to manage RStudio Addins dropdown list? 25 | 26 | Answering the affirmative to both will allow {rsam} to manipulate non R related files. Answering only one will allow for a narrow application of {rsam}. 27 | 28 | There are two ways to set answers to the questions: 29 | 30 | 1. On load or attach of the library a prompt is invoked asking the two questions. This is done to set the permissions once a session. 31 | 32 | 2. Use `rsam::create_yml()` to write \_rsam.yml to the home directory `(~)`. In this file there are three fields. When loading {rsam} looks for this file and if it exists then uses the field settings instead of asking questions via prompts. 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
FieldDescriptionSetting
write_jsonPermission to write ~/.R/rstudio/keybindings/addins.jsonyes
write_dcfPermission to duplicate and edit rstudio/addins.dcf of installed packages with addinsyes
verbosePermission to run onload/onattach script run with messages to consoleyes
65 | 66 | UI 67 | -- 68 | 69 | ``` r 70 | library(rsam) 71 | 72 | rsam() 73 | ``` 74 | 75 | [![rsam usage](http://img.youtube.com/vi/-XZWv7CJrs8/0.jpg)](https://www.youtube.com/watch?v=-XZWv7CJrs8) 76 | 77 | CLI 78 | --- 79 | 80 | ### Retrieve Summary of Installed Addins 81 | 82 | ``` r 83 | fetch_addins() 84 | ``` 85 | 86 | | Package | Name | Binding | Interactive | Key | Shortcut | 87 | |:--------------|:---------------------------------|:--------------------|:------------|:--------------------------------|:-------------| 88 | | blogdown | Serve Site | serve\_site | true | blogdown::serve\_site | ctrl+shift+a | 89 | | blogdown | New Post | new\_post\_addin | true | blogdown::new\_post\_addin | ctrl+shift+p | 90 | | blogdown | Update Metadata | update\_meta\_addin | true | blogdown::update\_meta\_addin | | 91 | | bookdown | Preview Book | serve\_book | true | bookdown::serve\_book | | 92 | | bookdown | Input LaTeX Math | mathquill | true | bookdown::mathquill | | 93 | | chunky | chunky | chunkify | false | chunky::chunkify | | 94 | | clipr | Value to clipboard | clipr\_result | false | clipr::clipr\_result | | 95 | | clipr | Output to clipboard | clipr\_output | false | clipr::clipr\_output | | 96 | | colourpicker | Plot Colour Helper | plotHelperAddin | true | colourpicker::plotHelperAddin | | 97 | | colourpicker | Colour Picker | colourPickerAddin | true | colourpicker::colourPickerAddin | | 98 | | covr | Calculate package test coverage | addin\_report | false | covr::addin\_report | | 99 | | cronR | Schedule R scripts on Linux/Unix | cron\_rstudioaddin | true | cronR::cron\_rstudioaddin | | 100 | | ggedit | ggedit | ggeditAddin | true | ggedit::ggeditAddin | | 101 | | remedy | Backtick | backtickr | false | remedy::backtickr | | 102 | | remedy | Bold | boldr | false | remedy::boldr | | 103 | | remedy | Chunk | chunkr | false | remedy::chunkr | | 104 | | remedy | Chunksplit | chunksplitr | false | remedy::chunksplitr | | 105 | | remedy | H1 | h1r | false | remedy::h1r | | 106 | | remedy | H2 | h2r | false | remedy::h2r | | 107 | | remedy | H3 | h3r | false | remedy::h3r | | 108 | | remedy | H4 | h4r | false | remedy::h4r | | 109 | | remedy | H5 | h5r | false | remedy::h5r | | 110 | | remedy | H6 | h6r | false | remedy::h6r | | 111 | | remedy | Htmlcomment | htmlcommentr | false | remedy::htmlcommentr | | 112 | | remedy | Image | imager | false | remedy::imager | | 113 | | remedy | Italics | italicsr | false | remedy::italicsr | | 114 | | remedy | LaTeX | latexr | false | remedy::latexr | | 115 | | remedy | List | listr | false | remedy::listr | | 116 | | remedy | Right | rightr | false | remedy::rightr | | 117 | | remedy | Strike | striker | false | remedy::striker | | 118 | | remedy | Table | tabler | false | remedy::tabler | | 119 | | remedy | Url | urlr | false | remedy::urlr | | 120 | | remedy | Xaringan | xaringanr | false | remedy::xaringanr | | 121 | | remedy | Youtube | youtuber | false | remedy::youtuber | | 122 | | reprex | Render reprex | reprex\_addin | true | reprex::reprex\_addin | | 123 | | rhandsontable | Edit a Data Frame | editAddin | true | rhandsontable::editAddin | | 124 | | rsam | lla1 | lla1 | true | rsam::lla1 | | 125 | | rsam | lla2 | lla2 | true | rsam::lla2 | | 126 | | rsam | lla3 | lla3 | true | rsam::lla3 | | 127 | | shinyjs | Colour Picker | colourPickerAddin | true | shinyjs::colourPickerAddin | | 128 | | sinew | createOxygen | oxygenAddin | false | sinew::oxygenAddin | | 129 | | sinew | interactiveOxygen | interOxyAddIn | true | sinew::interOxyAddIn | | 130 | | styler | Style package | style\_pkg | true | styler::style\_pkg | | 131 | | styler | Style active file | style\_active\_file | true | styler::style\_active\_file | | 132 | | styler | Style selection | style\_selection | true | styler::style\_selection | | 133 | | texPreview | texPreview | texAddin | false | texPreview::texAddin | | 134 | | vcs | alexa | alexa | true | vcs::alexa | | 135 | 136 | ### Building Keyboard Shortcuts 137 | 138 | `rsam` has a validation for keyboard keys through the class `key` 139 | 140 | ``` r 141 | 142 | KEYS$`left command/window key` 143 | #> [1] "Command" 144 | #> attr(,"class") 145 | #> [1] "character" "key" 146 | 147 | KEYS$shift 148 | #> [1] "Shift" 149 | #> attr(,"class") 150 | #> [1] "character" "key" 151 | 152 | KEYS$i 153 | #> [1] "I" 154 | #> attr(,"class") 155 | #> [1] "character" "key" 156 | 157 | key <- KEYS$`left command/window key` + KEYS$shift + KEYS$i 158 | 159 | key 160 | #> [1] "Command+Shift+I" 161 | ``` 162 | 163 | ### Set Keyboard Shortcut for Addins 164 | 165 | ``` r 166 | 167 | set_shortcut(fn = 'blogdown::serve_site',shortcut = key) 168 | 169 | #if the binding already has a shortcut mapped to it `overide` must be TRUE 170 | set_shortcut(fn = 'blogdown::serve_site',shortcut = key, overide = TRUE) 171 | ``` 172 | 173 | ### Remove Keyboard Shortcut for Addins 174 | 175 | ``` r 176 | rm_shortcut(fn = 'blogdown::serve_site') 177 | ``` 178 | 179 | ### Toggle Addins on/off 180 | 181 | Every time a binding is passed to the `toggle_addin` function it will switch states. 182 | 183 | ``` r 184 | toggle_addin(key = c("blogdown::serve_site","blogdown::new_post_addin","blogdown::update_meta_addin")) 185 | ``` 186 | 187 | ### Limited Liability Addins 188 | 189 | `rsam` gives you 3 empty addins to pass into them whatever you want and run them as your personal addins. You can also set keyboard shortcuts for each one with `set_shortcut`. 190 | 191 | Pass through an expression wrapped the global objects `rsam_fn_1()`, `rsam_fn_2()`, and `rsam_fn_3()` into the Rstudio Addin list. 192 | 193 | ``` r 194 | 195 | rsam_fn_1 <- function(){ 196 | library(ggplot2) 197 | library(dplyr) 198 | 199 | iris%>%ggplot(aes(x=Sepal.Length,y=Sepal.Width)) + geom_point() 200 | } 201 | 202 | # Change shortcuts to whatever you want 203 | 204 | keys <- KEYS$`left command/window key` + KEYS$shift + KEYS$l 205 | 206 | rsam::set_shortcut(fn = 'rsam::lla1',shortcut = keys + KEYS$`1`) 207 | 208 | rsam::set_shortcut(fn = 'rsam::lla2',shortcut = keys + KEYS$`2`) 209 | 210 | rsam::set_shortcut(fn = 'rsam::lla3',shortcut = keys + KEYS$`3`) 211 | ``` 212 | 213 | Feedbacks and enhancement 214 | ------------------------- 215 | 216 | You've found a bug, or have an enhancment idea? Feel free to open an issue : . 217 | --------------------------------------------------------------------------------