diff --git a/.Rbuildignore b/.Rbuildignore index 753470c98..a4912951e 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -16,3 +16,4 @@ CONTRIBUTING.md ^gitsum$ revdep ^cran-comments\.md$ +^tests/testmanual$ diff --git a/R/addins.R b/R/addins.R index ac63567ed..1376e60d5 100644 --- a/R/addins.R +++ b/R/addins.R @@ -1,29 +1,55 @@ #' Stylers for RStudio Addins #' #' Helper functions for styling via RStudio Addins. -#' +#' @section Addins: +#' - Set style: Select the style transformers to use. For flexibility, the user +#' input is passed to the `transformers` argument, not the `style` argument, so +#' entering `styler::tidyverse_style(scope = "spaces")` in the Addin is +#' equivalent to `styler::style_text("1+1", scope = "spaces")` and +#' `styler::style_text("1+1", transformers = styler::tidyverse_style(scope = "spaces"))` +#' if the text to style is `1+1`. The style transformers are memorized +#' within an R session via the R option `styler.addins_style_transformer` so +#' if you want it to persist over sessions, set the option +#' `styler.addins_style_transformer` in your `.Rprofile`. +#' - Style active file: Styles the active file, by default with +#' [tidyverse_style()] or the value of the option +#' `styler.addins_style_transformer` if specified. +#' - Style selection: Same as *Style active file*, but styles the highlighted +#' code instead of the whole file. #' @section Auto-Save Option: #' By default, both of the RStudio Addins will apply styling to the (selected) #' file contents without saving changes. Automatic saving can be enabled by #' setting the environment variable `save_after_styling` to `TRUE`. -#' #' Consider setting this in your `.Rprofile` file if you want to persist #' this setting across multiple sessions. Untitled files will always need to be #' saved manually after styling. -#' +#' @section Life cycle: +#' The way of specifying the style in the Addin as well as the auto-save option +#' (see below) are experimental. We are currently considering letting the user +#' specify the defaults for other style APIs like [styler::style_text()], +#' either via R options, config files or other ways as well. +#' See [r-lib/styler#319](https://github.com/r-lib/styler/issues/319) for +#' the current status of this. #' @name styler_addins #' @family stylers -#' @seealso [Sys.setenv()] +#' @examples +#' \dontrun{ +#' # save after styling when using the Addin +#' Sys.setenv(save_after_styling = TRUE) +#' # only style with scope = "spaces" when using the Addin +#' options( +#' styler.addins_style_transformer = "styler::tidyverse_style(scope = 'spaces')" +#' ) +#' } NULL -#' @describeIn styler_addins Styles the active file with [tidyverse_style()] and -#' `strict = TRUE`. + #' @importFrom rlang abort #' @keywords internal style_active_file <- function() { - communicate_addins_style() + communicate_addins_style_transformers() context <- get_rstudio_context() - transformer <- make_transformer(get_addins_style_fun()(), + transformer <- make_transformer(get_addins_style_transformer(), include_roxygen_examples = TRUE, warn_empty = is_plain_r_file(context$path) ) @@ -47,52 +73,28 @@ style_active_file <- function() { rstudioapi::setCursorPosition(context$selection[[1]]$range) } -#' Style a file as if it was an .R file -#' -#' If not successful, the file is most -#' likely not a .R file, so saving the file and try styling again will work if -#' the file is an .Rmd file. Otherwise, we can throw an error that the file must -#' be a .R or .Rmd file. -#' @param context The context from `styler:::get_rstudio_context()`. -#' @param transformer A transformer function most conveniently constructed with -#' [make_transformer()]. -#' @importFrom rlang with_handlers abort +#' Wrapper around [style_pkg()] for access via Addin. #' @keywords internal -try_transform_as_r_file <- function(context, transformer) { - with_handlers( - transformer(context$contents), - error = function(e) { - preamble_for_unsaved <- paste( - "Styling of unsaved files is only supported for R files with valid code.", - "Please save the file (as .R or .Rmd) and make sure that the R code in it", - "can be parsed. Then, try to style again." - ) - - if (context$path == "") { - abort(paste0(preamble_for_unsaved, " The error was \n", e$message)) - } else { - abort(e$message) - } - } - ) +style_active_pkg <- function() { + communicate_addins_style_transformers() + style_pkg(transformers = get_addins_style_transformer()) } -#' @describeIn styler_addins Styles the highlighted selection in a `.R` or -#' `.Rmd` file. +#' Styles the highlighted selection in a `.R` or `.Rmd` file. #' @importFrom rlang abort #' @keywords internal style_selection <- function() { - communicate_addins_style() + communicate_addins_style_transformers() context <- get_rstudio_context() text <- context$selection[[1]]$text if (all(nchar(text) == 0)) abort("No code selected") - out <- style_text(text, style = get_addins_style_fun()) + out <- style_text(text, transformers = get_addins_style_transformer()) rstudioapi::modifyRange( context$selection[[1]]$range, paste0(out, collapse = "\n"), id = context$id ) if (Sys.getenv("save_after_styling") == TRUE && context$path != "") { - rstudioapi::documentSave(context$id) + invisible(rstudioapi::documentSave(context$id)) } } @@ -100,43 +102,77 @@ get_rstudio_context <- function() { rstudioapi::getActiveDocumentContext() } -#' Ask the user to supply a style -#' +#' Asks the user to supply a style #' @importFrom rlang abort #' @keywords internal #' @importFrom rlang with_handlers abort -prompt_style <- function() { - current_style <- get_addins_style_name() +set_style_transformers <- function() { + current_style <- get_addins_style_transformer_name() new_style <- rstudioapi::showPrompt( "Select a style", - "Enter the name of a style function, e.g. `styler::tidyverse_style`", + "Enter the name of a style transformer, e.g. `styler::tidyverse_style()`", current_style ) - parsed_new_style <- with_handlers( - eval(parse(text = new_style)), + parsed_new_style <- with_handlers({ + transformers <- eval(parse(text = new_style)) + style_text(c("a = 2", "function() {", "NULL", "}")) + }, error = function(e) { - abort(paste0("The selected style \"", new_style, "\" is not valid: ", e$message)) + abort(paste0( + "The selected style transformers \"", + new_style, "\" is not valid: ", e$message + )) } ) - options(styler.addins.style = new_style) + options(styler.addins_style_transformer = new_style) invisible(current_style) } #' Return the style function or name #' #' @keywords internal -get_addins_style_name <- function() { - getOption("styler.addins.style", default = "styler::tidyverse_style") +get_addins_style_transformer_name <- function() { + getOption("styler.addins_style_transformer", default = "styler::tidyverse_style()") } -#' @rdname get_addins_style_name +#' @rdname get_addins_style_transformer_name #' @keywords internal -get_addins_style_fun <- function() { - eval(parse(text = get_addins_style_name())) +get_addins_style_transformer <- function() { + eval(parse(text = get_addins_style_transformer_name())) +} + +communicate_addins_style_transformers <- function() { + style_name <- get_addins_style_transformer_name() + cat("Using style transformers `", style_name, "`\n", sep = "") } -communicate_addins_style <- function() { - style_name <- get_addins_style_name() - cat("Using style `", style_name, "`\n", sep = "") +#' Style a file as if it was an .R file +#' +#' If not successful, the file is most +#' likely not a .R file, so saving the file and try styling again will work if +#' the file is an .Rmd file. Otherwise, we can throw an error that the file must +#' be a .R or .Rmd file. +#' @param context The context from `styler:::get_rstudio_context()`. +#' @param transformer A transformer function most conveniently constructed with +#' [make_transformer()]. +#' @importFrom rlang with_handlers abort +#' @keywords internal +try_transform_as_r_file <- function(context, transformer) { + with_handlers( + transformer(context$contents), + error = function(e) { + preamble_for_unsaved <- paste( + "Styling of unsaved files is only supported for R files with valid code.", + "Please save the file (as .R or .Rmd) and make sure that the R code in it", + "can be parsed. Then, try to style again." + ) + + if (context$path == "") { + abort(paste0(preamble_for_unsaved, " The error was \n", e$message)) + } else { + abort(e$message) + } + } + ) } diff --git a/R/style-guides.R b/R/style-guides.R index 89980ff83..385d1c38b 100644 --- a/R/style-guides.R +++ b/R/style-guides.R @@ -29,7 +29,6 @@ NULL #' @inheritParams create_style_guide #' @param math_token_spacing A list of parameters that define spacing around #' math token, conveniently constructed using [specify_math_token_spacing()]. - #' @details The following options for `scope` are available. #' #' * "none": Performs no transformation at all. diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf index 027ff00cb..fcef8f90d 100644 --- a/inst/rstudio/addins.dcf +++ b/inst/rstudio/addins.dcf @@ -1,6 +1,11 @@ Name: Set style -Description: Prompt for and set the style used by all STYLER addins -Binding: prompt_style +Description: Prompt for and set the style transformers used by all styler addins +Binding: set_style_transformers +Interactive: true + +Name: Style selection +Description: Pretty-print selection +Binding: style_selection Interactive: true Name: Style active file @@ -8,7 +13,7 @@ Description: Pretty-print active file Binding: style_active_file Interactive: true -Name: Style selection -Description: Pretty-print selection -Binding: style_selection +Name: Style active package +Description: Pretty-print active package +Binding: style_active_pkg Interactive: true diff --git a/man/get_addins_style_name.Rd b/man/get_addins_style_transformer_name.Rd similarity index 52% rename from man/get_addins_style_name.Rd rename to man/get_addins_style_transformer_name.Rd index 0873f3761..deccf5ff3 100644 --- a/man/get_addins_style_name.Rd +++ b/man/get_addins_style_transformer_name.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/addins.R -\name{get_addins_style_name} -\alias{get_addins_style_name} -\alias{get_addins_style_fun} +\name{get_addins_style_transformer_name} +\alias{get_addins_style_transformer_name} +\alias{get_addins_style_transformer} \title{Return the style function or name} \usage{ -get_addins_style_name() +get_addins_style_transformer_name() -get_addins_style_fun() +get_addins_style_transformer() } \description{ Return the style function or name diff --git a/man/prompt_style.Rd b/man/prompt_style.Rd deleted file mode 100644 index 539d25103..000000000 --- a/man/prompt_style.Rd +++ /dev/null @@ -1,12 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/addins.R -\name{prompt_style} -\alias{prompt_style} -\title{Ask the user to supply a style} -\usage{ -prompt_style() -} -\description{ -Ask the user to supply a style -} -\keyword{internal} diff --git a/man/set_style_transformers.Rd b/man/set_style_transformers.Rd new file mode 100644 index 000000000..410693bb3 --- /dev/null +++ b/man/set_style_transformers.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addins.R +\name{set_style_transformers} +\alias{set_style_transformers} +\title{Asks the user to supply a style} +\usage{ +set_style_transformers() +} +\description{ +Asks the user to supply a style +} +\keyword{internal} diff --git a/man/style_active_pkg.Rd b/man/style_active_pkg.Rd new file mode 100644 index 000000000..d16e22270 --- /dev/null +++ b/man/style_active_pkg.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addins.R +\name{style_active_pkg} +\alias{style_active_pkg} +\title{Wrapper around \code{\link[=style_pkg]{style_pkg()}} for access via Addin.} +\usage{ +style_active_pkg() +} +\description{ +Wrapper around \code{\link[=style_pkg]{style_pkg()}} for access via Addin. +} +\keyword{internal} diff --git a/man/style_selection.Rd b/man/style_selection.Rd new file mode 100644 index 000000000..668695a44 --- /dev/null +++ b/man/style_selection.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addins.R +\name{style_selection} +\alias{style_selection} +\title{Styles the highlighted selection in a \code{.R} or \code{.Rmd} file.} +\usage{ +style_selection() +} +\description{ +Styles the highlighted selection in a \code{.R} or \code{.Rmd} file. +} +\keyword{internal} diff --git a/man/styler_addins.Rd b/man/styler_addins.Rd index acddef317..78a8d6b7b 100644 --- a/man/styler_addins.Rd +++ b/man/styler_addins.Rd @@ -2,43 +2,63 @@ % Please edit documentation in R/addins.R \name{styler_addins} \alias{styler_addins} -\alias{style_active_file} -\alias{style_selection} \title{Stylers for RStudio Addins} -\usage{ -style_active_file() - -style_selection() -} \description{ Helper functions for styling via RStudio Addins. } -\section{Functions}{ -\itemize{ -\item \code{style_active_file}: Styles the active file with \code{\link[=tidyverse_style]{tidyverse_style()}} and -\code{strict = TRUE}. +\section{Addins}{ -\item \code{style_selection}: Styles the highlighted selection in a \code{.R} or -\code{.Rmd} file. -}} +\itemize{ +\item Set style: Select the style transformers to use. For flexibility, the user +input is passed to the \code{transformers} argument, not the \code{style} argument, so +entering \code{styler::tidyverse_style(scope = "spaces")} in the Addin is +equivalent to \code{styler::style_text("1+1", scope = "spaces")} and +\code{styler::style_text("1+1", transformers = styler::tidyverse_style(scope = "spaces"))} +if the text to style is \code{1+1}. The style transformers are memorized +within an R session via the R option \code{styler.addins_style_transformer} so +if you want it to persist over sessions, set the option +\code{styler.addins_style_transformer} in your \code{.Rprofile}. +\item Style active file: Styles the active file, by default with +\code{\link[=tidyverse_style]{tidyverse_style()}} or the value of the option +\code{styler.addins_style_transformer} if specified. +\item Style selection: Same as \emph{Style active file}, but styles the highlighted +code instead of the whole file. +} +} \section{Auto-Save Option}{ By default, both of the RStudio Addins will apply styling to the (selected) file contents without saving changes. Automatic saving can be enabled by setting the environment variable \code{save_after_styling} to \code{TRUE}. - Consider setting this in your \code{.Rprofile} file if you want to persist this setting across multiple sessions. Untitled files will always need to be saved manually after styling. } -\seealso{ -\code{\link[=Sys.setenv]{Sys.setenv()}} +\section{Life cycle}{ + +The way of specifying the style in the Addin as well as the auto-save option +(see below) are experimental. We are currently considering letting the user +specify the defaults for other style APIs like \code{\link[styler:style_text]{styler::style_text()}}, +either via R options, config files or other ways as well. +See \href{https://github.com/r-lib/styler/issues/319}{r-lib/styler#319} for +the current status of this. +} +\examples{ +\dontrun{ +# save after styling when using the Addin +Sys.setenv(save_after_styling = TRUE) +# only style with scope = "spaces" when using the Addin +options( + styler.addins_style_transformer = "styler::tidyverse_style(scope = 'spaces')" +) +} +} +\seealso{ Other stylers: \code{\link{style_dir}}, \code{\link{style_file}}, \code{\link{style_pkg}}, \code{\link{style_text}} } \concept{stylers} -\keyword{internal} diff --git a/tests/testmanual/addins/non-r.py b/tests/testmanual/addins/non-r.py new file mode 100644 index 000000000..381f905d2 --- /dev/null +++ b/tests/testmanual/addins/non-r.py @@ -0,0 +1,2 @@ +2 + 2 +" " diff --git a/tests/testmanual/addins/r-invalid.R b/tests/testmanual/addins/r-invalid.R new file mode 100644 index 000000000..88d5c0639 --- /dev/null +++ b/tests/testmanual/addins/r-invalid.R @@ -0,0 +1 @@ +1+ /1 diff --git a/tests/testmanual/addins/r-valid.R b/tests/testmanual/addins/r-valid.R new file mode 100644 index 000000000..612dabf52 --- /dev/null +++ b/tests/testmanual/addins/r-valid.R @@ -0,0 +1 @@ +1+ 1 diff --git a/tests/testmanual/addins/rmd-invalid.Rmd b/tests/testmanual/addins/rmd-invalid.Rmd new file mode 100644 index 000000000..5b7c2f3ee --- /dev/null +++ b/tests/testmanual/addins/rmd-invalid.Rmd @@ -0,0 +1,30 @@ +--- +title: "Untitled" +author: "Lorenz Walthert" +date: "4/28/2019" +output: html_document +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$setecho = -TRUE) +``` + +## R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this: + +```{r cars} +summary(cars ) +``` + +## Including Plots + +You can also embed plots, for example: + +```{r pressure, echo=FALSE} +plot(pressure) +``` + +Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot. diff --git a/tests/testmanual/addins/rmd-valid.Rmd b/tests/testmanual/addins/rmd-valid.Rmd new file mode 100644 index 000000000..b92ffe928 --- /dev/null +++ b/tests/testmanual/addins/rmd-valid.Rmd @@ -0,0 +1,30 @@ +--- +title: "Untitled" +author: "Lorenz Walthert" +date: "4/28/2019" +output: html_document +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = -TRUE) +``` + +## R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this: + +```{r cars} +summary(cars) +``` + +## Including Plots + +You can also embed plots, for example: + +```{r pressure, echo=FALSE} +plot(pressure) +``` + +Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot. diff --git a/tests/testmanual/addins/rnw-invalid.Rnw b/tests/testmanual/addins/rnw-invalid.Rnw new file mode 100644 index 000000000..046415c2c --- /dev/null +++ b/tests/testmanual/addins/rnw-invalid.Rnw @@ -0,0 +1,28 @@ +\documentclass{article} + +\begin{document} + +Some text +<>>= +# Some R code +f <- function(x) { + x +} +@ + +More text + +<<>>= +# More R code +g <- function(y) { + y +} +@ + +Final text +<<>>= +1 + 2 +@ + + +\end{document} diff --git a/tests/testmanual/addins/rnw-valid.Rnw b/tests/testmanual/addins/rnw-valid.Rnw new file mode 100644 index 000000000..e964baaf9 --- /dev/null +++ b/tests/testmanual/addins/rnw-valid.Rnw @@ -0,0 +1,28 @@ +\documentclass{article} + +\begin{document} + +Some text +<<>>= +# Some R code +f <- function(x) { + x +} +@ + +More text + +<<>>= +# More R code +g <- function(y) { + y +} +@ + +Final text +<<>>= +1 + 2 +@ + + +\end{document} diff --git a/tests/testmanual/tests b/tests/testmanual/tests new file mode 100644 index 000000000..e54f0373b --- /dev/null +++ b/tests/testmanual/tests @@ -0,0 +1,26 @@ +# Manual tests + +## Addins + +* set style: + - test setting a valid stlye + - test setting an invalid style +* style active file: + - saved .R file (valid and invalid code) + - unsaved .R file + - saved .Rmd file (valid and invalid code) + - unsaved .Rmd file + - saved .Rnw file (valid and invalid code) + - unsaved .Rnw file + - saved non-R file + - unsaved R file +* style selection: + - saved .R file (valid and invalid code) + - unsaved .R file + - saved .Rmd file (valid and invalid code) + - unsaved .Rmd file + - saved .Rnw file (valid and invalid code) + - unsaved .Rnw file + - saved non-R file + - unsaved R file + diff --git a/tic.R b/tic.R index b23d448ac..25e33dea2 100644 --- a/tic.R +++ b/tic.R @@ -1,4 +1,4 @@ -add_package_checks(error_on = ifelse(getRversion() >= "3.2", "note", "error")) +do_package_checks(error_on = ifelse(getRversion() >= "3.2", "note", "error")) if (Sys.getenv("id_rsa") != "" && ci()$get_branch() == "master" && Sys.getenv("BUILD_PKGDOWN") != "") { # pkgdown documentation can be built optionally. Other example criteria: