diff --git a/R/indentation_linter.R b/R/indentation_linter.R index 6fc59f2e7..4db29e3db 100644 --- a/R/indentation_linter.R +++ b/R/indentation_linter.R @@ -44,6 +44,27 @@ #' # body #' } #' ``` +#' @param assignment_as_infix Treat `<-` as a regular (i.e. left-associative) infix operator? +#' This means, that infix operators on the right hand side of an assignment do not trigger a second level of +#' indentation: +#' ```r +#' # complies to any style +#' variable <- a %+% +#' b %+% +#' c +#' +#' # complies to assignment_as_infix = TRUE +#' variable <- +#' a %+% +#' b %+% +#' c +#' +#' # complies to assignment_as_infix = FALSE +#' variable <- +#' a %+% +#' b %+% +#' c +#' ``` #' #' @examples #' # will produce lints @@ -97,7 +118,8 @@ #' - #' #' @export -indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "always", "never")) { +indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "always", "never"), + assignment_as_infix = TRUE) { paren_tokens_left <- c("OP-LEFT-BRACE", "OP-LEFT-PAREN", "OP-LEFT-BRACKET", "LBB") paren_tokens_right <- c("OP-RIGHT-BRACE", "OP-RIGHT-PAREN", "OP-RIGHT-BRACKET", "OP-RIGHT-BRACKET") infix_tokens <- setdiff(infix_metadata$xml_tag, c("OP-LEFT-BRACE", "OP-COMMA", paren_tokens_left)) @@ -118,6 +140,15 @@ indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "al } } + if (isTRUE(assignment_as_infix)) { + infix_condition <- glue::glue(" + and (not(ancestor::expr/preceding-sibling::LEFT_ASSIGN[{xp_last_on_line}]) or ancestor::expr[expr[SYMBOL_FUNCTION_CALL]]) + ") + # suppress only infix operators that are not inside of a function call + } else { + infix_condition <- "" + } + xp_block_ends <- paste0( "number(", paste( @@ -141,7 +172,7 @@ indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "al @line2 > @line1 and ({xp_or(paste0('descendant::', paren_tokens_left, '[', xp_last_on_line, ']'))}) ]/@line1)]"), - glue::glue("//{infix_tokens}[{xp_last_on_line}]"), + glue::glue("//{infix_tokens}[{xp_last_on_line}{infix_condition}]"), glue::glue("//{no_paren_keywords}[{xp_last_on_line}]"), glue::glue("//{keyword_tokens}/following-sibling::OP-RIGHT-PAREN[ {xp_last_on_line} and diff --git a/man/indentation_linter.Rd b/man/indentation_linter.Rd index 73a181ea8..869a24064 100644 --- a/man/indentation_linter.Rd +++ b/man/indentation_linter.Rd @@ -6,7 +6,8 @@ \usage{ indentation_linter( indent = 2L, - hanging_indent_style = c("tidy", "always", "never") + hanging_indent_style = c("tidy", "always", "never"), + assignment_as_infix = TRUE ) } \arguments{ @@ -54,6 +55,28 @@ function( # body \} }\if{html}{\out{}}} + +\item{assignment_as_infix}{Treat \verb{<-} as a regular (i.e. left-associative) infix operator? +This means, that infix operators on the right hand side of an assignment do not trigger a second level of +indentation: + +\if{html}{\out{
}}\preformatted{# complies to any style +variable <- a \%+\% + b \%+\% + c + +# complies to assignment_as_infix = TRUE +variable <- + a \%+\% + b \%+\% + c + +# complies to assignment_as_infix = FALSE +variable <- + a \%+\% + b \%+\% + c +}\if{html}{\out{
}}} } \description{ Check that indentation is consistent diff --git a/tests/testthat/test-indentation_linter.R b/tests/testthat/test-indentation_linter.R index b50b676f0..6cce575d5 100644 --- a/tests/testthat/test-indentation_linter.R +++ b/tests/testthat/test-indentation_linter.R @@ -634,6 +634,37 @@ test_that("hanging_indent_stlye works", { expect_lint(code_hanging_same_line, "Indent", non_hanging_linter) }) +test_that("assignment_as_infix works", { + code_infix <- trim_some(" + ok_code <- + var1 + + f( + var2 + + var3 + ) + + var4 + ") + + code_no_infix <- trim_some(" + ok_code <- + var1 + + f( + var2 + + var3 + ) + + var4 + ") + + tidy_linter <- indentation_linter() + no_infix_linter <- indentation_linter(assignment_as_infix = FALSE) + + expect_lint(code_infix, NULL, tidy_linter) + expect_lint(code_no_infix, rex::rex("Indentation should be 2 spaces but is 4 spaces."), tidy_linter) + + expect_lint(code_infix, rex::rex("Indentation should be 4 spaces but is 2 spaces."), no_infix_linter) + expect_lint(code_no_infix, NULL, no_infix_linter) +}) + test_that("consecutive same-level lints are suppressed", { bad_code <- trim_some(" ok_code <- 42