rfmt 1.5.3-aarch64-linux → 1.6.1-aarch64-linux

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: d82f09486291a07109b0fdc54c23899b3e9c077cb38109fc547a0e565c59cb29
4
- data.tar.gz: f63b715d048236b81484a0fcd46d1fe7b4cfa995ac91f3aebd94f3999ce4b351
3
+ metadata.gz: e36c79a715864d1545b7646e65a9de6afe9d2502fdc60702fe595c9c94fccba0
4
+ data.tar.gz: 40c48ce63e3d9d7f64593635dd13217079eab96e209861fe5529f715160c8ea3
5
5
  SHA512:
6
- metadata.gz: edc982a72084c9b06334d1c9f3a78d50774ecd0275d0f6fb427c63f56d3c4b99cf2d7c6c3dd227c8a4188769299f0d96b61cad38fbdba2452dd1234d2aeaf209
7
- data.tar.gz: aade66d5d03618a45d203c9adc5b83bef8b67aafdce56021bb2982a77b7ed64b82b56a25c25f2b506068f04841bb0bab26908606d463bfe34fd357f2162757c9
6
+ metadata.gz: d0e411f31a9c4c49be7cff8ecbe7f15f2196b4a005888eecdf206a7fdf6ba098e85fae7ce5ec8675920a43eb7a0fe22687930660b66a88c411d5353dcf3fbd23
7
+ data.tar.gz: 969b21932415241c2868e1adcda98e9c7e98942522c7aacb025fbaaa53b6543665142cebcdaaead4ff86c4f360e9d17286aa50b06599dddc7b2bf491b2799ad6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.6.1] - 2026-04-24
4
+
5
+ Follow-up release consolidating the 1.6.0 architecture work.
6
+
7
+ ### Rule-based formatter
8
+
9
+ The rule-based `format/` pipeline (`Formatter`, `Registry`, `Rule`) is the canonical formatting path, replacing the legacy monolithic emitter. Rules covering body indentation (`StatementsRule`), singleton classes (`SingletonClassRule`), and variable writes (`VariableWriteRule`) ship as part of the default registry. The Intermediate Representation (IR) module decouples parsing from emission for composability and testability.
10
+
11
+ ### Method chain reformatting
12
+
13
+ Multi-line method chains can be reformatted from aligned style (indented under the first dot) to indented style (one level beyond the receiver), preserving the source's base indent. The pass is wired into the fallback path for resilience.
14
+
15
+ ### Printer optimizations
16
+
17
+ The printer carries a pre-computed indent cache and inline hints for the hot path; `reformat_chain_lines` has been deduplicated across rules and uses `Cow<str>` to avoid allocations on pass-through.
18
+
19
+ ### Editor integration
20
+
21
+ Setup guides for VSCode, Neovim, Helix, Emacs, and Zed land in the repository; every editor uses the Ruby LSP addon system, so there are no editor-specific plugins to maintain. The README's Editor Integration section replaces the previous "Coming Soon" placeholder with a VSCode quick start.
22
+
23
+ ## [1.6.0] - 2026-04-23
24
+
25
+ ### Added
26
+ - **Rule-based formatter architecture**: new modular `format/` pipeline (`Formatter`, `Registry`, `Rule`) replacing the legacy monolithic emitter
27
+ - **Intermediate Representation (IR) module**: decouples parsing from emission for composability and testability
28
+ - New formatter rules: `StatementsRule` (body indentation), `SingletonClassRule`, `VariableWriteRule`
29
+ - Method chain reformatting: convert aligned style to indented style when lines exceed the configured width
30
+ - Chain reformatting wired into the fallback path for resilience
31
+ - `config` module exported for test consumption
32
+ - **Editor Integration Documentation**: comprehensive setup guides for VSCode, Neovim, Helix, Emacs, and Zed
33
+ - VSCode: Format on Save configuration with Ruby LSP, settings reference table, project-specific setup
34
+ - Zed: full configuration with `initialization_options` and `format_on_save`
35
+ - All editors work through the Ruby LSP addon system — no editor-specific plugins required
36
+ - README: Editor Integration section updated with VSCode quick start (replacing "Coming Soon")
37
+
38
+ ### Changed
39
+ - Printer optimized with indent cache and inline hints
40
+ - `reformat_chain_lines` deduplicated across rules and optimized with `Cow` to reduce allocations
41
+ - README: Neovim integration updated from CLI-based to Ruby LSP-based approach
42
+ - Removed Sublime Text section from editor documentation (replaced by Zed)
43
+
44
+ ### Fixed
45
+ - Prism comment JSON deserialization now accepts `comment_type` and `embdoc` fields (#97)
46
+ - BTreeMap range panic when computing comment indices on edge inputs
47
+ - Comment duplication during source extraction
48
+ - Empty source input handled gracefully by the formatter runner
49
+ - Clippy warnings: use `repeat_n`
50
+
51
+ ### Removed
52
+ - Legacy `Emitter` module (1844 LOC) — superseded by the new `Formatter`
53
+
3
54
  ## [1.5.3] - 2026-02-22
4
55
 
5
56
  ### Changed
data/README.md CHANGED
@@ -361,30 +361,34 @@ end
361
361
 
362
362
  ## Editor Integration
363
363
 
364
- ### Neovim
364
+ rfmt integrates with editors through [Ruby LSP](https://shopify.github.io/ruby-lsp/). For detailed setup instructions, see [Editor Integration Guide](docs/editors.md).
365
+
366
+ ### VSCode (Quick Start)
365
367
 
366
- Format Ruby files on save using autocmd:
368
+ 1. Install [Ruby LSP extension](https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp)
369
+ 2. Add to your `settings.json`:
370
+
371
+ ```json
372
+ {
373
+ "rubyLsp.formatter": "rfmt",
374
+ "editor.formatOnSave": true,
375
+ "[ruby]": {
376
+ "editor.defaultFormatter": "Shopify.ruby-lsp"
377
+ }
378
+ }
379
+ ```
380
+
381
+ ### Neovim
367
382
 
368
383
  ```lua
369
- -- ~/.config/nvim/init.lua
370
-
371
- vim.api.nvim_create_autocmd("BufWritePre", {
372
- pattern = { "*.rb", "*.rake", "Gemfile", "Rakefile" },
373
- callback = function()
374
- local filepath = vim.fn.expand("%:p")
375
- local result = vim.fn.system({ "rfmt", filepath })
376
- if vim.v.shell_error == 0 then
377
- vim.cmd("edit!")
378
- end
379
- end,
384
+ require("lspconfig").ruby_lsp.setup({
385
+ init_options = {
386
+ formatter = "rfmt"
387
+ }
380
388
  })
381
389
  ```
382
390
 
383
- ### Coming Soon
384
-
385
- - **VS Code** - Extension in development
386
- - **RubyMine** - Plugin in development
387
- - **Zed** - Extension in development
391
+ See [Editor Integration Guide](docs/editors.md) for Helix, Emacs, Sublime Text, and more.
388
392
 
389
393
  ## Development
390
394
 
data/lib/rfmt/3.3/rfmt.so CHANGED
Binary file
data/lib/rfmt/3.4/rfmt.so CHANGED
Binary file
@@ -62,17 +62,28 @@ module Rfmt
62
62
  # Serialize the Prism AST with comments to JSON
63
63
  def self.serialize_ast_with_comments(result)
64
64
  comments = result.comments.map do |comment|
65
+ loc = comment.location
66
+ end_line = loc.end_line
67
+ # Prism's `=begin ... =end` (EmbDocComment) location ends at
68
+ # `<=end_line>:0`, i.e. the column-0 start of the line AFTER the
69
+ # `=end` terminator. Reporting that larger end_line makes the
70
+ # comment appear to overlap with the next statement, so the
71
+ # comment gets misattributed to a deeper node (e.g. the first
72
+ # expression inside the next method body) and ends up emitted in
73
+ # the wrong place. Snap it back to the terminator line.
74
+ end_line = loc.end_line - 1 if loc.end_column.zero? && loc.end_line > loc.start_line
75
+
65
76
  {
66
77
  comment_type: comment.class.name.split('::').last.downcase.gsub('comment', ''),
67
78
  location: {
68
- start_line: comment.location.start_line,
69
- start_column: comment.location.start_column,
70
- end_line: comment.location.end_line,
71
- end_column: comment.location.end_column,
72
- start_offset: comment.location.start_offset,
73
- end_offset: comment.location.end_offset
79
+ start_line: loc.start_line,
80
+ start_column: loc.start_column,
81
+ end_line: end_line,
82
+ end_column: loc.end_column,
83
+ start_offset: loc.start_offset,
84
+ end_offset: loc.end_offset
74
85
  },
75
- text: comment.location.slice,
86
+ text: loc.slice,
76
87
  position: 'leading' # Default position, will be refined by Rust
77
88
  }
78
89
  end
@@ -120,7 +131,7 @@ module Rfmt
120
131
  closing = node.closing_loc
121
132
  if closing.end_offset > end_offset
122
133
  end_offset = closing.end_offset
123
- end_line = closing.end_line
134
+ end_line = heredoc_terminator_line(closing)
124
135
  end_column = closing.end_column
125
136
  end
126
137
  end
@@ -145,6 +156,19 @@ module Rfmt
145
156
  }
146
157
  end
147
158
 
159
+ # Prism reports a heredoc's `closing_loc` as `<terminator_line>:0..(terminator_line+1):0`,
160
+ # i.e. its `end_line` is the LINE AFTER the terminator. Using that as the
161
+ # node's `end_line` makes blank-line preservation fail: a real blank line
162
+ # right after the terminator looks identical (diff == 1) to two adjacent
163
+ # statements with no separator. Use the terminator's own line instead.
164
+ def self.heredoc_terminator_line(closing_loc)
165
+ if closing_loc.end_column.zero? && closing_loc.end_line > closing_loc.start_line
166
+ closing_loc.start_line
167
+ else
168
+ closing_loc.end_line
169
+ end
170
+ end
171
+
148
172
  # Recursively find the maximum closing_loc among all descendant nodes
149
173
  # Returns nil if no closing_loc found, otherwise { end_offset:, end_line:, end_column: }
150
174
  def self.find_max_closing_loc_recursive(node, depth: 0)
@@ -158,7 +182,7 @@ module Rfmt
158
182
  if max_closing.nil? || closing.end_offset > max_closing[:end_offset]
159
183
  max_closing = {
160
184
  end_offset: closing.end_offset,
161
- end_line: closing.end_line,
185
+ end_line: heredoc_terminator_line(closing),
162
186
  end_column: closing.end_column
163
187
  }
164
188
  end
@@ -424,9 +448,16 @@ module Rfmt
424
448
  metadata['name'] = name
425
449
  end
426
450
  when Prism::DefNode
427
- if (name = extract_node_name(node))
428
- metadata['name'] = name
429
- end
451
+ # Prefer `name_loc.slice` over `name.to_s` so unary operator suffixes
452
+ # (`def !@`, `def +@`, `def -@`) survive the round-trip. Prism
453
+ # normalizes `name` to the symbol with the `@` stripped for `!@`,
454
+ # which would otherwise rewrite `def !@` to `def !` silently.
455
+ name = if node.respond_to?(:name_loc) && node.name_loc
456
+ node.name_loc.slice
457
+ else
458
+ extract_node_name(node)
459
+ end
460
+ metadata['name'] = name if name
430
461
  metadata['parameters_count'] = extract_parameter_count(node).to_s
431
462
  # Extract parameters text directly from source
432
463
  if node.parameters
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.5.3'
4
+ VERSION = '1.6.1'
5
5
  end
@@ -10,6 +10,8 @@ module RubyLsp
10
10
  # @return [String, nil] Formatted text or nil on error
11
11
  def run_formatting(_uri, document)
12
12
  source = document.source
13
+ return "\n" if source.empty?
14
+
13
15
  ::Rfmt.format(source)
14
16
  rescue ::Rfmt::Error
15
17
  nil
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.5.3
4
+ version: 1.6.1
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - fujitani sora
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-22 00:00:00.000000000 Z
11
+ date: 2026-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs