ruby-lsp 0.27.0.beta1 → 0.27.0.beta3

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +0 -46
  4. data/exe/ruby-lsp-check +0 -15
  5. data/lib/ruby_lsp/addon.rb +19 -19
  6. data/lib/ruby_lsp/global_state.rb +1 -6
  7. data/lib/ruby_lsp/internal.rb +3 -2
  8. data/lib/ruby_lsp/listeners/code_lens.rb +1 -1
  9. data/lib/ruby_lsp/listeners/completion.rb +246 -382
  10. data/lib/ruby_lsp/listeners/definition.rb +7 -10
  11. data/lib/ruby_lsp/listeners/document_link.rb +4 -0
  12. data/lib/ruby_lsp/listeners/hover.rb +234 -82
  13. data/lib/ruby_lsp/listeners/signature_help.rb +11 -12
  14. data/lib/ruby_lsp/listeners/spec_style.rb +6 -1
  15. data/lib/ruby_lsp/listeners/test_discovery.rb +38 -15
  16. data/lib/ruby_lsp/listeners/test_style.rb +21 -9
  17. data/lib/ruby_lsp/node_context.rb +31 -8
  18. data/lib/ruby_lsp/requests/completion_resolve.rb +55 -39
  19. data/lib/ruby_lsp/requests/discover_tests.rb +5 -41
  20. data/lib/ruby_lsp/requests/hover.rb +2 -5
  21. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +66 -22
  22. data/lib/ruby_lsp/requests/references.rb +180 -66
  23. data/lib/ruby_lsp/requests/rename.rb +1 -1
  24. data/lib/ruby_lsp/requests/request.rb +3 -33
  25. data/lib/ruby_lsp/requests/support/common.rb +82 -68
  26. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +82 -46
  27. data/lib/ruby_lsp/ruby_document.rb +0 -73
  28. data/lib/ruby_lsp/rubydex/declaration.rb +174 -0
  29. data/lib/ruby_lsp/rubydex/definition.rb +73 -0
  30. data/lib/ruby_lsp/rubydex/reference.rb +6 -1
  31. data/lib/ruby_lsp/rubydex/signature.rb +107 -0
  32. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  33. data/lib/ruby_lsp/server.rb +56 -171
  34. data/lib/ruby_lsp/test_helper.rb +0 -1
  35. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +1 -1
  36. data/lib/ruby_lsp/type_inferrer.rb +89 -11
  37. metadata +12 -18
  38. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +0 -276
  39. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +0 -1101
  40. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +0 -44
  41. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +0 -605
  42. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +0 -1077
  43. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +0 -37
  44. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +0 -149
  45. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +0 -294
  46. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +0 -335
  47. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +0 -32
  48. data/lib/ruby_indexer/ruby_indexer.rb +0 -20
  49. data/lib/ruby_lsp/static_docs.rb +0 -20
  50. data/static_docs/break.md +0 -103
  51. data/static_docs/yield.md +0 -81
  52. /data/lib/{ruby_indexer/lib/ruby_indexer → ruby_lsp}/uri.rb +0 -0
@@ -1,37 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module RubyIndexer
5
- class Location
6
- class << self
7
- #: (Prism::Location prism_location, (^(Integer arg0) -> Integer | Prism::CodeUnitsCache) code_units_cache) -> instance
8
- def from_prism_location(prism_location, code_units_cache)
9
- new(
10
- prism_location.start_line,
11
- prism_location.end_line,
12
- prism_location.cached_start_code_units_column(code_units_cache),
13
- prism_location.cached_end_code_units_column(code_units_cache),
14
- )
15
- end
16
- end
17
-
18
- #: Integer
19
- attr_reader :start_line, :end_line, :start_column, :end_column
20
-
21
- #: (Integer start_line, Integer end_line, Integer start_column, Integer end_column) -> void
22
- def initialize(start_line, end_line, start_column, end_column)
23
- @start_line = start_line
24
- @end_line = end_line
25
- @start_column = start_column
26
- @end_column = end_column
27
- end
28
-
29
- #: ((Location | Prism::Location) other) -> bool
30
- def ==(other)
31
- start_line == other.start_line &&
32
- end_line == other.end_line &&
33
- start_column == other.start_column &&
34
- end_column == other.end_column
35
- end
36
- end
37
- end
@@ -1,149 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module RubyIndexer
5
- # A PrefixTree is a data structure that allows searching for partial strings fast. The tree is similar to a nested
6
- # hash structure, where the keys are the characters of the inserted strings.
7
- #
8
- # ## Example
9
- # ```ruby
10
- # tree = PrefixTree[String].new
11
- # # Insert entries using the same key and value
12
- # tree.insert("bar", "bar")
13
- # tree.insert("baz", "baz")
14
- # # Internally, the structure is analogous to this, but using nodes:
15
- # # {
16
- # # "b" => {
17
- # # "a" => {
18
- # # "r" => "bar",
19
- # # "z" => "baz"
20
- # # }
21
- # # }
22
- # # }
23
- # # When we search it, it finds all possible values based on partial (or complete matches):
24
- # tree.search("") # => ["bar", "baz"]
25
- # tree.search("b") # => ["bar", "baz"]
26
- # tree.search("ba") # => ["bar", "baz"]
27
- # tree.search("bar") # => ["bar"]
28
- # ```
29
- #
30
- # A PrefixTree is useful for autocomplete, since we always want to find all alternatives while the developer hasn't
31
- # finished typing yet. This PrefixTree implementation allows for string keys and any arbitrary value using the generic
32
- # `Value` type.
33
- #
34
- # See https://en.wikipedia.org/wiki/Trie for more information
35
- #: [Value]
36
- class PrefixTree
37
- #: -> void
38
- def initialize
39
- @root = Node.new(
40
- "",
41
- "", #: as untyped
42
- ) #: Node[Value]
43
- end
44
-
45
- # Search the PrefixTree based on a given `prefix`. If `foo` is an entry in the tree, then searching for `fo` will
46
- # return it as a result. The result is always an array of the type of value attribute to the generic `Value` type.
47
- # Notice that if the `Value` is an array, this method will return an array of arrays, where each entry is the array
48
- # of values for a given match
49
- #: (String prefix) -> Array[Value]
50
- def search(prefix)
51
- node = find_node(prefix)
52
- return [] unless node
53
-
54
- node.collect
55
- end
56
-
57
- # Inserts a `value` using the given `key`
58
- #: (String key, Value value) -> void
59
- def insert(key, value)
60
- node = @root
61
-
62
- key.each_char do |char|
63
- node = node.children[char] ||= Node.new(char, value, node)
64
- end
65
-
66
- # This line is to allow a value to be overridden. When we are indexing files, we want to be able to update entries
67
- # for a given fully qualified name if we find more occurrences of it. Without being able to override, that would
68
- # not be possible
69
- node.value = value
70
- node.leaf = true
71
- end
72
-
73
- # Deletes the entry identified by `key` from the tree. Notice that a partial match will still delete all entries
74
- # that match it. For example, if the tree contains `foo` and we ask to delete `fo`, then `foo` will be deleted
75
- #: (String key) -> void
76
- def delete(key)
77
- node = find_node(key)
78
- return unless node
79
-
80
- # Remove the node from the tree and then go up the parents to remove any of them with empty children
81
- parent = node.parent #: Node[Value]?
82
-
83
- while parent
84
- parent.children.delete(node.key)
85
- return if parent.children.any? || parent.leaf
86
-
87
- node = parent
88
- parent = parent.parent
89
- end
90
- end
91
-
92
- private
93
-
94
- # Find a node that matches the given `key`
95
- #: (String key) -> Node[Value]?
96
- def find_node(key)
97
- node = @root
98
-
99
- key.each_char do |char|
100
- snode = node.children[char]
101
- return nil unless snode
102
-
103
- node = snode
104
- end
105
-
106
- node
107
- end
108
-
109
- #: [Value]
110
- class Node
111
- #: Hash[String, Node[Value]]
112
- attr_reader :children
113
-
114
- #: String
115
- attr_reader :key
116
-
117
- #: Value
118
- attr_accessor :value
119
-
120
- #: bool
121
- attr_accessor :leaf
122
-
123
- #: Node[Value]?
124
- attr_reader :parent
125
-
126
- #: (String key, Value value, ?Node[Value]? parent) -> void
127
- def initialize(key, value, parent = nil)
128
- @key = key
129
- @value = value
130
- @parent = parent
131
- @children = {}
132
- @leaf = false
133
- end
134
-
135
- #: -> Array[Value]
136
- def collect
137
- result = []
138
- stack = [self]
139
-
140
- while (node = stack.pop)
141
- result << node.value if node.leaf
142
- stack.concat(node.children.values)
143
- end
144
-
145
- result
146
- end
147
- end
148
- end
149
- end
@@ -1,294 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module RubyIndexer
5
- class RBSIndexer
6
- HAS_UNTYPED_FUNCTION = !!defined?(RBS::Types::UntypedFunction) #: bool
7
-
8
- #: (Index index) -> void
9
- def initialize(index)
10
- @index = index
11
- end
12
-
13
- #: -> void
14
- def index_ruby_core
15
- loader = RBS::EnvironmentLoader.new
16
- RBS::Environment.from_loader(loader).resolve_type_names
17
-
18
- loader.each_signature do |_source, pathname, _buffer, declarations, _directives|
19
- process_signature(pathname, declarations)
20
- end
21
- end
22
-
23
- #: (Pathname pathname, Array[RBS::AST::Declarations::Base] declarations) -> void
24
- def process_signature(pathname, declarations)
25
- declarations.each do |declaration|
26
- process_declaration(declaration, pathname)
27
- end
28
- end
29
-
30
- private
31
-
32
- #: (RBS::AST::Declarations::Base declaration, Pathname pathname) -> void
33
- def process_declaration(declaration, pathname)
34
- case declaration
35
- when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
36
- handle_class_or_module_declaration(declaration, pathname)
37
- when RBS::AST::Declarations::Constant
38
- namespace_nesting = declaration.name.namespace.path.map(&:to_s)
39
- handle_constant(declaration, namespace_nesting, URI::Generic.from_path(path: pathname.to_s))
40
- when RBS::AST::Declarations::Global
41
- handle_global_variable(declaration, pathname)
42
- else # rubocop:disable Style/EmptyElse
43
- # Other kinds not yet handled
44
- end
45
- end
46
-
47
- #: ((RBS::AST::Declarations::Class | RBS::AST::Declarations::Module) declaration, Pathname pathname) -> void
48
- def handle_class_or_module_declaration(declaration, pathname)
49
- nesting = [declaration.name.name.to_s]
50
- uri = URI::Generic.from_path(path: pathname.to_s)
51
- location = to_ruby_indexer_location(declaration.location)
52
- comments = comments_to_string(declaration)
53
- entry = if declaration.is_a?(RBS::AST::Declarations::Class)
54
- parent_class = declaration.super_class&.name&.name&.to_s
55
- Entry::Class.new(@index.configuration, nesting, uri, location, location, comments, parent_class)
56
- else
57
- Entry::Module.new(@index.configuration, nesting, uri, location, location, comments)
58
- end
59
-
60
- add_declaration_mixins_to_entry(declaration, entry)
61
- @index.add(entry)
62
-
63
- declaration.members.each do |member|
64
- case member
65
- when RBS::AST::Members::MethodDefinition
66
- handle_method(member, entry)
67
- when RBS::AST::Declarations::Constant
68
- handle_constant(member, nesting, uri)
69
- when RBS::AST::Members::Alias
70
- # In RBS, an alias means that two methods have the same signature.
71
- # It does not mean the same thing as a Ruby alias.
72
- handle_signature_alias(member, entry)
73
- end
74
- end
75
- end
76
-
77
- #: (RBS::Location rbs_location) -> RubyIndexer::Location
78
- def to_ruby_indexer_location(rbs_location)
79
- RubyIndexer::Location.new(
80
- rbs_location.start_line,
81
- rbs_location.end_line,
82
- rbs_location.start_column,
83
- rbs_location.end_column,
84
- )
85
- end
86
-
87
- #: ((RBS::AST::Declarations::Class | RBS::AST::Declarations::Module) declaration, Entry::Namespace entry) -> void
88
- def add_declaration_mixins_to_entry(declaration, entry)
89
- declaration.each_mixin do |mixin|
90
- name = mixin.name.name.to_s
91
- case mixin
92
- when RBS::AST::Members::Include
93
- entry.mixin_operations << Entry::Include.new(name)
94
- when RBS::AST::Members::Prepend
95
- entry.mixin_operations << Entry::Prepend.new(name)
96
- when RBS::AST::Members::Extend
97
- singleton = @index.existing_or_new_singleton_class(entry.name)
98
- singleton.mixin_operations << Entry::Include.new(name)
99
- end
100
- end
101
- end
102
-
103
- #: (RBS::AST::Members::MethodDefinition member, Entry::Namespace owner) -> void
104
- def handle_method(member, owner)
105
- name = member.name.name
106
- uri = URI::Generic.from_path(path: member.location.buffer.name.to_s)
107
- location = to_ruby_indexer_location(member.location)
108
- comments = comments_to_string(member)
109
-
110
- real_owner = member.singleton? ? @index.existing_or_new_singleton_class(owner.name) : owner
111
- signatures = signatures(member)
112
- @index.add(Entry::Method.new(
113
- @index.configuration,
114
- name,
115
- uri,
116
- location,
117
- location,
118
- comments,
119
- signatures,
120
- member.visibility || :public,
121
- real_owner,
122
- ))
123
- end
124
-
125
- #: (RBS::AST::Members::MethodDefinition member) -> Array[Entry::Signature]
126
- def signatures(member)
127
- member.overloads.map do |overload|
128
- parameters = process_overload(overload)
129
- Entry::Signature.new(parameters)
130
- end
131
- end
132
-
133
- #: (RBS::AST::Members::MethodDefinition::Overload overload) -> Array[Entry::Parameter]
134
- def process_overload(overload)
135
- function = overload.method_type.type
136
-
137
- if function.is_a?(RBS::Types::Function)
138
- parameters = parse_arguments(function)
139
-
140
- block = overload.method_type.block
141
- parameters << Entry::BlockParameter.anonymous if block&.required
142
- return parameters
143
- end
144
-
145
- # Untyped functions are a new RBS feature (since v3.6.0) to declare methods that accept any parameters. For our
146
- # purposes, accepting any argument is equivalent to `...`
147
- if HAS_UNTYPED_FUNCTION && function.is_a?(RBS::Types::UntypedFunction)
148
- [Entry::ForwardingParameter.new]
149
- else
150
- []
151
- end
152
- end
153
-
154
- #: (RBS::Types::Function function) -> Array[Entry::Parameter]
155
- def parse_arguments(function)
156
- parameters = []
157
- parameters.concat(process_required_and_optional_positionals(function))
158
- parameters.concat(process_trailing_positionals(function)) if function.trailing_positionals
159
- parameters << process_rest_positionals(function) if function.rest_positionals
160
- parameters.concat(process_required_keywords(function)) if function.required_keywords
161
- parameters.concat(process_optional_keywords(function)) if function.optional_keywords
162
- parameters << process_rest_keywords(function) if function.rest_keywords
163
- parameters
164
- end
165
-
166
- #: (RBS::Types::Function function) -> Array[Entry::RequiredParameter]
167
- def process_required_and_optional_positionals(function)
168
- argument_offset = 0
169
-
170
- required = function.required_positionals.map.with_index(argument_offset) do |param, i|
171
- # Some parameters don't have names, e.g.
172
- # def self.try_convert: [U] (untyped) -> ::Array[U]?
173
- name = param.name || :"arg#{i}"
174
- argument_offset += 1
175
-
176
- Entry::RequiredParameter.new(name: name)
177
- end
178
-
179
- optional = function.optional_positionals.map.with_index(argument_offset) do |param, i|
180
- # Optional positionals may be unnamed, e.g.
181
- # def self.polar: (Numeric, ?Numeric) -> Complex
182
- name = param.name || :"arg#{i}"
183
-
184
- Entry::OptionalParameter.new(name: name)
185
- end
186
-
187
- required + optional
188
- end
189
-
190
- #: (RBS::Types::Function function) -> Array[Entry::OptionalParameter]
191
- def process_trailing_positionals(function)
192
- function.trailing_positionals.map do |param|
193
- Entry::OptionalParameter.new(name: param.name)
194
- end
195
- end
196
-
197
- #: (RBS::Types::Function function) -> Entry::RestParameter
198
- def process_rest_positionals(function)
199
- rest = function.rest_positionals
200
-
201
- rest_name = rest.name || Entry::RestParameter::DEFAULT_NAME
202
-
203
- Entry::RestParameter.new(name: rest_name)
204
- end
205
-
206
- #: (RBS::Types::Function function) -> Array[Entry::KeywordParameter]
207
- def process_required_keywords(function)
208
- function.required_keywords.map do |name, _param|
209
- Entry::KeywordParameter.new(name: name)
210
- end
211
- end
212
-
213
- #: (RBS::Types::Function function) -> Array[Entry::OptionalKeywordParameter]
214
- def process_optional_keywords(function)
215
- function.optional_keywords.map do |name, _param|
216
- Entry::OptionalKeywordParameter.new(name: name)
217
- end
218
- end
219
-
220
- #: (RBS::Types::Function function) -> Entry::KeywordRestParameter
221
- def process_rest_keywords(function)
222
- param = function.rest_keywords
223
-
224
- name = param.name || Entry::KeywordRestParameter::DEFAULT_NAME
225
-
226
- Entry::KeywordRestParameter.new(name: name)
227
- end
228
-
229
- # RBS treats constant definitions differently depend on where they are defined.
230
- # When constants' rbs are defined inside a class/module block, they are treated as
231
- # members of the class/module.
232
- #
233
- # module Encoding
234
- # US_ASCII = ... # US_ASCII is a member of Encoding
235
- # end
236
- #
237
- # When constants' rbs are defined outside a class/module block, they are treated as
238
- # top-level constants.
239
- #
240
- # Complex::I = ... # Complex::I is a top-level constant
241
- #
242
- # And we need to handle their nesting differently.
243
- #: (RBS::AST::Declarations::Constant declaration, Array[String] nesting, URI::Generic uri) -> void
244
- def handle_constant(declaration, nesting, uri)
245
- fully_qualified_name = [*nesting, declaration.name.name.to_s].join("::")
246
- @index.add(Entry::Constant.new(
247
- @index.configuration,
248
- fully_qualified_name,
249
- uri,
250
- to_ruby_indexer_location(declaration.location),
251
- comments_to_string(declaration),
252
- ))
253
- end
254
-
255
- #: (RBS::AST::Declarations::Global declaration, Pathname pathname) -> void
256
- def handle_global_variable(declaration, pathname)
257
- name = declaration.name.to_s
258
- uri = URI::Generic.from_path(path: pathname.to_s)
259
- location = to_ruby_indexer_location(declaration.location)
260
- comments = comments_to_string(declaration)
261
-
262
- @index.add(Entry::GlobalVariable.new(
263
- @index.configuration,
264
- name,
265
- uri,
266
- location,
267
- comments,
268
- ))
269
- end
270
-
271
- #: (RBS::AST::Members::Alias member, Entry::Namespace owner_entry) -> void
272
- def handle_signature_alias(member, owner_entry)
273
- uri = URI::Generic.from_path(path: member.location.buffer.name.to_s)
274
- comments = comments_to_string(member)
275
-
276
- entry = Entry::UnresolvedMethodAlias.new(
277
- @index.configuration,
278
- member.new_name.to_s,
279
- member.old_name.to_s,
280
- owner_entry,
281
- uri,
282
- to_ruby_indexer_location(member.location),
283
- comments,
284
- )
285
-
286
- @index.add(entry)
287
- end
288
-
289
- #: ((RBS::AST::Declarations::Class | RBS::AST::Declarations::Module | RBS::AST::Declarations::Constant | RBS::AST::Declarations::Global | RBS::AST::Members::MethodDefinition | RBS::AST::Members::Alias) declaration) -> String?
290
- def comments_to_string(declaration)
291
- declaration.comment&.string
292
- end
293
- end
294
- end