If you want to change the behavior of styler to match your desired style, there are multiple ways:
Use the tidyverse style guide, but not with the default options. Starting point for this approach is the
help("tidyverse_style")
for the functiontidyverse_style()
, which returns the transformer functions that prettify your code. Most of these options are explained invignette("styler")
.If you can’t get styler behaving the way you want using the arguments of
tidyverse_style()
, you have another option, which is described in avignette("customizing_styler")
: Creating your own style guide from scratch. Yes, I admit, it’s pretty long and if you don’t want to become a styler expert, it may be a little bit overwhelming.If you don’t care about how to create new rules but you simply want to remove a rule, I have good news for you: There is a quick way to do it. And that’s what the remainder of this vignette focuses on.
Once you are happy with your style guide, you might want to have a
look at how to distribute it, which is described in
vignette("distribute_custom_style_guides")
.
Theory
Here are the steps required to deactivate a rule you don’t like
Figure out which transformer function in the transformers returned by
tidyerse_style()
corresponds to the rule you want to remove.Set that element in the list to
NULL
, which is equivalent to removing it.Pass the list to
style_text
as a transformer.
Practice
Lets assume you want to remove the rule that turns =
into <-
for assignment. That means you want
string = "hi there"
to remain unchanged after applying styler. This is not the case if you use the default style guide of styler:
library(styler)
style_text("string = 'hi there'")
string <- "hi there"
So you need to figure out which rule is responsible for this. Let’s check the transformer categories used with the tidyverse style guide.
transformers <- tidyverse_style()
names(transformers)
#> [1] "initialize" "line_break" "space"
#> [4] "token" "indention" "use_raw_indention"
#> [7] "reindention" "style_guide_name" "style_guide_version"
#> [10] "more_specs_style_guide" "transformers_drop" "indent_character"
From the aforementioned vignette:
We note that there are different types of transformer functions. initialize initializes some variables in the nested parse table (so it is not actually a transformer), and the other elements modify either spacing, line breaks or tokens. use_raw_indention is not a function, it is just an option.
Now, we can look at the names of the rules that are sub-elements of the transformer categories.
library(magrittr)
levels <- c("space", "line_break", "indention", "token")
purrr::map(
levels,
~ names(transformers[[.x]])
) %>%
purrr::set_names(levels)
#> $space
#> [1] "remove_space_before_closing_paren"
#> [2] "remove_space_before_opening_paren"
#> [3] "add_space_after_for_if_while"
#> [4] "remove_space_before_comma"
#> [5] "style_space_around_math_token"
#> [6] "style_space_around_tilde"
#> [7] "spacing_around_op"
#> [8] "remove_space_after_opening_paren"
#> [9] "remove_space_after_excl"
#> [10] "set_space_after_bang_bang"
#> [11] "remove_space_around_dollar"
#> [12] "remove_space_after_function_declaration"
#> [13] "remove_space_around_colons"
#> [14] "start_comments_with_space"
#> [15] "remove_space_after_unary_plus_minus_nested"
#> [16] "spacing_before_comments"
#> [17] "set_space_between_levels"
#> [18] "set_space_between_eq_sub_and_comma"
#> [19] "set_space_in_curly"
#>
#> $line_break
#> [1] "remove_empty_lines_after_opening_and_before_closing_braces"
#> [2] "set_line_break_around_comma_and_or"
#> [3] "set_line_break_after_assignment"
#> [4] "set_line_break_before_curly_opening"
#> [5] "remove_line_break_before_round_closing_after_curly"
#> [6] "remove_line_breaks_in_function_declaration"
#> [7] "set_line_breaks_between_top_level_exprs"
#> [8] "style_line_break_around_curly"
#> [9] "set_line_break_around_curly_curly"
#> [10] "set_line_break_before_closing_call"
#> [11] "set_line_break_after_opening_if_call_is_multi_line"
#> [12] "remove_line_break_in_fun_call"
#> [13] "add_line_break_after_pipe"
#> [14] "set_line_break_after_ggplot2_plus"
#>
#> $indention
#> [1] "indent_braces"
#> [2] "unindent_function_declaration"
#> [3] "indent_op"
#> [4] "indent_eq_sub"
#> [5] "indent_without_paren"
#> [6] "update_indention_reference_function_declaration"
#>
#> $token
#> [1] "fix_quotes"
#> [2] "force_assignment_op"
#> [3] "resolve_semicolon"
#> [4] "add_brackets_in_pipe"
#> [5] "wrap_if_else_while_for_function_multi_line_in_curly"
Spotted the rule we want to get rid of? It’s under token
and it’s called force_assignment_op
. I agree, we could have
chosen a better name. If you are not sure if you can guess from the name
of the rule what it does you can also have a look at the function
declaration of this (unexported) function.
styler:::force_assignment_op
#> function (pd)
#> {
#> to_replace <- pd$token == "EQ_ASSIGN"
#> pd$token[to_replace] <- "LEFT_ASSIGN"
#> pd$text[to_replace] <- "<-"
#> pd
#> }
#> <bytecode: 0x55c30042be68>
#> <environment: namespace:styler>
Next, you simply set that element to NULL
.
transformers$token$force_assignment_op <- NULL
And you can use the modified transformer list as input to
style_text()
style_text("string = 'hi there'", transformers = transformers)
#> string = "hi there"
If you want to use it the same way as tidyverse_style()
,
here’s the last step:
eq_assign_style <- function(...) {
transformers <- tidyverse_style(...)
transformers$token$force_assignment_op <- NULL
transformers
}
style_text("string = 'hi there'", style = eq_assign_style)
#> string = "hi there"
That’s it. Note that the transformer functions and how they are
returned by tidyverse_style()
is not part of the exposed
API. This means that the order, the naming etc. may change. Also,
remember we did not add a rule to replace <-
with
=
, but we only removed a rule to replace =
with <-
, so <-
won’t be touched:
style_text("string <- 'hi there'", style = eq_assign_style)
#> string <- "hi there"
If you want to turn <-
into =
, you need
to add a rule as described in
vignette("customizing_styler")
.
If you have trouble identifying a rule based on rule names,
- First write an example whose results is not the one you wanted, e.g.
code <- "
f <- function () {
return (1)
}"
is code that will have the first empty line in the function body removed by styler.
- Then pinpoint the probable rule type (e.g. line breaks if you want less new lines).
- In a local styler clone, add e.g. a
return(pd)
at the top of the body to deactivate the rule quickly, or add aprint(pd)
orbrowser()
call in the functions of that type (e.g. the different functions ofR/rules-line-breaks.R
),load_all()
, run your example, see if that function made the change. move theprint(pd)
orbrowser()
call to another function if not. - Once you’ve identified the culprit (in this case
style_line_break_around_curly
), set it toNULL
as shown earlier.
Some other rules and their transformers
You don’t like multi-line ifelse statements getting wrapped around curly braces:
transformers$token$wrap_if_else_multi_line_in_curly
.You don’t like multi-line calls to be broken before the first named argument:
transformers$line_break$set_line_break_after_opening_if_call_is_multi_line
(interacting withtransformers$line_break$set_line_break_before_closing_call
).You don’t like the line being broken after the pipe:
transformers$line_break$add_line_break_after_pipe
You don’t like single quotes to be replaced by double quotes:
transformers$space$fix_quotes
.You don’t like comments to start with one space:
transformers$space$start_comments_with_space
I think you get the idea. I nevertheless recommend using the tidyverse style guide as is since
it is a well-established, thought-through style.
using a consistent style (no matter which) reduces friction in the community.
If you have questions, don’t hesitate to create an issue in the GitHub repo.