rfmt 1.4.0 → 1.4.1
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 +7 -0
- data/Cargo.lock +1 -1
- data/ext/rfmt/Cargo.toml +1 -1
- data/ext/rfmt/src/emitter/mod.rs +86 -18
- 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: a17203d9ab18d011d42790fc039889490f78bd9c1eb86701a15e15784bfafd4c
|
|
4
|
+
data.tar.gz: ae34f8b79a4d7e64fec13ea9b1a24ae8d1b46f03aeb4c64f302e52a3895c62e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 390bd25696b21224e5c182b6516a4a1733281a93bae01eb3ae58a787f3d53b430e308a760d1b47adc1389f2bd389b544aa6fe41e6990d0de654c5ead89d8e31f
|
|
7
|
+
data.tar.gz: f638716804d25efc8d74cd18c6a2c1e014d459a63a91dea4968ff2e1f21fee4c51890781051e6c92e2c5cac6e924687b531d9ac412d1e9eae6bfef8155b1b166
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.4.1] - 2026-01-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Fixed comment positioning issue where standalone comments before `end` statements were incorrectly attached to previous code lines
|
|
7
|
+
- Improved comment semantic preservation to maintain developer's original placement intent
|
|
8
|
+
- Enhanced standalone comment detection logic to distinguish between inline and independent comments
|
|
9
|
+
|
|
3
10
|
## [1.4.0] - 2026-01-17
|
|
4
11
|
|
|
5
12
|
### Added
|
data/Cargo.lock
CHANGED
data/ext/rfmt/Cargo.toml
CHANGED
data/ext/rfmt/src/emitter/mod.rs
CHANGED
|
@@ -237,34 +237,58 @@ impl Emitter {
|
|
|
237
237
|
})
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
/// Emit comments that
|
|
241
|
-
///
|
|
242
|
-
fn
|
|
240
|
+
/// Emit comments that appear immediately before the end statement while preserving their position
|
|
241
|
+
/// This is crucial for maintaining semantic relationships between comments and the code they precede
|
|
242
|
+
fn emit_comments_before_end(
|
|
243
243
|
&mut self,
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
construct_start_line: usize,
|
|
245
|
+
construct_end_line: usize,
|
|
246
246
|
indent_level: usize,
|
|
247
247
|
) -> Result<()> {
|
|
248
248
|
self.ensure_indent_cache(indent_level);
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
// Implement proper comment positioning logic
|
|
251
|
+
// Only emit standalone comments that appear on their own lines
|
|
252
|
+
// This prevents comments from being incorrectly attached to code statements
|
|
253
|
+
|
|
254
|
+
// Find comments that are between the construct and the end line
|
|
255
|
+
// Only emit comments that haven't been emitted yet AND are on their own lines
|
|
256
|
+
let indices =
|
|
257
|
+
self.get_comment_indices_in_range(construct_start_line + 1, construct_end_line);
|
|
251
258
|
|
|
252
259
|
let mut comments_to_emit: Vec<_> = indices
|
|
253
260
|
.into_iter()
|
|
254
|
-
.filter(|&idx|
|
|
261
|
+
.filter(|&idx| {
|
|
262
|
+
let comment = &self.all_comments[idx];
|
|
263
|
+
// Only emit if: not already emitted, before end line, and is standalone
|
|
264
|
+
!self.emitted_comment_indices.contains(&idx)
|
|
265
|
+
&& comment.location.end_line < construct_end_line
|
|
266
|
+
&& self.is_standalone_comment(comment)
|
|
267
|
+
})
|
|
255
268
|
.map(|idx| {
|
|
256
269
|
let comment = &self.all_comments[idx];
|
|
257
270
|
(idx, comment.location.start_line, comment.location.end_line)
|
|
258
271
|
})
|
|
259
272
|
.collect();
|
|
260
273
|
|
|
274
|
+
if comments_to_emit.is_empty() {
|
|
275
|
+
return Ok(());
|
|
276
|
+
}
|
|
277
|
+
|
|
261
278
|
comments_to_emit.sort_by_key(|(_, start, _)| *start);
|
|
262
279
|
|
|
263
|
-
|
|
280
|
+
// Ensure newline before first comment if buffer doesn't end with one
|
|
281
|
+
if !self.buffer.ends_with('\n') {
|
|
282
|
+
self.buffer.push('\n');
|
|
283
|
+
}
|
|
264
284
|
|
|
285
|
+
let mut last_emitted_line: Option<usize> = None;
|
|
286
|
+
|
|
287
|
+
// Emit comments while preserving their exact line positioning
|
|
265
288
|
for (idx, comment_start_line, comment_end_line) in comments_to_emit {
|
|
266
|
-
|
|
267
|
-
|
|
289
|
+
// Preserve blank lines between comments
|
|
290
|
+
if let Some(prev_line) = last_emitted_line {
|
|
291
|
+
let gap = comment_start_line.saturating_sub(prev_line);
|
|
268
292
|
for _ in 1..gap {
|
|
269
293
|
self.buffer.push('\n');
|
|
270
294
|
}
|
|
@@ -276,12 +300,50 @@ impl Emitter {
|
|
|
276
300
|
&self.indent_cache[indent_level], &self.all_comments[idx].text
|
|
277
301
|
)?;
|
|
278
302
|
self.emitted_comment_indices.insert(idx);
|
|
279
|
-
|
|
303
|
+
last_emitted_line = Some(comment_end_line);
|
|
280
304
|
}
|
|
281
305
|
|
|
282
306
|
Ok(())
|
|
283
307
|
}
|
|
284
308
|
|
|
309
|
+
/// Check if a comment should be treated as standalone
|
|
310
|
+
/// A standalone comment is one that should appear on its own line,
|
|
311
|
+
/// not attached to the end of a code statement
|
|
312
|
+
fn is_standalone_comment(&self, comment: &Comment) -> bool {
|
|
313
|
+
let comment_line = comment.location.start_line;
|
|
314
|
+
let _comment_start_offset = comment.location.start_offset;
|
|
315
|
+
|
|
316
|
+
// Get the source lines to analyze the comment's position
|
|
317
|
+
let lines: Vec<&str> = self.source.lines().collect();
|
|
318
|
+
|
|
319
|
+
// Check if we have a valid line number (1-indexed to 0-indexed)
|
|
320
|
+
if comment_line == 0 || comment_line > lines.len() {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
let line = lines[comment_line - 1]; // Convert to 0-indexed
|
|
325
|
+
|
|
326
|
+
// Find where the comment starts within the line
|
|
327
|
+
let comment_text = &comment.text;
|
|
328
|
+
|
|
329
|
+
// Look for the comment marker (#) in the line
|
|
330
|
+
if let Some(hash_pos) = line.find('#') {
|
|
331
|
+
// Check if there's only whitespace before the comment
|
|
332
|
+
let before_comment = &line[..hash_pos];
|
|
333
|
+
let is_only_whitespace = before_comment.trim().is_empty();
|
|
334
|
+
|
|
335
|
+
// Also verify this is actually our comment by checking the text matches
|
|
336
|
+
let line_comment_text = &line[hash_pos..];
|
|
337
|
+
let is_same_comment = line_comment_text.trim_end() == comment_text.trim_end();
|
|
338
|
+
|
|
339
|
+
return is_only_whitespace && is_same_comment;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// If we can't find the comment marker, assume it's standalone
|
|
343
|
+
// This is a fallback for edge cases
|
|
344
|
+
false
|
|
345
|
+
}
|
|
346
|
+
|
|
285
347
|
/// Emit comments that are within a given line range, preserving blank lines from prev_line
|
|
286
348
|
/// Uses BTreeMap index for O(log n) lookup instead of O(n) iteration
|
|
287
349
|
fn emit_comments_in_range_with_prev_line(
|
|
@@ -464,9 +526,8 @@ impl Emitter {
|
|
|
464
526
|
self.emit_node(child, indent_level + 1)?;
|
|
465
527
|
}
|
|
466
528
|
|
|
467
|
-
// Emit comments that
|
|
468
|
-
|
|
469
|
-
self.emit_comments_in_range(class_start_line + 1, class_end_line, indent_level + 1)?;
|
|
529
|
+
// Emit comments that appear before the end statement while preserving their position
|
|
530
|
+
self.emit_comments_before_end(class_start_line, class_end_line, indent_level + 1)?;
|
|
470
531
|
|
|
471
532
|
// Add newline before end if there was body content or internal comments
|
|
472
533
|
if (has_body_content || self.has_comments_in_range(class_start_line + 1, class_end_line))
|
|
@@ -512,8 +573,8 @@ impl Emitter {
|
|
|
512
573
|
self.emit_node(child, indent_level + 1)?;
|
|
513
574
|
}
|
|
514
575
|
|
|
515
|
-
// Emit comments that
|
|
516
|
-
self.
|
|
576
|
+
// Emit comments that appear before the end statement while preserving their position
|
|
577
|
+
self.emit_comments_before_end(module_start_line, module_end_line, indent_level + 1)?;
|
|
517
578
|
|
|
518
579
|
// Add newline before end if there was body content or internal comments
|
|
519
580
|
if (has_body_content || self.has_comments_in_range(module_start_line + 1, module_end_line))
|
|
@@ -573,6 +634,13 @@ impl Emitter {
|
|
|
573
634
|
self.emit_node(child, indent_level + 1)?;
|
|
574
635
|
}
|
|
575
636
|
|
|
637
|
+
// Emit comments that appear before the end statement while preserving their position
|
|
638
|
+
self.emit_comments_before_end(
|
|
639
|
+
node.location.start_line,
|
|
640
|
+
node.location.end_line,
|
|
641
|
+
indent_level + 1,
|
|
642
|
+
)?;
|
|
643
|
+
|
|
576
644
|
// Add newline before end if there was body content
|
|
577
645
|
if node
|
|
578
646
|
.children
|
|
@@ -1457,8 +1525,8 @@ impl Emitter {
|
|
|
1457
1525
|
}
|
|
1458
1526
|
}
|
|
1459
1527
|
|
|
1460
|
-
// Emit comments
|
|
1461
|
-
self.
|
|
1528
|
+
// Emit comments that appear before the end statement while preserving their position
|
|
1529
|
+
self.emit_comments_before_end(class_start_line, class_end_line, indent_level + 1)?;
|
|
1462
1530
|
|
|
1463
1531
|
// Add newline before end if there was body content
|
|
1464
1532
|
if (has_body_content || self.has_comments_in_range(class_start_line + 1, class_end_line))
|
data/lib/rfmt/version.rb
CHANGED