ruby-lsp 0.26.9 → 0.27.0.beta1
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/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +2 -2
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +8 -8
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +2 -2
- data/lib/ruby_lsp/global_state.rb +10 -1
- data/lib/ruby_lsp/internal.rb +5 -0
- data/lib/ruby_lsp/listeners/definition.rb +64 -98
- data/lib/ruby_lsp/listeners/hover.rb +35 -50
- data/lib/ruby_lsp/listeners/test_style.rb +1 -1
- data/lib/ruby_lsp/node_context.rb +2 -2
- data/lib/ruby_lsp/requests/on_type_formatting.rb +4 -0
- data/lib/ruby_lsp/requests/rename.rb +64 -72
- data/lib/ruby_lsp/requests/support/common.rb +40 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +15 -37
- data/lib/ruby_lsp/rubydex/definition.rb +200 -0
- data/lib/ruby_lsp/rubydex/reference.rb +16 -0
- data/lib/ruby_lsp/server.rb +39 -5
- data/lib/ruby_lsp/store.rb +0 -6
- data/lib/ruby_lsp/test_helper.rb +3 -0
- data/lib/ruby_lsp/type_inferrer.rb +25 -23
- metadata +17 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e5c88483f280d13f2691e131a16e35df07df898e8f380071d077479cd24133e
|
|
4
|
+
data.tar.gz: 7630ce8844fcb532ca63c77e299b692471b145530a623dcbc78ecbb50ce08596
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7757882e6e441d49705a389bad6b0b617b7f9a26fb1e5f34ebd3fc93eeb8921b31a703253cff79ed123ae411333fc7d91f0555ae162cafee1d10adfb13b76cf4
|
|
7
|
+
data.tar.gz: c215743ab00113e4dd3186732faabd462fef6a3be425f1c76bb65b045846effd7db0673478244218f1087e3fa9ca96f8668c86970def65bf2e5fbb4ea0728a8d
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.27.0.beta1
|
|
@@ -129,7 +129,7 @@ module RubyIndexer
|
|
|
129
129
|
|
|
130
130
|
if current_owner
|
|
131
131
|
expression = node.expression
|
|
132
|
-
name = (expression.is_a?(Prism::SelfNode) ? "
|
|
132
|
+
name = (expression.is_a?(Prism::SelfNode) ? "<#{last_name_in_stack}>" : "<#{expression.slice}>")
|
|
133
133
|
real_nesting = Index.actual_nesting(@stack, name)
|
|
134
134
|
|
|
135
135
|
existing_entries = @index[real_nesting.join("::")] #: as Array[Entry::SingletonClass]?
|
|
@@ -577,7 +577,7 @@ module RubyIndexer
|
|
|
577
577
|
|
|
578
578
|
# set the class variable's owner to the attached context when defined within a singleton scope.
|
|
579
579
|
if owner.is_a?(Entry::SingletonClass)
|
|
580
|
-
owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<
|
|
580
|
+
owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<") }
|
|
581
581
|
end
|
|
582
582
|
|
|
583
583
|
@index.add(Entry::ClassVariable.new(
|
|
@@ -507,7 +507,7 @@ module RubyIndexer
|
|
|
507
507
|
singleton_levels = 0
|
|
508
508
|
|
|
509
509
|
parts.reverse_each do |part|
|
|
510
|
-
break unless part.
|
|
510
|
+
break unless part.start_with?("<")
|
|
511
511
|
|
|
512
512
|
singleton_levels += 1
|
|
513
513
|
parts.pop
|
|
@@ -551,7 +551,7 @@ module RubyIndexer
|
|
|
551
551
|
|
|
552
552
|
if nesting.any?
|
|
553
553
|
singleton_levels.times do
|
|
554
|
-
nesting << "
|
|
554
|
+
nesting << "<#{nesting.last}>"
|
|
555
555
|
end
|
|
556
556
|
end
|
|
557
557
|
|
|
@@ -616,7 +616,7 @@ module RubyIndexer
|
|
|
616
616
|
if class_variables.any?
|
|
617
617
|
name_parts = owner_name.split("::")
|
|
618
618
|
|
|
619
|
-
if name_parts.last&.start_with?("<
|
|
619
|
+
if name_parts.last&.start_with?("<")
|
|
620
620
|
attached_name = name_parts[0..-2] #: as !nil
|
|
621
621
|
.join("::")
|
|
622
622
|
attached_ancestors = linearized_ancestors_of(attached_name)
|
|
@@ -707,7 +707,7 @@ module RubyIndexer
|
|
|
707
707
|
#: (String name) -> Entry::SingletonClass
|
|
708
708
|
def existing_or_new_singleton_class(name)
|
|
709
709
|
*_namespace, unqualified_name = name.split("::")
|
|
710
|
-
full_singleton_name = "#{name}
|
|
710
|
+
full_singleton_name = "#{name}::<#{unqualified_name}>"
|
|
711
711
|
singleton = self[full_singleton_name]&.first #: as Entry::SingletonClass?
|
|
712
712
|
|
|
713
713
|
unless singleton
|
|
@@ -744,7 +744,7 @@ module RubyIndexer
|
|
|
744
744
|
def linearized_attached_ancestors(name)
|
|
745
745
|
name_parts = name.split("::")
|
|
746
746
|
|
|
747
|
-
if name_parts.last&.start_with?("<
|
|
747
|
+
if name_parts.last&.start_with?("<")
|
|
748
748
|
attached_name = name_parts[0..-2] #: as !nil
|
|
749
749
|
.join("::")
|
|
750
750
|
linearized_ancestors_of(attached_name)
|
|
@@ -866,7 +866,7 @@ module RubyIndexer
|
|
|
866
866
|
|
|
867
867
|
parent_name_parts = parent_class_name.split("::")
|
|
868
868
|
singleton_levels.times do
|
|
869
|
-
parent_name_parts << "
|
|
869
|
+
parent_name_parts << "<#{parent_name_parts.last}>"
|
|
870
870
|
end
|
|
871
871
|
|
|
872
872
|
ancestors.concat(linearized_ancestors_of(parent_name_parts.join("::")))
|
|
@@ -878,7 +878,7 @@ module RubyIndexer
|
|
|
878
878
|
class_class_name_parts = ["Class"]
|
|
879
879
|
|
|
880
880
|
(singleton_levels - 1).times do
|
|
881
|
-
class_class_name_parts << "
|
|
881
|
+
class_class_name_parts << "<#{class_class_name_parts.last}>"
|
|
882
882
|
end
|
|
883
883
|
|
|
884
884
|
ancestors.concat(linearized_ancestors_of(class_class_name_parts.join("::")))
|
|
@@ -892,7 +892,7 @@ module RubyIndexer
|
|
|
892
892
|
module_class_name_parts = ["Module"]
|
|
893
893
|
|
|
894
894
|
(singleton_levels - 1).times do
|
|
895
|
-
module_class_name_parts << "
|
|
895
|
+
module_class_name_parts << "<#{module_class_name_parts.last}>"
|
|
896
896
|
end
|
|
897
897
|
|
|
898
898
|
ancestors.concat(linearized_ancestors_of(module_class_name_parts.join("::")))
|
|
@@ -134,7 +134,7 @@ module RubyIndexer
|
|
|
134
134
|
expression = node.expression
|
|
135
135
|
return unless expression.is_a?(Prism::SelfNode)
|
|
136
136
|
|
|
137
|
-
@stack << "
|
|
137
|
+
@stack << "<#{@stack.last}>"
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
#: (Prism::SingletonClassNode node) -> void
|
|
@@ -239,7 +239,7 @@ module RubyIndexer
|
|
|
239
239
|
end
|
|
240
240
|
|
|
241
241
|
if node.receiver.is_a?(Prism::SelfNode)
|
|
242
|
-
@stack << "
|
|
242
|
+
@stack << "<#{@stack.last}>"
|
|
243
243
|
end
|
|
244
244
|
end
|
|
245
245
|
|
|
@@ -30,6 +30,9 @@ module RubyLsp
|
|
|
30
30
|
#: RubyIndexer::Index
|
|
31
31
|
attr_reader :index
|
|
32
32
|
|
|
33
|
+
#: Rubydex::Graph
|
|
34
|
+
attr_reader :graph
|
|
35
|
+
|
|
33
36
|
#: Encoding
|
|
34
37
|
attr_reader :encoding
|
|
35
38
|
|
|
@@ -58,8 +61,9 @@ module RubyLsp
|
|
|
58
61
|
@test_library = "minitest" #: String
|
|
59
62
|
@has_type_checker = true #: bool
|
|
60
63
|
@index = RubyIndexer::Index.new #: RubyIndexer::Index
|
|
64
|
+
@graph = Rubydex::Graph.new #: Rubydex::Graph
|
|
61
65
|
@supported_formatters = {} #: Hash[String, Requests::Support::Formatter]
|
|
62
|
-
@type_inferrer = TypeInferrer.new(@
|
|
66
|
+
@type_inferrer = TypeInferrer.new(@graph) #: TypeInferrer
|
|
63
67
|
@addon_settings = {} #: Hash[String, untyped]
|
|
64
68
|
@top_level_bundle = begin
|
|
65
69
|
Bundler.with_original_env { Bundler.default_gemfile }
|
|
@@ -117,6 +121,7 @@ module RubyLsp
|
|
|
117
121
|
all_dependencies = gather_direct_and_indirect_dependencies
|
|
118
122
|
workspace_uri = options.dig(:workspaceFolders, 0, :uri)
|
|
119
123
|
@workspace_uri = URI(workspace_uri) if workspace_uri
|
|
124
|
+
@graph.workspace_path = workspace_path
|
|
120
125
|
|
|
121
126
|
specified_formatter = options.dig(:initializationOptions, :formatter)
|
|
122
127
|
rubocop_has_addon = defined?(::RuboCop::Version::STRING) &&
|
|
@@ -189,12 +194,16 @@ module RubyLsp
|
|
|
189
194
|
|
|
190
195
|
encodings = options.dig(:capabilities, :general, :positionEncodings)
|
|
191
196
|
@encoding = if !encodings || encodings.empty?
|
|
197
|
+
@graph.encoding = "utf16"
|
|
192
198
|
Encoding::UTF_16LE
|
|
193
199
|
elsif encodings.include?(Constant::PositionEncodingKind::UTF8)
|
|
200
|
+
@graph.encoding = "utf8"
|
|
194
201
|
Encoding::UTF_8
|
|
195
202
|
elsif encodings.include?(Constant::PositionEncodingKind::UTF16)
|
|
203
|
+
@graph.encoding = "utf16"
|
|
196
204
|
Encoding::UTF_16LE
|
|
197
205
|
else
|
|
206
|
+
@graph.encoding = "utf32"
|
|
198
207
|
Encoding::UTF_32
|
|
199
208
|
end
|
|
200
209
|
@index.configuration.encoding = @encoding
|
data/lib/ruby_lsp/internal.rb
CHANGED
|
@@ -20,6 +20,7 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.5")
|
|
|
20
20
|
end
|
|
21
21
|
require "set"
|
|
22
22
|
require "strscan"
|
|
23
|
+
require "rubydex"
|
|
23
24
|
require "prism"
|
|
24
25
|
require "prism/visitor"
|
|
25
26
|
require "language_server-protocol"
|
|
@@ -30,6 +31,10 @@ require "securerandom"
|
|
|
30
31
|
require "shellwords"
|
|
31
32
|
require "set"
|
|
32
33
|
|
|
34
|
+
# Rubydex LSP additions
|
|
35
|
+
require "ruby_lsp/rubydex/definition"
|
|
36
|
+
require "ruby_lsp/rubydex/reference"
|
|
37
|
+
|
|
33
38
|
require "ruby-lsp"
|
|
34
39
|
require "ruby_lsp/base_server"
|
|
35
40
|
require "ruby_indexer/ruby_indexer"
|
|
@@ -12,7 +12,7 @@ module RubyLsp
|
|
|
12
12
|
def initialize(response_builder, global_state, language_id, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
|
|
13
13
|
@response_builder = response_builder
|
|
14
14
|
@global_state = global_state
|
|
15
|
-
@
|
|
15
|
+
@graph = global_state.graph #: Rubydex::Graph
|
|
16
16
|
@type_inferrer = global_state.type_inferrer #: TypeInferrer
|
|
17
17
|
@language_id = language_id
|
|
18
18
|
@uri = uri
|
|
@@ -109,7 +109,7 @@ module RubyLsp
|
|
|
109
109
|
name = RubyIndexer::Index.constant_name(node)
|
|
110
110
|
return if name.nil?
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
handle_constant_definition(name)
|
|
113
113
|
end
|
|
114
114
|
|
|
115
115
|
#: (Prism::ConstantReadNode node) -> void
|
|
@@ -117,7 +117,7 @@ module RubyLsp
|
|
|
117
117
|
name = RubyIndexer::Index.constant_name(node)
|
|
118
118
|
return if name.nil?
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
handle_constant_definition(name)
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
#: (Prism::GlobalVariableAndWriteNode node) -> void
|
|
@@ -152,32 +152,32 @@ module RubyLsp
|
|
|
152
152
|
|
|
153
153
|
#: (Prism::InstanceVariableReadNode node) -> void
|
|
154
154
|
def on_instance_variable_read_node_enter(node)
|
|
155
|
-
|
|
155
|
+
handle_variable_definition(node.name.to_s)
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
#: (Prism::InstanceVariableWriteNode node) -> void
|
|
159
159
|
def on_instance_variable_write_node_enter(node)
|
|
160
|
-
|
|
160
|
+
handle_variable_definition(node.name.to_s)
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
#: (Prism::InstanceVariableAndWriteNode node) -> void
|
|
164
164
|
def on_instance_variable_and_write_node_enter(node)
|
|
165
|
-
|
|
165
|
+
handle_variable_definition(node.name.to_s)
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
#: (Prism::InstanceVariableOperatorWriteNode node) -> void
|
|
169
169
|
def on_instance_variable_operator_write_node_enter(node)
|
|
170
|
-
|
|
170
|
+
handle_variable_definition(node.name.to_s)
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
#: (Prism::InstanceVariableOrWriteNode node) -> void
|
|
174
174
|
def on_instance_variable_or_write_node_enter(node)
|
|
175
|
-
|
|
175
|
+
handle_variable_definition(node.name.to_s)
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
#: (Prism::InstanceVariableTargetNode node) -> void
|
|
179
179
|
def on_instance_variable_target_node_enter(node)
|
|
180
|
-
|
|
180
|
+
handle_variable_definition(node.name.to_s)
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
#: (Prism::SuperNode node) -> void
|
|
@@ -192,32 +192,32 @@ module RubyLsp
|
|
|
192
192
|
|
|
193
193
|
#: (Prism::ClassVariableAndWriteNode node) -> void
|
|
194
194
|
def on_class_variable_and_write_node_enter(node)
|
|
195
|
-
|
|
195
|
+
handle_variable_definition(node.name.to_s)
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
#: (Prism::ClassVariableOperatorWriteNode node) -> void
|
|
199
199
|
def on_class_variable_operator_write_node_enter(node)
|
|
200
|
-
|
|
200
|
+
handle_variable_definition(node.name.to_s)
|
|
201
201
|
end
|
|
202
202
|
|
|
203
203
|
#: (Prism::ClassVariableOrWriteNode node) -> void
|
|
204
204
|
def on_class_variable_or_write_node_enter(node)
|
|
205
|
-
|
|
205
|
+
handle_variable_definition(node.name.to_s)
|
|
206
206
|
end
|
|
207
207
|
|
|
208
208
|
#: (Prism::ClassVariableTargetNode node) -> void
|
|
209
209
|
def on_class_variable_target_node_enter(node)
|
|
210
|
-
|
|
210
|
+
handle_variable_definition(node.name.to_s)
|
|
211
211
|
end
|
|
212
212
|
|
|
213
213
|
#: (Prism::ClassVariableReadNode node) -> void
|
|
214
214
|
def on_class_variable_read_node_enter(node)
|
|
215
|
-
|
|
215
|
+
handle_variable_definition(node.name.to_s)
|
|
216
216
|
end
|
|
217
217
|
|
|
218
218
|
#: (Prism::ClassVariableWriteNode node) -> void
|
|
219
219
|
def on_class_variable_write_node_enter(node)
|
|
220
|
-
|
|
220
|
+
handle_variable_definition(node.name.to_s)
|
|
221
221
|
end
|
|
222
222
|
|
|
223
223
|
private
|
|
@@ -257,93 +257,63 @@ module RubyLsp
|
|
|
257
257
|
|
|
258
258
|
#: (String name) -> void
|
|
259
259
|
def handle_global_variable_definition(name)
|
|
260
|
-
|
|
260
|
+
declaration = @graph[name]
|
|
261
|
+
return unless declaration
|
|
261
262
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
entries.each do |entry|
|
|
265
|
-
location = entry.location
|
|
266
|
-
|
|
267
|
-
@response_builder << Interface::Location.new(
|
|
268
|
-
uri: entry.uri.to_s,
|
|
269
|
-
range: Interface::Range.new(
|
|
270
|
-
start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
|
|
271
|
-
end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
|
|
272
|
-
),
|
|
273
|
-
)
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
#: (String name) -> void
|
|
278
|
-
def handle_class_variable_definition(name)
|
|
279
|
-
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
280
|
-
return unless type
|
|
281
|
-
|
|
282
|
-
entries = @index.resolve_class_variable(name, type.name)
|
|
283
|
-
return unless entries
|
|
284
|
-
|
|
285
|
-
entries.each do |entry|
|
|
286
|
-
@response_builder << Interface::Location.new(
|
|
287
|
-
uri: entry.uri.to_s,
|
|
288
|
-
range: range_from_location(entry.location),
|
|
289
|
-
)
|
|
290
|
-
end
|
|
291
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
292
|
-
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
|
263
|
+
declaration.definitions.each { |definition| @response_builder << definition.to_lsp_selection_location }
|
|
293
264
|
end
|
|
294
265
|
|
|
266
|
+
# Handle class or instance variables. We collect all definitions across the ancestors of the type
|
|
267
|
+
#
|
|
295
268
|
#: (String name) -> void
|
|
296
|
-
def
|
|
297
|
-
# Sorbet enforces that all
|
|
298
|
-
#
|
|
269
|
+
def handle_variable_definition(name)
|
|
270
|
+
# Sorbet enforces that all variables be declared on typed strict or higher, which means it will be able to
|
|
271
|
+
# provide all features for them
|
|
299
272
|
return if @sorbet_level.strict?
|
|
300
273
|
|
|
301
274
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
302
275
|
return unless type
|
|
303
276
|
|
|
304
|
-
|
|
305
|
-
return unless
|
|
277
|
+
owner = @graph[type.name]
|
|
278
|
+
return unless owner.is_a?(Rubydex::Namespace)
|
|
306
279
|
|
|
307
|
-
|
|
308
|
-
|
|
280
|
+
owner.ancestors.each do |ancestor|
|
|
281
|
+
member = ancestor.member(name)
|
|
282
|
+
next unless member
|
|
309
283
|
|
|
310
|
-
@response_builder <<
|
|
311
|
-
uri: entry.uri.to_s,
|
|
312
|
-
range: Interface::Range.new(
|
|
313
|
-
start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
|
|
314
|
-
end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
|
|
315
|
-
),
|
|
316
|
-
)
|
|
284
|
+
member.definitions.each { |definition| @response_builder << definition.to_lsp_selection_location }
|
|
317
285
|
end
|
|
318
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
319
|
-
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
|
320
286
|
end
|
|
321
287
|
|
|
322
288
|
#: (String message, TypeInferrer::Type? receiver_type, ?inherited_only: bool) -> void
|
|
323
289
|
def handle_method_definition(message, receiver_type, inherited_only: false)
|
|
324
|
-
|
|
325
|
-
@
|
|
290
|
+
declaration = if receiver_type
|
|
291
|
+
owner = @graph[receiver_type.name]
|
|
292
|
+
owner.find_member("#{message}()", only_inherited: inherited_only) if owner.is_a?(Rubydex::Namespace)
|
|
326
293
|
end
|
|
327
294
|
|
|
328
|
-
# If the method doesn't have a receiver, or the guessed receiver doesn't have any matched candidates,
|
|
329
|
-
#
|
|
330
|
-
#
|
|
331
|
-
if receiver_type.nil? || (receiver_type.is_a?(TypeInferrer::GuessedType) &&
|
|
332
|
-
|
|
295
|
+
# If the method doesn't have a receiver, or the guessed receiver doesn't have any matched candidates, then we
|
|
296
|
+
# provide a few candidates to jump to. However, we don't want to provide too many candidates, as it can be
|
|
297
|
+
# overwhelming
|
|
298
|
+
if receiver_type.nil? || (receiver_type.is_a?(TypeInferrer::GuessedType) && declaration.nil?)
|
|
299
|
+
declaration = @graph.search("##{message}()").take(MAX_NUMBER_OF_DEFINITION_CANDIDATES_WITHOUT_RECEIVER)
|
|
333
300
|
end
|
|
334
301
|
|
|
335
|
-
return unless
|
|
302
|
+
return unless declaration
|
|
336
303
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
304
|
+
Array(declaration).each do |decl|
|
|
305
|
+
decl.definitions.each do |definition|
|
|
306
|
+
location = definition.location
|
|
307
|
+
uri = URI(location.uri)
|
|
308
|
+
full_path = uri.full_path
|
|
309
|
+
next if @sorbet_level.true_or_higher? && (!full_path || not_in_dependencies?(full_path))
|
|
341
310
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
311
|
+
@response_builder << Interface::LocationLink.new(
|
|
312
|
+
target_uri: uri.to_s,
|
|
313
|
+
target_range: definition.to_lsp_selection_range,
|
|
314
|
+
target_selection_range: definition.to_lsp_name_range || definition.to_lsp_selection_range,
|
|
315
|
+
)
|
|
316
|
+
end
|
|
347
317
|
end
|
|
348
318
|
end
|
|
349
319
|
|
|
@@ -351,12 +321,10 @@ module RubyLsp
|
|
|
351
321
|
def handle_require_definition(node, message)
|
|
352
322
|
case message
|
|
353
323
|
when :require
|
|
354
|
-
|
|
355
|
-
uri.require_path == node.content
|
|
356
|
-
end
|
|
324
|
+
document = @graph.resolve_require_path(node.content, $LOAD_PATH)
|
|
357
325
|
|
|
358
|
-
if
|
|
359
|
-
candidate =
|
|
326
|
+
if document
|
|
327
|
+
candidate = URI(document.uri).full_path
|
|
360
328
|
|
|
361
329
|
if candidate
|
|
362
330
|
@response_builder << Interface::Location.new(
|
|
@@ -392,35 +360,33 @@ module RubyLsp
|
|
|
392
360
|
constant_name = argument.value
|
|
393
361
|
return unless constant_name
|
|
394
362
|
|
|
395
|
-
|
|
363
|
+
handle_constant_definition(constant_name)
|
|
396
364
|
end
|
|
397
365
|
|
|
398
366
|
#: (String value) -> void
|
|
399
|
-
def
|
|
400
|
-
|
|
401
|
-
return unless
|
|
367
|
+
def handle_constant_definition(value)
|
|
368
|
+
declaration = @graph.resolve_constant(value, @node_context.nesting)
|
|
369
|
+
return unless declaration
|
|
402
370
|
|
|
371
|
+
# [RUBYDEX] TODO: temporarily commented out until we have the visibility API
|
|
372
|
+
#
|
|
403
373
|
# We should only allow jumping to the definition of private constants if the constant is defined in the same
|
|
404
374
|
# namespace as the reference
|
|
405
|
-
|
|
406
|
-
return if
|
|
375
|
+
#
|
|
376
|
+
# return if declaration.private? && declaration.name != "#{@node_context.fully_qualified_name}::#{value}"
|
|
407
377
|
|
|
408
|
-
|
|
378
|
+
declaration.definitions.each do |definition|
|
|
409
379
|
# If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
|
|
410
380
|
# additional behavior on top of jumping to RBIs. The only sigil where Sorbet cannot handle constants is typed
|
|
411
381
|
# ignore
|
|
412
|
-
uri =
|
|
382
|
+
uri = URI(definition.location.uri)
|
|
413
383
|
full_path = uri.full_path
|
|
414
384
|
|
|
415
385
|
if !@sorbet_level.ignore? && (!full_path || not_in_dependencies?(full_path))
|
|
416
386
|
next
|
|
417
387
|
end
|
|
418
388
|
|
|
419
|
-
@response_builder <<
|
|
420
|
-
target_uri: uri.to_s,
|
|
421
|
-
target_range: range_from_location(entry.location),
|
|
422
|
-
target_selection_range: range_from_location(entry.name_location),
|
|
423
|
-
)
|
|
389
|
+
@response_builder << definition.to_lsp_location_link
|
|
424
390
|
end
|
|
425
391
|
end
|
|
426
392
|
end
|
|
@@ -48,6 +48,7 @@ module RubyLsp
|
|
|
48
48
|
@response_builder = response_builder
|
|
49
49
|
@global_state = global_state
|
|
50
50
|
@index = global_state.index #: RubyIndexer::Index
|
|
51
|
+
@graph = global_state.graph #: Rubydex::Graph
|
|
51
52
|
@type_inferrer = global_state.type_inferrer #: TypeInferrer
|
|
52
53
|
@path = uri.to_standardized_path #: String?
|
|
53
54
|
@node_context = node_context
|
|
@@ -178,32 +179,32 @@ module RubyLsp
|
|
|
178
179
|
|
|
179
180
|
#: (Prism::InstanceVariableReadNode node) -> void
|
|
180
181
|
def on_instance_variable_read_node_enter(node)
|
|
181
|
-
|
|
182
|
+
handle_variable_hover(node.name.to_s)
|
|
182
183
|
end
|
|
183
184
|
|
|
184
185
|
#: (Prism::InstanceVariableWriteNode node) -> void
|
|
185
186
|
def on_instance_variable_write_node_enter(node)
|
|
186
|
-
|
|
187
|
+
handle_variable_hover(node.name.to_s)
|
|
187
188
|
end
|
|
188
189
|
|
|
189
190
|
#: (Prism::InstanceVariableAndWriteNode node) -> void
|
|
190
191
|
def on_instance_variable_and_write_node_enter(node)
|
|
191
|
-
|
|
192
|
+
handle_variable_hover(node.name.to_s)
|
|
192
193
|
end
|
|
193
194
|
|
|
194
195
|
#: (Prism::InstanceVariableOperatorWriteNode node) -> void
|
|
195
196
|
def on_instance_variable_operator_write_node_enter(node)
|
|
196
|
-
|
|
197
|
+
handle_variable_hover(node.name.to_s)
|
|
197
198
|
end
|
|
198
199
|
|
|
199
200
|
#: (Prism::InstanceVariableOrWriteNode node) -> void
|
|
200
201
|
def on_instance_variable_or_write_node_enter(node)
|
|
201
|
-
|
|
202
|
+
handle_variable_hover(node.name.to_s)
|
|
202
203
|
end
|
|
203
204
|
|
|
204
205
|
#: (Prism::InstanceVariableTargetNode node) -> void
|
|
205
206
|
def on_instance_variable_target_node_enter(node)
|
|
206
|
-
|
|
207
|
+
handle_variable_hover(node.name.to_s)
|
|
207
208
|
end
|
|
208
209
|
|
|
209
210
|
#: (Prism::SuperNode node) -> void
|
|
@@ -223,32 +224,32 @@ module RubyLsp
|
|
|
223
224
|
|
|
224
225
|
#: (Prism::ClassVariableAndWriteNode node) -> void
|
|
225
226
|
def on_class_variable_and_write_node_enter(node)
|
|
226
|
-
|
|
227
|
+
handle_variable_hover(node.name.to_s)
|
|
227
228
|
end
|
|
228
229
|
|
|
229
230
|
#: (Prism::ClassVariableOperatorWriteNode node) -> void
|
|
230
231
|
def on_class_variable_operator_write_node_enter(node)
|
|
231
|
-
|
|
232
|
+
handle_variable_hover(node.name.to_s)
|
|
232
233
|
end
|
|
233
234
|
|
|
234
235
|
#: (Prism::ClassVariableOrWriteNode node) -> void
|
|
235
236
|
def on_class_variable_or_write_node_enter(node)
|
|
236
|
-
|
|
237
|
+
handle_variable_hover(node.name.to_s)
|
|
237
238
|
end
|
|
238
239
|
|
|
239
240
|
#: (Prism::ClassVariableTargetNode node) -> void
|
|
240
241
|
def on_class_variable_target_node_enter(node)
|
|
241
|
-
|
|
242
|
+
handle_variable_hover(node.name.to_s)
|
|
242
243
|
end
|
|
243
244
|
|
|
244
245
|
#: (Prism::ClassVariableReadNode node) -> void
|
|
245
246
|
def on_class_variable_read_node_enter(node)
|
|
246
|
-
|
|
247
|
+
handle_variable_hover(node.name.to_s)
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
#: (Prism::ClassVariableWriteNode node) -> void
|
|
250
251
|
def on_class_variable_write_node_enter(node)
|
|
251
|
-
|
|
252
|
+
handle_variable_hover(node.name.to_s)
|
|
252
253
|
end
|
|
253
254
|
|
|
254
255
|
private
|
|
@@ -324,62 +325,46 @@ module RubyLsp
|
|
|
324
325
|
end
|
|
325
326
|
end
|
|
326
327
|
|
|
327
|
-
#: (String name) -> void
|
|
328
|
-
def handle_instance_variable_hover(name)
|
|
329
|
-
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
|
330
|
-
# to provide all features for them
|
|
331
|
-
return if @sorbet_level.strict?
|
|
332
|
-
|
|
333
|
-
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
334
|
-
return unless type
|
|
335
|
-
|
|
336
|
-
entries = @index.resolve_instance_variable(name, type.name)
|
|
337
|
-
return unless entries
|
|
338
|
-
|
|
339
|
-
categorized_markdown_from_index_entries(name, entries).each do |category, content|
|
|
340
|
-
@response_builder.push(content, category: category)
|
|
341
|
-
end
|
|
342
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
343
|
-
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
|
344
|
-
end
|
|
345
|
-
|
|
346
328
|
#: (String name) -> void
|
|
347
329
|
def handle_global_variable_hover(name)
|
|
348
|
-
|
|
349
|
-
return unless
|
|
330
|
+
declaration = @graph[name]
|
|
331
|
+
return unless declaration
|
|
350
332
|
|
|
351
|
-
|
|
333
|
+
categorized_markdown_from_definitions(name, declaration.definitions).each do |category, content|
|
|
352
334
|
@response_builder.push(content, category: category)
|
|
353
335
|
end
|
|
354
336
|
end
|
|
355
337
|
|
|
338
|
+
# Handle class or instance variables. We collect all definitions across the ancestors of the type
|
|
339
|
+
#
|
|
356
340
|
#: (String name) -> void
|
|
357
|
-
def
|
|
341
|
+
def handle_variable_hover(name)
|
|
342
|
+
# Sorbet enforces that all variables be declared on typed strict or higher, which means it will be able to
|
|
343
|
+
# provide all features for them
|
|
344
|
+
return if @sorbet_level.strict?
|
|
345
|
+
|
|
358
346
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
359
347
|
return unless type
|
|
360
348
|
|
|
361
|
-
|
|
362
|
-
return unless
|
|
349
|
+
owner = @graph[type.name]
|
|
350
|
+
return unless owner.is_a?(Rubydex::Namespace)
|
|
363
351
|
|
|
364
|
-
|
|
365
|
-
|
|
352
|
+
owner.ancestors.each do |ancestor|
|
|
353
|
+
member = ancestor.member(name)
|
|
354
|
+
next unless member
|
|
355
|
+
|
|
356
|
+
categorized_markdown_from_definitions(member.name, member.definitions).each do |category, content|
|
|
357
|
+
@response_builder.push(content, category: category)
|
|
358
|
+
end
|
|
366
359
|
end
|
|
367
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
368
|
-
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
|
369
360
|
end
|
|
370
361
|
|
|
371
362
|
#: (String name, Prism::Location location) -> void
|
|
372
363
|
def generate_hover(name, location)
|
|
373
|
-
|
|
374
|
-
return unless
|
|
375
|
-
|
|
376
|
-
# We should only show hover for private constants if the constant is defined in the same namespace as the
|
|
377
|
-
# reference
|
|
378
|
-
first_entry = entries.first #: as !nil
|
|
379
|
-
full_name = first_entry.name
|
|
380
|
-
return if first_entry.private? && full_name != "#{@node_context.fully_qualified_name}::#{name}"
|
|
364
|
+
declaration = @graph.resolve_constant(name, @node_context.nesting)
|
|
365
|
+
return unless declaration
|
|
381
366
|
|
|
382
|
-
|
|
367
|
+
categorized_markdown_from_definitions(declaration.name, declaration.definitions).each do |category, content|
|
|
383
368
|
@response_builder.push(content, category: category)
|
|
384
369
|
end
|
|
385
370
|
end
|
|
@@ -266,7 +266,7 @@ module RubyLsp
|
|
|
266
266
|
# We only support regular Minitest tests. The declarative syntax provided by ActiveSupport is handled by the
|
|
267
267
|
# Rails add-on
|
|
268
268
|
name_parts = fully_qualified_name.split("::")
|
|
269
|
-
singleton_name = "#{name_parts.join("::")}
|
|
269
|
+
singleton_name = "#{name_parts.join("::")}::<#{name_parts.last}>"
|
|
270
270
|
!@index.linearized_ancestors_of(singleton_name).include?("ActiveSupport::Testing::Declarative")
|
|
271
271
|
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
272
272
|
true
|