Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ Collate:
'roxygen-examples-find.R'
'roxygen-examples-parse.R'
'roxygen-examples.R'
'rules-line-break.R'
'rules-other.R'
'rules-replacement.R'
'rules-spacing.R'
'rules-indention.R'
'rules-line-breaks.R'
'rules-spaces.R'
'rules-tokens.R'
'serialize.R'
'set-assert-args.R'
'style-guides.R'
Expand Down
9 changes: 6 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
- added an option for disabling all communication when using the package
(`styler.quiet`) (#640).

- `scope` in [tidyverse_style()] can now be specified with higher granularity
through [I()], e.g. `I(c('spaces', 'tokens'))` allows it to style tokens
without styling line breaks and indention (#704).
- `scope` in `tidyverse_style()` can now be specified with higher granularity
through `I()`, e.g. `I(c('spaces', 'tokens'))` allows us to style spaces and
tokens without styling line breaks and indention. Previously, only a string
was allowed and all less invasive scopes were included, e.g. if you wanted to
style tokens, you had to always also style spaces, indention, line breaks as
well (#705, #707).

## Major changes

Expand Down
79 changes: 2 additions & 77 deletions R/indent.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,81 +8,6 @@
#' @keywords internal
NULL

#' @describeIn update_indention Inserts indention based on round, square and
#' curly brackets.
#' @keywords internal
indent_braces <- function(pd, indent_by) {
indent_indices <- compute_indent_indices(
pd,
token_opening = c("'('", "'['", "'{'"),
token_closing = c("')'", "']'", "'}'")
)
pd$indent[indent_indices] <- pd$indent[indent_indices] + indent_by
set_unindention_child(pd, token = "')'", unindent_by = indent_by)
}

#' @describeIn update_indention Indents *all* tokens after `token` - including
#' the last token.
#' @keywords internal
indent_op <- function(pd,
indent_by,
token = c(
math_token,
logical_token,
special_token,
"LEFT_ASSIGN",
"EQ_ASSIGN",
"'$'"
)) {
indent_indices <- compute_indent_indices(pd, token)
pd$indent[indent_indices] <- pd$indent[indent_indices] + indent_by
pd
}

#' Revert the indention of function declaration header
#'
#' Necessary for consistent indention of the function declaration header.
#' @param pd A parse table.
#' @seealso set_unindention_child update_indention_ref_fun_dec
#' @keywords internal
unindent_fun_dec <- function(pd) {
if (is_function_dec(pd)) {
idx_closing_brace <- which(pd$token %in% "')'")
fun_dec_head <- seq2(2L, idx_closing_brace)
pd$indent[fun_dec_head] <- 0L
}
pd
}

#' @describeIn update_indention Updates indention for token EQ_SUB. Only differs
#' from [indent_op()] in the sense that not all subsequent tokens in the parse
#' table are necessarily indented, as `EQ_SUB` and `EQ_FORMALS` can occur
#' multiple times in a parse table.
#' occurs is not indented (see[compute_indent_indices()])
#' @keywords internal
indent_eq_sub <- function(pd,
indent_by,
token = c("EQ_SUB", "EQ_FORMALS")) {
eq_sub <- which(pd$token %in% token)
if (length(eq_sub) == 0) {
return(pd)
}
has_line_break <- which(pd$lag_newlines > 0)
indent_indices <- intersect(eq_sub + 1, has_line_break)
pd$indent[indent_indices] <- pd$indent[indent_indices] + indent_by
pd
}


#' @describeIn update_indention Is used to indent for / while / if / if-else
#' statements that do not have curly parenthesis.
#' @keywords internal
indent_without_paren <- function(pd, indent_by = 2) {
pd %>%
indent_without_paren_for_while_fun(indent_by) %>%
indent_without_paren_if_else(indent_by)
}

#' @describeIn update_indention Is used to indent for and statements and function
#' definitions without parenthesis.
#' @keywords internal
Expand Down Expand Up @@ -295,8 +220,8 @@ pd_is_multi_line <- function(pd) {
#' Update the newlines attribute
#'
#' As we work only with the `lag_newlines` attribute for setting the line
#' breaks, (R/rules-line_break.R) but we need `newlines` to determine
#' whether or not to set `spaces` (R/rules-spacing.R), we have to update the
#' breaks (`R/rules-line_breaks.R`), but we need `newlines` to determine
#' whether or not to set `spaces` (`R/rules-spaces.R`), we have to update the
#' attribute. We cannot simply use `dplyr::lead(pd$lag_newlines)` since we would
#' lose information for the last token. `spaces` is left as is in
#' R/rules-spacing.R for tokens at the end of a line since this allows styling
Expand Down
30 changes: 0 additions & 30 deletions R/reindent.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@

#' Update the indention reference
#'
#' @param pd_nested A nested parse table.
#' @name update_indention_ref
#' @keywords internal
NULL

# @describeIn update_indention_ref Updates the reference pos_id for all
# tokens in `pd_nested` if `pd_nested` contains a function call. Tokens that
# start on the same line as the opening parenthesis, are not themselves
Expand Down Expand Up @@ -45,28 +37,6 @@ NULL
# pd_nested
# }

#' @describeIn update_indention_ref Updates the reference pos_id for all
#' tokens in `pd_nested` if `pd_nested` contains a function declaration.
#' Tokens inside a function declaration are are re-indented,
#' that is, they are indented up to the level at which the token FUNCTION
#' ends in terms of col2.
#' @examples
#' \dontrun{
#' a <- function(x,
#' y) {
#' x + y
#' }
#' }
#' @importFrom rlang seq2
#' @keywords internal
update_indention_ref_fun_dec <- function(pd_nested) {
if (pd_nested$token[1] == "FUNCTION") {
seq <- seq2(3, nrow(pd_nested) - 2)
pd_nested$indention_ref_pos_id[seq] <- pd_nested$pos_id[2]
}
pd_nested
}

#' Apply reference indention to tokens
#'
#' Applies the reference indention created with functions
Expand Down
102 changes: 102 additions & 0 deletions R/rules-indention.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#' @describeIn update_indention Inserts indention based on round, square and
#' curly brackets.
#' @keywords internal
indent_braces <- function(pd, indent_by) {
indent_indices <- compute_indent_indices(
pd,
token_opening = c("'('", "'['", "'{'"),
token_closing = c("')'", "']'", "'}'")
)
pd$indent[indent_indices] <- pd$indent[indent_indices] + indent_by
set_unindention_child(pd, token = "')'", unindent_by = indent_by)
}

#' Revert the indention of function declaration header
#'
#' Necessary for consistent indention of the function declaration header.
#' @param pd A parse table.
#' @seealso set_unindention_child update_indention_ref_fun_dec
#' @keywords internal
unindent_fun_dec <- function(pd) {
if (is_function_dec(pd)) {
idx_closing_brace <- which(pd$token %in% "')'")
fun_dec_head <- seq2(2L, idx_closing_brace)
pd$indent[fun_dec_head] <- 0L
}
pd
}

#' @describeIn update_indention Indents *all* tokens after `token` - including
#' the last token.
#' @keywords internal
indent_op <- function(pd,
indent_by,
token = c(
math_token,
logical_token,
special_token,
"LEFT_ASSIGN",
"EQ_ASSIGN",
"'$'"
)) {
indent_indices <- compute_indent_indices(pd, token)
pd$indent[indent_indices] <- pd$indent[indent_indices] + indent_by
pd
}

#' @describeIn update_indention Updates indention for token EQ_SUB. Only differs
#' from [indent_op()] in the sense that not all subsequent tokens in the parse
#' table are necessarily indented, as `EQ_SUB` and `EQ_FORMALS` can occur
#' multiple times in a parse table.
#' occurs is not indented (see[compute_indent_indices()])
#' @keywords internal
indent_eq_sub <- function(pd,
indent_by,
token = c("EQ_SUB", "EQ_FORMALS")) {
eq_sub <- which(pd$token %in% token)
if (length(eq_sub) == 0) {
return(pd)
}
has_line_break <- which(pd$lag_newlines > 0)
indent_indices <- intersect(eq_sub + 1, has_line_break)
pd$indent[indent_indices] <- pd$indent[indent_indices] + indent_by
pd
}

#' @describeIn update_indention Is used to indent for / while / if / if-else
#' statements that do not have curly parenthesis.
#' @keywords internal
indent_without_paren <- function(pd, indent_by = 2) {
pd %>%
indent_without_paren_for_while_fun(indent_by) %>%
indent_without_paren_if_else(indent_by)
}

#' Update the indention reference
#'
#' @param pd_nested A nested parse table.
#' @name update_indention_ref
#' @keywords internal
NULL

#' @describeIn update_indention_ref Updates the reference pos_id for all
#' tokens in `pd_nested` if `pd_nested` contains a function declaration.
#' Tokens inside a function declaration are are re-indented,
#' that is, they are indented up to the level at which the token FUNCTION
#' ends in terms of col2.
#' @examples
#' \dontrun{
#' a <- function(x,
#' y) {
#' x + y
#' }
#' }
#' @importFrom rlang seq2
#' @keywords internal
update_indention_ref_fun_dec <- function(pd_nested) {
if (pd_nested$token[1] == "FUNCTION") {
seq <- seq2(3, nrow(pd_nested) - 2)
pd_nested$indention_ref_pos_id[seq] <- pd_nested$pos_id[2]
}
pd_nested
}
File renamed without changes.
17 changes: 0 additions & 17 deletions R/rules-replacement.R

This file was deleted.

39 changes: 0 additions & 39 deletions R/rules-spacing.R → R/rules-spaces.R
Original file line number Diff line number Diff line change
Expand Up @@ -121,45 +121,6 @@ remove_space_after_unary_pm_nested <- function(pd) {
pd
}

#' Replace single quotes with double quotes
#'
#' We do not use `deparse()` as in previous implementations but `paste0()` since
#' the former approach escapes the reverse backslash in the line break character
#' `\\n` whereas the solution with `paste0()` does not.
#' @examples
#' style_text("'here
#' is a string
#' '")
#' @importFrom purrr map map_chr
#' @param pd_flat A flat parse table.
#' @importFrom rlang is_empty
#' @keywords internal
fix_quotes <- function(pd_flat) {
str_const <- which(pd_flat$token == "STR_CONST")
if (is_empty(str_const)) {
return(pd_flat)
}

pd_flat$text[str_const] <- map(pd_flat$text[str_const], fix_quotes_one)
pd_flat
}

#' @importFrom rlang is_empty
fix_quotes_one <- function(x) {
rx <- "^'([^\"]*)'$"
i <- grep(rx, x)
if (is_empty(i)) {
return(x)
}

# replace outer single quotes
xi <- gsub(rx, '"\\1"', x[i])

# Replace inner escaped quotes (\') by ' and keep all other instances of \., including \\
x[i] <- gsub("\\\\(')|(\\\\[^'])", "\\1\\2", xi)
x
}

remove_space_before_opening_paren <- function(pd_flat) {
paren_after <- pd_flat$token == "'('"
if (!any(paren_after)) {
Expand Down
57 changes: 57 additions & 0 deletions R/rules-other.R → R/rules-tokens.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
force_assignment_op <- function(pd) {
to_replace <- pd$token == "EQ_ASSIGN"
pd$token[to_replace] <- "LEFT_ASSIGN"
pd$text[to_replace] <- "<-"
pd
}


resolve_semicolon <- function(pd) {
is_semicolon <- pd$token == "';'"
if (!any(is_semicolon)) {
return(pd)
}
pd$lag_newlines[lag(is_semicolon)] <- 1L
pd <- pd[!is_semicolon, ]
pd
}

add_brackets_in_pipe <- function(pd) {
is_pipe <- pd$token == "SPECIAL-PIPE"
Reduce(add_brackets_in_pipe_one, which(is_pipe), init = pd)
Expand Down Expand Up @@ -149,3 +167,42 @@ if_for_while_part_requires_braces <- function(pd, key_token) {
child <- pd$child[[next_non_comment(pd, pos_first_key_token)]]
pd_is_multi_line(pd) && !is_curly_expr(child)
}

#' Replace single quotes with double quotes
#'
#' We do not use `deparse()` as in previous implementations but `paste0()` since
#' the former approach escapes the reverse backslash in the line break character
#' `\\n` whereas the solution with `paste0()` does not.
#' @examples
#' style_text("'here
#' is a string
#' '")
#' @importFrom purrr map map_chr
#' @param pd_flat A flat parse table.
#' @importFrom rlang is_empty
#' @keywords internal
fix_quotes <- function(pd_flat) {
str_const <- which(pd_flat$token == "STR_CONST")
if (is_empty(str_const)) {
return(pd_flat)
}

pd_flat$text[str_const] <- map(pd_flat$text[str_const], fix_quotes_one)
pd_flat
}

#' @importFrom rlang is_empty
fix_quotes_one <- function(x) {
rx <- "^'([^\"]*)'$"
i <- grep(rx, x)
if (is_empty(i)) {
return(x)
}

# replace outer single quotes
xi <- gsub(rx, '"\\1"', x[i])

# Replace inner escaped quotes (\') by ' and keep all other instances of \., including \\
x[i] <- gsub("\\\\(')|(\\\\[^'])", "\\1\\2", xi)
x
}
Loading