rfmt 1.2.4 → 1.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c95517c6abaad1c4bf47425dd4853dcd78bf5a2e47ab2bdc0cae1a3d3698c54
4
- data.tar.gz: a207798a5811f989a5ebb3405e48e0c86ac60d40b208f141e6d31a83de62dc0d
3
+ metadata.gz: b43c4cd99b99ae5b4525bc2efc9a3759e315cdbb200853345e2422d161fc58b6
4
+ data.tar.gz: e2f2f9fe52c401fadcd509e2705cbfca4a5bf0e84265f3ce7f764c1916e73470
5
5
  SHA512:
6
- metadata.gz: 86307164b77b1836c57718c62ac84bbc920fbfc36a7f0367656bc4fadd65cd846df9f45e5d8985a3eff2f49a548a576a8a73cb05e8e78679fe666589e904762c
7
- data.tar.gz: 69a7f17c2e547616ebea1a109628df5d3695fb9d9359715d90707a51c4d1c2d72095bad48ffc1d370e7229a01f193392235c3c7c2a0f13fd211dc0885ef2c447
6
+ metadata.gz: 9e728fee6c041313543cd631255e9ac6fdc3a69c7a22f32b2846be6cbed6a59e1d1ba2dd46d989850e9ac6bc8d4b31bd630a4477e6d0d767ef7dd73c4a5c76ed
7
+ data.tar.gz: 6a7d78ae563cc30ae96970562ddf027005631ae9a2d79755b49a44411fc0f90a2c81ba48a29150c326cc5e5ad793159890f46ae2ee4658a0baeeef7f5907a3d1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.2.6] - 2026-01-04
4
+
5
+ ### Changed
6
+ - Version bump
7
+
8
+ ## [1.2.5] - 2026-01-04
9
+
10
+ ### Fixed
11
+ - Fix trailing comments on `end` keyword (e.g., `end # rubocop:disable`)
12
+ - Fix block internal comments being moved outside the block
13
+ - Fix blank line preservation between code and comments inside blocks
14
+ - Fix leading blank line being added to comment-only files
15
+
3
16
  ## [1.2.4] - 2026-01-04
4
17
 
5
18
  ### Fixed
data/Cargo.lock CHANGED
@@ -1219,7 +1219,7 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
1219
1219
 
1220
1220
  [[package]]
1221
1221
  name = "rfmt"
1222
- version = "1.2.4"
1222
+ version = "1.2.6"
1223
1223
  dependencies = [
1224
1224
  "anyhow",
1225
1225
  "clap",
data/ext/rfmt/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rfmt"
3
- version = "1.2.4"
3
+ version = "1.2.6"
4
4
  edition = "2021"
5
5
  authors = ["fujitani sora <fujitanisora0414@gmail.com>"]
6
6
  license = "MIT"
@@ -79,24 +79,37 @@ impl Emitter {
79
79
  /// Emit all comments that haven't been emitted yet
80
80
  fn emit_remaining_comments(&mut self, last_code_line: usize) -> Result<()> {
81
81
  let mut last_end_line: Option<usize> = Some(last_code_line);
82
+ let mut is_first_comment = true;
83
+
82
84
  for (idx, comment) in self.all_comments.iter().enumerate() {
83
85
  if self.emitted_comment_indices.contains(&idx) {
84
86
  continue;
85
87
  }
86
- // Ensure we start on a new line for remaining comments
87
- if !self.buffer.ends_with('\n') {
88
+
89
+ // For the first remaining comment:
90
+ // - If buffer is empty, don't add any leading newline
91
+ // - If buffer has content, ensure we start on a new line
92
+ if is_first_comment && self.buffer.is_empty() {
93
+ // Don't add leading newline for first comment when buffer is empty
94
+ } else if !self.buffer.ends_with('\n') {
88
95
  self.buffer.push('\n');
89
96
  }
97
+
90
98
  // Preserve blank lines between code/comments
91
- if let Some(prev_line) = last_end_line {
92
- let gap = comment.location.start_line.saturating_sub(prev_line);
93
- for _ in 1..gap {
94
- self.buffer.push('\n');
99
+ // But only if this is not the first comment in an empty buffer
100
+ if !(is_first_comment && self.buffer.is_empty()) {
101
+ if let Some(prev_line) = last_end_line {
102
+ let gap = comment.location.start_line.saturating_sub(prev_line);
103
+ for _ in 1..gap {
104
+ self.buffer.push('\n');
105
+ }
95
106
  }
96
107
  }
108
+
97
109
  writeln!(self.buffer, "{}", comment.text)?;
98
110
  self.emitted_comment_indices.push(idx);
99
111
  last_end_line = Some(comment.location.end_line);
112
+ is_first_comment = false;
100
113
  }
101
114
  Ok(())
102
115
  }
@@ -221,6 +234,55 @@ impl Emitter {
221
234
  Ok(())
222
235
  }
223
236
 
237
+ /// Emit comments that are within a given line range, preserving blank lines from prev_line
238
+ fn emit_comments_in_range_with_prev_line(
239
+ &mut self,
240
+ start_line: usize,
241
+ end_line: usize,
242
+ indent_level: usize,
243
+ prev_line: usize,
244
+ ) -> Result<()> {
245
+ let indent_str = match self.config.formatting.indent_style {
246
+ IndentStyle::Spaces => " ".repeat(self.config.formatting.indent_width * indent_level),
247
+ IndentStyle::Tabs => "\t".repeat(indent_level),
248
+ };
249
+
250
+ let mut comments_to_emit = Vec::new();
251
+ for (idx, comment) in self.all_comments.iter().enumerate() {
252
+ if self.emitted_comment_indices.contains(&idx) {
253
+ continue;
254
+ }
255
+
256
+ if comment.location.start_line >= start_line && comment.location.end_line < end_line {
257
+ comments_to_emit.push((
258
+ idx,
259
+ comment.text.clone(),
260
+ comment.location.start_line,
261
+ comment.location.end_line,
262
+ ));
263
+ }
264
+ }
265
+
266
+ // Sort by start_line to emit in order
267
+ comments_to_emit.sort_by_key(|(_, _, start, _)| *start);
268
+
269
+ let mut last_end_line: usize = prev_line;
270
+
271
+ for (idx, text, comment_start_line, comment_end_line) in comments_to_emit {
272
+ // Preserve blank lines between previous content and this comment
273
+ let gap = comment_start_line.saturating_sub(last_end_line);
274
+ for _ in 1..gap {
275
+ self.buffer.push('\n');
276
+ }
277
+
278
+ writeln!(self.buffer, "{}{}", indent_str, text)?;
279
+ self.emitted_comment_indices.push(idx);
280
+ last_end_line = comment_end_line;
281
+ }
282
+
283
+ Ok(())
284
+ }
285
+
224
286
  /// Emit comments that appear on the same line (trailing comments)
225
287
  fn emit_trailing_comments(&mut self, line: usize) -> Result<()> {
226
288
  let mut indices_to_emit = Vec::new();
@@ -376,6 +438,8 @@ impl Emitter {
376
438
 
377
439
  self.emit_indent(indent_level)?;
378
440
  write!(self.buffer, "end")?;
441
+ // Emit trailing comments on end line (e.g., `end # rubocop:disable`)
442
+ self.emit_trailing_comments(node.location.end_line)?;
379
443
 
380
444
  Ok(())
381
445
  }
@@ -421,6 +485,8 @@ impl Emitter {
421
485
 
422
486
  self.emit_indent(indent_level)?;
423
487
  write!(self.buffer, "end")?;
488
+ // Emit trailing comments on end line (e.g., `end # rubocop:disable`)
489
+ self.emit_trailing_comments(node.location.end_line)?;
424
490
 
425
491
  Ok(())
426
492
  }
@@ -493,6 +559,8 @@ impl Emitter {
493
559
 
494
560
  self.emit_indent(indent_level)?;
495
561
  write!(self.buffer, "end")?;
562
+ // Emit trailing comments on end line (e.g., `end # rubocop:disable`)
563
+ self.emit_trailing_comments(node.location.end_line)?;
496
564
 
497
565
  Ok(())
498
566
  }
@@ -524,6 +592,8 @@ impl Emitter {
524
592
 
525
593
  self.emit_indent(indent_level)?;
526
594
  write!(self.buffer, "end")?;
595
+ // Emit trailing comments on end line
596
+ self.emit_trailing_comments(node.location.end_line)?;
527
597
  } else {
528
598
  // Implicit begin - emit children directly
529
599
  for (i, child) in node.children.iter().enumerate() {
@@ -714,6 +784,8 @@ impl Emitter {
714
784
  // Emit "end" keyword
715
785
  self.emit_indent(indent_level)?;
716
786
  write!(self.buffer, "end")?;
787
+ // Emit trailing comments on end line
788
+ self.emit_trailing_comments(node.location.end_line)?;
717
789
 
718
790
  Ok(())
719
791
  }
@@ -931,6 +1003,8 @@ impl Emitter {
931
1003
  if !is_elsif {
932
1004
  self.emit_indent(indent_level)?;
933
1005
  write!(self.buffer, "end")?;
1006
+ // Emit trailing comments on end line
1007
+ self.emit_trailing_comments(node.location.end_line)?;
934
1008
  }
935
1009
 
936
1010
  Ok(())
@@ -1021,17 +1095,46 @@ impl Emitter {
1021
1095
  self.buffer.push('\n');
1022
1096
 
1023
1097
  // Find and emit the body (StatementsNode among children)
1098
+ let block_start_line = block_node.location.start_line;
1099
+ let block_end_line = block_node.location.end_line;
1100
+ let mut last_stmt_end_line = block_start_line;
1101
+
1024
1102
  for child in &block_node.children {
1025
1103
  if matches!(child.node_type, NodeType::StatementsNode) {
1026
1104
  self.emit_statements(child, indent_level + 1)?;
1105
+ // Track the last statement's end line for blank line preservation
1106
+ if let Some(last_child) = child.children.last() {
1107
+ last_stmt_end_line = last_child.location.end_line;
1108
+ }
1027
1109
  self.buffer.push('\n');
1028
1110
  break;
1029
1111
  }
1030
1112
  }
1031
1113
 
1114
+ // Emit comments that are inside the block but not attached to any node
1115
+ // (comments between last statement and 'end')
1116
+ let had_internal_comments =
1117
+ self.has_comments_in_range(block_start_line + 1, block_end_line);
1118
+ if had_internal_comments {
1119
+ // Preserve blank line between last statement and first comment
1120
+ self.emit_comments_in_range_with_prev_line(
1121
+ block_start_line + 1,
1122
+ block_end_line,
1123
+ indent_level + 1,
1124
+ last_stmt_end_line,
1125
+ )?;
1126
+ }
1127
+
1128
+ // Add newline if there were internal comments
1129
+ if had_internal_comments && !self.buffer.ends_with('\n') {
1130
+ self.buffer.push('\n');
1131
+ }
1132
+
1032
1133
  // Emit 'end'
1033
1134
  self.emit_indent(indent_level)?;
1034
1135
  write!(self.buffer, "end")?;
1136
+ // Emit trailing comments on end line
1137
+ self.emit_trailing_comments(block_end_line)?;
1035
1138
 
1036
1139
  Ok(())
1037
1140
  }
@@ -1220,6 +1323,8 @@ impl Emitter {
1220
1323
 
1221
1324
  self.emit_indent(indent_level)?;
1222
1325
  write!(self.buffer, "end")?;
1326
+ // Emit trailing comments on end line
1327
+ self.emit_trailing_comments(node.location.end_line)?;
1223
1328
 
1224
1329
  Ok(())
1225
1330
  }
@@ -1271,6 +1376,8 @@ impl Emitter {
1271
1376
 
1272
1377
  self.emit_indent(indent_level)?;
1273
1378
  write!(self.buffer, "end")?;
1379
+ // Emit trailing comments on end line
1380
+ self.emit_trailing_comments(node.location.end_line)?;
1274
1381
 
1275
1382
  Ok(())
1276
1383
  }
data/lib/rfmt/rfmt.so CHANGED
Binary file
data/lib/rfmt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rfmt
4
- VERSION = '1.2.4'
4
+ VERSION = '1.2.6'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rfmt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - fujitani sora
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-03 00:00:00.000000000 Z
11
+ date: 2026-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys