Skip to content

Commit 95c2f75

Browse files
Merge branch 'main' into copilot/fix-70
2 parents 1b8f6a8 + 69cff65 commit 95c2f75

19 files changed

+215
-173
lines changed

crates/roughly/tests/format/formatter.template.md

Lines changed: 87 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Roughly applies specific formatting rules to different R code constructs. The fo
4949
```r
5050
# assignment_operators : compare
5151
x<-1
52-
result<<-calculate()
52+
data<<-compute()
5353
```
5454

5555
**Binary operators** get spaces around them, except for range (`:`) and power (`^`) operators:
@@ -67,7 +67,7 @@ sequence=1:10
6767
# pipeline_operators : compare
6868
data %>%
6969
filter(condition) %>%
70-
summarize(mean_value=mean(value))
70+
select(value)
7171
```
7272

7373
### Code Blocks and Braced Expressions
@@ -114,12 +114,11 @@ The formatter normalizes line spacing between expressions, allowing at most one
114114

115115
```r
116116
# line_spacing : compare
117-
calculate_mean <- function(data) {
118-
clean_data <- data[!is.na(data)]
117+
x <- 1
118+
y <- 2
119119

120120

121-
mean(clean_data)
122-
}
121+
z <- 3
123122
```
124123

125124
### Function Calls and Arguments
@@ -128,30 +127,62 @@ Function calls receive consistent formatting with proper spacing around argument
128127

129128
```r
130129
# function_calls : compare
131-
calculate(data=dataset,method="mean",na.rm=TRUE)
132-
complex_call(argument1,
133-
argument2=value,
134-
argument3)
130+
process(data=dataset,method="mean",na.rm=TRUE)
131+
call(arg1,
132+
arg2=value,
133+
arg3)
134+
```
135+
136+
**Nested function calls** can be formatted in a hugged style:
137+
138+
```r
139+
# hugging_nested_function_calls : format
140+
# Hugged format - both functions start on the same line
141+
result <- outer(inner(
142+
arg
143+
))
144+
145+
# Expanded format - also valid
146+
result <- outer(
147+
inner(
148+
arg
149+
)
150+
)
135151
```
136152

137-
**Argument hugging**: When function arguments can fit on a single line and the last argument's value starts on the same line as the opening parenthesis, the formatter keeps a compact format. Otherwise, it expands to multiple lines with proper indentation.
153+
**Mixed line formats** are allowed when the last argument starts on the same line:
154+
155+
```r
156+
# mixed_line_format : format
157+
# This format is preserved - last argument starts on same line
158+
call(a = x, b = y, c = inner(
159+
expr
160+
))
161+
```
138162

139-
**Nested function calls** are formatted with hugging when appropriate:
163+
This behavior is particularly useful for testing frameworks and S4 method definitions:
140164

141165
```r
142-
# nested_function_calls : compare
143-
result <- outer(inner(a,b),other(c,d))
166+
# test_that_and_s4_example: format
167+
test_that("description", {
168+
expect_equal(result, expected)
169+
})
170+
171+
setMethod("show", "MyClass", function(object) {
172+
cat("MyClass object\n")
173+
})
144174
```
145175

176+
146177
### Function Definitions
147178

148179
Function definitions follow consistent formatting rules for parameters and body structure:
149180

150181
```r
151182
# function_definitions : compare
152-
calc<-function(x,y=1){x+y}
153-
stats<-function(data,method="mean"){
154-
result(data,method)
183+
process<-function(x,y=1){x+y}
184+
filter<-function(data,method="simple"){
185+
select(data,method)
155186
}
156187
```
157188

@@ -172,17 +203,15 @@ lapply(data,\(x)x+1)
172203

173204
```r
174205
# conditional_statements : compare
175-
if(condition){action} else{alternative}
206+
if(condition){action()} else{action()}
176207

177208
if(
178-
long_condition ||
209+
condition ||
179210
other_condition){
180211
action()
181212
}
182213
```
183214

184-
**Condition hugging**: When conditions fit on a single line without comments, the formatter keeps them compact. For multiline conditions, proper indentation is applied.
185-
186215
**Block enforcement**: If an if-statement has a multiline condition, the formatter ensures the body is wrapped in braces even if it's a single expression.
187216

188217
### Loops and Control Flow
@@ -198,31 +227,29 @@ for(item in collection) process(item)
198227

199228
```r
200229
# while_loops : compare
201-
while(condition) action()
230+
while(condition) process()
202231
```
203232

204233
**Repeat loops** also enforce braced blocks:
205234

206235
```r
207236
# repeat_loops : compare
208-
repeat action()
237+
repeat process()
209238
```
210239

211240
**Loop condition formatting**: Complex conditions that span multiple lines receive proper indentation within the parentheses.
212241

213242
### Parenthesized Expressions
214243

215-
Parenthesized expressions maintain their layout with smart formatting for readability:
244+
Parenthesized expressions receive proper spacing for operators:
216245

217246
```r
218247
# parenthesized_expressions : compare
219-
(x+y*z)
220-
(long_expression+
221-
other_part)
248+
(
249+
expression +
250+
other_part)
222251
```
223252

224-
**Parenthesis hugging**: If the content fits on one line, parentheses hug the content. For multiline content, proper indentation is applied.
225-
226253
### String Literals
227254

228255
String literals receive intelligent quote normalization. The formatter prefers double quotes (`"`) unless the string contains unescaped double quotes:
@@ -239,17 +266,17 @@ quoted_content <- 'Say "hello"'
239266

240267
```r
241268
# subsetting : compare
242-
data[row_index,column_index]
243-
environment[["variable_name"]]
244-
object$member_variable
269+
data[row,col]
270+
data[["name"]]
271+
object$value
245272
```
246273

247274
**Namespace operators** (`::` and `:::`):
248275

249276
```r
250277
# namespace_operators : compare
251-
package::public_function
252-
package:::private_function
278+
pkg::process
279+
pkg:::filter
253280
```
254281

255282
### Unary Operators
@@ -259,15 +286,15 @@ Unary operators receive appropriate spacing based on their type and context:
259286
```r
260287
# unary_operators : compare
261288
result = ! condition
262-
number = - 42
263-
formula = ~ response + predictor
289+
value = - 42
290+
formula = ~ x + y
264291
```
265292

266293
**Special spacing rule**: The `~` (formula) operator gets a space when followed by complex expressions, but not when followed by simple identifiers.
267294

268295
## Format Suppression
269296

270-
You can disable formatting for specific code sections using the `# fmt: skip` comment directive:
297+
You can disable formatting for specific code sections using the `# fmt: skip` comment directive. This is useful when you want to preserve specific formatting for readability, such as aligned data structures.
271298

272299
```r
273300
# format_suppression : format
@@ -280,15 +307,19 @@ matrix(
280307
nrow=2
281308
) # This code won't be reformatted
282309

310+
# fmt: skip
283311
matrix(c(1, 2,
284-
3, 4), nrow=2) # fmt: skip
285-
# The line above won't be reformatted
312+
3, 4), nrow=2) # The line above won't be reformatted
286313
```
287314

315+
Without the `fmt: skip` directive, the `matrix(...)` expression would be broken into multiple lines according to standard formatting rules.
316+
288317
The `fmt: skip` directive can be placed:
289318
- Before a line to skip formatting that entire expression
290319
- At the end of a line to skip formatting just that line
291320

321+
You can also skip formatting for an entire file by placing `# fmt: skip-file` at the top of the file. This directive must be placed at the very beginning of the file to take effect.
322+
292323
## Advanced Formatting Features
293324

294325
The formatter intelligently handles various R idioms and special patterns:
@@ -341,7 +372,6 @@ PersonClass <- R6Class(
341372
- **Switch statements**: Fallthrough cases (`case = ,`) are handled correctly
342373
- **Multi-line strings**: String literal structure is preserved
343374
- **Formula objects**: Proper spacing around `~` operator based on complexity
344-
- **S4 slot access**: `@` operator formatting maintained
345375

346376
## Auto-Bracing
347377

@@ -351,7 +381,7 @@ The formatter automatically adds braces to control flow structures when they imp
351381

352382
```r
353383
# auto_bracing_function_defintions : compare
354-
f <- function(x)
384+
process <- function(x)
355385
x + 1
356386
```
357387

@@ -360,7 +390,7 @@ f <- function(x)
360390
```r
361391
# auto_bracing_conditional_statements : compare
362392
if (condition)
363-
single_statement
393+
action()
364394
```
365395

366396
**Loops**: All loop bodies are automatically braced for consistency:
@@ -373,7 +403,7 @@ for (i in 1:n)
373403

374404
## Hugging Behavior
375405

376-
"Hugging" refers to how nested function calls are formatted - keeping them compact by allowing the inner calls to start on the same line as the outer call's opening parenthesis. This is part of roughly's non-invasive approach: both hugged and expanded formats are allowed.
406+
"Hugging" refers to how nested expressions are formatted in multiline contexts - keeping them compact by allowing inner expressions to start on the same line as the outer expression's opening delimiter. This is part of roughly's non-invasive approach: both hugged and expanded formats are allowed, but hugging only applies to multiline expressions.
377407

378408
**Nested function calls** can be formatted in a hugged style:
379409

@@ -392,6 +422,20 @@ result <- outer(
392422
)
393423
```
394424

425+
**Parenthesized expressions** can also use hugging:
426+
427+
```r
428+
# hugging_parenthesized : format
429+
(expression +
430+
other_part)
431+
432+
# Also allowed
433+
(
434+
expression +
435+
other_part
436+
)
437+
```
438+
395439
**Non-invasive multi-line formatting**: When expressions are already multi-line, roughly only adds necessary spacing but preserves the overall structure. However, if all arguments don't fit on their separate lines, they will be properly separated:
396440

397441
```r
@@ -401,29 +445,6 @@ call(
401445
b=y, c=z)
402446
```
403447

404-
**Mixed line formats** are allowed when the last argument starts on the same line:
405-
406-
```r
407-
# mixed_line_format : format
408-
# This format is preserved - last argument starts on same line
409-
call(a = x, b = y, c = inner(
410-
expr
411-
))
412-
```
413-
414-
This behavior is particularly useful for testing frameworks and S4 method definitions:
415-
416-
```r
417-
# test_that_and_s4_example: format
418-
test_that("description", {
419-
expect_equal(result, expected)
420-
})
421-
422-
setMethod("show", "MyClass", function(object) {
423-
cat("MyClass object\n")
424-
})
425-
```
426-
427448
## Line Endings
428449

429450
The formatter automatically detects and preserves the line ending style (`LF` or `CRLF`) used in the original file.

crates/roughly/tests/snapshots/test_format__documentation_examples__assignment_operators.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
55
x <- 1
6-
result <<- calculate()
6+
data <<- compute()

crates/roughly/tests/snapshots/test_format__documentation_examples__auto_bracing_conditional_statements.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
55
if (condition) {
6-
single_statement
6+
action()
77
}

crates/roughly/tests/snapshots/test_format__documentation_examples__auto_bracing_function_defintions.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
5-
f <- function(x) {
5+
process <- function(x) {
66
x + 1
77
}

crates/roughly/tests/snapshots/test_format__documentation_examples__conditional_statements.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
5-
if (condition) { action } else { alternative }
5+
if (condition) { action() } else { action() }
66

77
if (
8-
long_condition ||
8+
condition ||
99
other_condition
1010
) {
1111
action()

crates/roughly/tests/snapshots/test_format__documentation_examples__for_loops.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
5-
for (item in collection) {
5+
for (item in data) {
66
process(item)
77
}

crates/roughly/tests/snapshots/test_format__documentation_examples__format_suppression.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ matrix(
1111
nrow=2
1212
) # This code won't be reformatted
1313

14+
# fmt: skip
1415
matrix(c(1, 2,
15-
3, 4), nrow=2) # fmt: skip
16-
# The line above won't be reformatted
16+
3, 4), nrow=2) # The line above won't be reformatted

crates/roughly/tests/snapshots/test_format__documentation_examples__function_calls.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
5-
calculate(data = dataset, method = "mean", na.rm = TRUE)
6-
complex_call(
7-
argument1,
8-
argument2 = value,
9-
argument3
5+
process(data = dataset, method = "mean", na.rm = TRUE)
6+
call(
7+
arg1,
8+
arg2 = value,
9+
arg3
1010
)

crates/roughly/tests/snapshots/test_format__documentation_examples__function_definitions.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
source: crates/roughly/tests/test_format.rs
33
expression: code
44
---
5-
calc <- function(x, y = 1) { x + y }
6-
stats <- function(data, method = "mean") {
7-
result(data, method)
5+
process <- function(x, y = 1) { x + y }
6+
filter <- function(data, method = "simple") {
7+
select(data, method)
88
}

0 commit comments

Comments
 (0)