rformat applies base R style conventions to R code. All transforms
operate on the token stream from parse() +
getParseData(), so they never change the meaning of your
code – only its whitespace and style.
This vignette walks through each option with before/after examples.
With no options, rformat normalizes spacing, converts =
assignment to <-, and indents by nesting depth.
> library(rformat)
> cat(rformat("x=1+2"))
x <- 1 + 2
> cat(rformat("f=function(x,y){
+ if(x>0)
+ y=mean(x,na.rm=TRUE)
+ else y=NA
+ }"))
f <- function(x, y) {
if (x > 0)
y <- mean(x, na.rm = TRUE)
else y <- NA
}indentIndentation per nesting level. Default is 4 spaces. Pass an integer for spaces or a character string for a literal indent.
> # 2 spaces per level
> cat(rformat("f <- function(x) {\nif (x) {\ny\n}\n}", indent = 2L))
f <- function(x) {
if (x) {
y
}
}
> # Tab indent (shown as \t in output)
> rformat("f <- function(x) {\nif (x) {\ny\n}\n}", indent = "\t")
[1] "f <- function(x) {\n\tif (x) {\n\t\ty\n\t}\n}\n"line_limitMaximum line width before wrapping kicks in (default 80). This affects function signature wrapping and long expression wrapping.
> long_call <- "result <- some_function(alpha, bravo, charlie, delta)"
> # Default 80: fits on one line
> cat(rformat(long_call))
result <- some_function(alpha, bravo, charlie, delta)
> # Narrow limit: forces wrapping
> cat(rformat(long_call, line_limit = 40))
result <- some_function(alpha, bravo,
charlie, delta)wrapControls continuation indent style for wrapped function signatures.
"paren" (default): aligns continuation to the opening
parenthesis"fixed": uses an 8-space continuation indent> long_sig <- paste0(
+ "my_function <- function(alpha, beta, gamma, ",
+ "delta, epsilon, zeta, eta, theta, iota) ",
+ "{\n 1\n}")
> # Paren-aligned (default): continuation aligns to (
> cat(rformat(long_sig, wrap = "paren"))
my_function <- function(alpha, beta, gamma, delta, epsilon, zeta, eta, theta,
iota) {
1
}
> # Fixed: continuation uses 8-space indent
> cat(rformat(long_sig, wrap = "fixed"))
my_function <- function(alpha, beta, gamma, delta, epsilon, zeta, eta, theta,
iota) {
1
}brace_styleControls opening brace placement for function definitions.
"kr" (default): K&R style, opening brace on same
line as )"allman": opening brace on its own line> long_def <- paste0(
+ "my_function <- function(alpha, beta, gamma, ",
+ "delta, epsilon, zeta, eta, theta, iota) ",
+ "{\n y <- 1\n y\n}")
> # K&R (default): { on same line as )
> cat(rformat(long_def, brace_style = "kr"))
my_function <- function(alpha, beta, gamma, delta, epsilon, zeta, eta, theta,
iota) {
y <- 1
y
}
> # Allman: { on its own line
> cat(rformat(long_def, brace_style = "allman"))
my_function <- function(alpha, beta, gamma, delta, epsilon, zeta, eta, theta,
iota)
{
y <- 1
y
}control_bracesWhen TRUE, adds braces to bare (unbraced) control flow bodies. Default FALSE matches R Core source code, where 59% of control flow bodies are bare.
> code <- "f <- function(x) {
+ if (x > 0) y <- log(x)
+ if (x < 0) stop('negative')
+ }"
> # Default: bare bodies left alone
> cat(rformat(code))
f <- function(x) {
if (x > 0) y <- log(x)
if (x < 0) stop('negative')
}
> # Add braces
> cat(rformat(code, control_braces = TRUE))
f <- function(x) {
if (x > 0) { y <- log(x) }
if (x < 0) { stop('negative') }
}expand_ifWhen TRUE, expands inline if-else expressions to multi-line form.
> code <- "y <- if (x > 0) log(x) else NA"
> # Default: inline if-else preserved
> cat(rformat(code))
y <- if (x > 0) log(x) else NA
> # Expanded to multi-line
> cat(rformat(code, expand_if = TRUE))
if (x > 0) {
y <- log(x)
} else {
y <- NA
}else_same_lineIn R, else on its own line is a parse error at top level
(though it’s valid inside braces). When TRUE (default), this option
repairs top-level }\nelse by joining them to
} else before formatting. When FALSE, unparseable input is
returned unchanged with a warning.
> # Top-level } else on separate lines is a parse error.
> # else_same_line (the default) repairs it:
> code <- "if (x) {\n 1\n}\nelse {\n 2\n}"
> cat(rformat(code))
if (x) {
1
} else {
2
}join_elseWhen TRUE (default), moves else to the same line as the
preceding }. Matches R Core source code where 70% use
same-line else. When FALSE, }\nelse on separate lines is
preserved.
This is an AST-level transform that works on already-valid code
inside braces, unlike else_same_line which is a text-level
parse repair.
> code <- "f <- function(x) {
+ if (x > 0) {
+ y <- log(x)
+ }
+ else {
+ y <- NA
+ }
+ y
+ }"
> # Default: else joins the } line
> cat(rformat(code))
f <- function(x) {
if (x > 0) {
y <- log(x)
} else {
y <- NA
}
y
}
> # Preserve } / else on separate lines
> cat(rformat(code, join_else = FALSE))
f <- function(x) {
if (x > 0) {
y <- log(x)
}
else {
y <- NA
}
y
}function_spaceWhen TRUE, adds a space before ( in function
definitions: function (x) instead of
function(x). Default FALSE matches 96% of R Core source
code.
> code <- "f <- function(x, y) {\n x + y\n}"
> # Default: no space
> cat(rformat(code))
f <- function(x, y) {
x + y
}
> # With space
> cat(rformat(code, function_space = TRUE))
f <- function (x, y) {
x + y
}Options compose naturally. Here is a more opinionated style that adds braces, expands if-else, and uses Allman braces with 2-space indent:
> code <- "f=function(x){
+ y=if(x>0) log(x) else NA
+ y
+ }"
> cat(rformat(code,
+ indent = 2L,
+ brace_style = "allman",
+ control_braces = TRUE,
+ expand_if = TRUE))
f <- function(x) {
if (x > 0) {
y <- log(x)
} else {
y <- NA
}
y
}rformat_file() formats a file in place (or to a new
path). rformat_dir() formats all .R files in a
directory. Both accept the same options as rformat().
> # Format a file (dry run)
> f <- tempfile(fileext = ".R")
> writeLines("x=1+2", f)
> rformat_file(f, dry_run = TRUE)
> # Format all R files in a directory (dry run)
> d <- file.path(tempdir(), "rformat_demo")
> dir.create(d, showWarnings = FALSE)
> writeLines("y = 3", file.path(d, "example.R"))
> rformat_dir(d, dry_run = TRUE)
Would format: /tmp/RtmpqnaPGt/rformat_demo/example.R
> unlink(d, recursive = TRUE)
> unlink(f)