ruby-lsp 0.27.0.beta3 → 0.27.0.beta4
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_lsp/base_server.rb +2 -0
- data/lib/ruby_lsp/listeners/completion.rb +8 -11
- data/lib/ruby_lsp/requests/support/common.rb +10 -0
- data/lib/ruby_lsp/server.rb +33 -6
- data/lib/ruby_lsp/setup_bundler.rb +1 -1
- data/lib/ruby_lsp/type_inferrer.rb +56 -38
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de1859a4f73bdc2007364195d5e2c8aae9f999455a7523ad290263efb0edab30
|
|
4
|
+
data.tar.gz: 63e9388bc11ef954ed197db00c166a900e0f422c346c48af7bc485ab51a630c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cade33d50651fb915408b36b0537cb201c9b61ee0151e2ae6a8a1bee3099054af2a184e93b7790a0d283860159326f31d391c71bda798f00229262c4c58123f2
|
|
7
|
+
data.tar.gz: 01f24b527c33cc3d741fe682d79b70a0881760a9dc6d599101356563cbfce30ce0e719619312f530f42256b6ecb82ac2a40c93d6cde0ad97ef5e2a8087922d3d
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.27.0.
|
|
1
|
+
0.27.0.beta4
|
data/lib/ruby_lsp/base_server.rb
CHANGED
|
@@ -74,6 +74,8 @@ module RubyLsp
|
|
|
74
74
|
)
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
|
+
rescue URI::Error
|
|
78
|
+
# A client can send a document URI with a scheme Ruby's URI parser rejects, so we don't want to fail
|
|
77
79
|
rescue Store::NonExistingDocumentError
|
|
78
80
|
# If we receive a request for a file that no longer exists, we don't want to fail
|
|
79
81
|
end
|
|
@@ -256,7 +256,7 @@ module RubyLsp
|
|
|
256
256
|
#
|
|
257
257
|
#: () -> Array[(Rubydex::Declaration | Rubydex::Keyword)]
|
|
258
258
|
def expression_candidates
|
|
259
|
-
@graph.complete_expression(@node_context.nesting, self_receiver:
|
|
259
|
+
@graph.complete_expression(@node_context.nesting, self_receiver: @type_inferrer.self_receiver_name(@node_context))
|
|
260
260
|
end
|
|
261
261
|
|
|
262
262
|
#: (Interface::Range range, String prefix) -> void
|
|
@@ -322,14 +322,14 @@ module RubyLsp
|
|
|
322
322
|
end
|
|
323
323
|
|
|
324
324
|
candidates = if namespace_prefix.empty?
|
|
325
|
-
@graph.complete_expression([], self_receiver:
|
|
325
|
+
@graph.complete_expression([], self_receiver: @type_inferrer.self_receiver_name(@node_context))
|
|
326
326
|
else
|
|
327
327
|
# Rubydex's resolver handles a leading `::` on `namespace_prefix` by resolving from the top-level scope, so
|
|
328
328
|
# we don't need to special-case top-level references here
|
|
329
329
|
resolved = @graph.resolve_constant(namespace_prefix, @node_context.nesting)
|
|
330
330
|
return unless resolved
|
|
331
331
|
|
|
332
|
-
@graph.complete_namespace_access(resolved.name, self_receiver:
|
|
332
|
+
@graph.complete_namespace_access(resolved.name, self_receiver: @type_inferrer.self_receiver_name(@node_context))
|
|
333
333
|
end
|
|
334
334
|
|
|
335
335
|
candidates.each do |candidate|
|
|
@@ -378,7 +378,7 @@ module RubyLsp
|
|
|
378
378
|
|
|
379
379
|
guessed_type = type.is_a?(TypeInferrer::GuessedType) && type.name
|
|
380
380
|
|
|
381
|
-
@graph.complete_method_call(type.name, self_receiver:
|
|
381
|
+
@graph.complete_method_call(type.name, self_receiver: @type_inferrer.self_receiver_name(@node_context)).each do |candidate|
|
|
382
382
|
if method_name
|
|
383
383
|
display_name = candidate.unqualified_name.delete_suffix("()")
|
|
384
384
|
next unless display_name.start_with?(method_name)
|
|
@@ -390,16 +390,13 @@ module RubyLsp
|
|
|
390
390
|
|
|
391
391
|
# Variable completion (instance, class, and global). The variable kind is selected by the prefix the user typed:
|
|
392
392
|
# `$…` only matches globals, `@@…` only class variables, and `@…` matches both instance and class variables (since
|
|
393
|
-
# `@@foo`.start_with?("@") is true).
|
|
394
|
-
# variables
|
|
395
|
-
#
|
|
393
|
+
# `@@foo`.start_with?("@") is true). This uses the same query as expression completion: the lexical nesting drives
|
|
394
|
+
# constants and class variables, while the `self` type (which may differ from the nesting, e.g. inside
|
|
395
|
+
# `def self.foo` or `def Bar.baz`) drives instance variables.
|
|
396
396
|
#
|
|
397
397
|
#: (Interface::Range, String) -> void
|
|
398
398
|
def complete_variable(range, prefix)
|
|
399
|
-
|
|
400
|
-
nesting = type ? type.name.split("::") : []
|
|
401
|
-
|
|
402
|
-
@graph.complete_expression(nesting, self_receiver: nil).each do |candidate|
|
|
399
|
+
expression_candidates.each do |candidate|
|
|
403
400
|
next unless candidate.is_a?(Rubydex::Declaration)
|
|
404
401
|
|
|
405
402
|
variable_name = candidate.unqualified_name
|
|
@@ -120,6 +120,16 @@ module RubyLsp
|
|
|
120
120
|
markdown_title = "```ruby\n#{title}\n```"
|
|
121
121
|
file_links = []
|
|
122
122
|
content = +""
|
|
123
|
+
|
|
124
|
+
# Include documentation for method alias targets
|
|
125
|
+
definitions = definitions.flat_map do |definition|
|
|
126
|
+
if definition.is_a?(Rubydex::MethodAliasDefinition) && (target = definition.target)
|
|
127
|
+
[definition, *target.definitions]
|
|
128
|
+
else
|
|
129
|
+
[definition]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
123
133
|
defs = max_entries ? definitions.take(max_entries) : definitions
|
|
124
134
|
defs.each do |definition|
|
|
125
135
|
# For Markdown links, we need 1 based display locations
|
data/lib/ruby_lsp/server.rb
CHANGED
|
@@ -371,6 +371,7 @@ module RubyLsp
|
|
|
371
371
|
end
|
|
372
372
|
end
|
|
373
373
|
|
|
374
|
+
load_rubydex_config
|
|
374
375
|
perform_initial_indexing
|
|
375
376
|
check_formatter_is_available
|
|
376
377
|
update_server if @global_state.enabled_feature?(:launcher)
|
|
@@ -435,10 +436,15 @@ module RubyLsp
|
|
|
435
436
|
if [:ruby, :rbs].include?(language_id)
|
|
436
437
|
graph = @global_state.graph
|
|
437
438
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
439
|
+
begin_progress("incremental-indexing-progress", "Ruby LSP: indexing files")
|
|
440
|
+
|
|
441
|
+
progress("incremental-indexing-progress", message: "Indexing file...")
|
|
442
|
+
benchmark("index_source") { graph.index_source(text_document[:uri].to_s, document.source, language_id.to_s) }
|
|
443
|
+
|
|
444
|
+
progress("incremental-indexing-progress", message: "Resolving graph...")
|
|
441
445
|
benchmark("incremental_resolve") { graph.resolve }
|
|
446
|
+
|
|
447
|
+
end_progress("incremental-indexing-progress")
|
|
442
448
|
end
|
|
443
449
|
end
|
|
444
450
|
|
|
@@ -1032,9 +1038,17 @@ module RubyLsp
|
|
|
1032
1038
|
acc << path
|
|
1033
1039
|
end
|
|
1034
1040
|
end
|
|
1041
|
+
|
|
1042
|
+
begin_progress("incremental-indexing-progress", "Ruby LSP: indexing files")
|
|
1043
|
+
|
|
1044
|
+
progress("incremental-indexing-progress", message: "Indexing files...")
|
|
1035
1045
|
benchmark("index_all") { graph.index_all(additions_and_changes) }
|
|
1046
|
+
|
|
1047
|
+
progress("incremental-indexing-progress", message: "Resolving graph...")
|
|
1036
1048
|
benchmark("incremental_resolve") { graph.resolve }
|
|
1037
1049
|
|
|
1050
|
+
end_progress("incremental-indexing-progress")
|
|
1051
|
+
|
|
1038
1052
|
changes.each do |change|
|
|
1039
1053
|
# File change events include folders, but we're only interested in files
|
|
1040
1054
|
uri = URI(change[:uri])
|
|
@@ -1209,8 +1223,8 @@ module RubyLsp
|
|
|
1209
1223
|
end_progress("indexing-progress")
|
|
1210
1224
|
end
|
|
1211
1225
|
|
|
1212
|
-
#: (String id, String title, ?percentage: Integer) -> void
|
|
1213
|
-
def begin_progress(id, title, percentage:
|
|
1226
|
+
#: (String id, String title, ?percentage: Integer?, ?message: String?) -> void
|
|
1227
|
+
def begin_progress(id, title, percentage: nil, message: nil)
|
|
1214
1228
|
return unless @global_state.client_capabilities.supports_progress
|
|
1215
1229
|
|
|
1216
1230
|
send_message(Request.new(
|
|
@@ -1219,7 +1233,10 @@ module RubyLsp
|
|
|
1219
1233
|
params: Interface::WorkDoneProgressCreateParams.new(token: id),
|
|
1220
1234
|
))
|
|
1221
1235
|
|
|
1222
|
-
|
|
1236
|
+
# Omitting the percentage tells the client to show indefinite progress. Only fabricate a "% completed" message
|
|
1237
|
+
# when a caller reports incremental percentages and didn't provide an explicit message
|
|
1238
|
+
message ||= "#{percentage}% completed" if percentage
|
|
1239
|
+
send_message(Notification.progress_begin(id, title, percentage: percentage, message: message))
|
|
1223
1240
|
end
|
|
1224
1241
|
|
|
1225
1242
|
#: (String, ?message: String?, ?percentage: Integer?) -> void
|
|
@@ -1443,5 +1460,15 @@ module RubyLsp
|
|
|
1443
1460
|
|
|
1444
1461
|
result
|
|
1445
1462
|
end
|
|
1463
|
+
|
|
1464
|
+
#: () -> void
|
|
1465
|
+
def load_rubydex_config
|
|
1466
|
+
@global_state.graph.load_config
|
|
1467
|
+
rescue Rubydex::ConfigError => e
|
|
1468
|
+
send_message(Notification.window_show_message(
|
|
1469
|
+
"Error loading rubydex config: #{e.message}",
|
|
1470
|
+
type: Constant::MessageType::ERROR,
|
|
1471
|
+
))
|
|
1472
|
+
end
|
|
1446
1473
|
end
|
|
1447
1474
|
end
|
|
@@ -445,7 +445,7 @@ module RubyLsp
|
|
|
445
445
|
requirement = Gem::Requirement.new(@bundler_version.to_s)
|
|
446
446
|
return if Gem::Specification.any? { |s| s.name == "bundler" && requirement =~ s.version }
|
|
447
447
|
|
|
448
|
-
Gem.install("bundler", @bundler_version.to_s)
|
|
448
|
+
Gem.install("bundler", @bundler_version.to_s, env_shebang: true)
|
|
449
449
|
end
|
|
450
450
|
|
|
451
451
|
#: -> bool
|
|
@@ -20,13 +20,67 @@ module RubyLsp
|
|
|
20
20
|
when Prism::InstanceVariableReadNode, Prism::InstanceVariableAndWriteNode, Prism::InstanceVariableWriteNode,
|
|
21
21
|
Prism::InstanceVariableOperatorWriteNode, Prism::InstanceVariableOrWriteNode, Prism::InstanceVariableTargetNode,
|
|
22
22
|
Prism::SuperNode, Prism::ForwardingSuperNode, Prism::DefNode
|
|
23
|
-
|
|
23
|
+
infer_self_type(node_context)
|
|
24
24
|
when Prism::ClassVariableAndWriteNode, Prism::ClassVariableWriteNode, Prism::ClassVariableOperatorWriteNode,
|
|
25
25
|
Prism::ClassVariableOrWriteNode, Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
|
|
26
26
|
infer_receiver_for_class_variables(node_context)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# Infers the type of `self` in the given context. Unlike `infer_receiver_type`, this does not depend on the node
|
|
31
|
+
# being completed — it's derived purely from the lexical nesting and the surrounding method's receiver. This matters
|
|
32
|
+
# because methods and instance variables are attached to the type of `self`, which doesn't always match the lexical
|
|
33
|
+
# scope (e.g. inside `def self.foo` or a class/module body).
|
|
34
|
+
#
|
|
35
|
+
#: (NodeContext node_context) -> Type?
|
|
36
|
+
def infer_self_type(node_context)
|
|
37
|
+
nesting = node_context.nesting
|
|
38
|
+
# If we're at the top level, then the invocation is happening on `<main>`, which is a special singleton that
|
|
39
|
+
# inherits from Object
|
|
40
|
+
return Type.new("Object") if nesting.empty?
|
|
41
|
+
|
|
42
|
+
surrounding_method = node_context.surrounding_method
|
|
43
|
+
|
|
44
|
+
if surrounding_method
|
|
45
|
+
receiver_name = surrounding_method.receiver
|
|
46
|
+
|
|
47
|
+
case receiver_name
|
|
48
|
+
when "self"
|
|
49
|
+
# `def self.foo` — self is the singleton of the enclosing class/module
|
|
50
|
+
return resolve_singleton_type_from_nesting(nesting)
|
|
51
|
+
when "none"
|
|
52
|
+
# Instance method — self is an instance of the enclosing class/module
|
|
53
|
+
return resolve_type_from_nesting(nesting)
|
|
54
|
+
when nil
|
|
55
|
+
# Dynamic receiver that we cannot handle
|
|
56
|
+
return
|
|
57
|
+
else
|
|
58
|
+
# Explicit constant receiver (e.g. `def Bar.baz`) — self is that constant's singleton class
|
|
59
|
+
resolved = resolve_receiver_singleton_type(receiver_name, nesting)
|
|
60
|
+
return resolved if resolved
|
|
61
|
+
|
|
62
|
+
return resolve_type_from_nesting(nesting)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# If we're not inside a method, then we're inside the body of a class or module, which is a singleton
|
|
67
|
+
# context. Resolve through the graph to get the correct fully qualified name
|
|
68
|
+
resolve_singleton_type_from_nesting(nesting)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The type of `self`, which may or may not match the current lexical scope. For example, if we have `def Bar.foo` or
|
|
72
|
+
# if something else mutates the type
|
|
73
|
+
#
|
|
74
|
+
#: (NodeContext) -> String?
|
|
75
|
+
def self_receiver_name(node_context)
|
|
76
|
+
return if node_context.nesting.empty?
|
|
77
|
+
|
|
78
|
+
name = infer_self_type(node_context)&.name
|
|
79
|
+
return unless name
|
|
80
|
+
|
|
81
|
+
name if @graph[name]
|
|
82
|
+
end
|
|
83
|
+
|
|
30
84
|
private
|
|
31
85
|
|
|
32
86
|
#: (Prism::CallNode node, NodeContext node_context) -> Type?
|
|
@@ -49,7 +103,7 @@ module RubyLsp
|
|
|
49
103
|
|
|
50
104
|
case receiver
|
|
51
105
|
when Prism::SelfNode, nil
|
|
52
|
-
|
|
106
|
+
infer_self_type(node_context)
|
|
53
107
|
when Prism::StringNode
|
|
54
108
|
Type.new("String")
|
|
55
109
|
when Prism::SymbolNode
|
|
@@ -129,42 +183,6 @@ module RubyLsp
|
|
|
129
183
|
GuessedType.new(declaration.name)
|
|
130
184
|
end
|
|
131
185
|
|
|
132
|
-
#: (NodeContext node_context) -> Type?
|
|
133
|
-
def self_receiver_handling(node_context)
|
|
134
|
-
nesting = node_context.nesting
|
|
135
|
-
# If we're at the top level, then the invocation is happening on `<main>`, which is a special singleton that
|
|
136
|
-
# inherits from Object
|
|
137
|
-
return Type.new("Object") if nesting.empty?
|
|
138
|
-
|
|
139
|
-
surrounding_method = node_context.surrounding_method
|
|
140
|
-
|
|
141
|
-
if surrounding_method
|
|
142
|
-
receiver_name = surrounding_method.receiver
|
|
143
|
-
|
|
144
|
-
case receiver_name
|
|
145
|
-
when "self"
|
|
146
|
-
# `def self.foo` — self is the singleton of the enclosing class/module
|
|
147
|
-
return resolve_singleton_type_from_nesting(nesting)
|
|
148
|
-
when "none"
|
|
149
|
-
# Instance method — self is an instance of the enclosing class/module
|
|
150
|
-
return resolve_type_from_nesting(nesting)
|
|
151
|
-
when nil
|
|
152
|
-
# Dynamic receiver that we cannot handle
|
|
153
|
-
return
|
|
154
|
-
else
|
|
155
|
-
# Explicit constant receiver (e.g. `def Bar.baz`) — self is that constant's singleton class
|
|
156
|
-
resolved = resolve_receiver_singleton_type(receiver_name, nesting)
|
|
157
|
-
return resolved if resolved
|
|
158
|
-
|
|
159
|
-
return resolve_type_from_nesting(nesting)
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
# If we're not inside a method, then we're inside the body of a class or module, which is a singleton
|
|
164
|
-
# context. Resolve through the graph to get the correct fully qualified name
|
|
165
|
-
resolve_singleton_type_from_nesting(nesting)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
186
|
# Resolves the fully qualified name of the innermost constant from the nesting and returns it as a type.
|
|
169
187
|
# For instance methods, the nesting won't have singleton markers, so the result is an instance type.
|
|
170
188
|
# For `def self.` methods, the nesting includes a singleton marker, which is preserved in the result.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-lsp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.27.0.
|
|
4
|
+
version: 0.27.0.beta4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
@@ -67,9 +67,9 @@ dependencies:
|
|
|
67
67
|
name: rubydex
|
|
68
68
|
requirement: !ruby/object:Gem::Requirement
|
|
69
69
|
requirements:
|
|
70
|
-
- - "
|
|
70
|
+
- - ">="
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: 0.2.
|
|
72
|
+
version: 0.2.7
|
|
73
73
|
- - "<"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
75
|
version: 0.3.0
|
|
@@ -77,9 +77,9 @@ dependencies:
|
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- - "
|
|
80
|
+
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: 0.2.
|
|
82
|
+
version: 0.2.7
|
|
83
83
|
- - "<"
|
|
84
84
|
- !ruby/object:Gem::Version
|
|
85
85
|
version: 0.3.0
|
|
@@ -213,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
213
213
|
- !ruby/object:Gem::Version
|
|
214
214
|
version: '0'
|
|
215
215
|
requirements: []
|
|
216
|
-
rubygems_version: 4.0.
|
|
216
|
+
rubygems_version: 4.0.10
|
|
217
217
|
specification_version: 4
|
|
218
218
|
summary: An opinionated language server for Ruby
|
|
219
219
|
test_files: []
|