ruby-lsp-rails 0.3.31 → 0.4.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/Rakefile +11 -2
- data/lib/ruby_lsp/ruby_lsp_rails/addon.rb +68 -61
- data/lib/ruby_lsp/ruby_lsp_rails/code_lens.rb +15 -24
- data/lib/ruby_lsp/ruby_lsp_rails/completion.rb +6 -14
- data/lib/ruby_lsp/ruby_lsp_rails/definition.rb +9 -20
- data/lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb +12 -24
- data/lib/ruby_lsp/ruby_lsp_rails/hover.rb +39 -27
- data/lib/ruby_lsp/ruby_lsp_rails/indexing_enhancement.rb +7 -20
- data/lib/ruby_lsp/ruby_lsp_rails/rails_test_style.rb +150 -0
- data/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb +90 -59
- data/lib/ruby_lsp/ruby_lsp_rails/server.rb +174 -17
- data/lib/ruby_lsp/ruby_lsp_rails/support/active_support_test_case_helper.rb +1 -3
- data/lib/ruby_lsp/ruby_lsp_rails/support/location_builder.rb +1 -3
- data/lib/ruby_lsp_rails/version.rb +1 -1
- metadata +6 -5
@@ -3,19 +3,42 @@
|
|
3
3
|
|
4
4
|
require "json"
|
5
5
|
require "open3"
|
6
|
+
require "delegate"
|
6
7
|
|
7
8
|
module RubyLsp
|
8
9
|
module Rails
|
9
10
|
module Common
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
class Progress
|
12
|
+
def initialize(stderr, id, supports_progress)
|
13
|
+
@stderr = stderr
|
14
|
+
@id = id
|
15
|
+
@supports_progress = supports_progress
|
16
|
+
end
|
17
|
+
|
18
|
+
def report(percentage: nil, message: nil)
|
19
|
+
return unless @supports_progress
|
20
|
+
return unless percentage || message
|
21
|
+
|
22
|
+
json_message = {
|
23
|
+
method: "$/progress",
|
24
|
+
params: {
|
25
|
+
token: @id,
|
26
|
+
value: {
|
27
|
+
kind: "report",
|
28
|
+
percentage: percentage,
|
29
|
+
message: message,
|
30
|
+
},
|
31
|
+
},
|
32
|
+
}.to_json
|
33
|
+
|
34
|
+
@stderr.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
|
35
|
+
end
|
14
36
|
end
|
15
37
|
|
16
|
-
# Log a message to the editor's output panel
|
17
|
-
|
18
|
-
|
38
|
+
# Log a message to the editor's output panel. The type is the number of the message type, which can be found in
|
39
|
+
# the specification https://microsoft.github.io/language-server-protocol/specification/#messageType
|
40
|
+
def log_message(message, type: 4)
|
41
|
+
send_notification({ method: "window/logMessage", params: { type: type, message: message } })
|
19
42
|
end
|
20
43
|
|
21
44
|
# Sends an error result to a request, if the request failed. DO NOT INVOKE THIS METHOD FOR NOTIFICATIONS! Use
|
@@ -54,6 +77,82 @@ module RubyLsp
|
|
54
77
|
rescue => e
|
55
78
|
log_message("Request #{notification_name} failed:\n#{e.full_message(highlight: false)}")
|
56
79
|
end
|
80
|
+
|
81
|
+
def begin_progress(id, title, percentage: nil, message: nil)
|
82
|
+
return unless @capabilities[:supports_progress]
|
83
|
+
|
84
|
+
# This is actually a request, but it is sent asynchronously and we do not return the response back to the
|
85
|
+
# server, so we consider it a notification from the perspective of the client/runtime server dynamic
|
86
|
+
send_notification({
|
87
|
+
id: "progress-request-#{id}",
|
88
|
+
method: "window/workDoneProgress/create",
|
89
|
+
params: { token: id },
|
90
|
+
})
|
91
|
+
|
92
|
+
send_notification({
|
93
|
+
method: "$/progress",
|
94
|
+
params: {
|
95
|
+
token: id,
|
96
|
+
value: {
|
97
|
+
kind: "begin",
|
98
|
+
title: title,
|
99
|
+
percentage: percentage,
|
100
|
+
message: message,
|
101
|
+
},
|
102
|
+
},
|
103
|
+
})
|
104
|
+
end
|
105
|
+
|
106
|
+
def report_progress(id, percentage: nil, message: nil)
|
107
|
+
return unless @capabilities[:supports_progress]
|
108
|
+
|
109
|
+
send_notification({
|
110
|
+
method: "$/progress",
|
111
|
+
params: {
|
112
|
+
token: id,
|
113
|
+
value: {
|
114
|
+
kind: "report",
|
115
|
+
percentage: percentage,
|
116
|
+
message: message,
|
117
|
+
},
|
118
|
+
},
|
119
|
+
})
|
120
|
+
end
|
121
|
+
|
122
|
+
def end_progress(id)
|
123
|
+
return unless @capabilities[:supports_progress]
|
124
|
+
|
125
|
+
send_notification({
|
126
|
+
method: "$/progress",
|
127
|
+
params: {
|
128
|
+
token: id,
|
129
|
+
value: { kind: "end" },
|
130
|
+
},
|
131
|
+
})
|
132
|
+
end
|
133
|
+
|
134
|
+
def with_progress(id, title, percentage: nil, message: nil, &block)
|
135
|
+
progress_block = Progress.new(@stderr, id, @capabilities[:supports_progress])
|
136
|
+
return block.call(progress_block) unless @capabilities[:supports_progress]
|
137
|
+
|
138
|
+
begin_progress(id, title, percentage: percentage, message: message)
|
139
|
+
block.call(progress_block)
|
140
|
+
end_progress(id)
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# Write a response message back to the client
|
146
|
+
def send_message(message)
|
147
|
+
json_message = message.to_json
|
148
|
+
@stdout.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
|
149
|
+
end
|
150
|
+
|
151
|
+
# Write a notification to the client to be transmitted to the editor
|
152
|
+
def send_notification(message)
|
153
|
+
json_message = message.to_json
|
154
|
+
@stderr.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
|
155
|
+
end
|
57
156
|
end
|
58
157
|
|
59
158
|
class ServerAddon
|
@@ -76,16 +175,18 @@ module RubyLsp
|
|
76
175
|
end
|
77
176
|
|
78
177
|
# Instantiate all server addons and store them in a hash for easy access after we have discovered the classes
|
79
|
-
def finalize_registrations!(stdout)
|
178
|
+
def finalize_registrations!(stdout, stderr, capabilities)
|
80
179
|
until @server_addon_classes.empty?
|
81
|
-
addon = @server_addon_classes.shift.new(stdout)
|
180
|
+
addon = @server_addon_classes.shift.new(stdout, stderr, capabilities)
|
82
181
|
@server_addons[addon.name] = addon
|
83
182
|
end
|
84
183
|
end
|
85
184
|
end
|
86
185
|
|
87
|
-
def initialize(stdout)
|
186
|
+
def initialize(stdout, stderr, capabilities)
|
88
187
|
@stdout = stdout
|
188
|
+
@stderr = stderr
|
189
|
+
@capabilities = capabilities
|
89
190
|
end
|
90
191
|
|
91
192
|
def name
|
@@ -97,14 +198,31 @@ module RubyLsp
|
|
97
198
|
end
|
98
199
|
end
|
99
200
|
|
201
|
+
class IOWrapper < SimpleDelegator
|
202
|
+
def puts(*args)
|
203
|
+
args.each { |arg| log("#{arg}\n") }
|
204
|
+
end
|
205
|
+
|
206
|
+
def print(*args)
|
207
|
+
args.each { |arg| log(arg.to_s) }
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def log(message)
|
213
|
+
json_message = { method: "window/logMessage", params: { type: 4, message: message } }.to_json
|
214
|
+
write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
100
218
|
class Server
|
101
219
|
include Common
|
102
220
|
|
103
|
-
def initialize(stdout: $stdout, override_default_output_device: true)
|
221
|
+
def initialize(stdout: $stdout, stderr: $stderr, override_default_output_device: true, capabilities: {})
|
104
222
|
# Grab references to the original pipes so that we can change the default output device further down
|
105
223
|
@stdin = $stdin
|
106
224
|
@stdout = stdout
|
107
|
-
@stderr =
|
225
|
+
@stderr = stderr
|
108
226
|
@stdin.sync = true
|
109
227
|
@stdout.sync = true
|
110
228
|
@stderr.sync = true
|
@@ -112,10 +230,13 @@ module RubyLsp
|
|
112
230
|
@stdout.binmode
|
113
231
|
@stderr.binmode
|
114
232
|
|
233
|
+
# A hash containing the capabilities of the editor that may be relevant for the runtime server
|
234
|
+
@capabilities = capabilities
|
235
|
+
|
115
236
|
# # Set the default output device to be $stderr. This means that using `puts` by itself will default to printing
|
116
237
|
# # to $stderr and only explicit `$stdout.puts` will go to $stdout. This reduces the chance that output coming
|
117
238
|
# # from the Rails app will be accidentally sent to the client
|
118
|
-
$> =
|
239
|
+
$> = IOWrapper.new(@stderr) if override_default_output_device
|
119
240
|
|
120
241
|
@running = true
|
121
242
|
end
|
@@ -155,8 +276,10 @@ module RubyLsp
|
|
155
276
|
send_result(run_migrations)
|
156
277
|
end
|
157
278
|
when "reload"
|
158
|
-
|
159
|
-
|
279
|
+
with_progress("rails-reload", "Reloading Ruby LSP Rails instance") do
|
280
|
+
with_notification_error_handling(request) do
|
281
|
+
::Rails.application.reloader.reload!
|
282
|
+
end
|
160
283
|
end
|
161
284
|
when "route_location"
|
162
285
|
with_request_error_handling(request) do
|
@@ -169,7 +292,7 @@ module RubyLsp
|
|
169
292
|
when "server_addon/register"
|
170
293
|
with_notification_error_handling(request) do
|
171
294
|
require params[:server_addon_path]
|
172
|
-
ServerAddon.finalize_registrations!(@stdout)
|
295
|
+
ServerAddon.finalize_registrations!(@stdout, @stderr, @capabilities)
|
173
296
|
end
|
174
297
|
when "server_addon/delegate"
|
175
298
|
server_addon_name = params[:server_addon_name]
|
@@ -241,6 +364,8 @@ module RubyLsp
|
|
241
364
|
info = {
|
242
365
|
columns: const.columns.map { |column| [column.name, column.type, column.default, column.null] },
|
243
366
|
primary_keys: Array(const.primary_key),
|
367
|
+
foreign_keys: collect_model_foreign_keys(const),
|
368
|
+
indexes: collect_model_indexes(const),
|
244
369
|
}
|
245
370
|
|
246
371
|
if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:schema_dump_path)
|
@@ -312,8 +437,40 @@ module RubyLsp
|
|
312
437
|
::ActionView::PathRegistry.file_system_resolver_hooks.clear
|
313
438
|
end
|
314
439
|
end
|
440
|
+
|
441
|
+
def collect_model_foreign_keys(model)
|
442
|
+
return [] unless model.connection.respond_to?(:supports_foreign_keys?) &&
|
443
|
+
model.connection.supports_foreign_keys?
|
444
|
+
|
445
|
+
model.connection.foreign_keys(model.table_name).map do |key_definition|
|
446
|
+
key_definition.options[:column]
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def collect_model_indexes(model)
|
451
|
+
return [] unless database_supports_indexing?(model)
|
452
|
+
|
453
|
+
model.connection.indexes(model.table_name).map do |index_definition|
|
454
|
+
{
|
455
|
+
name: index_definition.name,
|
456
|
+
columns: index_definition.columns,
|
457
|
+
unique: index_definition.unique,
|
458
|
+
}
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
def database_supports_indexing?(model)
|
463
|
+
return @database_supports_indexing if instance_variable_defined?(:@database_supports_indexing)
|
464
|
+
|
465
|
+
model.connection.indexes(model.table_name)
|
466
|
+
@database_supports_indexing = true
|
467
|
+
rescue NotImplementedError
|
468
|
+
@database_supports_indexing = false
|
469
|
+
end
|
315
470
|
end
|
316
471
|
end
|
317
472
|
end
|
318
473
|
|
319
|
-
|
474
|
+
if ARGV.first == "start"
|
475
|
+
RubyLsp::Rails::Server.new(capabilities: JSON.parse(ARGV[1], symbolize_names: true)).start
|
476
|
+
end
|
@@ -4,9 +4,7 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
module Rails
|
6
6
|
module ActiveSupportTestCaseHelper
|
7
|
-
|
8
|
-
|
9
|
-
sig { params(node: Prism::CallNode).returns(T.nilable(String)) }
|
7
|
+
#: (Prism::CallNode node) -> String?
|
10
8
|
def extract_test_case_name(node)
|
11
9
|
message_value = node.message
|
12
10
|
return unless message_value == "test" || message_value == "it"
|
@@ -6,9 +6,7 @@ module RubyLsp
|
|
6
6
|
module Support
|
7
7
|
class LocationBuilder
|
8
8
|
class << self
|
9
|
-
|
10
|
-
|
11
|
-
sig { params(location_string: String).returns(Interface::Location) }
|
9
|
+
#: (String location_string) -> Interface::Location
|
12
10
|
def line_location_from_s(location_string)
|
13
11
|
*file_parts, line = location_string.split(":")
|
14
12
|
raise ArgumentError, "Invalid location string given" if file_parts.empty?
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: ruby-lsp
|
@@ -15,7 +15,7 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.23.
|
18
|
+
version: 0.23.14
|
19
19
|
- - "<"
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: 0.24.0
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: 0.23.
|
28
|
+
version: 0.23.14
|
29
29
|
- - "<"
|
30
30
|
- !ruby/object:Gem::Version
|
31
31
|
version: 0.24.0
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb
|
48
48
|
- lib/ruby_lsp/ruby_lsp_rails/hover.rb
|
49
49
|
- lib/ruby_lsp/ruby_lsp_rails/indexing_enhancement.rb
|
50
|
+
- lib/ruby_lsp/ruby_lsp_rails/rails_test_style.rb
|
50
51
|
- lib/ruby_lsp/ruby_lsp_rails/runner_client.rb
|
51
52
|
- lib/ruby_lsp/ruby_lsp_rails/server.rb
|
52
53
|
- lib/ruby_lsp/ruby_lsp_rails/support/active_support_test_case_helper.rb
|
@@ -78,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
79
|
- !ruby/object:Gem::Version
|
79
80
|
version: '0'
|
80
81
|
requirements: []
|
81
|
-
rubygems_version: 3.6.
|
82
|
+
rubygems_version: 3.6.8
|
82
83
|
specification_version: 4
|
83
84
|
summary: A Ruby LSP addon for Rails
|
84
85
|
test_files: []
|