ruby-lsp-rails 0.3.13 → 0.3.15
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 +2 -10
- data/Rakefile +1 -0
- data/lib/ruby_lsp/ruby_lsp_rails/addon.rb +13 -9
- data/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb +8 -7
- data/lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb +2 -1
- data/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb +11 -8
- data/lib/ruby_lsp/ruby_lsp_rails/server.rb +20 -8
- data/lib/ruby_lsp/ruby_lsp_rails/support/location_builder.rb +4 -4
- data/lib/ruby_lsp_rails/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8864e641f204eaafb608b703228bd98d5a2234413f48ee1d1232f277b7385144
|
4
|
+
data.tar.gz: 3db424bb7e32fbd1a1dce231d56b9d98d92e23b0c9ef70f56cbab86b878f9133
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3820483222f6b082c3f939e9b797a71e775776fd3e5a3d9422a99ab1c3af992dce883a69781cf4b2a07e8492c87e3054a351df4f22c398fd12cb20c6a4472ff8
|
7
|
+
data.tar.gz: 72e7715cefc65926b7d8011933e0152f90ee896b6530cea5edec0b41c70be701ae55619ea9c73dbb60e4becaf73df9f48ce122448ab2f6688204eda1d85edfb8
|
data/README.md
CHANGED
@@ -2,15 +2,7 @@
|
|
2
2
|
|
3
3
|
# Ruby LSP Rails
|
4
4
|
|
5
|
-
Ruby LSP Rails is a [Ruby LSP](https://github.com/Shopify/ruby-lsp) addon for extra Rails editor features
|
6
|
-
|
7
|
-
* Hover over an ActiveRecord model to reveal its schema.
|
8
|
-
* Run or debug a test by clicking on the code lens which appears above the test class, or an individual test.
|
9
|
-
* Navigate to associations, validations, callbacks and test cases using your editor's "Go to Symbol" feature, or outline view.
|
10
|
-
* Jump to the definition of callbacks using your editor's "Go to Definition" feature.
|
11
|
-
* Jump to the declaration of a route.
|
12
|
-
* Code Lens allowing fast-forwarding or rewinding of migrations.
|
13
|
-
* Code Lens showing the path that a route action corresponds to.
|
5
|
+
Ruby LSP Rails is a [Ruby LSP](https://github.com/Shopify/ruby-lsp) addon for extra [Rails editor features](https://shopify.github.io/ruby-lsp-rails/FEATURES_md.html).
|
14
6
|
|
15
7
|
## Installation
|
16
8
|
|
@@ -22,7 +14,7 @@ There is no need to add the gem to your bundle.
|
|
22
14
|
## Documentation
|
23
15
|
|
24
16
|
See the [documentation](https://shopify.github.io/ruby-lsp-rails) for more in-depth details about the
|
25
|
-
[supported features](https://shopify.github.io/ruby-lsp-rails/
|
17
|
+
[supported features](https://shopify.github.io/ruby-lsp-rails/FEATURES_md.html).
|
26
18
|
|
27
19
|
## How Runtime Introspection Works
|
28
20
|
|
data/Rakefile
CHANGED
@@ -23,6 +23,7 @@ RDoc::Task.new do |rdoc|
|
|
23
23
|
rdoc.rdoc_files.include("*.md", "lib/**/*.rb")
|
24
24
|
rdoc.rdoc_dir = "docs"
|
25
25
|
rdoc.markup = "markdown"
|
26
|
+
rdoc.title = "Ruby LSP Rails"
|
26
27
|
rdoc.generator = "snapper"
|
27
28
|
rdoc.options.push("--copy-files", "misc")
|
28
29
|
rdoc.options.push("--copy-files", "LICENSE.txt")
|
@@ -26,23 +26,27 @@ module RubyLsp
|
|
26
26
|
|
27
27
|
# We first initialize the client as a NullClient, so that we can start the server in a background thread. Until
|
28
28
|
# the real client is initialized, features that depend on it will not be blocked by using the NullClient
|
29
|
-
@
|
29
|
+
@rails_runner_client = T.let(NullClient.new, RunnerClient)
|
30
|
+
@global_state = T.let(nil, T.nilable(GlobalState))
|
30
31
|
end
|
31
32
|
|
33
|
+
sig { returns(RunnerClient) }
|
34
|
+
attr_reader :rails_runner_client
|
35
|
+
|
32
36
|
sig { override.params(global_state: GlobalState, message_queue: Thread::Queue).void }
|
33
37
|
def activate(global_state, message_queue)
|
34
|
-
@global_state =
|
38
|
+
@global_state = global_state
|
35
39
|
$stderr.puts("Activating Ruby LSP Rails addon v#{VERSION}")
|
36
40
|
# Start booting the real client in a background thread. Until this completes, the client will be a NullClient
|
37
|
-
Thread.new { @
|
41
|
+
Thread.new { @rails_runner_client = RunnerClient.create_client }
|
38
42
|
register_additional_file_watchers(global_state: global_state, message_queue: message_queue)
|
39
43
|
|
40
|
-
|
44
|
+
@global_state.index.register_enhancement(IndexingEnhancement.new)
|
41
45
|
end
|
42
46
|
|
43
47
|
sig { override.void }
|
44
48
|
def deactivate
|
45
|
-
@
|
49
|
+
@rails_runner_client.shutdown
|
46
50
|
end
|
47
51
|
|
48
52
|
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
|
@@ -54,7 +58,7 @@ module RubyLsp
|
|
54
58
|
).void
|
55
59
|
end
|
56
60
|
def create_code_lens_listener(response_builder, uri, dispatcher)
|
57
|
-
CodeLens.new(@
|
61
|
+
CodeLens.new(@rails_runner_client, T.must(@global_state), response_builder, uri, dispatcher)
|
58
62
|
end
|
59
63
|
|
60
64
|
sig do
|
@@ -65,7 +69,7 @@ module RubyLsp
|
|
65
69
|
).void
|
66
70
|
end
|
67
71
|
def create_hover_listener(response_builder, node_context, dispatcher)
|
68
|
-
Hover.new(@
|
72
|
+
Hover.new(@rails_runner_client, response_builder, node_context, T.must(@global_state), dispatcher)
|
69
73
|
end
|
70
74
|
|
71
75
|
sig do
|
@@ -90,7 +94,7 @@ module RubyLsp
|
|
90
94
|
end
|
91
95
|
def create_definition_listener(response_builder, uri, node_context, dispatcher)
|
92
96
|
index = T.must(@global_state).index
|
93
|
-
Definition.new(@
|
97
|
+
Definition.new(@rails_runner_client, response_builder, node_context, index, dispatcher)
|
94
98
|
end
|
95
99
|
|
96
100
|
sig { params(changes: T::Array[{ uri: String, type: Integer }]).void }
|
@@ -98,7 +102,7 @@ module RubyLsp
|
|
98
102
|
if changes.any? do |change|
|
99
103
|
change[:uri].end_with?("db/schema.rb") || change[:uri].end_with?("structure.sql")
|
100
104
|
end
|
101
|
-
@
|
105
|
+
@rails_runner_client.trigger_reload
|
102
106
|
end
|
103
107
|
end
|
104
108
|
|
@@ -138,22 +138,23 @@ module RubyLsp
|
|
138
138
|
class_name = node.constant_path.slice
|
139
139
|
superclass_name = node.superclass&.slice
|
140
140
|
|
141
|
+
# We need to use a stack because someone could define a nested class
|
142
|
+
# inside a controller. When we exit that nested class declaration, we are
|
143
|
+
# back in a controller context. This part is used in other places in the LSP
|
144
|
+
@constant_name_stack << [class_name, superclass_name]
|
145
|
+
|
141
146
|
if class_name.end_with?("Test")
|
142
|
-
|
147
|
+
fully_qualified_name = @constant_name_stack.map(&:first).join("::")
|
148
|
+
command = "#{test_command} #{@path} --name \"/#{Shellwords.escape(fully_qualified_name)}(#|::)/\""
|
143
149
|
add_test_code_lens(node, name: class_name, command: command, kind: :group)
|
144
150
|
@group_id_stack.push(@group_id)
|
145
151
|
@group_id += 1
|
146
152
|
end
|
147
153
|
|
148
|
-
if superclass_name&.start_with?("ActiveRecord::Migration")
|
154
|
+
if @path && superclass_name&.start_with?("ActiveRecord::Migration")
|
149
155
|
command = "#{migrate_command} VERSION=#{migration_version}"
|
150
156
|
add_migrate_code_lens(node, name: class_name, command: command)
|
151
157
|
end
|
152
|
-
|
153
|
-
# We need to use a stack because someone could define a nested class
|
154
|
-
# inside a controller. When we exit that nested class declaration, we are
|
155
|
-
# back in a controller context. This part is used in other places in the LSP
|
156
|
-
@constant_name_stack << [class_name, superclass_name]
|
157
158
|
end
|
158
159
|
|
159
160
|
sig { params(node: Prism::ClassNode).void }
|
@@ -151,7 +151,8 @@ module RubyLsp
|
|
151
151
|
selection_range: range_from_location(argument.location),
|
152
152
|
)
|
153
153
|
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
154
|
-
name = argument
|
154
|
+
name = constant_name(argument)
|
155
|
+
next unless name
|
155
156
|
next if name.empty?
|
156
157
|
|
157
158
|
append_document_symbol(
|
@@ -63,8 +63,11 @@ module RubyLsp
|
|
63
63
|
@stdout = T.let(stdout, IO)
|
64
64
|
@stderr = T.let(stderr, IO)
|
65
65
|
@wait_thread = T.let(wait_thread, Process::Waiter)
|
66
|
-
|
67
|
-
|
66
|
+
|
67
|
+
# We set binmode for Windows compatibility
|
68
|
+
@stdin.binmode
|
69
|
+
@stdout.binmode
|
70
|
+
@stderr.binmode
|
68
71
|
|
69
72
|
$stderr.puts("Ruby LSP Rails booting server")
|
70
73
|
count = 0
|
@@ -158,8 +161,6 @@ module RubyLsp
|
|
158
161
|
[@stdin, @stdout, @stderr].all?(&:closed?) && !@wait_thread.alive?
|
159
162
|
end
|
160
163
|
|
161
|
-
private
|
162
|
-
|
163
164
|
sig do
|
164
165
|
params(
|
165
166
|
request: String,
|
@@ -171,6 +172,12 @@ module RubyLsp
|
|
171
172
|
read_response
|
172
173
|
end
|
173
174
|
|
175
|
+
# Notifications are like messages, but one-way, with no response sent back.
|
176
|
+
sig { params(request: String, params: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
177
|
+
def send_notification(request, params = nil) = send_message(request, params)
|
178
|
+
|
179
|
+
private
|
180
|
+
|
174
181
|
sig { overridable.params(request: String, params: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
175
182
|
def send_message(request, params = nil)
|
176
183
|
message = { method: request }
|
@@ -184,10 +191,6 @@ module RubyLsp
|
|
184
191
|
# The server connection died
|
185
192
|
end
|
186
193
|
|
187
|
-
# Notifications are like messages, but one-way, with no response sent back.
|
188
|
-
sig { params(request: String, params: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
189
|
-
def send_notification(request, params = nil) = send_message(request, params)
|
190
|
-
|
191
194
|
sig { overridable.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
192
195
|
def read_response
|
193
196
|
raw_response = @mutex.synchronize do
|
@@ -12,10 +12,22 @@ module RubyLsp
|
|
12
12
|
VOID = Object.new
|
13
13
|
|
14
14
|
def initialize
|
15
|
-
|
16
|
-
|
17
|
-
$
|
18
|
-
$
|
15
|
+
# Grab references to the original pipes so that we can change the default output device further down
|
16
|
+
@stdin = $stdin
|
17
|
+
@stdout = $stdout
|
18
|
+
@stderr = $stderr
|
19
|
+
@stdin.sync = true
|
20
|
+
@stdout.sync = true
|
21
|
+
@stderr.sync = true
|
22
|
+
@stdin.binmode
|
23
|
+
@stdout.binmode
|
24
|
+
@stderr.binmode
|
25
|
+
|
26
|
+
# # Set the default output device to be $stderr. This means that using `puts` by itself will default to printing
|
27
|
+
# # to $stderr and only explicit `$stdout.puts` will go to $stdout. This reduces the chance that output coming
|
28
|
+
# # from the Rails app will be accidentally sent to the client
|
29
|
+
$> = $stderr
|
30
|
+
|
19
31
|
@running = true
|
20
32
|
end
|
21
33
|
|
@@ -25,18 +37,18 @@ module RubyLsp
|
|
25
37
|
routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
|
26
38
|
|
27
39
|
initialize_result = { result: { message: "ok", root: ::Rails.root.to_s } }.to_json
|
28
|
-
|
40
|
+
@stdout.write("Content-Length: #{initialize_result.length}\r\n\r\n#{initialize_result}")
|
29
41
|
|
30
42
|
while @running
|
31
|
-
headers =
|
32
|
-
json =
|
43
|
+
headers = @stdin.gets("\r\n\r\n")
|
44
|
+
json = @stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i)
|
33
45
|
|
34
46
|
request = JSON.parse(json, symbolize_names: true)
|
35
47
|
response = execute(request.fetch(:method), request[:params])
|
36
48
|
next if response == VOID
|
37
49
|
|
38
50
|
json_response = response.to_json
|
39
|
-
|
51
|
+
@stdout.write("Content-Length: #{json_response.length}\r\n\r\n#{json_response}")
|
40
52
|
end
|
41
53
|
end
|
42
54
|
|
@@ -11,18 +11,18 @@ module RubyLsp
|
|
11
11
|
sig { params(location_string: String).returns(Interface::Location) }
|
12
12
|
def line_location_from_s(location_string)
|
13
13
|
*file_parts, line = location_string.split(":")
|
14
|
-
|
15
|
-
raise ArgumentError, "Invalid location string given" unless file_parts
|
14
|
+
raise ArgumentError, "Invalid location string given" if file_parts.empty?
|
16
15
|
|
17
16
|
# On Windows, file paths will look something like `C:/path/to/file.rb:123`. Only the last colon is the line
|
18
17
|
# number and all other parts compose the file path
|
19
18
|
file_path = file_parts.join(":")
|
19
|
+
line_as_number = line ? Integer(line.to_i) - 1 : 0
|
20
20
|
|
21
21
|
Interface::Location.new(
|
22
22
|
uri: URI::Generic.from_path(path: file_path).to_s,
|
23
23
|
range: Interface::Range.new(
|
24
|
-
start: Interface::Position.new(line:
|
25
|
-
end: Interface::Position.new(line:
|
24
|
+
start: Interface::Position.new(line: line_as_number, character: 0),
|
25
|
+
end: Interface::Position.new(line: line_as_number, character: 0),
|
26
26
|
),
|
27
27
|
)
|
28
28
|
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.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-lsp
|
@@ -80,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '0'
|
82
82
|
requirements: []
|
83
|
-
rubygems_version: 3.5.
|
83
|
+
rubygems_version: 3.5.18
|
84
84
|
signing_key:
|
85
85
|
specification_version: 4
|
86
86
|
summary: A Ruby LSP addon for Rails
|