rfmt 1.6.3 → 1.7.0
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 +13 -0
- data/Cargo.lock +1 -1
- data/README.md +29 -1
- data/exe/rfmt-lsp +8 -0
- data/exe/rfmt_fast +12 -0
- data/ext/rfmt/Cargo.toml +1 -1
- data/lib/rfmt/lsp/document_store.rb +27 -0
- data/lib/rfmt/lsp/formatter.rb +37 -0
- data/lib/rfmt/lsp/message_io.rb +55 -0
- data/lib/rfmt/lsp/server.rb +168 -0
- data/lib/rfmt/lsp/uri.rb +35 -0
- data/lib/rfmt/lsp/workspace.rb +62 -0
- data/lib/rfmt/lsp.rb +8 -0
- data/lib/rfmt/version.rb +1 -1
- metadata +53 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a0859791a44c6bb50fb43c42d132ed44da02bd39c61c48fd23258bf6277dddfa
|
|
4
|
+
data.tar.gz: fa2ecf36f2cf0bb5c478470a80587c7939a533e613341139598aebd95c07b5c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 067c43a9db65ff398d3a4c7ab4166084cb0796dbdeb4908aa925f93f0b833bcd8f65b4abf254f786b17d0adc122958979d8d922af65183531b51bfd7adfae222
|
|
7
|
+
data.tar.gz: e1d7acad6ca7efa9885f25e3408638842875aa801ec73506d4fb29010bd31efd51a91d59b200ab318e0e5cbb22433447dadf7128bf1d0ad76c88217d75dd9a42
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.7.0] - 2026-06-04
|
|
4
|
+
|
|
5
|
+
rfmt now ships a standalone LSP server. Point any LSP-capable editor at `rfmt-lsp` and you get format-on-save — no Ruby LSP, no Gemfile, and no editor-specific plugin required. This makes rfmt usable from Helix, Neovim, Emacs, and any other LSP client, including in projects that don't bundle rfmt.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Standalone LSP server `rfmt-lsp` (#108). Provides format-on-save in any LSP-capable editor without requiring Ruby LSP or a Gemfile:
|
|
10
|
+
- `textDocument/formatting` with full document sync; unsaved buffer contents are formatted via `didOpen`/`didChange` tracking
|
|
11
|
+
- `.rfmt.yml` is resolved relative to the workspace root (`rootUri`/`workspaceFolders`)
|
|
12
|
+
- Graceful handling of syntax errors (returns no edits instead of crashing), empty files, and unsupported LSP methods
|
|
13
|
+
- New `exe/rfmt-lsp` executable shipped with the gem
|
|
14
|
+
- Editor setup guides for the standalone server (Neovim, Helix, Emacs eglot) in `docs/editors.md`
|
|
15
|
+
|
|
3
16
|
## [1.6.3] - 2026-04-24
|
|
4
17
|
|
|
5
18
|
Minor stability refinements on top of the 1.6.x architecture release. See the 1.6.1 notes below for the feature set this series delivers.
|
data/Cargo.lock
CHANGED
data/README.md
CHANGED
|
@@ -361,7 +361,35 @@ end
|
|
|
361
361
|
|
|
362
362
|
## Editor Integration
|
|
363
363
|
|
|
364
|
-
rfmt
|
|
364
|
+
rfmt can integrate with editors in two ways:
|
|
365
|
+
|
|
366
|
+
- Standalone LSP: run `rfmt-lsp` directly from your editor. This works well for single
|
|
367
|
+
Ruby scripts or projects without a Gemfile.
|
|
368
|
+
- Ruby LSP add-on: use rfmt as the formatter inside
|
|
369
|
+
[Ruby LSP](https://shopify.github.io/ruby-lsp/).
|
|
370
|
+
|
|
371
|
+
For detailed setup instructions, see [Editor Integration Guide](docs/editors.md).
|
|
372
|
+
|
|
373
|
+
### Standalone LSP
|
|
374
|
+
|
|
375
|
+
After installing rfmt, configure your editor's Ruby language server command to `rfmt-lsp`.
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
gem install rfmt
|
|
379
|
+
rfmt-lsp
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Example Helix configuration:
|
|
383
|
+
|
|
384
|
+
```toml
|
|
385
|
+
[language-server.rfmt]
|
|
386
|
+
command = "rfmt-lsp"
|
|
387
|
+
|
|
388
|
+
[[language]]
|
|
389
|
+
name = "ruby"
|
|
390
|
+
language-servers = ["rfmt"]
|
|
391
|
+
auto-format = true
|
|
392
|
+
```
|
|
365
393
|
|
|
366
394
|
### VSCode (Quick Start)
|
|
367
395
|
|
data/exe/rfmt-lsp
ADDED
data/exe/rfmt_fast
ADDED
data/ext/rfmt/Cargo.toml
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rfmt
|
|
4
|
+
module LSP
|
|
5
|
+
class DocumentStore
|
|
6
|
+
def initialize
|
|
7
|
+
@documents = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def open(uri, text)
|
|
11
|
+
@documents[uri] = text
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def change(uri, text)
|
|
15
|
+
@documents[uri] = text
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def close(uri)
|
|
19
|
+
@documents.delete(uri)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def source_for(uri)
|
|
23
|
+
@documents[uri]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rfmt'
|
|
4
|
+
|
|
5
|
+
module Rfmt
|
|
6
|
+
module LSP
|
|
7
|
+
class Formatter
|
|
8
|
+
def self.format_edits(source)
|
|
9
|
+
formatted = source.empty? ? "\n" : Rfmt.format(source)
|
|
10
|
+
return [] if formatted == source
|
|
11
|
+
|
|
12
|
+
[
|
|
13
|
+
{
|
|
14
|
+
range: full_document_range(source),
|
|
15
|
+
newText: formatted
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
rescue Rfmt::Error
|
|
19
|
+
[]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.full_document_range(source)
|
|
23
|
+
return { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } } if source.empty?
|
|
24
|
+
|
|
25
|
+
lines = source.split("\n", -1)
|
|
26
|
+
|
|
27
|
+
{
|
|
28
|
+
start: { line: 0, character: 0 },
|
|
29
|
+
end: {
|
|
30
|
+
line: lines.length - 1,
|
|
31
|
+
character: lines.last.length
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Rfmt
|
|
6
|
+
module LSP
|
|
7
|
+
# Reads and writes LSP JSON-RPC messages over an IO pair.
|
|
8
|
+
class MessageIO
|
|
9
|
+
HEADER_SEPARATOR = "\r\n\r\n"
|
|
10
|
+
CONTENT_LENGTH = /\AContent-Length:\s*(\d+)\z/i
|
|
11
|
+
|
|
12
|
+
def initialize(input: $stdin, output: $stdout)
|
|
13
|
+
@input = input
|
|
14
|
+
@output = output
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def read_message
|
|
18
|
+
headers = read_headers
|
|
19
|
+
return nil if headers.nil?
|
|
20
|
+
|
|
21
|
+
content_length = headers.fetch('content-length').to_i
|
|
22
|
+
JSON.parse(@input.read(content_length))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def write_message(payload)
|
|
26
|
+
body = JSON.generate(payload)
|
|
27
|
+
@output.write("Content-Length: #{body.bytesize}#{HEADER_SEPARATOR}#{body}")
|
|
28
|
+
@output.flush if @output.respond_to?(:flush)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def read_headers
|
|
34
|
+
headers = {}
|
|
35
|
+
|
|
36
|
+
loop do
|
|
37
|
+
line = @input.gets
|
|
38
|
+
return nil if line.nil?
|
|
39
|
+
|
|
40
|
+
line = line.chomp
|
|
41
|
+
line = line.delete_suffix("\r")
|
|
42
|
+
break if line.empty?
|
|
43
|
+
|
|
44
|
+
match = CONTENT_LENGTH.match(line)
|
|
45
|
+
headers['content-length'] = match[1] if match
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
headers.fetch('content-length')
|
|
49
|
+
headers
|
|
50
|
+
rescue KeyError
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'language_server/protocol'
|
|
4
|
+
require 'rfmt/version'
|
|
5
|
+
|
|
6
|
+
require_relative 'document_store'
|
|
7
|
+
require_relative 'formatter'
|
|
8
|
+
require_relative 'message_io'
|
|
9
|
+
require_relative 'uri'
|
|
10
|
+
require_relative 'workspace'
|
|
11
|
+
|
|
12
|
+
module Rfmt
|
|
13
|
+
module LSP
|
|
14
|
+
class Server
|
|
15
|
+
TEXT_DOCUMENT_SYNC_FULL = 1
|
|
16
|
+
METHOD_NOT_FOUND = -32_601
|
|
17
|
+
INTERNAL_ERROR = -32_603
|
|
18
|
+
|
|
19
|
+
def initialize(input: $stdin, output: $stdout)
|
|
20
|
+
@io = MessageIO.new(input: input, output: output)
|
|
21
|
+
@documents = DocumentStore.new
|
|
22
|
+
@workspace = Workspace.new
|
|
23
|
+
@shutdown_requested = false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run
|
|
27
|
+
while (message = @io.read_message)
|
|
28
|
+
return @shutdown_requested ? 0 : 1 if handle_message(message) == :exit
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
0
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def handle_message(message)
|
|
35
|
+
method = message['method']
|
|
36
|
+
id = message['id']
|
|
37
|
+
params = message['params'] || {}
|
|
38
|
+
|
|
39
|
+
dispatch_message(method, id, params)
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
respond_error(id, INTERNAL_ERROR, e.message) if id
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def dispatch_message(method, id, params)
|
|
47
|
+
if request_handler?(method)
|
|
48
|
+
dispatch_request(method, id, params)
|
|
49
|
+
else
|
|
50
|
+
dispatch_notification(method, params) || respond_method_not_found(id, method)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def request_handler?(method)
|
|
55
|
+
%w[initialize textDocument/formatting shutdown].include?(method)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def dispatch_request(method, id, params)
|
|
59
|
+
case method
|
|
60
|
+
when 'initialize'
|
|
61
|
+
handle_initialize(id, params)
|
|
62
|
+
when 'textDocument/formatting'
|
|
63
|
+
handle_formatting(id, params)
|
|
64
|
+
when 'shutdown'
|
|
65
|
+
handle_shutdown(id)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def dispatch_notification(method, params)
|
|
70
|
+
case method
|
|
71
|
+
when 'initialized'
|
|
72
|
+
true
|
|
73
|
+
when 'textDocument/didOpen'
|
|
74
|
+
handle_did_open(params)
|
|
75
|
+
true
|
|
76
|
+
when 'textDocument/didChange'
|
|
77
|
+
handle_did_change(params)
|
|
78
|
+
true
|
|
79
|
+
when 'textDocument/didClose'
|
|
80
|
+
handle_did_close(params)
|
|
81
|
+
true
|
|
82
|
+
when 'exit'
|
|
83
|
+
:exit
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def respond_method_not_found(id, method)
|
|
88
|
+
respond_error(id, METHOD_NOT_FOUND, "Method not found: #{method}") if id
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def handle_initialize(id, params)
|
|
92
|
+
@workspace.configure(params)
|
|
93
|
+
|
|
94
|
+
respond(id, {
|
|
95
|
+
capabilities: {
|
|
96
|
+
documentFormattingProvider: true,
|
|
97
|
+
textDocumentSync: TEXT_DOCUMENT_SYNC_FULL
|
|
98
|
+
},
|
|
99
|
+
serverInfo: {
|
|
100
|
+
name: 'rfmt',
|
|
101
|
+
version: Rfmt::VERSION
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def handle_did_open(params)
|
|
107
|
+
text_document = params.fetch('textDocument')
|
|
108
|
+
@documents.open(text_document.fetch('uri'), text_document.fetch('text'))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def handle_did_change(params)
|
|
112
|
+
uri = params.fetch('textDocument').fetch('uri')
|
|
113
|
+
change = Array(params['contentChanges']).last
|
|
114
|
+
return unless change&.key?('text')
|
|
115
|
+
|
|
116
|
+
@documents.change(uri, change.fetch('text'))
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def handle_did_close(params)
|
|
120
|
+
uri = params.fetch('textDocument').fetch('uri')
|
|
121
|
+
@documents.close(uri)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def handle_formatting(id, params)
|
|
125
|
+
uri = params.fetch('textDocument').fetch('uri')
|
|
126
|
+
source = @documents.source_for(uri) || read_file_source(uri)
|
|
127
|
+
edits = if source
|
|
128
|
+
@workspace.with_root_for(uri) { Formatter.format_edits(source) }
|
|
129
|
+
else
|
|
130
|
+
[]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
respond(id, edits)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def handle_shutdown(id)
|
|
137
|
+
@shutdown_requested = true
|
|
138
|
+
respond(id, nil)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def read_file_source(uri)
|
|
142
|
+
path = URI.file_uri_to_path(uri)
|
|
143
|
+
return nil unless path && File.file?(path)
|
|
144
|
+
|
|
145
|
+
File.read(path)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def respond(id, result)
|
|
149
|
+
@io.write_message({
|
|
150
|
+
jsonrpc: '2.0',
|
|
151
|
+
id: id,
|
|
152
|
+
result: result
|
|
153
|
+
})
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def respond_error(id, code, message)
|
|
157
|
+
@io.write_message({
|
|
158
|
+
jsonrpc: '2.0',
|
|
159
|
+
id: id,
|
|
160
|
+
error: {
|
|
161
|
+
code: code,
|
|
162
|
+
message: message
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
data/lib/rfmt/lsp/uri.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
module Rfmt
|
|
6
|
+
module LSP
|
|
7
|
+
module URI
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def file_uri_to_path(uri)
|
|
11
|
+
parsed = ::URI.parse(uri)
|
|
12
|
+
return nil unless parsed.scheme == 'file'
|
|
13
|
+
|
|
14
|
+
percent_decode(parsed.path)
|
|
15
|
+
rescue ::URI::InvalidURIError
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def path_to_file_uri(path)
|
|
20
|
+
"file://#{percent_encode(File.expand_path(path))}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def percent_decode(value)
|
|
24
|
+
value.gsub(/%[0-9A-Fa-f]{2}/) { |match| [match[1..].to_i(16)].pack('C') }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def percent_encode(value)
|
|
28
|
+
value.bytes.map do |byte|
|
|
29
|
+
char = byte.chr
|
|
30
|
+
char.match?(%r{[A-Za-z0-9._~/-]}) ? char : format('%%%02X', byte)
|
|
31
|
+
end.join
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
require_relative 'uri'
|
|
6
|
+
|
|
7
|
+
module Rfmt
|
|
8
|
+
module LSP
|
|
9
|
+
class Workspace
|
|
10
|
+
def initialize
|
|
11
|
+
@roots = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def configure(params)
|
|
15
|
+
@roots = workspace_folder_roots(params)
|
|
16
|
+
root_uri = params['rootUri']
|
|
17
|
+
@roots << URI.file_uri_to_path(root_uri) if root_uri
|
|
18
|
+
@roots = @roots.compact.map { |root| File.expand_path(root) }.uniq
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def root_for(uri)
|
|
22
|
+
path = URI.file_uri_to_path(uri)
|
|
23
|
+
return existing_root(@roots.first) unless path
|
|
24
|
+
|
|
25
|
+
matching_root = @roots
|
|
26
|
+
.select { |root| path_inside?(path, root) }
|
|
27
|
+
.max_by(&:length)
|
|
28
|
+
return existing_root(matching_root) if matching_root
|
|
29
|
+
|
|
30
|
+
existing_root(File.dirname(path))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def with_root_for(uri, &block)
|
|
34
|
+
root = root_for(uri)
|
|
35
|
+
return block.call unless root
|
|
36
|
+
|
|
37
|
+
Dir.chdir(root, &block)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def workspace_folder_roots(params)
|
|
43
|
+
Array(params['workspaceFolders']).filter_map do |folder|
|
|
44
|
+
URI.file_uri_to_path(folder['uri'])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def path_inside?(path, root)
|
|
49
|
+
relative = Pathname.new(path).relative_path_from(Pathname.new(root)).to_s
|
|
50
|
+
relative == '.' || !relative.start_with?('..')
|
|
51
|
+
rescue ArgumentError
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def existing_root(root)
|
|
56
|
+
return nil unless root && File.directory?(root)
|
|
57
|
+
|
|
58
|
+
root
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/rfmt/lsp.rb
ADDED
data/lib/rfmt/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rfmt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fujitani sora
|
|
@@ -37,6 +37,48 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '3.4'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: language_server-protocol
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.17'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.17'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: parallel
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '1.24'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '1.24'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: prism
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '1.6'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '1.6'
|
|
40
82
|
- !ruby/object:Gem::Dependency
|
|
41
83
|
name: rb_sys
|
|
42
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -70,6 +112,7 @@ email:
|
|
|
70
112
|
- fujitanisora0414@gmail.com
|
|
71
113
|
executables:
|
|
72
114
|
- rfmt
|
|
115
|
+
- rfmt-lsp
|
|
73
116
|
extensions:
|
|
74
117
|
- ext/rfmt/extconf.rb
|
|
75
118
|
extra_rdoc_files: []
|
|
@@ -80,6 +123,8 @@ files:
|
|
|
80
123
|
- LICENSE.txt
|
|
81
124
|
- README.md
|
|
82
125
|
- exe/rfmt
|
|
126
|
+
- exe/rfmt-lsp
|
|
127
|
+
- exe/rfmt_fast
|
|
83
128
|
- ext/rfmt/Cargo.toml
|
|
84
129
|
- ext/rfmt/extconf.rb
|
|
85
130
|
- ext/rfmt/src/ast/mod.rs
|
|
@@ -118,6 +163,13 @@ files:
|
|
|
118
163
|
- lib/rfmt/cache.rb
|
|
119
164
|
- lib/rfmt/cli.rb
|
|
120
165
|
- lib/rfmt/configuration.rb
|
|
166
|
+
- lib/rfmt/lsp.rb
|
|
167
|
+
- lib/rfmt/lsp/document_store.rb
|
|
168
|
+
- lib/rfmt/lsp/formatter.rb
|
|
169
|
+
- lib/rfmt/lsp/message_io.rb
|
|
170
|
+
- lib/rfmt/lsp/server.rb
|
|
171
|
+
- lib/rfmt/lsp/uri.rb
|
|
172
|
+
- lib/rfmt/lsp/workspace.rb
|
|
121
173
|
- lib/rfmt/native_extension_loader.rb
|
|
122
174
|
- lib/rfmt/prism_bridge.rb
|
|
123
175
|
- lib/rfmt/prism_node_extractor.rb
|