Skip to content

Commit 54f4e11

Browse files
Merge pull request #560 from lorenzwalthert/stylerignore
- Ignore certain lines when styling (#560).
2 parents 37c427a + 38f8c25 commit 54f4e11

26 files changed

+682
-9
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Collate:
7373
'set-assert-args.R'
7474
'style-guides.R'
7575
'styler.R'
76+
'stylerignore.R'
7677
'testing-mocks.R'
7778
'testing-public-api.R'
7879
'testing.R'

NEWS.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# styler 1.2.0.9000
22

3+
* ignore certain lines using `# styler: off` and `#styler: on` or custom
4+
markers, see `help("stylerignore")` (#560).
5+
36
* function documentation now contains many more linebreaks due to roxygen2
47
update to version 7.0.1 (#566).
5-
8+
69
# styler 1.2.0
710

811
## Breaking changes

R/detect-alignment-utils.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ alignment_serialize_column <- function(relevant_pd_by_line, column) {
101101
#'
102102
#' @inheritParams alignment_serialize_column
103103
#' @inheritParams alignment_col1_is_named
104+
#' @keywords internal
104105
alignment_serialize_line <- function(relevant_pd_by_line, column) {
105106
# TODO
106107
# better also add lover bound for column. If you already checked up to comma 2,

R/detect-alignment.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#'
2525
#' @importFrom purrr map_int map_lgl map compact
2626
#' @importFrom rlang seq2
27+
#' @keywords internal
2728
#' @examples
2829
#' library("magrittr")
2930
#' transformers <- tidyverse_style()

R/environments.R

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,17 @@ parser_version_find <- function(pd) {
4646
}
4747

4848

49-
49+
#' The elements that are added to this environment are:
50+
#'
51+
#' @details
52+
#' * `parser_version`: Needed to dispatch between parser versions, see
53+
#' [parser_version_set()] for details.
54+
#' * `stylerignore`: A tibble with parse data containing tokens that fall within
55+
#' a stylerignore sequence. This is used after serializing the flattened
56+
#' parse table to apply the initial formatting to these tokens. See
57+
#' [stylerignore] for details.
58+
#' * `any_stylerignore`: Whether there is any stylerignore marker. The idea is
59+
#' to check early in the runtime if this is the case and then if so, take
60+
#' as many short-cuts as possible. See [stylerignore] for details.
61+
#' @keywords internal
5062
env_current <- rlang::new_environment(parent = rlang::empty_env())

R/nest.R

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
compute_parse_data_nested <- function(text) {
1111
parse_data <- tokenize(text) %>%
1212
add_terminal_token_before() %>%
13-
add_terminal_token_after()
13+
add_terminal_token_after() %>%
14+
add_stylerignore()
15+
16+
env_add_stylerignore(parse_data)
1417

1518
parse_data$child <- rep(list(NULL), length(parse_data$text))
1619
pd_nested <- parse_data %>%
@@ -21,6 +24,57 @@ compute_parse_data_nested <- function(text) {
2124
pd_nested
2225
}
2326

27+
#' Turn off styling for parts of the code
28+
#'
29+
#' Using stylerignore markers, you can temporarily turn off styler. See a
30+
#' few illustrative examples below.
31+
#' @details
32+
#' Styling is on by default when you run styler.
33+
#' - To mark the start of a sequence where you want to turn styling off, use
34+
#' `# styler: off`.
35+
#' - To mark the end of this sequence, put `# styler: on` in your code. After
36+
#' that line, styler will again format your code.
37+
#' - To ignore an inline statement (i.e. just one line), place `# styler: off`
38+
#' at the end of the line. Note that inline statements cannot contain other
39+
#' comments apart from the marker, i.e. a line like
40+
#' `1 # comment # styler: off` won't be ignored.
41+
#'
42+
#' To use something else as start and stop markers, set the R options
43+
#' `styler.ignore_start` and
44+
#' `styler.ignore_stop` using [options()]. If you want these
45+
#' settings to persist over mulitple R sessions, consider setting them in your
46+
#' R profile, e.g. with `usethis::edit_rprofile()`.
47+
#' @name stylerignore
48+
#' @examples
49+
#' # as long as the order of the markers is correct, the lines are ignored.
50+
#' style_text(
51+
#' "
52+
#' 1+1
53+
#' # styler: off
54+
#' 1+1
55+
#' # styler: on
56+
#' 1+1
57+
#' "
58+
#')
59+
#'
60+
#' # if there is a stop marker before a start marker, styler won't be able
61+
#' # to figure out which lines you want to ignore and won't ignore anything,
62+
#' # issuing a warning.
63+
#' \dontrun{
64+
#' style_text(
65+
#' "
66+
#' 1+1
67+
#' # styler: off
68+
#' 1+1
69+
#' # styler: off
70+
#' 1+1
71+
#' "
72+
#')
73+
#'}
74+
#'
75+
NULL
76+
77+
2478
#' Enhance the mapping of text to the token "SPECIAL"
2579
#'
2680
#' Map text corresponding to the token "SPECIAL" to a (more) unique token

R/serialize.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#' Serialize flattened parse data
22
#'
33
#' Collapses a flattened parse table into character vector representation.
4-
#' @param flattened_pd A flattened parse table.
4+
#' @inheritParams apply_stylerignore
55
#' @param start_line The line number on which the code starts.
66
#' @keywords internal
77
serialize_parse_data_flattened <- function(flattened_pd, start_line = 1) {
88
flattened_pd$lag_newlines[1] <- start_line - 1
9+
flattened_pd <- apply_stylerignore(flattened_pd)
910
res <- with(
1011
flattened_pd,
1112
paste0(

R/stylerignore.R

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#' Add positional information of token to next terminal
2+
#'
3+
#' This is needed because at serialization time, we also have terminals only
4+
#' and positional argument of non-terminals were already propagated to terminals
5+
#' with [context_to_terminals()].
6+
#' @inheritParams add_stylerignore
7+
#' @keywords internal
8+
env_add_stylerignore <- function(pd_flat) {
9+
if (!env_current$any_stylerignore) {
10+
env_current$stylerignore <- pd_flat[0, ]
11+
return()
12+
}
13+
pd_flat_temp <- pd_flat[pd_flat$terminal, ] %>%
14+
default_style_guide_attributes()
15+
pd_flat_temp$lag_newlines <- pd_flat_temp$lag_newlines
16+
pd_flat_temp$lag_spaces <- lag(pd_flat_temp$spaces, default = 0)
17+
is_terminal_to_ignore <- pd_flat_temp$terminal & pd_flat_temp$stylerignore
18+
env_current$stylerignore <- pd_flat_temp[is_terminal_to_ignore, ]
19+
}
20+
21+
#' Adds the stylerignore column
22+
#'
23+
#' If a token should be ignored, the column is set to `TRUE`,
24+
#' otherwise to `FALSE`.
25+
#' @details
26+
#' A token is ignored iff one of the two conditions hold:
27+
#'
28+
#' - it falls between a start and a stop marker whereas the markers are on
29+
#' their own line. Which tokens are recognized as markers is controlled with
30+
#' the R options `styler.ignore_start` and `styler.ignore_stop`.
31+
#' - it is not a comment, but the last token on the line is a marker.
32+
#'
33+
#' See examples in [stylerignore].
34+
#' @param pd_flat A parse table.
35+
#' @keywords internal
36+
add_stylerignore <- function(pd_flat) {
37+
parse_text <- trimws(pd_flat$text)
38+
start_candidate <- parse_text == option_read("styler.ignore_start")
39+
pd_flat$stylerignore <- rep(FALSE, length(start_candidate))
40+
env_current$any_stylerignore <- any(start_candidate)
41+
if (!env_current$any_stylerignore) {
42+
return(pd_flat)
43+
}
44+
pd_flat_terminals <- pd_flat[pd_flat$terminal, ]
45+
pd_flat_lat_line1 <- lag(pd_flat$line2, default = 0)
46+
on_same_line <- pd_flat$line1 == pd_flat_lat_line1
47+
cumsum_start <- cumsum(start_candidate & !on_same_line)
48+
cumsum_stop <- cumsum(parse_text == option_read("styler.ignore_stop"))
49+
pd_flat$indicator_off <- cumsum_start + cumsum_stop
50+
is_invalid <- cumsum_start - cumsum_stop < 0 | cumsum_start - cumsum_stop > 1
51+
if (any(is_invalid)) {
52+
warn(paste0(
53+
"Invalid stylerignore sequences found, potentially ignoring some of the ",
54+
"markers set.\nSee `help(\"stylerignore\", \"styler\")`."
55+
))
56+
}
57+
58+
to_ignore <- as.logical(pd_flat$indicator_off %% 2)
59+
to_ignore[is_invalid] <- FALSE
60+
single_lines_to_ignore <- pd_flat$line1[start_candidate & on_same_line]
61+
to_ignore[pd_flat$line1 %in% single_lines_to_ignore] <- TRUE
62+
pd_flat$indicator_off <- NULL
63+
pd_flat[to_ignore & pd_flat$terminal, "stylerignore"] <- TRUE
64+
pd_flat
65+
}
66+
67+
#' Ensure correct positional information for stylerignore expressions
68+
#'
69+
#' @param flattened_pd A flattened parse table.
70+
#' @details
71+
#' * Get the positional information for tokens with a stylerignore tag from
72+
#' `env_current`, which recorded that information from the input text.
73+
#' * Replace the computed lag_newlines and lag_spaces information in the parse
74+
#' table with this information.
75+
#' @keywords internal
76+
apply_stylerignore <- function(flattened_pd) {
77+
if (!env_current$any_stylerignore) {
78+
return(flattened_pd)
79+
}
80+
pos_ids <- env_current$stylerignore$pos_id
81+
colnames_required_apply_stylerignore <- c(
82+
"pos_id", "lag_newlines", "lag_spaces", "text"
83+
)
84+
flattened_pd <- merge(
85+
flattened_pd,
86+
env_current$stylerignore[, colnames_required_apply_stylerignore],
87+
by = "pos_id", all.x = TRUE
88+
) %>%
89+
as_tibble()
90+
flattened_pd %>%
91+
stylerignore_consolidate_col("lag_newlines") %>%
92+
stylerignore_consolidate_col("lag_spaces") %>%
93+
stylerignore_consolidate_col("text")
94+
}
95+
96+
#' Consolidate columns after a merge
97+
#'
98+
#' After [base::merge()], all non-id columns that were present in `x` and `y`
99+
#' do get a suffix `.x` and `.y`. If the `y` value is missing, use the `x`
100+
#' value (because the information for this token was not stylerignored),
101+
#' otherwise the `y` value (i.e. the styled value).
102+
#' @param col A string indicating the name of the column that should be
103+
#' consolidated.
104+
#' @inheritParams apply_stylerignore
105+
#' @keywords internal
106+
stylerignore_consolidate_col <- function(flattened_pd, col) {
107+
col_x <- paste0(col, ".x")
108+
col_y <- paste0(col, ".y")
109+
flattened_pd[[col]] <- ifelse(is.na(flattened_pd[[col_y]]),
110+
flattened_pd[[col_x]],
111+
flattened_pd[[col_y]]
112+
)
113+
flattened_pd[[col_x]] <- NULL
114+
flattened_pd[[col_y]] <- NULL
115+
flattened_pd
116+
}

R/token-create.R

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ create_tokens <- function(tokens,
3030
indention_ref_pos_ids = NA,
3131
indents = 0,
3232
terminal = TRUE,
33-
child = NULL) {
33+
child = NULL,
34+
stylerignore = FALSE) {
3435
len_text <- length(texts)
3536
new_tibble(
3637
list(
@@ -48,7 +49,8 @@ create_tokens <- function(tokens,
4849
multi_line = rep(FALSE, len_text),
4950
indention_ref_pos_id = indention_ref_pos_ids,
5051
indent = indents,
51-
child = rep(list(child), len_text)
52+
child = rep(list(child), len_text),
53+
stylerignore = stylerignore
5254
),
5355
nrow = len_text
5456
)

R/utils.R

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,19 @@ calls_sys <- function(sys_call, ...) {
5959
error <- system(sys_call, ...)
6060
}
6161
}
62+
63+
#' Get the value of an option
64+
#'
65+
#' Basically a `getOptions()` that fails fast by default.
66+
#' @inheritParams base::getOption
67+
#' @param error_if_not_found Whether or not an error should be returned if the
68+
#' option was not set.
69+
#' @keywords internal
70+
option_read <- function(x, default = NULL, error_if_not_found = TRUE) {
71+
if (x %in% names(options()) | !error_if_not_found) {
72+
getOption(x, default)
73+
} else {
74+
rlang::abort(paste("R option", x, "most be set."))
75+
}
76+
77+
}

R/zzz.R

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
backports::import(pkgname, "trimws")
33
op <- options()
44
op.styler <- list(
5-
styler.colored_print.vertical = TRUE
5+
styler.colored_print.vertical = TRUE,
6+
styler.ignore_start = "# styler: off",
7+
styler.ignore_stop = "# styler: on"
68
)
79
toset <- !(names(op.styler) %in% names(op))
810
if (any(toset)) options(op.styler[toset])

man/add_stylerignore.Rd

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/alignment_serialize_line.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/apply_stylerignore.Rd

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/create_tokens.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/env_add_stylerignore.Rd

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)