ruby-lsp-rails 0.3.0 → 0.3.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/README.md +1 -14
- data/lib/ruby_lsp/ruby_lsp_rails/addon.rb +25 -6
- data/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb +3 -19
- data/lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb +42 -0
- data/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb +73 -7
- data/lib/ruby_lsp/ruby_lsp_rails/server.rb +59 -39
- data/lib/ruby_lsp/ruby_lsp_rails/support/active_support_test_case_helper.rb +38 -0
- data/lib/ruby_lsp_rails/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75f1c942c624b415b9ac1207d42c3cd0d32fe5403ef49626c3be6f18f8cb3682
|
4
|
+
data.tar.gz: 7a6740caeae1fd86c55f917bd3ae59c1b1fc4d0080875ee37875e04ad3dc8c55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a86197ecdea2653c87dfb3d79b092681504391fd76e1a0849b754aca21b60fdcc8855f6c4d8fab4ee8e9a1816a1e39d896311bf30f558fb8a9b195ac6de3711
|
7
|
+
data.tar.gz: f295e7756887b52128eafd56a1cbb70017c48f0128c1f82d521b81098e50c894ae1c32f97c66dddd3752a62a5a9171f35dd7368ef6444a13acb467a368cd5cee
|
data/README.md
CHANGED
@@ -15,19 +15,6 @@ group :development do
|
|
15
15
|
gem "ruby-lsp-rails"
|
16
16
|
end
|
17
17
|
```
|
18
|
-
Some features rely on server introspection, and use a Rack server which is automatically mounted by using a Railtie.
|
19
|
-
|
20
|
-
For applications with specialized routing requirements, such as custom sharding, this may not be compatible. It can
|
21
|
-
be disabled with:
|
22
|
-
|
23
|
-
```ruby
|
24
|
-
# config/environments/development.rb
|
25
|
-
Rails.application.configure do
|
26
|
-
# ...
|
27
|
-
config.ruby_lsp_rails.server = false
|
28
|
-
# ...
|
29
|
-
end
|
30
|
-
```
|
31
18
|
|
32
19
|
## Usage
|
33
20
|
|
@@ -53,7 +40,7 @@ See the [documentation](https://shopify.github.io/ruby-lsp-rails) for more in-de
|
|
53
40
|
## How It Works
|
54
41
|
|
55
42
|
When Ruby LSP Rails starts, it spawns a `rails runner` instance which runs
|
56
|
-
`
|
43
|
+
[`server.rb`](https://github.com/Shopify/ruby-lsp-rails/blob/main/lib/ruby_lsp/ruby_lsp_rails/server.rb).
|
57
44
|
The addon communicates with this process over a pipe (i.e. `stdin` and `stdout`) to fetch runtime information about the application.
|
58
45
|
|
59
46
|
When extension is stopped (e.g. by quitting the editor), the server instance is shut down.
|
@@ -3,26 +3,35 @@
|
|
3
3
|
|
4
4
|
require "ruby_lsp/addon"
|
5
5
|
|
6
|
+
require_relative "support/active_support_test_case_helper"
|
6
7
|
require_relative "runner_client"
|
7
8
|
require_relative "hover"
|
8
9
|
require_relative "code_lens"
|
10
|
+
require_relative "document_symbol"
|
9
11
|
|
10
12
|
module RubyLsp
|
11
13
|
module Rails
|
12
14
|
class Addon < ::RubyLsp::Addon
|
13
15
|
extend T::Sig
|
14
16
|
|
15
|
-
sig {
|
16
|
-
def
|
17
|
-
|
17
|
+
sig { void }
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
|
21
|
+
# We first initialize the client as a NullClient, so that we can start the server in a background thread. Until
|
22
|
+
# the real client is initialized, features that depend on it will not be blocked by using the NullClient
|
23
|
+
@client = T.let(NullClient.new, RunnerClient)
|
18
24
|
end
|
19
25
|
|
20
26
|
sig { override.params(message_queue: Thread::Queue).void }
|
21
|
-
def activate(message_queue)
|
27
|
+
def activate(message_queue)
|
28
|
+
# Start booting the real client in a background thread. Until this completes, the client will be a NullClient
|
29
|
+
Thread.new { @client = RunnerClient.create_client }
|
30
|
+
end
|
22
31
|
|
23
32
|
sig { override.void }
|
24
33
|
def deactivate
|
25
|
-
client.shutdown
|
34
|
+
@client.shutdown
|
26
35
|
end
|
27
36
|
|
28
37
|
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
|
@@ -46,7 +55,17 @@ module RubyLsp
|
|
46
55
|
).void
|
47
56
|
end
|
48
57
|
def create_hover_listener(response_builder, nesting, index, dispatcher)
|
49
|
-
Hover.new(client, response_builder, nesting, index, dispatcher)
|
58
|
+
Hover.new(@client, response_builder, nesting, index, dispatcher)
|
59
|
+
end
|
60
|
+
|
61
|
+
sig do
|
62
|
+
override.params(
|
63
|
+
response_builder: ResponseBuilders::DocumentSymbol,
|
64
|
+
dispatcher: Prism::Dispatcher,
|
65
|
+
).returns(Object)
|
66
|
+
end
|
67
|
+
def create_document_symbol_listener(response_builder, dispatcher)
|
68
|
+
DocumentSymbol.new(response_builder, dispatcher)
|
50
69
|
end
|
51
70
|
|
52
71
|
sig { override.returns(String) }
|
@@ -35,6 +35,7 @@ module RubyLsp
|
|
35
35
|
class CodeLens
|
36
36
|
extend T::Sig
|
37
37
|
include Requests::Support::Common
|
38
|
+
include ActiveSupportTestCaseHelper
|
38
39
|
|
39
40
|
BASE_COMMAND = "bin/rails test"
|
40
41
|
|
@@ -56,26 +57,9 @@ module RubyLsp
|
|
56
57
|
|
57
58
|
sig { params(node: Prism::CallNode).void }
|
58
59
|
def on_call_node_enter(node)
|
59
|
-
|
60
|
-
return unless message_value == "test"
|
60
|
+
content = extract_test_case_name(node)
|
61
61
|
|
62
|
-
|
63
|
-
return unless arguments&.any?
|
64
|
-
|
65
|
-
first_argument = arguments.first
|
66
|
-
|
67
|
-
content = case first_argument
|
68
|
-
when Prism::InterpolatedStringNode
|
69
|
-
parts = first_argument.parts
|
70
|
-
|
71
|
-
if parts.all? { |part| part.is_a?(Prism::StringNode) }
|
72
|
-
T.cast(parts, T::Array[Prism::StringNode]).map(&:content).join
|
73
|
-
end
|
74
|
-
when Prism::StringNode
|
75
|
-
first_argument.content
|
76
|
-
end
|
77
|
-
|
78
|
-
return unless content && !content.empty?
|
62
|
+
return unless content
|
79
63
|
|
80
64
|
line_number = node.location.start_line
|
81
65
|
command = "#{BASE_COMMAND} #{@path}:#{line_number}"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Rails
|
6
|
+
# 
|
7
|
+
#
|
8
|
+
# The [document symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol)
|
9
|
+
# request allows users to navigate between ActiveSupport test cases with VS Code's "Go to Symbol" feature.
|
10
|
+
class DocumentSymbol
|
11
|
+
extend T::Sig
|
12
|
+
include Requests::Support::Common
|
13
|
+
include ActiveSupportTestCaseHelper
|
14
|
+
|
15
|
+
sig do
|
16
|
+
params(
|
17
|
+
response_builder: ResponseBuilders::DocumentSymbol,
|
18
|
+
dispatcher: Prism::Dispatcher,
|
19
|
+
).void
|
20
|
+
end
|
21
|
+
def initialize(response_builder, dispatcher)
|
22
|
+
@response_builder = response_builder
|
23
|
+
|
24
|
+
dispatcher.register(self, :on_call_node_enter)
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { params(node: Prism::CallNode).void }
|
28
|
+
def on_call_node_enter(node)
|
29
|
+
content = extract_test_case_name(node)
|
30
|
+
|
31
|
+
return unless content
|
32
|
+
|
33
|
+
@response_builder.last.children << RubyLsp::Interface::DocumentSymbol.new(
|
34
|
+
name: content,
|
35
|
+
kind: LanguageServer::Protocol::Constant::SymbolKind::METHOD,
|
36
|
+
selection_range: range_from_node(node),
|
37
|
+
range: range_from_node(node),
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,17 +4,38 @@
|
|
4
4
|
require "json"
|
5
5
|
require "open3"
|
6
6
|
|
7
|
-
# NOTE: We should avoid printing to stderr since it causes problems. We never read the standard error pipe
|
8
|
-
# from the client, so it will become full and eventually hang or crash.
|
9
|
-
# Instead, return a response with an `error` key.
|
10
|
-
|
11
7
|
module RubyLsp
|
12
8
|
module Rails
|
13
9
|
class RunnerClient
|
10
|
+
class << self
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { returns(RunnerClient) }
|
14
|
+
def create_client
|
15
|
+
new
|
16
|
+
rescue Errno::ENOENT, StandardError => e # rubocop:disable Lint/ShadowedException
|
17
|
+
warn("Ruby LSP Rails failed to initialize server: #{e.message}\n#{e.backtrace&.join("\n")}")
|
18
|
+
warn("Server dependent features will not be available")
|
19
|
+
NullClient.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class InitializationError < StandardError; end
|
24
|
+
class IncompleteMessageError < StandardError; end
|
25
|
+
|
14
26
|
extend T::Sig
|
15
27
|
|
16
28
|
sig { void }
|
17
29
|
def initialize
|
30
|
+
# Spring needs a Process session ID. It uses this ID to "attach" itself to the parent process, so that when the
|
31
|
+
# parent ends, the spring process ends as well. If this is not set, Spring will throw an error while trying to
|
32
|
+
# set its own session ID
|
33
|
+
begin
|
34
|
+
Process.setsid
|
35
|
+
rescue Errno::EPERM
|
36
|
+
# If we can't set the session ID, continue
|
37
|
+
end
|
38
|
+
|
18
39
|
stdin, stdout, stderr, wait_thread = Open3.popen3(
|
19
40
|
"bin/rails",
|
20
41
|
"runner",
|
@@ -27,11 +48,20 @@ module RubyLsp
|
|
27
48
|
@wait_thread = T.let(wait_thread, Process::Waiter)
|
28
49
|
@stdin.binmode # for Windows compatibility
|
29
50
|
@stdout.binmode # for Windows compatibility
|
51
|
+
|
52
|
+
warn("Ruby LSP Rails booting server")
|
53
|
+
read_response
|
54
|
+
warn("Finished booting Ruby LSP Rails server")
|
55
|
+
rescue Errno::EPIPE, IncompleteMessageError
|
56
|
+
raise InitializationError, @stderr.read
|
30
57
|
end
|
31
58
|
|
32
59
|
sig { params(name: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
33
60
|
def model(name)
|
34
61
|
make_request("model", name: name)
|
62
|
+
rescue IncompleteMessageError
|
63
|
+
warn("Ruby LSP Rails failed to get model information: #{@stderr.read}")
|
64
|
+
nil
|
35
65
|
end
|
36
66
|
|
37
67
|
sig { void }
|
@@ -48,13 +78,18 @@ module RubyLsp
|
|
48
78
|
|
49
79
|
private
|
50
80
|
|
51
|
-
sig
|
81
|
+
sig do
|
82
|
+
params(
|
83
|
+
request: String,
|
84
|
+
params: T.nilable(T::Hash[Symbol, T.untyped]),
|
85
|
+
).returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
86
|
+
end
|
52
87
|
def make_request(request, params = nil)
|
53
88
|
send_message(request, params)
|
54
89
|
read_response
|
55
90
|
end
|
56
91
|
|
57
|
-
sig { params(request:
|
92
|
+
sig { params(request: String, params: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
58
93
|
def send_message(request, params = nil)
|
59
94
|
message = { method: request }
|
60
95
|
message[:params] = params if params
|
@@ -68,8 +103,9 @@ module RubyLsp
|
|
68
103
|
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
69
104
|
def read_response
|
70
105
|
headers = @stdout.gets("\r\n\r\n")
|
71
|
-
|
106
|
+
raise IncompleteMessageError unless headers
|
72
107
|
|
108
|
+
raw_response = @stdout.read(headers[/Content-Length: (\d+)/i, 1].to_i)
|
73
109
|
response = JSON.parse(T.must(raw_response), symbolize_names: true)
|
74
110
|
|
75
111
|
if response[:error]
|
@@ -80,5 +116,35 @@ module RubyLsp
|
|
80
116
|
response.fetch(:result)
|
81
117
|
end
|
82
118
|
end
|
119
|
+
|
120
|
+
class NullClient < RunnerClient
|
121
|
+
extend T::Sig
|
122
|
+
|
123
|
+
sig { void }
|
124
|
+
def initialize # rubocop:disable Lint/MissingSuper
|
125
|
+
end
|
126
|
+
|
127
|
+
sig { override.void }
|
128
|
+
def shutdown
|
129
|
+
# no-op
|
130
|
+
end
|
131
|
+
|
132
|
+
sig { override.returns(T::Boolean) }
|
133
|
+
def stopped?
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
sig { override.params(request: String, params: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
140
|
+
def send_message(request, params = nil)
|
141
|
+
# no-op
|
142
|
+
end
|
143
|
+
|
144
|
+
sig { override.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
145
|
+
def read_response
|
146
|
+
# no-op
|
147
|
+
end
|
148
|
+
end
|
83
149
|
end
|
84
150
|
end
|
@@ -19,6 +19,9 @@ rescue
|
|
19
19
|
nil
|
20
20
|
end
|
21
21
|
|
22
|
+
# NOTE: We should avoid printing to stderr since it causes problems. We never read the standard error pipe from the
|
23
|
+
# client, so it will become full and eventually hang or crash. Instead, return a response with an `error` key.
|
24
|
+
|
22
25
|
module RubyLsp
|
23
26
|
module Rails
|
24
27
|
class Server
|
@@ -26,59 +29,76 @@ module RubyLsp
|
|
26
29
|
|
27
30
|
extend T::Sig
|
28
31
|
|
29
|
-
sig {
|
32
|
+
sig { void }
|
33
|
+
def initialize
|
34
|
+
$stdin.sync = true
|
35
|
+
$stdout.sync = true
|
36
|
+
@running = T.let(true, T::Boolean)
|
37
|
+
end
|
38
|
+
|
39
|
+
sig { void }
|
40
|
+
def start
|
41
|
+
initialize_result = { result: { message: "ok" } }.to_json
|
42
|
+
$stdout.write("Content-Length: #{initialize_result.length}\r\n\r\n#{initialize_result}")
|
43
|
+
|
44
|
+
while @running
|
45
|
+
headers = $stdin.gets("\r\n\r\n")
|
46
|
+
json = $stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i)
|
47
|
+
|
48
|
+
request = JSON.parse(json, symbolize_names: true)
|
49
|
+
response = execute(request.fetch(:method), request[:params])
|
50
|
+
next if response == VOID
|
51
|
+
|
52
|
+
json_response = response.to_json
|
53
|
+
$stdout.write("Content-Length: #{json_response.length}\r\n\r\n#{json_response}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
sig do
|
58
|
+
params(
|
59
|
+
request: String,
|
60
|
+
params: T::Hash[Symbol, T.untyped],
|
61
|
+
).returns(T.any(Object, T::Hash[Symbol, T.untyped]))
|
62
|
+
end
|
63
|
+
def execute(request, params = {})
|
64
|
+
case request
|
65
|
+
when "shutdown"
|
66
|
+
@running = false
|
67
|
+
VOID
|
68
|
+
when "model"
|
69
|
+
resolve_database_info_from_model(params.fetch(:name))
|
70
|
+
else
|
71
|
+
VOID
|
72
|
+
end
|
73
|
+
rescue => e
|
74
|
+
{ error: e.full_message(highlight: false) }
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
sig { params(model_name: String).returns(T::Hash[Symbol, T.untyped]) }
|
30
80
|
def resolve_database_info_from_model(model_name)
|
31
81
|
const = ActiveSupport::Inflector.safe_constantize(model_name)
|
32
|
-
unless const && const < ActiveRecord::Base && !const.abstract_class?
|
82
|
+
unless const && defined?(ActiveRecord) && const < ActiveRecord::Base && !const.abstract_class?
|
33
83
|
return {
|
34
84
|
result: nil,
|
35
85
|
}
|
36
86
|
end
|
37
87
|
|
38
|
-
|
39
|
-
|
40
|
-
{
|
88
|
+
info = {
|
41
89
|
result: {
|
42
90
|
columns: const.columns.map { |column| [column.name, column.type] },
|
43
|
-
schema_file: ::Rails.root + schema_file,
|
44
91
|
},
|
45
92
|
}
|
46
|
-
rescue => e
|
47
|
-
{
|
48
|
-
error: e.message,
|
49
|
-
}
|
50
|
-
end
|
51
|
-
|
52
|
-
sig { void }
|
53
|
-
def start
|
54
|
-
$stdin.sync = true
|
55
|
-
$stdout.sync = true
|
56
|
-
|
57
|
-
running = T.let(true, T::Boolean)
|
58
|
-
|
59
|
-
while running
|
60
|
-
headers = $stdin.gets("\r\n\r\n")
|
61
|
-
request = $stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i)
|
62
|
-
|
63
|
-
json = JSON.parse(request, symbolize_names: true)
|
64
|
-
request_method = json.fetch(:method)
|
65
|
-
params = json[:params]
|
66
|
-
|
67
|
-
response = case request_method
|
68
|
-
when "shutdown"
|
69
|
-
running = false
|
70
|
-
VOID
|
71
|
-
when "model"
|
72
|
-
resolve_database_info_from_model(params.fetch(:name))
|
73
|
-
else
|
74
|
-
VOID
|
75
|
-
end
|
76
93
|
|
77
|
-
|
94
|
+
if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:schema_dump_path)
|
95
|
+
info[:result][:schema_file] =
|
96
|
+
ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
|
78
97
|
|
79
|
-
json_response = response.to_json
|
80
|
-
$stdout.write("Content-Length: #{json_response.length}\r\n\r\n#{json_response}")
|
81
98
|
end
|
99
|
+
info
|
100
|
+
rescue => e
|
101
|
+
{ error: e.full_message(highlight: false) }
|
82
102
|
end
|
83
103
|
end
|
84
104
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Rails
|
6
|
+
module ActiveSupportTestCaseHelper
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { params(node: Prism::CallNode).returns(T.nilable(String)) }
|
10
|
+
def extract_test_case_name(node)
|
11
|
+
message_value = node.message
|
12
|
+
return unless message_value == "test" || message_value == "it"
|
13
|
+
|
14
|
+
return unless node.arguments
|
15
|
+
|
16
|
+
arguments = node.arguments&.arguments
|
17
|
+
return unless arguments&.any?
|
18
|
+
|
19
|
+
first_argument = arguments.first
|
20
|
+
|
21
|
+
content = case first_argument
|
22
|
+
when Prism::InterpolatedStringNode
|
23
|
+
parts = first_argument.parts
|
24
|
+
|
25
|
+
if parts.all? { |part| part.is_a?(Prism::StringNode) }
|
26
|
+
T.cast(parts, T::Array[Prism::StringNode]).map(&:content).join
|
27
|
+
end
|
28
|
+
when Prism::StringNode
|
29
|
+
first_argument.content
|
30
|
+
end
|
31
|
+
|
32
|
+
if content && !content.empty?
|
33
|
+
content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.14.
|
61
|
+
version: 0.14.2
|
62
62
|
- - "<"
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: 0.15.0
|
@@ -68,7 +68,7 @@ dependencies:
|
|
68
68
|
requirements:
|
69
69
|
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
|
-
version: 0.14.
|
71
|
+
version: 0.14.2
|
72
72
|
- - "<"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 0.15.0
|
@@ -99,9 +99,11 @@ files:
|
|
99
99
|
- lib/ruby-lsp-rails.rb
|
100
100
|
- lib/ruby_lsp/ruby_lsp_rails/addon.rb
|
101
101
|
- lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
|
102
|
+
- lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb
|
102
103
|
- lib/ruby_lsp/ruby_lsp_rails/hover.rb
|
103
104
|
- lib/ruby_lsp/ruby_lsp_rails/runner_client.rb
|
104
105
|
- lib/ruby_lsp/ruby_lsp_rails/server.rb
|
106
|
+
- lib/ruby_lsp/ruby_lsp_rails/support/active_support_test_case_helper.rb
|
105
107
|
- lib/ruby_lsp/ruby_lsp_rails/support/rails_document_client.rb
|
106
108
|
- lib/ruby_lsp_rails/railtie.rb
|
107
109
|
- lib/ruby_lsp_rails/version.rb
|