diff --git a/.gitattributes b/.gitattributes index f2e9ea02a..0f2dadb50 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -tests/testthat/**/*_tree linguist-generated=true \ No newline at end of file +tests/testthat/**/*_tree linguist-generated=true diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 0d80e6962..74b28bdd7 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -27,9 +27,10 @@ jobs: matrix: config: - {os: macOS-latest, r: 'release'} + - {os: windows-latest, r: 'devel'} - {os: windows-latest, r: 'release'} - - {os: windows-latest, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/latest"} - - {os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", http-user-agent: "R/4.0.0 (ubuntu-18.04) R (4.0.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" } + - {os: windows-latest, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/latest"} + - {os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", http-user-agent: "R/4.0.0 (ubuntu-18.04) R (4.0.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" } - {os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} - {os: ubuntu-18.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} - {os: ubuntu-18.04, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} diff --git a/.github/workflows/check-full.yaml b/.github/workflows/check-full.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 8bc92105d..d1a13500f 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,6 +1,6 @@ on: push: - branches: master + branches: main name: pkgdown diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 000000000..0cdf2e517 --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,55 @@ +name: pre-commit +on: + push: + branches-ignore: + - 'master' + - 'main' + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +jobs: + pre-commit: + runs-on: ubuntu-18.04 + if: >- + !contains(github.event.head_commit.message, 'ci skip') && + ( + startsWith(github.ref, 'refs/heads') || + github.event.pull_request.draft == false + ) + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.6.0 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Install system dependencies + if: runner.os == 'Linux' + run: | + # your system installation code here + # sudo apt-get install -y libcurl4-openssl-dev + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.8" + architecture: "x64" + - name: Run pre-commit + uses: pre-commit/action@v2.0.3 + - name: Commit files + if: failure() && startsWith(github.ref, 'refs/heads') + run: | + if [[ `git status --porcelain --untracked-files=no` ]]; then + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git checkout -- .github/workflows + git commit -m "pre-commit" -a + fi + - name: Push changes + if: failure() && startsWith(github.ref, 'refs/heads') + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ github.ref }} + env: + RENV_CONFIG_CACHE_ENABLED: FALSE diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 3058d037b..7dabe0282 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,10 +1,10 @@ on: push: branches: - - master + - main pull_request: branches: - - master + - main name: test-coverage diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 115c448f8..71bd1be0d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,17 +4,22 @@ default_stages: [commit] repos: - repo: https://github.com/lorenzwalthert/precommit - rev: v0.1.3.9014 + rev: v0.1.3.9139 hooks: - id: style-files args: [--style_pkg=styler, --style_fun=tidyverse_style] exclude: > (?x)^( - tests/testthat/.*/.*\.R(md)?| + tests/testthat/.*/.*\.R(md|nw)?| vignettes/customizing_styler\.Rmd| tests/testthat/public-api/xyzfile-rnw/random4\.Rnw| + vignettes/detect-alignment\.Rmd| + tests/testmanual/addins/.*invalid.*| + tests/testmanual/addins/r-valid\.R| )$ - id: roxygenize + additional_dependencies: + - r-lib/pkgapi - id: use-tidy-description - id: spell-check exclude: > @@ -49,7 +54,8 @@ repos: tests/testthat/public-api/xyzaddin/addin_region-.*| tests/testmanual/addins/r-invalid\.R| tests/testthat/escaping/basic-escape-out\.R| - tests/testthat/indention_operators/base_pipe_and_assignment-.*| + tests/testthat/indention_operators/.*pipe.*| + tests/testthat/line_breaks_and_other/.*pipe.*| tests/testthat/exception_handling/parser-error.R| )$ - id: no-browser-statement @@ -58,14 +64,15 @@ repos: tests/testthat/public-api/xyzaddin/addin_region-.*| tests/testmanual/addins/r-invalid\.R| tests/testthat/escaping/basic-escape-out\.R| - tests/testthat/indention_operators/base_pipe_and_assignment-.*| + tests/testthat/indention_operators/.*pipe.*| + tests/testthat/line_breaks_and_other/.*pipe.*| tests/testthat/exception_handling/parser-error.R| )$ - id: deps-in-desc exclude: > (?x)^( touchstone/.*| - tests/testmanual/addins/r-invalid\.R| + tests/testmanual/addins/.*invalid.*| tests/testthat/escaping/basic-escape-out\.R| tests/testthat/rnw/011-conditional-eval-out\.Rnw| tests/testthat/.*\.R(md)? @@ -76,7 +83,13 @@ repos: - id: check-added-large-files args: ['--maxkb=200'] - id: end-of-file-fixer - exclude: '\.Rd' + exclude: > + (?x)^( + \.Rd| + tests/testthat/exception_handling/empty_file\.R| + tests/testthat/parse_comments/eol_eof_spaces-.*| + tests/testthat/reference-objects/.*| + )$ - repo: local hooks: - id: forbid-to-commit diff --git a/DESCRIPTION b/DESCRIPTION index a04314cc0..4aa682d9f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: styler Title: Non-Invasive Pretty Printing of R Code -Version: 1.6.2 +Version: 1.6.2.9000 Authors@R: c(person(given = "Kirill", family = "Müller", @@ -16,8 +16,9 @@ Description: Pretty-prints R code without changing the user's formatting License: MIT + file LICENSE URL: https://github.com/r-lib/styler, https://styler.r-lib.org BugReports: https://github.com/r-lib/styler/issues +Depends: + R (>= 3.4.0) Imports: - backports (>= 1.1.0), cli (>= 1.1.0), glue, magrittr (>= 2.0.0), @@ -29,7 +30,6 @@ Imports: tibble (>= 1.4.2), tools, withr (>= 1.0.0), - xfun (>= 0.1) Suggests: data.tree (>= 0.1.6), digest, @@ -46,7 +46,7 @@ VignetteBuilder: Encoding: UTF-8 Roxygen: list(markdown = TRUE, roclets = c("rd", "namespace", "collate", "pkgapi::api_roclet")) -RoxygenNote: 7.1.1.9001 +RoxygenNote: 7.1.2 Collate: 'addins.R' 'communicate.R' diff --git a/NEWS.md b/NEWS.md index 586b55446..05090dff0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,39 @@ -# styler 1.2 +# styler 1.6.2.9000 (Development version) + +* Piped function without brackets `substitute(x %>% y)` don't get `()` added + anymore, as this can change outcome of the code (#876). +* Alignment detection respects stylerignore (#850). +* Add vignette on distributing style guide (#846, #861). +* Enable pre-commit.ci (#843). +* new R option `styler.cache_root` (defaulting to `"styler"`) that determines + the sub-directory under the {R.cache} cache directory that {styler} uses. Non- + default caches won't be cleaned up by {styler}. We suggest `"styler-perm"` + (also used by {precommit}). +* rename default branch to main (#859). +* Fix argument name `filetype` in Example for `style_dir()` (#855). +* ensure a trailing blank line also if the input is cached (#867). +* Bump minimal R requirement to 3.4 in line with the [tidyverse](https://www.tidyverse.org/blog/2019/04/r-version-support/), which + allowed to remove the dependency at {backports} and some exception handling. +* Remove dependency on {xfun} (#866). +* use pre-commit via GitHub Actions (#872). + +* stylerignore markers are now interpreted as regular expressions instead of + comments that must match exactly. This allows to specify multiple markers in + one regular expression for `styler.ignore_start` and `styler.ignore_stop`, + e.g. to use markers for lintr and styler on the same line, you can use + `options(styler.ignore_start = "nolint start|styler: off"`: + + ```r + # nolint start, styler: off + 1 +1 + # nolint end + # styler: on + ``` + As a consequence of this approach, the defaults for `styler.ignore_start` and + `styler.ignore_stop` omit the `#` (#849). + + +# styler 1.6.2 * clean up cache files older than one week (#842). diff --git a/R/addins.R b/R/addins.R index 44f7c3fea..5e265b11f 100644 --- a/R/addins.R +++ b/R/addins.R @@ -3,8 +3,8 @@ #' 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 +#' 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 diff --git a/R/communicate.R b/R/communicate.R index bb1a87a57..e4e0b58dd 100644 --- a/R/communicate.R +++ b/R/communicate.R @@ -7,7 +7,7 @@ #' @inheritParams can_verify_roundtrip #' @keywords internal communicate_warning <- function(changed, transformers) { - if (any(changed, na.rm = TRUE) && + if (any(changed, na.rm = TRUE) && !can_verify_roundtrip(transformers) && !getOption("styler.quiet", FALSE) ) { diff --git a/R/detect-alignment.R b/R/detect-alignment.R index 2143ac5cb..49093011f 100644 --- a/R/detect-alignment.R +++ b/R/detect-alignment.R @@ -49,6 +49,10 @@ token_is_on_aligned_line <- function(pd_flat) { pd_flat$lag_newlines <- pd_flat$pos_id <- NULL pd_flat$.lag_spaces <- lag(pd_flat$spaces) pd_by_line <- split(pd_flat, line_idx) + pd_by_line[purrr::map_lgl(pd_by_line, ~ any(.x$stylerignore))] <- NULL + if (length(pd_by_line) < 1) { + return(TRUE) + } last_line_is_closing_brace_only <- nrow(last(pd_by_line)) == 1 relevant_idx <- seq2(2, ifelse(last_line_is_closing_brace_only, length(pd_by_line) - 1, @@ -86,7 +90,11 @@ token_is_on_aligned_line <- function(pd_flat) { } pd_by_line <- alignment_drop_comments(pd_by_line) %>% - alignment_ensure_no_closing_brace(last_line_is_closing_brace_only) %>% + alignment_ensure_no_closing_brace(last_line_is_closing_brace_only) + if (length(pd_by_line) < 1) { + return(TRUE) + } + pd_by_line <- pd_by_line %>% alignment_ensure_trailing_comma() # now, pd only contains arguments separated by values, ideal for iterating # over columns. diff --git a/R/io.R b/R/io.R index 9caad1a67..0c588500e 100644 --- a/R/io.R +++ b/R/io.R @@ -42,7 +42,7 @@ transform_utf8_one <- function(path, fun, dry) { } else if (dry == "on") { # don't do anything } else if (dry == "off") { - xfun::write_utf8(new, path) + write_utf8(new, path) } else { # not implemented } @@ -114,3 +114,10 @@ read_utf8_bare <- function(con, warn = TRUE) { invalid_utf8 <- function(x) { which(!is.na(x) & is.na(iconv(x, "UTF-8", "UTF-8"))) } + +#' Drop-in replacement for `xfun::write_utf8()` +#' @keywords internal +write_utf8 <- function(text, con, ...) { + withr::local_options(encoding = "native.enc") + writeLines(enc2utf8(text), con, ..., useBytes = TRUE) +} diff --git a/R/nest.R b/R/nest.R index 9fa5d96da..12aadfc90 100644 --- a/R/nest.R +++ b/R/nest.R @@ -159,22 +159,20 @@ find_pos_id_to_keep <- function(pd) { #' [detected by styler](https://styler.r-lib.org/articles/detect-alignment.html), #' making stylerignore redundant. See a few illustrative examples below. #' @details -#' Styling is on by default when you run styler. +#' Styling is on for all lines by default when you run styler. #' #' - To mark the start of a sequence where you want to turn styling off, use #' `# styler: off`. #' - To mark the end of this sequence, put `# styler: on` in your code. After #' that line, styler will again format your code. #' - To ignore an inline statement (i.e. just one line), place `# styler: off` -#' at the end of the line. Note that inline statements cannot contain other -#' comments apart from the marker, i.e. a line like -#' `1 # comment # styler: off` won't be ignored. -#' +#' at the end of the line. #' To use something else as start and stop markers, set the R options #' `styler.ignore_start` and -#' `styler.ignore_stop` using [options()]. If you want these -#' settings to persist over multiple R sessions, consider setting them in your -#' R profile, e.g. with `usethis::edit_rprofile()`. +#' `styler.ignore_stop` using [options()]. For styler version > 1.6.2, the +#' option supports character vectors longer than one and the marker are not +#' exactly matched, but using a regular expression, which means you can have +#' multiple marker on one line, e.g. `# nolint start styler: off`. #' @name stylerignore #' @examples #' # as long as the order of the markers is correct, the lines are ignored. diff --git a/R/parse.R b/R/parse.R index 13a4788e6..a82c60637 100644 --- a/R/parse.R +++ b/R/parse.R @@ -127,7 +127,6 @@ add_id_and_short <- function(pd) { #' @importFrom magrittr or #' @keywords internal ensure_correct_txt <- function(pd, text) { - ensure_valid_pd(pd) is_problematic_text <- or( is_insufficiently_parsed_string(pd), is_insufficiently_parsed_number(pd) @@ -173,30 +172,6 @@ ensure_correct_txt <- function(pd, text) { arrange_pos_id() } -#' Ensure that the parse data is valid -#' -#' Test whether all non-terminals have at least one child and throw an error -#' otherwise. As this is check is rather expensive, it is only -#' carried out for configurations we have good reasons to expect problems. -#' @param pd A parse table. -#' @importFrom rlang abort -#' @keywords internal -ensure_valid_pd <- function(pd) { - if (getRversion() < "3.2") { - non_terminals <- pd %>% - filter(terminal == FALSE) - valid_pd <- non_terminals$id %>% - map_lgl(~ .x %in% pd$parent) %>% - all() - if (!valid_pd) { - abort(paste( - "The parse data is not valid and the problem is most likely related", - "to the parser in base R. Please install R >= 3.2 and try again." - )) - } - } - TRUE -} #' Identify strings that were not fully parsed #' diff --git a/R/roxygen-examples-find.R b/R/roxygen-examples-find.R index 6b0be661e..941414b14 100644 --- a/R/roxygen-examples-find.R +++ b/R/roxygen-examples-find.R @@ -22,7 +22,7 @@ identify_start_to_stop_of_roxygen_examples_from_text <- function(text) { } identify_start_to_stop_of_roxygen_examples <- function(path) { - content <- xfun::read_utf8(path) + content <- read_utf8_bare(path) identify_start_to_stop_of_roxygen_examples_from_text(content) } diff --git a/R/rules-line-breaks.R b/R/rules-line-breaks.R index eb93240e4..3212ee46f 100644 --- a/R/rules-line-breaks.R +++ b/R/rules-line-breaks.R @@ -41,7 +41,8 @@ #' # brace expressions go on new line if part of a pipe, in function call... #' c( #' data %>% -#' filter(bar) %>% { +#' filter(bar) %>% +#' { #' cor(.$col1, .$col2, use = "complete.obs") #' } #' ) diff --git a/R/rules-tokens.R b/R/rules-tokens.R index d0517499b..50ddc1a59 100644 --- a/R/rules-tokens.R +++ b/R/rules-tokens.R @@ -17,6 +17,13 @@ resolve_semicolon <- function(pd) { } add_brackets_in_pipe <- function(pd) { + if (!identical(pd$text[next_non_comment(pd, 0L)], "substitute")) { + pd$child <- map(pd$child, add_brackets_in_pipe_child) + } + pd +} + +add_brackets_in_pipe_child <- function(pd) { is_pipe <- pd$token %in% c("SPECIAL-PIPE", "PIPE") Reduce(add_brackets_in_pipe_one, which(is_pipe), init = pd) } diff --git a/R/stylerignore.R b/R/stylerignore.R index 7a107bf6e..246f83002 100644 --- a/R/stylerignore.R +++ b/R/stylerignore.R @@ -48,13 +48,15 @@ env_add_stylerignore <- function(pd_flat) { #' #' See examples in [stylerignore]. Note that you should reuse the stylerignore #' column to compute switch points or similar and not a plain -#' `pd$text == option_read("styler.ignore_start")` because that will fail to +#' `pd$text %in% option_read("styler.ignore_start")` because that will fail to #' give correct switch points in the case stylerignore sequences are invalid. #' @param pd_flat A parse table. #' @keywords internal add_stylerignore <- function(pd_flat) { parse_text <- trimws(pd_flat$text) - start_candidate <- parse_text == option_read("styler.ignore_start") + start_candidate <- grepl( + option_read("styler.ignore_start"), parse_text + ) & pd_flat$token == "COMMENT" pd_flat$stylerignore <- rep(FALSE, length(start_candidate)) env_current$any_stylerignore <- any(start_candidate) if (!env_current$any_stylerignore) { @@ -64,7 +66,10 @@ add_stylerignore <- function(pd_flat) { pd_flat_lat_line1 <- lag(pd_flat$line2, default = 0) on_same_line <- pd_flat$line1 == pd_flat_lat_line1 cumsum_start <- cumsum(start_candidate & !on_same_line) - cumsum_stop <- cumsum(parse_text == option_read("styler.ignore_stop")) + cumsum_stop <- cumsum( + grepl(option_read("styler.ignore_stop"), parse_text) & + pd_flat$token == "COMMENT" + ) pd_flat$indicator_off <- cumsum_start + cumsum_stop is_invalid <- cumsum_start - cumsum_stop < 0 | cumsum_start - cumsum_stop > 1 if (any(is_invalid)) { diff --git a/R/testing.R b/R/testing.R index 9754b9a16..e1de386e8 100644 --- a/R/testing.R +++ b/R/testing.R @@ -110,7 +110,7 @@ transform_and_check <- function(in_item, out_item, write_tree = NA, out_tree = "_tree", ...) { write_tree <- set_arg_write_tree(write_tree) - read_in <- xfun::read_utf8(in_item) + read_in <- read_utf8_bare(in_item) if (write_tree) { create_tree(read_in) %>% write.table(out_tree, @@ -337,6 +337,7 @@ activate_testthat_cache <- purrr::partial(cache_activate, "testthat") #' @param .local_envir The environment to use for scoping. #' @details #' * make styler quiet. +#' @keywords internal local_test_setup <- function(cache = FALSE, .local_envir = parent.frame()) { current_cache <- cache_info(format = "tabular") diff --git a/R/transform-files.R b/R/transform-files.R index b8cf90f0c..6a5d29c06 100644 --- a/R/transform-files.R +++ b/R/transform-files.R @@ -88,7 +88,7 @@ make_transformer <- function(transformers, assert_transformers(transformers) function(text) { - text <- trimws(text, which = "right") + text <- ensure_last_n_empty(trimws(text, which = "right"), n = 0L) should_use_cache <- cache_is_activated() if (should_use_cache) { @@ -232,7 +232,7 @@ parse_transform_serialize_r <- function(text, return("") } transformers <- transformers_drop( - if (getRversion() < 3.4) text else pd_nested$text[!pd_nested$is_cached], + pd_nested$text[!pd_nested$is_cached], transformers ) diff --git a/R/ui-styling.R b/R/ui-styling.R index 5e4a88d1d..bd035c336 100644 --- a/R/ui-styling.R +++ b/R/ui-styling.R @@ -229,7 +229,7 @@ style_text <- function(text, #' @family stylers #' @examples #' \dontrun{ -#' style_dir("path/to/dir", file_type = c("rmd", ".R")) +#' style_dir("path/to/dir", filetype = c("rmd", ".R")) #' #' # the following is identical (because of ... and defaults) #' # but the first is most convenient: @@ -312,7 +312,7 @@ prettify_any <- function(transformers, #' @inheritSection style_pkg Round trip validation #' @examples #' file <- tempfile("styler", fileext = ".R") -#' xfun::write_utf8("1++1", file) +#' writeLines("1++1", file) #' #' # the following is identical (because of ... and defaults), #' # but the first is most convenient: @@ -325,7 +325,7 @@ prettify_any <- function(transformers, #' # name levels explicitly to not style less invasive levels #' style_file(file, scope = I(c("tokens", "spaces")), strict = TRUE) #' -#' xfun::read_utf8(file) +#' readLines(file) #' unlink(file) #' @family stylers #' @export diff --git a/R/utils-cache.R b/R/utils-cache.R index a1991d4ea..517ddd6c8 100644 --- a/R/utils-cache.R +++ b/R/utils-cache.R @@ -1,13 +1,13 @@ #' Standardize text for hashing #' #' Make sure text after styling results in the same hash as text before styling -#' if it is indeed identical. +#' if it is indeed identical. This function expects trailing blank lines in +#' `text` were removed prior to passing it to this function. #' @param text A character vector. #' @keywords internal hash_standardize <- function(text) { text %>% convert_newlines_to_linebreaks() %>% - ensure_last_n_empty() %>% enc2utf8() %>% paste0(collapse = "\n") %>% list() @@ -24,7 +24,7 @@ hash_standardize <- function(text) { is_cached <- function(text, transformers, more_specs, - cache_dir = cache_dir_default()) { + cache_dir = get_cache_dir()) { R.cache::generateCache( key = cache_make_key(text, transformers, more_specs), dirs = cache_dir @@ -41,7 +41,7 @@ is_cached <- function(text, #' @param transformers A list of transformer functions, because we can only #' know if text is already correct if we know which transformer function it #' should be styled with. -#' @param more_args A named vector coercible to it character that determine the +#' @param more_specs A named vector coercible to character that determines the #' styling but are style guide independent, such as `include_roxygen_examples` #' or `base_indention`. #' @details @@ -111,7 +111,7 @@ cache_make_key <- function(text, transformers, more_specs) { #' @keywords internal cache_find_path <- function(cache_name = NULL) { cache_name <- cache_get_or_derive_name(cache_name) - R.cache::getCachePath(c("styler", cache_name)) + R.cache::getCachePath(get_cache_dir(cache_name)) } #' Check if a cache is activated @@ -173,7 +173,7 @@ cache_by_expression <- function(text, cache_write <- function(text, transformers, more_specs) { R.cache::generateCache( key = cache_make_key(text, transformers, more_specs), - dirs = cache_dir_default() + dirs = get_cache_dir() ) %>% file.create() } @@ -194,8 +194,8 @@ cache_get_or_derive_name <- function(cache_name) { cache_name } -cache_dir_default <- function() { - c("styler", cache_get_name()) +get_cache_dir <- function(cache_name = cache_get_name()) { + c(getOption("styler.cache_root", "styler"), cache_name) } diff --git a/R/zzz.R b/R/zzz.R index 2917d4f6f..4356d0a1c 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,22 +1,45 @@ .onLoad <- function(libname, pkgname) { - backports::import(pkgname, "trimws") op <- options() op.styler <- list( styler.addins_style_transformer = "styler::tidyverse_style()", + styler.cache_root = NULL, styler.cache_name = styler_version, styler.colored_print.vertical = TRUE, - styler.ignore_start = "# styler: off", - styler.ignore_stop = "# styler: on", + styler.ignore_start = "styler: off", + styler.ignore_stop = "styler: on", styler.quiet = FALSE, styler.test_dir_writable = TRUE ) toset <- !(names(op.styler) %in% names(op)) if (any(toset)) options(op.styler[toset]) + ask_to_switch_to_non_default_cache_root() remove_cache_old_versions() remove_old_cache_files() invisible() } + +ask_to_switch_to_non_default_cache_root <- function(ask = interactive()) { + if (ask && runif(1) > 0.9 && is.null(getOption("styler.cache_root"))) { + cli::cli_inform(paste0( + "The R option `styler.cache_root` is not set, which means the cache ", + "will get cleaned up after 6 days (and repeated styling will be slower).", + " To keep cache files longer, set ", + "the option to location within the {{R.cache}} cache where you want to ", + "store the cache, e.g. `\"styler-perm\"`.\n\n", + "options(styler.cache_root = \"styler-perm\")\n\n", + "in your .Rprofile. Note that the cache literally ", + "takes zero space on your disk, only the inode, and you can always ", + "manually clean up with `styler::cache_clear()`, and if you update the ", + "{{styler}} package, the cache is removed in any case. To ignore this ", + "message in the future, set the default explictly to \"styler\" with\n\n", + "options(styler.cache_root = \"styler\")\n\nin your `.Rprofile`. This ", + "message will only be displayed once in a while.\n" + )) + options(styler.cache_root = "styler") + } +} + remove_old_cache_files <- function() { all_cached <- list.files( R.cache::getCachePath(c("styler", styler_version)), diff --git a/README.Rmd b/README.Rmd index 8c05c87f6..7f25cb253 100644 --- a/README.Rmd +++ b/README.Rmd @@ -19,7 +19,7 @@ knitr::opts_chunk$set( [![R build status](https://github.com/r-lib/styler/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/styler/actions) [![Life cycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html) -[![codecov test coverage](https://codecov.io/gh/r-lib/styler/branch/master/graph/badge.svg)](https://codecov.io/gh/r-lib/styler) +[![codecov test coverage](https://codecov.io/gh/r-lib/styler/branch/main/graph/badge.svg)](https://codecov.io/gh/r-lib/styler) [![CRAN Status](https://www.r-pkg.org/badges/version/styler)](https://cran.r-project.org/package=styler) diff --git a/README.md b/README.md index f05c722d1..4ad42762a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ status](https://github.com/r-lib/styler/workflows/R-CMD-check/badge.svg)](https: [![Life cycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html) [![codecov test -coverage](https://codecov.io/gh/r-lib/styler/branch/master/graph/badge.svg)](https://codecov.io/gh/r-lib/styler) +coverage](https://codecov.io/gh/r-lib/styler/branch/main/graph/badge.svg)](https://codecov.io/gh/r-lib/styler) [![CRAN Status](https://www.r-pkg.org/badges/version/styler)](https://cran.r-project.org/package=styler) diff --git a/_pkgdown.yml b/_pkgdown.yml index c6dac5a27..080c0ac2f 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -42,6 +42,7 @@ template: api_key: 13580d327d8a7159f83a7cff178d2141 index_name: r-lib_styler + authors: Kirill Müller: href: https://krlmlr.info @@ -76,5 +77,7 @@ articles: - title: Developers navbar: Developers contents: - - caching + - remove_rules - customizing_styler + - distribute_custom_style_guides + - caching diff --git a/inst/WORDLIST b/inst/WORDLIST index 5caeaf2ef..e01a1a2db 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -64,6 +64,7 @@ filetype forcond formatter funct +gadenbuie gcc getChecksum getOption @@ -71,6 +72,7 @@ getRversion ggplot github gitsum +grkstyle GSOC hashFiles helpfiles @@ -103,6 +105,7 @@ LF LIBS lifecycle Ligges +lintr linux lorenz lorenzwalthert @@ -111,6 +114,7 @@ macOS magrittr md MERCHANTABILITY +mlr Müller mutli na @@ -121,6 +125,7 @@ NONINFRINGEMENT nph NUM oldrel +oneliner os ourself packagemanager @@ -166,10 +171,12 @@ rmd Rmd rnw Rnw +roadmap roclet roclets rootPath ROOTPATH +ropensci roundtrip roxgen roxygen @@ -190,6 +197,7 @@ rstudioapi saamwerk saveRDS seealso +semicoloner sep sessioninfo setCacheRootPath @@ -200,6 +208,7 @@ shinymeta shinyMonacoEditor shinyobjects ShinyQuickStarter +spaceout sprintf stackoverflow StackOverflow diff --git a/inst/hooks/require-news-update.R b/inst/hooks/require-news-update.R index 5fc72578d..05d8c950c 100755 --- a/inst/hooks/require-news-update.R +++ b/inst/hooks/require-news-update.R @@ -1,7 +1,7 @@ #! /usr/local/bin/Rscript args <- system2( "git", - c("diff", "upstream/master", "--name-only"), + c("diff", "upstream/main", "--name-only"), stdout = TRUE ) diff --git a/man/add_stylerignore.Rd b/man/add_stylerignore.Rd index d00725f3b..e9262cc31 100644 --- a/man/add_stylerignore.Rd +++ b/man/add_stylerignore.Rd @@ -24,7 +24,7 @@ the R options \code{styler.ignore_start} and \code{styler.ignore_stop}. See examples in \link{stylerignore}. Note that you should reuse the stylerignore column to compute switch points or similar and not a plain -\code{pd$text == option_read("styler.ignore_start")} because that will fail to +\code{pd$text \%in\% option_read("styler.ignore_start")} because that will fail to give correct switch points in the case stylerignore sequences are invalid. } \keyword{internal} diff --git a/man/cache_by_expression.Rd b/man/cache_by_expression.Rd index c5dbfb39f..3ae78e774 100644 --- a/man/cache_by_expression.Rd +++ b/man/cache_by_expression.Rd @@ -12,6 +12,10 @@ cache_by_expression(text, transformers, more_specs) \item{transformers}{A list of transformer functions, because we can only know if text is already correct if we know which transformer function it should be styled with.} + +\item{more_specs}{A named vector coercible to character that determines the +styling but are style guide independent, such as \code{include_roxygen_examples} +or \code{base_indention}.} } \description{ Splits \code{text} into expressions and adds these to the cache. Note that diff --git a/man/cache_make_key.Rd b/man/cache_make_key.Rd index dc9f4bd1c..ec1cdb9d8 100644 --- a/man/cache_make_key.Rd +++ b/man/cache_make_key.Rd @@ -14,7 +14,7 @@ approach used by styler does not cache input, but styled code.} know if text is already correct if we know which transformer function it should be styled with.} -\item{more_args}{A named vector coercible to it character that determine the +\item{more_specs}{A named vector coercible to character that determines the styling but are style guide independent, such as \code{include_roxygen_examples} or \code{base_indention}.} } diff --git a/man/cache_write.Rd b/man/cache_write.Rd index 286e9abe0..703ba5328 100644 --- a/man/cache_write.Rd +++ b/man/cache_write.Rd @@ -13,6 +13,10 @@ approach used by styler does not cache input, but styled code.} \item{transformers}{A list of transformer functions, because we can only know if text is already correct if we know which transformer function it should be styled with.} + +\item{more_specs}{A named vector coercible to character that determines the +styling but are style guide independent, such as \code{include_roxygen_examples} +or \code{base_indention}.} } \description{ Write to the cache diff --git a/man/combine_children.Rd b/man/combine_children.Rd index fef5d4a3a..f587b9aaf 100644 --- a/man/combine_children.Rd +++ b/man/combine_children.Rd @@ -16,8 +16,8 @@ Binds two parse tables together and arranges them so that the tokens are in the correct order. } \details{ -Essentially, this is a wrapper around \code{\link[dplyr:bind]{dplyr::bind_rows()}}, but -returns \code{NULL} if the result of \code{\link[dplyr:bind]{dplyr::bind_rows()}} is a data frame with +Essentially, this is a wrapper around \code{\link[dplyr:bind_rows]{dplyr::bind_rows()}}, but +returns \code{NULL} if the result of \code{\link[dplyr:bind_rows]{dplyr::bind_rows()}} is a data frame with zero rows. } \keyword{internal} diff --git a/man/ensure_valid_pd.Rd b/man/ensure_valid_pd.Rd deleted file mode 100644 index c6e1cd8d9..000000000 --- a/man/ensure_valid_pd.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/parse.R -\name{ensure_valid_pd} -\alias{ensure_valid_pd} -\title{Ensure that the parse data is valid} -\usage{ -ensure_valid_pd(pd) -} -\arguments{ -\item{pd}{A parse table.} -} -\description{ -Test whether all non-terminals have at least one child and throw an error -otherwise. As this is check is rather expensive, it is only -carried out for configurations we have good reasons to expect problems. -} -\keyword{internal} diff --git a/man/hash_standardize.Rd b/man/hash_standardize.Rd index 8f210cc1e..104b8e85b 100644 --- a/man/hash_standardize.Rd +++ b/man/hash_standardize.Rd @@ -11,6 +11,7 @@ hash_standardize(text) } \description{ Make sure text after styling results in the same hash as text before styling -if it is indeed identical. +if it is indeed identical. This function expects trailing blank lines in +\code{text} were removed prior to passing it to this function. } \keyword{internal} diff --git a/man/is_cached.Rd b/man/is_cached.Rd index 1ef4e9783..868c7c50f 100644 --- a/man/is_cached.Rd +++ b/man/is_cached.Rd @@ -4,7 +4,7 @@ \alias{is_cached} \title{Check if text is cached} \usage{ -is_cached(text, transformers, more_specs, cache_dir = cache_dir_default()) +is_cached(text, transformers, more_specs, cache_dir = get_cache_dir()) } \arguments{ \item{text, transformers, more_specs}{Passed to \code{\link[=cache_make_key]{cache_make_key()}} to generate diff --git a/man/local_test_setup.Rd b/man/local_test_setup.Rd index 108b3eb68..ddc76702c 100644 --- a/man/local_test_setup.Rd +++ b/man/local_test_setup.Rd @@ -20,3 +20,4 @@ Establish testing setup for current environment \item make styler quiet. } } +\keyword{internal} diff --git a/man/rds_to_version.Rd b/man/rds_to_version.Rd index 59d9d15b7..5a4b236a4 100644 --- a/man/rds_to_version.Rd +++ b/man/rds_to_version.Rd @@ -12,6 +12,6 @@ rds_to_version(path, version = 2) \item{version}{The target version.} } \description{ -Needed to make \code{\link[testthat:expect_known_output]{testthat::expect_known_value()}} work on R < 3.6. +Needed to make \code{\link[testthat:expect_known_value]{testthat::expect_known_value()}} work on R < 3.6. } \keyword{internal} diff --git a/man/set_line_break_before_curly_opening.Rd b/man/set_line_break_before_curly_opening.Rd index bae84e953..f2f2efd9a 100644 --- a/man/set_line_break_before_curly_opening.Rd +++ b/man/set_line_break_before_curly_opening.Rd @@ -50,7 +50,8 @@ tryGugus( # brace expressions go on new line if part of a pipe, in function call... c( data \%>\% - filter(bar) \%>\% { + filter(bar) \%>\% + { cor(.$col1, .$col2, use = "complete.obs") } ) diff --git a/man/style_dir.Rd b/man/style_dir.Rd index da4060a82..1ce1c6310 100644 --- a/man/style_dir.Rd +++ b/man/style_dir.Rd @@ -110,7 +110,7 @@ See section 'Warning' for a good strategy to apply styling safely. \examples{ \dontrun{ -style_dir("path/to/dir", file_type = c("rmd", ".R")) +style_dir("path/to/dir", filetype = c("rmd", ".R")) # the following is identical (because of ... and defaults) # but the first is most convenient: diff --git a/man/style_file.Rd b/man/style_file.Rd index 3c58e917f..95fec034e 100644 --- a/man/style_file.Rd +++ b/man/style_file.Rd @@ -97,7 +97,7 @@ See section 'Warning' for a good strategy to apply styling safely. \examples{ file <- tempfile("styler", fileext = ".R") -xfun::write_utf8("1++1", file) +writeLines("1++1", file) # the following is identical (because of ... and defaults), # but the first is most convenient: @@ -110,7 +110,7 @@ style_file(file, scope = "indention", strict = TRUE) # name levels explicitly to not style less invasive levels style_file(file, scope = I(c("tokens", "spaces")), strict = TRUE) -xfun::read_utf8(file) +readLines(file) unlink(file) } \seealso{ diff --git a/man/styler_addins.Rd b/man/styler_addins.Rd index 052b6ffa6..24daeb37f 100644 --- a/man/styler_addins.Rd +++ b/man/styler_addins.Rd @@ -10,8 +10,8 @@ Helper functions for styling via RStudio Addins. \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 +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 diff --git a/man/stylerignore.Rd b/man/stylerignore.Rd index abf91f23a..f43563654 100644 --- a/man/stylerignore.Rd +++ b/man/stylerignore.Rd @@ -10,23 +10,21 @@ for \verb{styler > 1.2.0}, some alignment is making stylerignore redundant. See a few illustrative examples below. } \details{ -Styling is on by default when you run styler. +Styling is on for all lines by default when you run styler. \itemize{ \item To mark the start of a sequence where you want to turn styling off, use \verb{# styler: off}. \item To mark the end of this sequence, put \verb{# styler: on} in your code. After that line, styler will again format your code. \item To ignore an inline statement (i.e. just one line), place \verb{# styler: off} -at the end of the line. Note that inline statements cannot contain other -comments apart from the marker, i.e. a line like -\code{1 # comment # styler: off} won't be ignored. -} - +at the end of the line. To use something else as start and stop markers, set the R options \code{styler.ignore_start} and -\code{styler.ignore_stop} using \code{\link[=options]{options()}}. If you want these -settings to persist over multiple R sessions, consider setting them in your -R profile, e.g. with \code{usethis::edit_rprofile()}. +\code{styler.ignore_stop} using \code{\link[=options]{options()}}. For styler version > 1.6.2, the +option supports character vectors longer than one and the marker are not +exactly matched, but using a regular expression, which means you can have +multiple marker on one line, e.g. \verb{# nolint start styler: off}. +} } \examples{ # as long as the order of the markers is correct, the lines are ignored. diff --git a/man/write_utf8.Rd b/man/write_utf8.Rd new file mode 100644 index 000000000..9955e86e2 --- /dev/null +++ b/man/write_utf8.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/io.R +\name{write_utf8} +\alias{write_utf8} +\title{Drop-in replacement for \code{xfun::write_utf8()}} +\usage{ +write_utf8(text, con, ...) +} +\description{ +Drop-in replacement for \code{xfun::write_utf8()} +} +\keyword{internal} diff --git a/tests/testthat/indention_multiple/edge_strict_random-in.R b/tests/testthat/indention_multiple/edge_strict_random-in.R index cc8f8c0c5..7ec47f29d 100644 --- a/tests/testthat/indention_multiple/edge_strict_random-in.R +++ b/tests/testthat/indention_multiple/edge_strict_random-in.R @@ -11,4 +11,3 @@ { c("x", "y", "z", "sin(x)") } - diff --git a/tests/testthat/indention_operators/plus_minus-in.R b/tests/testthat/indention_operators/plus_minus-in.R index a543addce..079b0918f 100644 --- a/tests/testthat/indention_operators/plus_minus-in.R +++ b/tests/testthat/indention_operators/plus_minus-in.R @@ -5,4 +5,3 @@ 5 1 + 1 - diff --git a/tests/testthat/indention_round_brackets/arithmetic_no_start-in.R b/tests/testthat/indention_round_brackets/arithmetic_no_start-in.R index e4d2a565a..01e7fb8e3 100644 --- a/tests/testthat/indention_round_brackets/arithmetic_no_start-in.R +++ b/tests/testthat/indention_round_brackets/arithmetic_no_start-in.R @@ -1,4 +1,3 @@ 1 + 2 + ( 3 + 4) - diff --git a/tests/testthat/insertion_comment_interaction/if_else_if_else_non_strict-in.R b/tests/testthat/insertion_comment_interaction/if_else_if_else_non_strict-in.R index 7296968b6..7699633d2 100644 --- a/tests/testthat/insertion_comment_interaction/if_else_if_else_non_strict-in.R +++ b/tests/testthat/insertion_comment_interaction/if_else_if_else_non_strict-in.R @@ -38,4 +38,3 @@ TRUE)NULL else if(FALSE)NULL else NULL if # comment (TRUE)NULL else if(FALSE)NULL else NULL - diff --git a/tests/testthat/insertion_comment_interaction/if_else_if_else_strict-in.R b/tests/testthat/insertion_comment_interaction/if_else_if_else_strict-in.R index 7296968b6..7699633d2 100644 --- a/tests/testthat/insertion_comment_interaction/if_else_if_else_strict-in.R +++ b/tests/testthat/insertion_comment_interaction/if_else_if_else_strict-in.R @@ -38,4 +38,3 @@ TRUE)NULL else if(FALSE)NULL else NULL if # comment (TRUE)NULL else if(FALSE)NULL else NULL - diff --git a/tests/testthat/insertion_comment_interaction/just_if_strict-in.R b/tests/testthat/insertion_comment_interaction/just_if_strict-in.R index 643a9de03..5fbaf5d47 100644 --- a/tests/testthat/insertion_comment_interaction/just_if_strict-in.R +++ b/tests/testthat/insertion_comment_interaction/just_if_strict-in.R @@ -13,4 +13,4 @@ if( # comment TRUE)NULL if # comment -(TRUE)NULL \ No newline at end of file +(TRUE)NULL diff --git a/tests/testthat/public-api/xyzfile-rnw/random4.Rnw b/tests/testthat/public-api/xyzfile-rnw/random4.Rnw index 4b929ff4c..691bda529 100644 --- a/tests/testthat/public-api/xyzfile-rnw/random4.Rnw +++ b/tests/testthat/public-api/xyzfile-rnw/random4.Rnw @@ -11,7 +11,7 @@ f <- function(x) { @ More text -<<>>= +<>= # More R code which is invalid g <- function(y) { y diff --git a/tests/testthat/public-api/xyzpackage-rmd/NAMESPACE b/tests/testthat/public-api/xyzpackage-rmd/NAMESPACE index 6ae926839..e651b9448 100644 --- a/tests/testthat/public-api/xyzpackage-rmd/NAMESPACE +++ b/tests/testthat/public-api/xyzpackage-rmd/NAMESPACE @@ -1,2 +1 @@ # Generated by roxygen2: do not edit by hand - diff --git a/tests/testthat/public-api/xyzpackage-rnw/NAMESPACE b/tests/testthat/public-api/xyzpackage-rnw/NAMESPACE index 6ae926839..e651b9448 100644 --- a/tests/testthat/public-api/xyzpackage-rnw/NAMESPACE +++ b/tests/testthat/public-api/xyzpackage-rnw/NAMESPACE @@ -1,2 +1 @@ # Generated by roxygen2: do not edit by hand - diff --git a/tests/testthat/rnw/011-conditional-eval-in.Rnw b/tests/testthat/rnw/011-conditional-eval-in.Rnw index 14b53e0ba..e33cd957e 100644 --- a/tests/testthat/rnw/011-conditional-eval-in.Rnw +++ b/tests/testthat/rnw/011-conditional-eval-in.Rnw @@ -7,11 +7,11 @@ dothis <- TRUE @ -<>= +<>= print( "say hello world" ) @ -<>= +<>= print( "silence is gold" ) @ diff --git a/tests/testthat/rnw/011-conditional-eval-out.Rnw b/tests/testthat/rnw/011-conditional-eval-out.Rnw index 48f3a9348..67c6d81a1 100644 --- a/tests/testthat/rnw/011-conditional-eval-out.Rnw +++ b/tests/testthat/rnw/011-conditional-eval-out.Rnw @@ -7,11 +7,11 @@ dothis <- TRUE @ -<>= +<>= print("say hello world") @ -<>= +<>= print("silence is gold") @ diff --git a/tests/testthat/roxygen-examples-complete/6-multiple-function-examples-no-last-run-in.R b/tests/testthat/roxygen-examples-complete/6-multiple-function-examples-no-last-run-in.R index 8ae3f8614..9b8c45923 100644 --- a/tests/testthat/roxygen-examples-complete/6-multiple-function-examples-no-last-run-in.R +++ b/tests/testthat/roxygen-examples-complete/6-multiple-function-examples-no-last-run-in.R @@ -20,4 +20,3 @@ a <- 2 #' @importFrom purrr partial #' @export a <- call; - diff --git a/tests/testthat/roxygen-examples-identify/6-multiple-function-examples-not-last-proper-run.R b/tests/testthat/roxygen-examples-identify/6-multiple-function-examples-not-last-proper-run.R index 2156d22ad..1ecfe7bcf 100644 --- a/tests/testthat/roxygen-examples-identify/6-multiple-function-examples-not-last-proper-run.R +++ b/tests/testthat/roxygen-examples-identify/6-multiple-function-examples-not-last-proper-run.R @@ -18,4 +18,3 @@ a <- 2 #' @importFrom purrr partial #' @export a <- call - diff --git a/tests/testthat/serialize_tests/correct-in.R b/tests/testthat/serialize_tests/correct-in.R index d70f6df36..01e79c32a 100644 --- a/tests/testthat/serialize_tests/correct-in.R +++ b/tests/testthat/serialize_tests/correct-in.R @@ -1,4 +1,3 @@ 1 2 3 - diff --git a/tests/testthat/serialize_tests/correct-out.R b/tests/testthat/serialize_tests/correct-out.R index d70f6df36..01e79c32a 100644 --- a/tests/testthat/serialize_tests/correct-out.R +++ b/tests/testthat/serialize_tests/correct-out.R @@ -1,4 +1,3 @@ 1 2 3 - diff --git a/tests/testthat/stylerignore/alignment-in.R b/tests/testthat/stylerignore/alignment-in.R new file mode 100644 index 000000000..b128cbac5 --- /dev/null +++ b/tests/testthat/stylerignore/alignment-in.R @@ -0,0 +1,5 @@ +ps( + interaction_constraints = p_uty(tgs = "train"), + monotone_constraints = p_uty(dfault = 0, tags = c("train", "control"), custom_check = function(x) { checkmate::check_integerish(x, lower = -1, upper = 1, any.missing = FALSE) }), # styler: off + normalize_type = p_fct(c("tee", "forest"), default = "tree", tags = "train"), +) diff --git a/tests/testthat/stylerignore/alignment-in_tree b/tests/testthat/stylerignore/alignment-in_tree new file mode 100644 index 000000000..18ae34374 --- /dev/null +++ b/tests/testthat/stylerignore/alignment-in_tree @@ -0,0 +1,110 @@ +ROOT (token: short_text [lag_newlines/spaces] {pos_id}) + °--expr: ps( + [0/0] {1} + ¦--expr: ps [0/0] {3} + ¦ °--SYMBOL_FUNCTION_CALL: ps [0/0] {2} + ¦--'(': ( [0/2] {4} + ¦--SYMBOL_SUB: inter [1/1] {5} + ¦--EQ_SUB: = [0/1] {6} + ¦--expr: p_uty [0/0] {7} + ¦ ¦--expr: p_uty [0/0] {9} + ¦ ¦ °--SYMBOL_FUNCTION_CALL: p_uty [0/0] {8} + ¦ ¦--'(': ( [0/0] {10} + ¦ ¦--SYMBOL_SUB: tgs [0/1] {11} + ¦ ¦--EQ_SUB: = [0/1] {12} + ¦ ¦--expr: "trai [0/0] {14} + ¦ ¦ °--STR_CONST: "trai [0/0] {13} + ¦ °--')': ) [0/0] {15} + ¦--',': , [0/2] {16} + ¦--SYMBOL_SUB: monot [1/4] {17} + ¦--EQ_SUB: = [0/1] {18} + ¦--expr: p_uty [0/0] {19} + ¦ ¦--expr: p_uty [0/0] {21} + ¦ ¦ °--SYMBOL_FUNCTION_CALL: p_uty [0/0] {20} + ¦ ¦--'(': ( [0/0] {22} + ¦ ¦--SYMBOL_SUB: dfaul [0/1] {23} + ¦ ¦--EQ_SUB: = [0/1] {24} + ¦ ¦--expr: 0 [0/0] {26} + ¦ ¦ °--NUM_CONST: 0 [0/0] {25} + ¦ ¦--',': , [0/1] {27} + ¦ ¦--SYMBOL_SUB: tags [0/1] {28} + ¦ ¦--EQ_SUB: = [0/1] {29} + ¦ ¦--expr: c("tr [0/0] {30} + ¦ ¦ ¦--expr: c [0/0] {32} + ¦ ¦ ¦ °--SYMBOL_FUNCTION_CALL: c [0/0] {31} + ¦ ¦ ¦--'(': ( [0/0] {33} + ¦ ¦ ¦--expr: "trai [0/0] {35} + ¦ ¦ ¦ °--STR_CONST: "trai [0/0] {34} + ¦ ¦ ¦--',': , [0/1] {36} + ¦ ¦ ¦--expr: "cont [0/0] {38} + ¦ ¦ ¦ °--STR_CONST: "cont [0/0] {37} + ¦ ¦ °--')': ) [0/0] {39} + ¦ ¦--',': , [0/1] {40} + ¦ ¦--SYMBOL_SUB: custo [0/1] {41} + ¦ ¦--EQ_SUB: = [0/1] {42} + ¦ ¦--expr: funct [0/0] {43} + ¦ ¦ ¦--FUNCTION: funct [0/0] {44} + ¦ ¦ ¦--'(': ( [0/0] {45} + ¦ ¦ ¦--SYMBOL_FORMALS: x [0/0] {46} + ¦ ¦ ¦--')': ) [0/1] {47} + ¦ ¦ °--expr: { ch [0/0] {48} + ¦ ¦ ¦--'{': { [0/2] {49} + ¦ ¦ ¦--expr: check [0/1] {50} + ¦ ¦ ¦ ¦--expr: check [0/0] {51} + ¦ ¦ ¦ ¦ ¦--SYMBOL_PACKAGE: check [0/0] {52} + ¦ ¦ ¦ ¦ ¦--NS_GET: :: [0/0] {53} + ¦ ¦ ¦ ¦ °--SYMBOL_FUNCTION_CALL: check [0/0] {54} + ¦ ¦ ¦ ¦--'(': ( [0/0] {55} + ¦ ¦ ¦ ¦--expr: x [0/0] {57} + ¦ ¦ ¦ ¦ °--SYMBOL: x [0/0] {56} + ¦ ¦ ¦ ¦--',': , [0/1] {58} + ¦ ¦ ¦ ¦--SYMBOL_SUB: lower [0/1] {59} + ¦ ¦ ¦ ¦--EQ_SUB: = [0/1] {60} + ¦ ¦ ¦ ¦--expr: -1 [0/0] {61} + ¦ ¦ ¦ ¦ ¦--'-': - [0/0] {62} + ¦ ¦ ¦ ¦ °--expr: 1 [0/0] {64} + ¦ ¦ ¦ ¦ °--NUM_CONST: 1 [0/0] {63} + ¦ ¦ ¦ ¦--',': , [0/1] {65} + ¦ ¦ ¦ ¦--SYMBOL_SUB: upper [0/1] {66} + ¦ ¦ ¦ ¦--EQ_SUB: = [0/1] {67} + ¦ ¦ ¦ ¦--expr: 1 [0/0] {69} + ¦ ¦ ¦ ¦ °--NUM_CONST: 1 [0/0] {68} + ¦ ¦ ¦ ¦--',': , [0/1] {70} + ¦ ¦ ¦ ¦--SYMBOL_SUB: any.m [0/1] {71} + ¦ ¦ ¦ ¦--EQ_SUB: = [0/1] {72} + ¦ ¦ ¦ ¦--expr: FALSE [0/0] {74} + ¦ ¦ ¦ ¦ °--NUM_CONST: FALSE [0/0] {73} + ¦ ¦ ¦ °--')': ) [0/0] {75} + ¦ ¦ °--'}': } [0/0] {76} + ¦ °--')': ) [0/0] {77} + ¦--',': , [0/1] {78} + ¦--COMMENT: # sty [0/2] {79} + ¦--SYMBOL_SUB: norma [1/10] {80} + ¦--EQ_SUB: = [0/1] {81} + ¦--expr: p_fct [0/0] {82} + ¦ ¦--expr: p_fct [0/0] {84} + ¦ ¦ °--SYMBOL_FUNCTION_CALL: p_fct [0/0] {83} + ¦ ¦--'(': ( [0/0] {85} + ¦ ¦--expr: c("te [0/0] {86} + ¦ ¦ ¦--expr: c [0/0] {88} + ¦ ¦ ¦ °--SYMBOL_FUNCTION_CALL: c [0/0] {87} + ¦ ¦ ¦--'(': ( [0/0] {89} + ¦ ¦ ¦--expr: "tee" [0/0] {91} + ¦ ¦ ¦ °--STR_CONST: "tee" [0/0] {90} + ¦ ¦ ¦--',': , [0/1] {92} + ¦ ¦ ¦--expr: "fore [0/0] {94} + ¦ ¦ ¦ °--STR_CONST: "fore [0/0] {93} + ¦ ¦ °--')': ) [0/0] {95} + ¦ ¦--',': , [0/1] {96} + ¦ ¦--SYMBOL_SUB: defau [0/1] {97} + ¦ ¦--EQ_SUB: = [0/1] {98} + ¦ ¦--expr: "tree [0/0] {100} + ¦ ¦ °--STR_CONST: "tree [0/0] {99} + ¦ ¦--',': , [0/1] {101} + ¦ ¦--SYMBOL_SUB: tags [0/1] {102} + ¦ ¦--EQ_SUB: = [0/1] {103} + ¦ ¦--expr: "trai [0/0] {105} + ¦ ¦ °--STR_CONST: "trai [0/0] {104} + ¦ °--')': ) [0/0] {106} + ¦--',': , [0/0] {107} + °--')': ) [1/0] {108} diff --git a/tests/testthat/stylerignore/alignment-out.R b/tests/testthat/stylerignore/alignment-out.R new file mode 100644 index 000000000..b128cbac5 --- /dev/null +++ b/tests/testthat/stylerignore/alignment-out.R @@ -0,0 +1,5 @@ +ps( + interaction_constraints = p_uty(tgs = "train"), + monotone_constraints = p_uty(dfault = 0, tags = c("train", "control"), custom_check = function(x) { checkmate::check_integerish(x, lower = -1, upper = 1, any.missing = FALSE) }), # styler: off + normalize_type = p_fct(c("tee", "forest"), default = "tree", tags = "train"), +) diff --git a/tests/testthat/stylerignore/simple-in.R b/tests/testthat/stylerignore/simple-in.R index da04e6081..f507d8cea 100644 --- a/tests/testthat/stylerignore/simple-in.R +++ b/tests/testthat/stylerignore/simple-in.R @@ -23,4 +23,3 @@ more_calls(with(arguments)) # styler: off 1 + 1 a(!b) - diff --git a/tests/testthat/test-parsing.R b/tests/testthat/test-parsing.R index 08d3d410b..73d0db1cf 100644 --- a/tests/testthat/test-parsing.R +++ b/tests/testthat/test-parsing.R @@ -21,15 +21,13 @@ test_that("repreated parsing solves wrong parent assignment", { "R -q -e \"styler::cache_deactivate(); styler::style_file(\\\"", path_temp, "\\\")\"" ) calls_sys(sys_call, intern = FALSE, ignore.stdout = TRUE, ignore.stderr = TRUE) - ref <- xfun::read_utf8(testthat_file("parsing", "repeated_parsing-out.R")) - result <- xfun::read_utf8(path_temp) + ref <- read_utf8_bare(testthat_file("parsing", "repeated_parsing-out.R")) + result <- read_utf8_bare(path_temp) expect_equal(ref, result) unlink(dir) }) test_that("long strings are parsed correctly", { - if (getRversion() < "3.2") skip("skip on R < 3.2 because of parsing problems") - expect_warning( test_collection("parsing", "long_strings", transformer = style_text), NA @@ -47,20 +45,7 @@ test_that("0x number representation is preserved with(out) L", { }) -test_that("issues with parsing long strings on R 3.1 can be detected", { - if (getRversion() >= "3.2") { - skip("skip on R >= 3.2 because parsing probmes don't appear") - } - expect_error( - test_collection("parsing", "long_strings", transformer = style_text), - "install R .* 3.2" - ) -}) - - test_that("CRLF EOLs fail with informative error", { - skip_if(getRversion() < "3.4") - expect_error( style_text("glück <- 3\r\n glück + 1"), "Please change the EOL character in your editor to Unix style and try again." diff --git a/tests/testthat/test-public_api.R b/tests/testthat/test-public_api.R index 177e975cf..5226db1cb 100644 --- a/tests/testthat/test-public_api.R +++ b/tests/testthat/test-public_api.R @@ -395,7 +395,7 @@ test_that("dry run options work:", { test_dry(test_path("public-api/dry/unstyled.Rmd"), style_file, styled = FALSE) test_dry(test_path("public-api/dry/styled.Rmd"), style_file, styled = TRUE) - ## Rmd + ## Rnw test_dry(test_path("public-api/dry/unstyled.Rnw"), style_file, styled = FALSE) test_dry(test_path("public-api/dry/styled.Rnw"), style_file, styled = TRUE) }) diff --git a/tests/testthat/test-stylerignore.R b/tests/testthat/test-stylerignore.R index c3c1af875..e17fb9adf 100644 --- a/tests/testthat/test-stylerignore.R +++ b/tests/testthat/test-stylerignore.R @@ -77,6 +77,35 @@ test_that("works with other markers", { ) }) + +test_that("works for multiple markers inline", { + withr::local_options(styler.ignore_start = "# noeq", ) + expect_equal( + style_text(c( + "1+1", + "1+1# noeq", + "1+1" + )) %>% + as.character(), + c("1 + 1", "1+1# noeq", "1 + 1") + ) +}) + + +test_that("works for multiple markers inline on one line", { + withr::local_options(styler.ignore_start = "nolint start|styler: off") + expect_equal( + style_text(c( + "1+1", + "1+1# nolint start styler: off", + "1+1" + )) %>% + as.character(), + c("1 + 1", "1+1# nolint start styler: off", "1 + 1") + ) +}) + + test_that("works with other markers", { expect_warning( withr::with_options( @@ -120,3 +149,9 @@ test_that("no token added or removed in complex case", { transformer = style_text ), NA) }) + +test_that("stylerignore sequences are respected in alignment detection", { + expect_warning(test_collection("stylerignore", "alignment", + transformer = style_text + ), NA) +}) diff --git a/tests/testthat/test-token_adding_removing.R b/tests/testthat/test-token_adding_removing.R index 2f42e5c15..0b2d2d28a 100644 --- a/tests/testthat/test-token_adding_removing.R +++ b/tests/testthat/test-token_adding_removing.R @@ -43,3 +43,9 @@ test_that("No braces are added if conditional statement is within pipe", { transformer = style_text ), NA) }) + +test_that("No brace is added within `substitute()`", { + expect_warning(test_collection("token_adding_removing", "substitute", + transformer = style_text + ), NA) +}) diff --git a/tests/testthat/token_adding_removing/add_brackets_in_pipe-in.R b/tests/testthat/token_adding_removing/add_brackets_in_pipe-in.R index 6bc56624d..a803abadb 100644 --- a/tests/testthat/token_adding_removing/add_brackets_in_pipe-in.R +++ b/tests/testthat/token_adding_removing/add_brackets_in_pipe-in.R @@ -3,4 +3,3 @@ 1 %x% y 1 %>% x 1 %s% 1 - diff --git a/tests/testthat/token_adding_removing/substitute-in.R b/tests/testthat/token_adding_removing/substitute-in.R new file mode 100644 index 000000000..83305008d --- /dev/null +++ b/tests/testthat/token_adding_removing/substitute-in.R @@ -0,0 +1,3 @@ +expr <- substitute(airquality %>% FUN_EXPR, env = list(FUN_EXPR = call("FUN_head"))) +a %>% + x diff --git a/tests/testthat/token_adding_removing/substitute-in_tree b/tests/testthat/token_adding_removing/substitute-in_tree new file mode 100644 index 000000000..70c35013e --- /dev/null +++ b/tests/testthat/token_adding_removing/substitute-in_tree @@ -0,0 +1,39 @@ +ROOT (token: short_text [lag_newlines/spaces] {pos_id}) + ¦--expr: expr [0/0] {1} + ¦ ¦--expr: expr [0/1] {3} + ¦ ¦ °--SYMBOL: expr [0/0] {2} + ¦ ¦--LEFT_ASSIGN: <- [0/1] {4} + ¦ °--expr: subst [0/0] {5} + ¦ ¦--expr: subst [0/0] {7} + ¦ ¦ °--SYMBOL_FUNCTION_CALL: subst [0/0] {6} + ¦ ¦--'(': ( [0/0] {8} + ¦ ¦--expr: airqu [0/0] {9} + ¦ ¦ ¦--expr: airqu [0/1] {11} + ¦ ¦ ¦ °--SYMBOL: airqu [0/0] {10} + ¦ ¦ ¦--SPECIAL-PIPE: %>% [0/1] {12} + ¦ ¦ °--expr: FUN_E [0/0] {14} + ¦ ¦ °--SYMBOL: FUN_E [0/0] {13} + ¦ ¦--',': , [0/1] {15} + ¦ ¦--SYMBOL_SUB: env [0/1] {16} + ¦ ¦--EQ_SUB: = [0/1] {17} + ¦ ¦--expr: list( [0/0] {18} + ¦ ¦ ¦--expr: list [0/0] {20} + ¦ ¦ ¦ °--SYMBOL_FUNCTION_CALL: list [0/0] {19} + ¦ ¦ ¦--'(': ( [0/0] {21} + ¦ ¦ ¦--SYMBOL_SUB: FUN_E [0/1] {22} + ¦ ¦ ¦--EQ_SUB: = [0/1] {23} + ¦ ¦ ¦--expr: call( [0/0] {24} + ¦ ¦ ¦ ¦--expr: call [0/0] {26} + ¦ ¦ ¦ ¦ °--SYMBOL_FUNCTION_CALL: call [0/0] {25} + ¦ ¦ ¦ ¦--'(': ( [0/0] {27} + ¦ ¦ ¦ ¦--expr: "FUN_ [0/0] {29} + ¦ ¦ ¦ ¦ °--STR_CONST: "FUN_ [0/0] {28} + ¦ ¦ ¦ °--')': ) [0/0] {30} + ¦ ¦ °--')': ) [0/0] {31} + ¦ °--')': ) [0/0] {32} + °--expr: a %>% [1/0] {33} + ¦--expr: a [0/1] {35} + ¦ °--SYMBOL: a [0/0] {34} + ¦--SPECIAL-PIPE: %>% [0/2] {36} + °--expr: x [1/0] {38} + °--SYMBOL: x [0/0] {37} diff --git a/tests/testthat/token_adding_removing/substitute-out.R b/tests/testthat/token_adding_removing/substitute-out.R new file mode 100644 index 000000000..415d84d87 --- /dev/null +++ b/tests/testthat/token_adding_removing/substitute-out.R @@ -0,0 +1,3 @@ +expr <- substitute(airquality %>% FUN_EXPR, env = list(FUN_EXPR = call("FUN_head"))) +a %>% + x() diff --git a/touchstone/script.R b/touchstone/script.R index 9d2a1e1d0..1bbcec1df 100644 --- a/touchstone/script.R +++ b/touchstone/script.R @@ -1,18 +1,18 @@ library(touchstone) -refs_install() +branch_install() -clear_ref_caches <- function() { - purrr::walk(c(ref_get_or_fail("GITHUB_BASE_REF"), ref_get_or_fail("GITHUB_HEAD_REF")), +clear_branch_caches <- function() { + purrr::walk(c(branch_get_or_fail("GITHUB_BASE_REF"), branch_get_or_fail("GITHUB_HEAD_REF")), styler::cache_clear, ask = FALSE ) } -clear_ref_caches() +clear_branch_caches() -benchmark_run_ref( +benchmark_run( expr_before_benchmark = { library(styler) cache_deactivate() @@ -21,8 +21,8 @@ benchmark_run_ref( n = 30 ) -clear_ref_caches() -benchmark_run_ref( +clear_branch_caches() +benchmark_run( expr_before_benchmark = { library(styler) cache_activate(gert::git_branch()) @@ -31,8 +31,9 @@ benchmark_run_ref( n = 30 ) -clear_ref_caches() -benchmark_run_ref( +clear_branch_caches() + +benchmark_run( expr_before_benchmark = { library(styler) cache_activate(gert::git_branch()) @@ -44,6 +45,6 @@ benchmark_run_ref( n = 30 ) -clear_ref_caches() +clear_branch_caches() -benchmarks_analyze() +benchmark_analyze() diff --git a/vignettes/caching.Rmd b/vignettes/caching.Rmd index 64048bd89..fa47d18fb 100644 --- a/vignettes/caching.Rmd +++ b/vignettes/caching.Rmd @@ -44,8 +44,8 @@ The main caching features were implemented in the following two pull requests: ```{r, eval = FALSE} function() { - # a comment - x = 2 # <- change this line + # a comment + x <- 2 # <- change this line } another(call) @@ -107,4 +107,3 @@ changes introduced here: For more detailed explanation and documentation, please consult the help files of the internals. - diff --git a/vignettes/customizing_styler.Rmd b/vignettes/customizing_styler.Rmd index 75d40b192..237009aa0 100644 --- a/vignettes/customizing_styler.Rmd +++ b/vignettes/customizing_styler.Rmd @@ -8,7 +8,11 @@ vignette: > --- This vignette provides a high-level overview of how styler works and how you can -define your own style guide and format code according to it. +define your own style guide and format code according to it. If you simply want +to customize the tidyverse style guide to your needs, check out +`vignette("styler")`, to remove some rules, have a look at +`vignette("remove_rules")`. How to distribute a custom style guide is described +in `vignette("distribute_custom_style_guides")`. # How styler works diff --git a/vignettes/detect-alignment.Rmd b/vignettes/detect-alignment.Rmd index a8c8b2b12..d2b5dfd84 100644 --- a/vignettes/detect-alignment.Rmd +++ b/vignettes/detect-alignment.Rmd @@ -60,7 +60,7 @@ tibble::tribble( "long string", "shrt" # columns can overlap ('~' above ',') ) -# right-aligned after = +# right-aligned after = purrr::map(x, fun, # arguments on same line as opening brace are not considered arg2 = 2, ar = f(k, x) @@ -122,7 +122,6 @@ gell( p = 2, g = gg(x), n = 3 * 3, # 31, fds = -1, gz = f / 3, ) - ``` ... or match position of `=` vertically and align everything after this operator diff --git a/vignettes/distribute_custom_style_guides.Rmd b/vignettes/distribute_custom_style_guides.Rmd new file mode 100644 index 000000000..94a4eaaec --- /dev/null +++ b/vignettes/distribute_custom_style_guides.Rmd @@ -0,0 +1,91 @@ +--- +title: "Distribute custom style guides" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Distribute custom style guides} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +This vignette describes how you can distribute your own style guide. It builds +on `vignette("customizing_styler")` and assumes you understand how to create a +style guide with `create_style_guide()`. + +## Reference implementations + +There are a few packages that implement a third-party style guide that are +maintained by styler contributors: + +* [lorenzwalthert/semicoloner](https://github.com/lorenzwalthert/semicoloner) +* [lorenzwalthert/oneliner](https://github.com/lorenzwalthert/oneliner) +* [mlr-org/styler.mlr](https://github.com/mlr-org/styler.mlr) + +Other available style guides include: + +* [ropensci-review-tools/spaceout](https://github.com/ropensci-review-tools/spaceout) +* [gadenbuie/grkstyle](https://github.com/gadenbuie/grkstyle) + +To start out, you can use the +[GitHub Template](https://github.com/lorenzwalthert/styler.yours) for +third-party style guides that has already the right directory structure and +patterns described below in place. + +You made one too? Please submit a PR to include it in the list. + +## Design patterns + +The style guides mentioned above follow best practices and can serve as a good +and rather minimal example of how to implement your own style guide. Most +importantly, these two packages: + +* export all functions that {styler} exports, but the `style` argument set + to the custom style guide, plus custom style guides. + The advantage of this is that you can use that namespace as a drop-in + replacement for styler everywhere. In particular, if you want to use the + tidyverse style guide, use `styler::style_pkg()`, if you want to use a + third-party style guide, use the other namespace, e.g. `styler.mlr::style_pkg()` +* depend on {styler} and use {styler} internals via `:::`. + These internals are subject to change without prior notice, which is why the + packages also have unit tests. Also note that importing internals from another + package means your package can't be added to CRAN because packages calling + private methods from other packages don't pass CRAN checks. The only way around this + would be to export some styler internals, e.g. via a {styler.infra} package, + but that would be a lot of work on our side and therefore not currently on the + roadmap. Another alternative for + developers might be to use https://github.com/wch/staticimports, which we have + not explored so far. +* implement unit tests following {styler}'s testing convention with `*-in.R` and + `*-out.R` files that are checked with `styler:::test_collection()`. + + +When creating a custom style guide and distribute it, we want to quickly recall +important arguments for `create_style_guide()` from the docs: + +* `style_guide_name`, `style_guide_version` and `more_specs_style_guide`: + These arguments are relevant for caching and make sure the user's cache is + invalidated on releasing a new version. The documentation specifies how to + set these arguments. +* `transformers_drop`: This argument can be created with `specify_transformers_drop()` + to define conditions under which a transformer can be removed from the style + guide without an effect on the result. This makes styler faster. For example, + if you have a transformer that removes the token `;` and replaces it with a + line break, it is only required if the code to style contains this token. + Since this will hardly be the case for people who adhere to the tidyverse + style guide, we formulate such a rule like this + +```{r} +styler::specify_transformers_drop( + spaces = list(style_space_around_tilde = "'~'"), + tokens = list(resolve_semicolon = "';'") +) +``` + +Where the name must correspond to the transformer function in question and the +value is the token that must be absent in order to drop the transformer. diff --git a/vignettes/remove_rules.Rmd b/vignettes/remove_rules.Rmd new file mode 100644 index 000000000..964f6d127 --- /dev/null +++ b/vignettes/remove_rules.Rmd @@ -0,0 +1,196 @@ +--- +title: "Remove rules" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Remove rules} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r, echo = FALSE, include = FALSE} +options(styler.colored_print.vertical = FALSE) +``` + +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 file](http://styler.r-lib.org/reference/tidyverse_style.html) for + the function `tidyverse_style()`, which returns the transformer functions that + prettify your code. Most of these options are explained in `vignette("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 a + `vignette("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 ant 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: + +```{r, comment = ""} +library(styler) +style_text("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. + +```{r} +transformers <- tidyverse_style() +names(transformers) +``` + +From the aforementioned +[vignette](http://styler.r-lib.org/articles/customizing_styler.html): + +> 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. + +```{r} +library(magrittr) +levels <- c("space", "line_break", "indention", "token") +purrr::map( + levels, + ~ names(transformers[[.x]]) +) %>% + purrr::set_names(levels) +``` + +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. + +```{r} +styler:::force_assignment_op +``` + +Next, you simply set that element to `NULL`. + +```{r} +transformers$token$force_assignment_op <- NULL +``` + +And you can use the modified transformer list as input to `style_text()` + +```{r} +style_text("string = 'hi there'", transformers = transformers) +``` + +If you want to use it the same way as `tidyverse_style()`, here's the last step: + +```{r} +eq_assign_style <- function(...) { + transformers <- tidyverse_style(...) + transformers$token$force_assignment_op <- NULL + transformers +} + +style_text("string = 'hi there'", style = eq_assign_style) +``` + + +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: + +```{r} +style_text("string <- 'hi there'", style = eq_assign_style) +``` + +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. + +```r +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 a `print(pd)` or `browser()` call in the functions + of that type (e.g. the different functions of `R/rules-line-breaks.R`), + `load_all()`, run your example, see if that function made the change. + move the `print(pd)` or `browser()` call to another function if not. + * Once you've identified the culprit (in this case `style_line_break_around_curly`), + set it to `NULL` 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 with + `transformers$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](http://style.tidyverse.org/) 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. diff --git a/vignettes/styler.Rmd b/vignettes/styler.Rmd index 15f773a6c..677dd1700 100644 --- a/vignettes/styler.Rmd +++ b/vignettes/styler.Rmd @@ -235,4 +235,9 @@ style_text( 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")`. +further: + +* either by removing rules from the tidyverse style guide as described in + `vignette("remove_rules")`. +* or by creating your own style guide from scratch as described in + `vignette("customizing_styler")`.