forked from r-lib/styler
-
Notifications
You must be signed in to change notification settings - Fork 2
/
ui.R
206 lines (196 loc) · 7.4 KB
/
ui.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#' @api
#' @import tibble
#' @importFrom magrittr %>%
NULL
#' Prettify R source code
#'
#' Performs various substitutions in all `.R` files in a package
#' (code and tests).
#' Carefully examine the results after running this function!
#'
#' @param pkg Path to a (subdirectory of an) R package.
#' @param ... Arguments passed on to the `style` function.
#' @param style A function that creates a style guide to use, by default
#' [tidyverse_style()] (without the parentheses). Not used
#' further except to construct the argument `transformers`. See
#' [style_guides()] for details.
#' @param transformers A set of transformer functions. This argument is most
#' conveniently constructed via the `style` argument and `...`. See
#' 'Examples'.
#' @param filetype Vector of file extensions indicating which file types should
#' be styled. Case is ignored, and the `.` is optional, e.g. `c(".R", ".Rmd")`
#' or `c("r", "rmd")`.
#' @param exclude_files Character vector with paths to files that should be
#' excluded from styling.
#' @section Warning:
#' This function overwrites files (if styling results in a change of the
#' code to be formatted). It is strongly suggested to only style files
#' that are under version control or to create a backup copy.
#'
#' We suggest to first style with `scope < "tokens"` and inspect and commit
#' changes, because these changes are guaranteed to leave the abstract syntax
#' tree (AST) unchanged. See section 'Roundtrip Validation' for details.
#'
#' Then, we suggest to style with `scope = "tokens"` (if desired) and carefully
#' inspect the changes to make sure the AST is not changed in an unexpected way
#' that invalidates code.
#' @section Roundtrip Validation:
#' The following section describes when and how styling is guaranteed to
#' yield correct code.
#'
#' If the style guide has `scope < "tokens"`, no tokens are changed and the
#' abstract syntax tree (AST) should not change.
#' Hence, it is possible to validate the styling by comparing whether the parsed
#' expression before and after styling have the same AST.
#' This comparison omits comments. styler compares
#' error if the AST has changed through styling.
#'
#' Note that with `scope = "tokens"` such a comparison is not conducted because
#' the AST might well change and such a change is intended. There is no way
#' styler can validate styling, that is why we inform the user to carefully
#' inspect the changes.
#'
#' See section 'Warning' for a good strategy to apply styling safely.
#' @inheritSection transform_files Value
#' @family stylers
#' @examples
#' \dontrun{
#'
#' style_pkg(style = tidyverse_style, strict = TRUE)
#' style_pkg(
#' scope = "line_breaks",
#' math_token_spacing = specify_math_token_spacing(zero = "'+'")
#' )
#' }
#' @export
style_pkg <- function(pkg = ".",
...,
style = tidyverse_style,
transformers = style(...),
filetype = "R",
exclude_files = "R/RcppExports.R") {
pkg_root <- rprojroot::find_package_root_file(path = pkg)
changed <- withr::with_dir(pkg_root,
prettify_pkg(transformers, filetype, exclude_files)
)
invisible(changed)
}
prettify_pkg <- function(transformers, filetype, exclude_files) {
filetype <- set_and_assert_arg_filetype(filetype)
r_files <- vignette_files <- readme <- NULL
if ("\\.r" %in% filetype) {
r_files <- dir(
path = c("R", "tests", "data-raw"), pattern = "\\.r$",
ignore.case = TRUE, recursive = TRUE, full.names = TRUE
)
}
if ("\\.rmd" %in% filetype) {
vignette_files <- dir(
path = "vignettes", pattern = "\\.rmd$",
ignore.case = TRUE, recursive = TRUE, full.names = TRUE
)
readme <- dir(pattern = "^readme\\.rmd$", ignore.case = TRUE)
}
files <- setdiff(c(r_files, vignette_files, readme), exclude_files)
transform_files(files, transformers)
}
#' Style a string
#'
#' Styles a character vector. Each element of the character vector corresponds
#' to one line of code.
#' @param text A character vector with text to style.
#' @inheritParams style_pkg
#' @family stylers
#' @examples
#' style_text("call( 1)")
#' style_text("1 + 1", strict = FALSE)
#' style_text("a%>%b", scope = "spaces")
#' style_text("a%>%b; a", scope = "line_breaks")
#' style_text("a%>%b; a", scope = "tokens")
#' # the following is identical but the former is more convenient:
#' style_text("a<-3++1", style = tidyverse_style, strict = TRUE)
#' style_text("a<-3++1", transformers = tidyverse_style(strict = TRUE))
#' @export
style_text <- function(text,
...,
style = tidyverse_style,
transformers = style(...)) {
transformer <- make_transformer(transformers)
styled_text <- transformer(text)
construct_vertical(styled_text)
}
#' Prettify arbitrary R code
#'
#' Performs various substitutions in all `.R` files in a directory.
#' Carefully examine the results after running this function!
#' @param path Path to a directory with files to transform.
#' @param recursive A logical value indicating whether or not files in subdirectories
#' of `path` should be styled as well.
#' @inheritParams style_pkg
#' @inheritSection transform_files Value
#' @inheritSection style_pkg Warning
#' @inheritSection style_pkg Roundtrip Validation
#' @family stylers
#' @examples
#' \dontrun{
#' style_dir(file_type = "r")
#' }
#' @export
style_dir <- function(path = ".",
...,
style = tidyverse_style,
transformers = style(...),
filetype = "R",
recursive = TRUE,
exclude_files = NULL) {
changed <- withr::with_dir(
path, prettify_any(transformers, filetype, recursive, exclude_files)
)
invisible(changed)
}
#' Prettify R code in current working directory
#'
#' This is a helper function for style_dir.
#' @inheritParams style_pkg
#' @param recursive A logical value indicating whether or not files in subdirectories
#' should be styled as well.
#' @keywords internal
prettify_any <- function(transformers, filetype, recursive, exclude_files) {
files <- dir(
path = ".", pattern = map_filetype_to_pattern(filetype),
ignore.case = TRUE, recursive = recursive, full.names = TRUE
)
transform_files(setdiff(files, exclude_files), transformers)
}
#' Style `.R` and/or `.Rmd` files
#'
#' Performs various substitutions in the files specified.
#' Carefully examine the results after running this function!
#' @section Encoding:
#' UTF-8 encoding is assumed. Please convert your code to UTF-8 if necessary
#' before applying styler.
#' @param path A character vector with paths to files to style.
#' @inheritParams style_pkg
#' @inheritSection transform_files Value
#' @inheritSection style_pkg Warning
#' @inheritSection style_pkg Roundtrip Validation
#' @examples
#' # the following is identical but the former is more convenient:
#' file <- tempfile("styler", fileext = ".R")
#' enc::write_lines_enc("1++1", file)
#' style_file(file, style = tidyverse_style, strict = TRUE)
#' style_file(file, transformers = tidyverse_style(strict = TRUE))
#' enc::read_lines_enc(file)
#' unlink(file)
#' @family stylers
#' @export
style_file <- function(path,
...,
style = tidyverse_style,
transformers = style(...)) {
changed <- withr::with_dir(
dirname(path),
transform_files(basename(path), transformers)
)
invisible(changed)
}