rfmt 1.2.3 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Cargo.lock +1 -1
- data/ext/rfmt/Cargo.toml +1 -1
- data/ext/rfmt/src/emitter/mod.rs +148 -19
- data/lib/rfmt/rfmt.so +0 -0
- data/lib/rfmt/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c95517c6abaad1c4bf47425dd4853dcd78bf5a2e47ab2bdc0cae1a3d3698c54
|
|
4
|
+
data.tar.gz: a207798a5811f989a5ebb3405e48e0c86ac60d40b208f141e6d31a83de62dc0d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86307164b77b1836c57718c62ac84bbc920fbfc36a7f0367656bc4fadd65cd846df9f45e5d8985a3eff2f49a548a576a8a73cb05e8e78679fe666589e904762c
|
|
7
|
+
data.tar.gz: 69a7f17c2e547616ebea1a109628df5d3695fb9d9359715d90707a51c4d1c2d72095bad48ffc1d370e7229a01f193392235c3c7c2a0f13fd211dc0885ef2c447
|
data/CHANGELOG.md
CHANGED
data/Cargo.lock
CHANGED
data/ext/rfmt/Cargo.toml
CHANGED
data/ext/rfmt/src/emitter/mod.rs
CHANGED
|
@@ -50,8 +50,11 @@ impl Emitter {
|
|
|
50
50
|
|
|
51
51
|
self.emit_node(ast, 0)?;
|
|
52
52
|
|
|
53
|
+
// Find the last emitted code line for proper blank line handling
|
|
54
|
+
let last_code_line = Self::find_last_code_line(ast);
|
|
55
|
+
|
|
53
56
|
// Emit any remaining comments that weren't emitted
|
|
54
|
-
self.emit_remaining_comments()?;
|
|
57
|
+
self.emit_remaining_comments(last_code_line)?;
|
|
55
58
|
|
|
56
59
|
// Ensure file ends with a newline
|
|
57
60
|
if !self.buffer.ends_with('\n') {
|
|
@@ -61,14 +64,30 @@ impl Emitter {
|
|
|
61
64
|
Ok(self.buffer.clone())
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
/// Find the last line of code in the AST (excluding comments)
|
|
68
|
+
fn find_last_code_line(ast: &Node) -> usize {
|
|
69
|
+
let mut max_line = ast.location.end_line;
|
|
70
|
+
for child in &ast.children {
|
|
71
|
+
let child_end = Self::find_last_code_line(child);
|
|
72
|
+
if child_end > max_line {
|
|
73
|
+
max_line = child_end;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
max_line
|
|
77
|
+
}
|
|
78
|
+
|
|
64
79
|
/// Emit all comments that haven't been emitted yet
|
|
65
|
-
fn emit_remaining_comments(&mut self) -> Result<()> {
|
|
66
|
-
let mut last_end_line: Option<usize> =
|
|
80
|
+
fn emit_remaining_comments(&mut self, last_code_line: usize) -> Result<()> {
|
|
81
|
+
let mut last_end_line: Option<usize> = Some(last_code_line);
|
|
67
82
|
for (idx, comment) in self.all_comments.iter().enumerate() {
|
|
68
83
|
if self.emitted_comment_indices.contains(&idx) {
|
|
69
84
|
continue;
|
|
70
85
|
}
|
|
71
|
-
//
|
|
86
|
+
// Ensure we start on a new line for remaining comments
|
|
87
|
+
if !self.buffer.ends_with('\n') {
|
|
88
|
+
self.buffer.push('\n');
|
|
89
|
+
}
|
|
90
|
+
// Preserve blank lines between code/comments
|
|
72
91
|
if let Some(prev_line) = last_end_line {
|
|
73
92
|
let gap = comment.location.start_line.saturating_sub(prev_line);
|
|
74
93
|
for _ in 1..gap {
|
|
@@ -104,16 +123,37 @@ impl Emitter {
|
|
|
104
123
|
}
|
|
105
124
|
|
|
106
125
|
if comment.location.end_line < line {
|
|
107
|
-
comments_to_emit.push((
|
|
126
|
+
comments_to_emit.push((
|
|
127
|
+
idx,
|
|
128
|
+
comment.text.clone(),
|
|
129
|
+
comment.location.start_line,
|
|
130
|
+
comment.location.end_line,
|
|
131
|
+
));
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
|
|
135
|
+
// Sort by start_line to emit in order
|
|
136
|
+
comments_to_emit.sort_by_key(|(_, _, start, _)| *start);
|
|
137
|
+
|
|
111
138
|
let comments_count = comments_to_emit.len();
|
|
112
|
-
|
|
139
|
+
let mut last_comment_end_line: Option<usize> = None;
|
|
140
|
+
|
|
141
|
+
for (i, (idx, text, comment_start_line, comment_end_line)) in
|
|
142
|
+
comments_to_emit.into_iter().enumerate()
|
|
143
|
+
{
|
|
144
|
+
// Preserve blank lines between comments
|
|
145
|
+
if let Some(prev_end) = last_comment_end_line {
|
|
146
|
+
let gap = comment_start_line.saturating_sub(prev_end);
|
|
147
|
+
for _ in 1..gap {
|
|
148
|
+
self.buffer.push('\n');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
113
152
|
writeln!(self.buffer, "{}{}", indent_str, text)?;
|
|
114
153
|
self.emitted_comment_indices.push(idx);
|
|
154
|
+
last_comment_end_line = Some(comment_end_line);
|
|
115
155
|
|
|
116
|
-
//
|
|
156
|
+
// Add blank line after the LAST comment if there was a gap to the code
|
|
117
157
|
if i == comments_count - 1 && line > comment_end_line + 1 {
|
|
118
158
|
self.buffer.push('\n');
|
|
119
159
|
}
|
|
@@ -122,6 +162,65 @@ impl Emitter {
|
|
|
122
162
|
Ok(())
|
|
123
163
|
}
|
|
124
164
|
|
|
165
|
+
/// Check if there are any unemitted comments in the given line range
|
|
166
|
+
fn has_comments_in_range(&self, start_line: usize, end_line: usize) -> bool {
|
|
167
|
+
self.all_comments.iter().enumerate().any(|(idx, comment)| {
|
|
168
|
+
!self.emitted_comment_indices.contains(&idx)
|
|
169
|
+
&& comment.location.start_line >= start_line
|
|
170
|
+
&& comment.location.end_line < end_line
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/// Emit comments that are within a given line range (exclusive of end_line)
|
|
175
|
+
fn emit_comments_in_range(
|
|
176
|
+
&mut self,
|
|
177
|
+
start_line: usize,
|
|
178
|
+
end_line: usize,
|
|
179
|
+
indent_level: usize,
|
|
180
|
+
) -> Result<()> {
|
|
181
|
+
let indent_str = match self.config.formatting.indent_style {
|
|
182
|
+
IndentStyle::Spaces => " ".repeat(self.config.formatting.indent_width * indent_level),
|
|
183
|
+
IndentStyle::Tabs => "\t".repeat(indent_level),
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
let mut comments_to_emit = Vec::new();
|
|
187
|
+
for (idx, comment) in self.all_comments.iter().enumerate() {
|
|
188
|
+
if self.emitted_comment_indices.contains(&idx) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if comment.location.start_line >= start_line && comment.location.end_line < end_line {
|
|
193
|
+
comments_to_emit.push((
|
|
194
|
+
idx,
|
|
195
|
+
comment.text.clone(),
|
|
196
|
+
comment.location.start_line,
|
|
197
|
+
comment.location.end_line,
|
|
198
|
+
));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Sort by start_line to emit in order
|
|
203
|
+
comments_to_emit.sort_by_key(|(_, _, start, _)| *start);
|
|
204
|
+
|
|
205
|
+
let mut last_comment_end_line: Option<usize> = None;
|
|
206
|
+
|
|
207
|
+
for (idx, text, comment_start_line, comment_end_line) in comments_to_emit {
|
|
208
|
+
// Preserve blank lines between comments
|
|
209
|
+
if let Some(prev_end) = last_comment_end_line {
|
|
210
|
+
let gap = comment_start_line.saturating_sub(prev_end);
|
|
211
|
+
for _ in 1..gap {
|
|
212
|
+
self.buffer.push('\n');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
writeln!(self.buffer, "{}{}", indent_str, text)?;
|
|
217
|
+
self.emitted_comment_indices.push(idx);
|
|
218
|
+
last_comment_end_line = Some(comment_end_line);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
Ok(())
|
|
222
|
+
}
|
|
223
|
+
|
|
125
224
|
/// Emit comments that appear on the same line (trailing comments)
|
|
126
225
|
fn emit_trailing_comments(&mut self, line: usize) -> Result<()> {
|
|
127
226
|
let mut indices_to_emit = Vec::new();
|
|
@@ -249,6 +348,9 @@ impl Emitter {
|
|
|
249
348
|
// Emit body (children), but skip structural nodes (class name, superclass)
|
|
250
349
|
// Use start_line check to properly handle CallNode superclasses like ActiveRecord::Migration[8.0]
|
|
251
350
|
let class_start_line = node.location.start_line;
|
|
351
|
+
let class_end_line = node.location.end_line;
|
|
352
|
+
let mut has_body_content = false;
|
|
353
|
+
|
|
252
354
|
for child in &node.children {
|
|
253
355
|
// Skip nodes on the same line as class definition (name, superclass)
|
|
254
356
|
if child.location.start_line == class_start_line {
|
|
@@ -257,13 +359,18 @@ impl Emitter {
|
|
|
257
359
|
if self.is_structural_node(&child.node_type) {
|
|
258
360
|
continue;
|
|
259
361
|
}
|
|
362
|
+
has_body_content = true;
|
|
260
363
|
self.emit_node(child, indent_level + 1)?;
|
|
261
364
|
}
|
|
262
365
|
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
366
|
+
// Emit comments that are inside the class body but not attached to any node
|
|
367
|
+
// These are comments between class_start_line and class_end_line
|
|
368
|
+
self.emit_comments_in_range(class_start_line + 1, class_end_line, indent_level + 1)?;
|
|
369
|
+
|
|
370
|
+
// Add newline before end if there was body content or internal comments
|
|
371
|
+
if (has_body_content || self.has_comments_in_range(class_start_line + 1, class_end_line))
|
|
372
|
+
&& !self.buffer.ends_with('\n')
|
|
373
|
+
{
|
|
267
374
|
self.buffer.push('\n');
|
|
268
375
|
}
|
|
269
376
|
|
|
@@ -289,19 +396,25 @@ impl Emitter {
|
|
|
289
396
|
self.emit_trailing_comments(node.location.start_line)?;
|
|
290
397
|
self.buffer.push('\n');
|
|
291
398
|
|
|
399
|
+
let module_start_line = node.location.start_line;
|
|
400
|
+
let module_end_line = node.location.end_line;
|
|
401
|
+
let mut has_body_content = false;
|
|
402
|
+
|
|
292
403
|
// Emit body (children), but skip structural nodes
|
|
293
404
|
for child in &node.children {
|
|
294
405
|
if self.is_structural_node(&child.node_type) {
|
|
295
406
|
continue;
|
|
296
407
|
}
|
|
408
|
+
has_body_content = true;
|
|
297
409
|
self.emit_node(child, indent_level + 1)?;
|
|
298
410
|
}
|
|
299
411
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
412
|
+
// Emit comments that are inside the module body but not attached to any node
|
|
413
|
+
self.emit_comments_in_range(module_start_line + 1, module_end_line, indent_level + 1)?;
|
|
414
|
+
|
|
415
|
+
// Add newline before end if there was body content or internal comments
|
|
416
|
+
if (has_body_content || self.has_comments_in_range(module_start_line + 1, module_end_line))
|
|
417
|
+
&& !self.buffer.ends_with('\n')
|
|
305
418
|
{
|
|
306
419
|
self.buffer.push('\n');
|
|
307
420
|
}
|
|
@@ -463,7 +576,8 @@ impl Emitter {
|
|
|
463
576
|
}
|
|
464
577
|
} else if expect_continuation {
|
|
465
578
|
// Continuation line after trailing comma or backslash
|
|
466
|
-
|
|
579
|
+
// Add space after comma or if no trailing space
|
|
580
|
+
if !rescue_decl.ends_with(' ') {
|
|
467
581
|
rescue_decl.push(' ');
|
|
468
582
|
}
|
|
469
583
|
let content = trimmed.trim_end_matches('\\').trim();
|
|
@@ -995,6 +1109,20 @@ impl Emitter {
|
|
|
995
1109
|
if let Some(text) = text_owned {
|
|
996
1110
|
self.emit_indent(indent_level)?;
|
|
997
1111
|
write!(self.buffer, "{}", text)?;
|
|
1112
|
+
|
|
1113
|
+
// Mark comments that are strictly inside this node's line range as emitted
|
|
1114
|
+
// (they are included in the source extraction)
|
|
1115
|
+
// Don't mark trailing comments on the last line (they come after the node ends)
|
|
1116
|
+
for (idx, comment) in self.all_comments.iter().enumerate() {
|
|
1117
|
+
if !self.emitted_comment_indices.contains(&idx)
|
|
1118
|
+
&& comment.location.start_line >= node.location.start_line
|
|
1119
|
+
&& comment.location.end_line < node.location.end_line
|
|
1120
|
+
{
|
|
1121
|
+
self.emitted_comment_indices.push(idx);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// Emit trailing comments on the same line (after the node ends)
|
|
998
1126
|
self.emit_trailing_comments(node.location.end_line)?;
|
|
999
1127
|
}
|
|
1000
1128
|
}
|
|
@@ -1015,12 +1143,13 @@ impl Emitter {
|
|
|
1015
1143
|
self.emit_indent(indent_level)?;
|
|
1016
1144
|
write!(self.buffer, "{}", text)?;
|
|
1017
1145
|
|
|
1018
|
-
// Mark comments
|
|
1146
|
+
// Mark comments that are strictly inside this node's line range as emitted
|
|
1019
1147
|
// (they are included in the source extraction)
|
|
1148
|
+
// Don't mark trailing comments on the last line (they come after the node ends)
|
|
1020
1149
|
for (idx, comment) in self.all_comments.iter().enumerate() {
|
|
1021
1150
|
if !self.emitted_comment_indices.contains(&idx)
|
|
1022
1151
|
&& comment.location.start_line >= node.location.start_line
|
|
1023
|
-
&& comment.location.end_line
|
|
1152
|
+
&& comment.location.end_line < node.location.end_line
|
|
1024
1153
|
{
|
|
1025
1154
|
self.emitted_comment_indices.push(idx);
|
|
1026
1155
|
}
|
data/lib/rfmt/rfmt.so
CHANGED
|
Binary file
|
data/lib/rfmt/version.rb
CHANGED