---
title: "An introduction to styler"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{An introduction to styler}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

> This is an old vignette superseded by *Get started*. It might be outdated and 
  is not yet deleted to avoid HTTP 404 errors until re-directs are implemented 
  in pkgdown: https://github.com/r-lib/pkgdown/issues/1259

```{r, echo = FALSE}
knitr::opts_chunk$set(echo = TRUE, comment = "")
knitr::knit_engines$set(list(
  styler = function(options) {
    options$comment <- ""
    knitr::engine_output(
      options,
      c("# Before", options$code),
      c("# After", styler::style_text(options$code))
    )
  }
))
```

# Entry-points

styler provides the following API to format code:

* `style_file()` styles .R, .Rmd .Rnw and .Rprofile files.

* `style_dir()` styles all .R and/or .Rmd files in a directory.

* `style_pkg()` styles the source files of an R package.

* RStudio Addins for styling the active file, styling the current package and
  styling the highlighted selection, see `help("styler_addins")`.

Beyond that, styler can be used through other tools documented in the
`vignette("third-party-integrations")`.

### Passing arguments to the style guide

styler separates the abstract definition of a style guide from the application
of it. That's why you must supply a style guide via `transformers` when
styling (in case you don't want to rely on the defaults):

```{r}
library(styler)
style_text("a + b", transformers = tidyverse_style(scope = "indention"))
```

The styler API was designed so that you can pass arguments to the style guide
via the styling function (e.g. `style_file()`) to allow more concise syntax:

```{r, results = 'hide'}
# equivalent
style_text("a + b", transformers = tidyverse_style(scope = "indention"))
style_text("a + b", scope = "indention")
```

The magic is possible thanks to `...`. See `style_text()` for details.

# Invasiveness 

### `scope`: What to style? 

This argument of `tidyverse_style()` determines the invasiveness of styling. The
following levels for `scope` are available (in increasing order):

* "none": Performs no transformation at all.

* "spaces": Manipulates spacing between token on the same line.

* "indention": Manipulates the indention, i.e. number of spaces at the beginning
  of each line.

* "line_breaks": Manipulates line breaks between tokens.

* "tokens": manipulates tokens.

There are two ways to specify the scope of styling.

* As a string: In this case all less invasive scope levels are implied, e.g.
  `"line_breaks"` includes `"indention"`, `"spaces"`. This is brief and what
  most users need. This is supported in `styler >= 1.0.0`.

* As vector of class `AsIs`: Each level has to be listed explicitly by wrapping
  one ore more levels of the scope in `I()`. This offers more granular control
  at the expense of more verbosity. This is supported in `styler > 1.3.2`.

```{r}
# tokens and everything less invasive
style_text("a=2", scope = "tokens")

# just tokens and indention
style_text("a=2", scope = I(c("tokens", "indention")))
```

As you can see from the output, the assignment operator `=` is replaced with
`<-` in both cases, but spacing remained unchanged in the second example.

### How `strict` do you want styler to be?

Another option that is helpful to determine the level of 'invasiveness' is
`strict` (defaulting to `TRUE`). Some rules won't be applied so strictly with
`strict = FALSE`, assuming you deliberately formatted things the way they are.
Please see in `vignette("strict")`. For `styler >= 1.2` alignment in function
calls is detected and preserved so you don't need `strict = FALSE`, e.g.
```{r}
style_text(
  "tibble::tibble(
     small  = 2 ,
     medium = 4,#comment without space
     large  = 6
   )"
)
```

The details are in `vignette("detect-alignment")`.

# Ignoring certain lines

You can tell styler to ignore some lines if you want to keep current formatting.
You can mark whole blocks or inline expressions with `styler: on` and `styler:
off`:

```{r}
styler::style_text(
  "
  #> blocks
  blibala= 3
  # styler: off
  I_have(good+reasons, to = turn_off,
    styler
  )
  # styler: on
  1+1

  #> inline
  ignore( this) # styler: off
  f( ) # not ignored anymore
"
)
```
You can also use custom markers as described in 
`help("stylerignore", package = "styler")`. As described above and in
`vignette("detect-alignment")`,
some alignment is recognized and hence, *stylerignore* should not 
be necessary in that context.

# Caching

styler is rather slow, so leveraging a cache for styled code brings big speedups
in many situations. Starting with version `1.3.0`, you can benefit from it. For
people using styler interactively (e.g. in RStudio), typing
`styler::cache_info()` and then confirming the creation of a permanent cache is
sufficient. Please refer to `help("caching")` for more information. The cache is
by default dependent on the version of styler which means if you upgrade, the
cache will be re-built. Also, the cache takes literally 0 disk space because
only the hash of styled code is stored.

# Dry mode

As of version `1.3.2`, styler has a dry mode which avoids writing output to the
file(s) you want to format. The following options are available:

- *off* (default): Write back to the file if applying styling changes the
  input.

- *on*: Applies styling and returns the results without writing changes (if any) back to the file(s).

- *fail*: returns an error if the result of styling is not identical to the
  input.

In any case, you can use the (invisible) return value of `style_file()` and
friends to learn how files were changed (or would have changed):

```{r}
out <- withr::with_tempfile(
  "code.R",
  {
    writeLines("1+1", "code.R")
    style_file("code.R", dry = "on")
  }
)
out
```

# More configuration options

### Roxygen code example styling

This is enabled by default, you can turn it off with `include_roxygen_examples = FALSE`.

### Custom math token spacing

`styler` can identify and handle unary operators and other math tokens:

```{styler}
1++1-1-1/2
```

This is tidyverse style. However, styler offers very granular control for math
token spacing. Assuming you like spacing around `+` and `-`, but not around `/`
and `*` and `^`, do the following:

```{r}
style_text(
  "1++1/2*2^2",
  math_token_spacing = specify_math_token_spacing(zero = c("'/'", "'*'", "'^'"))
)
```

### Custom indention

If you, say, don't want comments starting with `###` to be indented and
indention to be 4 instead of two spaces, you can formulate an unindention rule
and set `indent_by` to 4:

```{r}
style_text(
  c(
    "a <- function() {",
    "### not to be indented",
    "# indent normally",
    "33",
    "}"
  ),
  reindention = specify_reindention(regex_pattern = "###", indention = 0),
  indent_by = 4
)
```

### Custom style guides

These verse some (not all) configurations exposed in `style_file()` and friends
as well as `tidyverse_style()`. If the above did not give you the flexibility
you hoped for, your can create your own style guide and customize styler even
further, as described in `vignette("customizing_styler")`.
