ruby-lsp 0.13.1 → 0.13.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -0
  3. data/VERSION +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +30 -1
  6. data/lib/ruby_lsp/check_docs.rb +3 -3
  7. data/lib/ruby_lsp/document.rb +15 -7
  8. data/lib/ruby_lsp/executor.rb +85 -226
  9. data/lib/ruby_lsp/listener.rb +1 -50
  10. data/lib/ruby_lsp/listeners/code_lens.rb +233 -0
  11. data/lib/ruby_lsp/listeners/completion.rb +275 -0
  12. data/lib/ruby_lsp/listeners/definition.rb +158 -0
  13. data/lib/ruby_lsp/listeners/document_highlight.rb +556 -0
  14. data/lib/ruby_lsp/listeners/document_link.rb +162 -0
  15. data/lib/ruby_lsp/listeners/document_symbol.rb +223 -0
  16. data/lib/ruby_lsp/listeners/folding_ranges.rb +271 -0
  17. data/lib/ruby_lsp/listeners/hover.rb +152 -0
  18. data/lib/ruby_lsp/listeners/inlay_hints.rb +80 -0
  19. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +430 -0
  20. data/lib/ruby_lsp/listeners/signature_help.rb +74 -0
  21. data/lib/ruby_lsp/requests/code_action_resolve.rb +5 -5
  22. data/lib/ruby_lsp/requests/code_actions.rb +15 -6
  23. data/lib/ruby_lsp/requests/code_lens.rb +21 -221
  24. data/lib/ruby_lsp/requests/completion.rb +64 -246
  25. data/lib/ruby_lsp/requests/definition.rb +34 -147
  26. data/lib/ruby_lsp/requests/diagnostics.rb +17 -5
  27. data/lib/ruby_lsp/requests/document_highlight.rb +12 -536
  28. data/lib/ruby_lsp/requests/document_link.rb +11 -132
  29. data/lib/ruby_lsp/requests/document_symbol.rb +23 -210
  30. data/lib/ruby_lsp/requests/folding_ranges.rb +16 -252
  31. data/lib/ruby_lsp/requests/formatting.rb +4 -4
  32. data/lib/ruby_lsp/requests/hover.rb +48 -92
  33. data/lib/ruby_lsp/requests/inlay_hints.rb +23 -56
  34. data/lib/ruby_lsp/requests/on_type_formatting.rb +18 -6
  35. data/lib/ruby_lsp/requests/request.rb +17 -0
  36. data/lib/ruby_lsp/requests/selection_ranges.rb +4 -3
  37. data/lib/ruby_lsp/requests/semantic_highlighting.rb +21 -408
  38. data/lib/ruby_lsp/requests/show_syntax_tree.rb +5 -5
  39. data/lib/ruby_lsp/requests/signature_help.rb +87 -0
  40. data/lib/ruby_lsp/requests/support/common.rb +3 -2
  41. data/lib/ruby_lsp/requests/support/dependency_detector.rb +2 -0
  42. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -1
  43. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
  44. data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
  45. data/lib/ruby_lsp/requests.rb +3 -1
  46. data/lib/ruby_lsp/store.rb +1 -1
  47. data/lib/ruby_lsp/utils.rb +8 -0
  48. metadata +20 -8
  49. data/lib/ruby_lsp/requests/base_request.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78df9c8d35fc18cea6fc06a0f679b48b69e3daaaf504d762d2f5ae4df9d99ad0
4
- data.tar.gz: 3c251eed7939e81c5aa115d303b2876d3769c509ef0487b0faa26d1a2de79c50
3
+ metadata.gz: 28e657dce7a85c270d1c647a158fd1a1c5f81dca211844defd817070fd264126
4
+ data.tar.gz: f129245dd0e632916573c0b9dcf04bfaa2c7b942b39aaa6aa1618dd70f13e69e
5
5
  SHA512:
6
- metadata.gz: af33b81309429318e7fe61dc4a2bd989328b8e9127097ab621eab162e61e1b2d93f1be1b192307d3b48f47659489343e093d92125e9c68895c40517803dba5ed
7
- data.tar.gz: 6373eb77209eb865e29026fba603f4db8d3249949bcff7c0aee3f550569a7225c84b76d5872fd61a8798c0ef04da2d538b50b4d3045697ef40cc85336a2c715b
6
+ metadata.gz: 3ab4afce37f672fd0d3c3ecc54c7b30247f893fc4b7b4f10549e13db4ab181c67a9b84da37dea9fbdd195e8d87ca2f2f794cbcce300c68b4709ee0ae3b3171b2
7
+ data.tar.gz: ffdb3a1bdb2d5c4172f74c934da896bd6c19f09158effa137afd0443e79b8c2dfd392989997d5745616db58e1286191a9e35570bd69024779137e7aaf15bb987
data/README.md CHANGED
@@ -46,6 +46,36 @@ See the [documentation](https://shopify.github.io/ruby-lsp) for more in-depth de
46
46
  For creating rich themes for Ruby using the semantic highlighting information, see the [semantic highlighting
47
47
  documentation](SEMANTIC_HIGHLIGHTING.md).
48
48
 
49
+ ### Configuring code indexing
50
+
51
+ By default, the Ruby LSP indexes all Ruby files defined in the current project and all of its dependencies, including
52
+ default gems, except for
53
+
54
+ - Gems that only appear under the `:development` group
55
+ - All Ruby files under `test/**/*.rb`
56
+
57
+ By creating a `.index.yml` file, these configurations can be overridden and tuned.
58
+
59
+ ```yaml
60
+ # Exclude files based on a given pattern. Often used to exclude test files or fixtures
61
+ excluded_patterns:
62
+ - "**/spec/**/*.rb"
63
+
64
+ # Include files based on a given pattern. Can be used to index Ruby files that use different extensions
65
+ included_patterns:
66
+ - "**/bin/*"
67
+
68
+ # Exclude gems by name. If a gem is never referenced in the project's code and is only used as a tool, excluding it will
69
+ # speed up indexing and reduce the amount of results in features like definition or completion
70
+ excluded_gems:
71
+ - rubocop
72
+ - pathname
73
+
74
+ # Include gems by name. Normally used to include development gems that are excluded by default
75
+ included_gems:
76
+ - prism
77
+ ```
78
+
49
79
  ### Addons
50
80
 
51
81
  The Ruby LSP provides an addon system that allows other gems to enhance the base functionality with more editor
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.13.1
1
+ 0.13.3
@@ -193,7 +193,7 @@ module RubyIndexer
193
193
  # When working on a gem, we need to make sure that its gemspec dependencies can't be excluded. This is necessary
194
194
  # because Bundler doesn't assign groups to gemspec dependencies
195
195
  this_gem = Bundler.definition.dependencies.find do |d|
196
- d.to_spec.full_gem_path == Dir.pwd
196
+ d.to_spec&.full_gem_path == Dir.pwd
197
197
  rescue Gem::MissingSpecError
198
198
  false
199
199
  end
@@ -81,9 +81,13 @@ module RubyIndexer
81
81
 
82
82
  abstract!
83
83
 
84
+ # Name includes just the name of the parameter, excluding symbols like splats
84
85
  sig { returns(Symbol) }
85
86
  attr_reader :name
86
87
 
88
+ # Decorated name is the parameter name including the splat or block prefix, e.g.: `*foo`, `**foo` or `&block`
89
+ alias_method :decorated_name, :name
90
+
87
91
  sig { params(name: Symbol).void }
88
92
  def initialize(name:)
89
93
  @name = name
@@ -100,25 +104,48 @@ module RubyIndexer
100
104
 
101
105
  # An required keyword method parameter, e.g. `def foo(a:)`
102
106
  class KeywordParameter < Parameter
107
+ sig { override.returns(Symbol) }
108
+ def decorated_name
109
+ :"#{@name}:"
110
+ end
103
111
  end
104
112
 
105
113
  # An optional keyword method parameter, e.g. `def foo(a: 123)`
106
114
  class OptionalKeywordParameter < Parameter
115
+ sig { override.returns(Symbol) }
116
+ def decorated_name
117
+ :"#{@name}:"
118
+ end
107
119
  end
108
120
 
109
121
  # A rest method parameter, e.g. `def foo(*a)`
110
122
  class RestParameter < Parameter
111
123
  DEFAULT_NAME = T.let(:"<anonymous splat>", Symbol)
124
+
125
+ sig { override.returns(Symbol) }
126
+ def decorated_name
127
+ :"*#{@name}"
128
+ end
112
129
  end
113
130
 
114
131
  # A keyword rest method parameter, e.g. `def foo(**a)`
115
132
  class KeywordRestParameter < Parameter
116
133
  DEFAULT_NAME = T.let(:"<anonymous keyword splat>", Symbol)
134
+
135
+ sig { override.returns(Symbol) }
136
+ def decorated_name
137
+ :"**#{@name}"
138
+ end
117
139
  end
118
140
 
119
141
  # A block method parameter, e.g. `def foo(&block)`
120
142
  class BlockParameter < Parameter
121
143
  DEFAULT_NAME = T.let(:"<anonymous block>", Symbol)
144
+
145
+ sig { override.returns(Symbol) }
146
+ def decorated_name
147
+ :"&#{@name}"
148
+ end
122
149
  end
123
150
 
124
151
  class Member < Entry
@@ -220,7 +247,7 @@ module RubyIndexer
220
247
 
221
248
  rest = parameters_node.rest
222
249
 
223
- if rest
250
+ if rest.is_a?(Prism::RestParameterNode)
224
251
  rest_name = rest.name || RestParameter::DEFAULT_NAME
225
252
  parameters << RestParameter.new(name: rest_name)
226
253
  end
@@ -261,6 +288,8 @@ module RubyIndexer
261
288
  names << (rest.operator == "*" ? "*#{name}".to_sym : name&.to_sym)
262
289
  end
263
290
 
291
+ names << nil if rest.is_a?(Prism::ImplicitRestNode)
292
+
264
293
  names.concat(node.rights.map { |parameter_node| parameter_name(parameter_node) })
265
294
 
266
295
  names_with_commas = names.join(", ")
@@ -51,15 +51,15 @@ module RubyLsp
51
51
 
52
52
  # Find all classes that inherit from BaseRequest or Listener, which are the ones we want to make sure are
53
53
  # documented
54
- features = ObjectSpace.each_object(Class).filter_map do |k|
54
+ features = ObjectSpace.each_object(Class).select do |k|
55
55
  klass = T.unsafe(k)
56
- klass if klass < Requests::BaseRequest || (klass < Listener && klass != ExtensibleListener)
56
+ klass < Requests::Request
57
57
  end
58
58
 
59
59
  missing_docs = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, T::Array[String]])
60
60
 
61
61
  features.each do |klass|
62
- class_name = T.must(klass.name)
62
+ class_name = T.unsafe(klass).name
63
63
  file_path, line_number = Module.const_source_location(class_name)
64
64
  next unless file_path && line_number
65
65
 
@@ -8,10 +8,6 @@ module RubyLsp
8
8
 
9
9
  abstract!
10
10
 
11
- PositionShape = T.type_alias { { line: Integer, character: Integer } }
12
- RangeShape = T.type_alias { { start: PositionShape, end: PositionShape } }
13
- EditShape = T.type_alias { { range: RangeShape, text: String } }
14
-
15
11
  sig { returns(Prism::ParseResult) }
16
12
  attr_reader :parse_result
17
13
 
@@ -80,7 +76,7 @@ module RubyLsp
80
76
  @cache[request_name]
81
77
  end
82
78
 
83
- sig { params(edits: T::Array[EditShape], version: Integer).void }
79
+ sig { params(edits: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).void }
84
80
  def push_edits(edits, version:)
85
81
  edits.each do |edit|
86
82
  range = edit[:range]
@@ -112,7 +108,7 @@ module RubyLsp
112
108
 
113
109
  sig do
114
110
  params(
115
- position: PositionShape,
111
+ position: T::Hash[Symbol, T.untyped],
116
112
  node_types: T::Array[T.class_of(Prism::Node)],
117
113
  ).returns([T.nilable(Prism::Node), T.nilable(Prism::Node), T::Array[String]])
118
114
  end
@@ -177,6 +173,18 @@ module RubyLsp
177
173
  [closest, parent, nesting.map { |n| n.constant_path.location.slice }]
178
174
  end
179
175
 
176
+ sig { returns(T::Boolean) }
177
+ def sorbet_sigil_is_true_or_higher
178
+ parse_result.magic_comments.any? do |comment|
179
+ comment.key == "typed" && ["true", "strict", "strong"].include?(comment.value)
180
+ end
181
+ end
182
+
183
+ sig { returns(T::Boolean) }
184
+ def typechecker_enabled?
185
+ DependencyDetector.instance.typechecker && sorbet_sigil_is_true_or_higher
186
+ end
187
+
180
188
  class Scanner
181
189
  extend T::Sig
182
190
 
@@ -193,7 +201,7 @@ module RubyLsp
193
201
  end
194
202
 
195
203
  # Finds the character index inside the source string for a given line and column
196
- sig { params(position: PositionShape).returns(Integer) }
204
+ sig { params(position: T::Hash[Symbol, T.untyped]).returns(Integer) }
197
205
  def find_char_position(position)
198
206
  # Find the character index for the beginning of the requested line
199
207
  until @current_line == position[:line]
@@ -25,6 +25,7 @@ module RubyLsp
25
25
  begin
26
26
  response = run(request)
27
27
  rescue StandardError, LoadError => e
28
+ warn(e.message)
28
29
  error = e
29
30
  end
30
31
 
@@ -93,7 +94,7 @@ module RubyLsp
93
94
  cached_response = document.cache_get(request[:method])
94
95
  return cached_response if cached_response
95
96
 
96
- # Run listeners for the document
97
+ # Run requests for the document
97
98
  dispatcher = Prism::Dispatcher.new
98
99
  folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher)
99
100
  document_symbol = Requests::DocumentSymbol.new(dispatcher)
@@ -106,13 +107,13 @@ module RubyLsp
106
107
 
107
108
  # Store all responses retrieve in this round of visits in the cache and then return the response for the request
108
109
  # we actually received
109
- document.cache_set("textDocument/foldingRange", folding_range.response)
110
- document.cache_set("textDocument/documentSymbol", document_symbol.response)
111
- document.cache_set("textDocument/documentLink", document_link.response)
112
- document.cache_set("textDocument/codeLens", code_lens.response)
110
+ document.cache_set("textDocument/foldingRange", folding_range.perform)
111
+ document.cache_set("textDocument/documentSymbol", document_symbol.perform)
112
+ document.cache_set("textDocument/documentLink", document_link.perform)
113
+ document.cache_set("textDocument/codeLens", code_lens.perform)
113
114
  document.cache_set(
114
115
  "textDocument/semanticTokens/full",
115
- Requests::Support::SemanticTokenEncoder.new.encode(semantic_highlighting.response),
116
+ Requests::Support::SemanticTokenEncoder.new.encode(semantic_highlighting.perform),
116
117
  )
117
118
  document.cache_get(request[:method])
118
119
  when "textDocument/semanticTokens/range"
@@ -142,13 +143,30 @@ module RubyLsp
142
143
  nil
143
144
  end
144
145
  when "textDocument/documentHighlight"
145
- document_highlight(uri, request.dig(:params, :position))
146
+ dispatcher = Prism::Dispatcher.new
147
+ document = @store.get(uri)
148
+ request = Requests::DocumentHighlight.new(document, request.dig(:params, :position), dispatcher)
149
+ dispatcher.dispatch(document.tree)
150
+ request.perform
146
151
  when "textDocument/onTypeFormatting"
147
152
  on_type_formatting(uri, request.dig(:params, :position), request.dig(:params, :ch))
148
153
  when "textDocument/hover"
149
- hover(uri, request.dig(:params, :position))
154
+ dispatcher = Prism::Dispatcher.new
155
+ document = @store.get(uri)
156
+ Requests::Hover.new(
157
+ document,
158
+ @index,
159
+ request.dig(:params, :position),
160
+ dispatcher,
161
+ document.typechecker_enabled?,
162
+ ).perform
150
163
  when "textDocument/inlayHint"
151
- inlay_hint(uri, request.dig(:params, :range))
164
+ hints_configurations = T.must(@store.features_configuration.dig(:inlayHint))
165
+ dispatcher = Prism::Dispatcher.new
166
+ document = @store.get(uri)
167
+ request = Requests::InlayHints.new(document, request.dig(:params, :range), hints_configurations, dispatcher)
168
+ dispatcher.visit(document.tree)
169
+ request.perform
152
170
  when "textDocument/codeAction"
153
171
  code_action(uri, request.dig(:params, :range), request.dig(:params, :context))
154
172
  when "codeAction/resolve"
@@ -168,9 +186,36 @@ module RubyLsp
168
186
  nil
169
187
  end
170
188
  when "textDocument/completion"
171
- completion(uri, request.dig(:params, :position))
189
+ dispatcher = Prism::Dispatcher.new
190
+ document = @store.get(uri)
191
+ Requests::Completion.new(
192
+ document,
193
+ @index,
194
+ request.dig(:params, :position),
195
+ document.typechecker_enabled?,
196
+ dispatcher,
197
+ ).perform
198
+ when "textDocument/signatureHelp"
199
+ dispatcher = Prism::Dispatcher.new
200
+ document = @store.get(uri)
201
+
202
+ Requests::SignatureHelp.new(
203
+ document,
204
+ @index,
205
+ request.dig(:params, :position),
206
+ request.dig(:params, :context),
207
+ dispatcher,
208
+ ).perform
172
209
  when "textDocument/definition"
173
- definition(uri, request.dig(:params, :position))
210
+ dispatcher = Prism::Dispatcher.new
211
+ document = @store.get(uri)
212
+ Requests::Definition.new(
213
+ document,
214
+ @index,
215
+ request.dig(:params, :position),
216
+ dispatcher,
217
+ document.typechecker_enabled?,
218
+ ).perform
174
219
  when "workspace/didChangeWatchedFiles"
175
220
  did_change_watched_files(request.dig(:params, :changes))
176
221
  when "workspace/symbol"
@@ -242,66 +287,16 @@ module RubyLsp
242
287
 
243
288
  sig { params(query: T.nilable(String)).returns(T::Array[Interface::WorkspaceSymbol]) }
244
289
  def workspace_symbol(query)
245
- Requests::WorkspaceSymbol.new(query, @index).run
290
+ Requests::WorkspaceSymbol.new(query, @index).perform
246
291
  end
247
292
 
248
- sig { params(uri: URI::Generic, range: T.nilable(Document::RangeShape)).returns({ ast: String }) }
293
+ sig { params(uri: URI::Generic, range: T.nilable(T::Hash[Symbol, T.untyped])).returns({ ast: String }) }
249
294
  def show_syntax_tree(uri, range)
250
- { ast: Requests::ShowSyntaxTree.new(@store.get(uri), range).run }
251
- end
252
-
253
- sig do
254
- params(
255
- uri: URI::Generic,
256
- position: Document::PositionShape,
257
- ).returns(T.nilable(T.any(T::Array[Interface::Location], Interface::Location)))
258
- end
259
- def definition(uri, position)
260
- document = @store.get(uri)
261
- target, parent, nesting = document.locate_node(
262
- position,
263
- node_types: [Prism::CallNode, Prism::ConstantReadNode, Prism::ConstantPathNode],
264
- )
265
-
266
- target = parent if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
267
-
268
- dispatcher = Prism::Dispatcher.new
269
- base_listener = Requests::Definition.new(uri, nesting, @index, dispatcher)
270
- dispatcher.dispatch_once(target)
271
- base_listener.response
272
- end
273
-
274
- sig do
275
- params(
276
- uri: URI::Generic,
277
- position: Document::PositionShape,
278
- ).returns(T.nilable(Interface::Hover))
279
- end
280
- def hover(uri, position)
281
- document = @store.get(uri)
282
- target, parent, nesting = document.locate_node(
283
- position,
284
- node_types: Requests::Hover::ALLOWED_TARGETS,
285
- )
286
-
287
- if (Requests::Hover::ALLOWED_TARGETS.include?(parent.class) &&
288
- !Requests::Hover::ALLOWED_TARGETS.include?(target.class)) ||
289
- (parent.is_a?(Prism::ConstantPathNode) && target.is_a?(Prism::ConstantReadNode))
290
- target = parent
291
- end
292
-
293
- # Instantiate all listeners
294
- dispatcher = Prism::Dispatcher.new
295
- hover = Requests::Hover.new(@index, nesting, dispatcher)
296
-
297
- # Emit events for all listeners
298
- dispatcher.dispatch_once(target)
299
-
300
- hover.response
295
+ { ast: Requests::ShowSyntaxTree.new(@store.get(uri), range).perform }
301
296
  end
302
297
 
303
298
  sig do
304
- params(uri: URI::Generic, content_changes: T::Array[Document::EditShape], version: Integer).returns(Object)
299
+ params(uri: URI::Generic, content_changes: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).returns(Object)
305
300
  end
306
301
  def text_document_did_change(uri, content_changes, version)
307
302
  @store.push_edits(uri: uri, edits: content_changes, version: version)
@@ -323,12 +318,12 @@ module RubyLsp
323
318
  sig do
324
319
  params(
325
320
  uri: URI::Generic,
326
- positions: T::Array[Document::PositionShape],
321
+ positions: T::Array[T::Hash[Symbol, T.untyped]],
327
322
  ).returns(T.nilable(T::Array[T.nilable(Requests::Support::SelectionRange)]))
328
323
  end
329
324
  def selection_range(uri, positions)
330
325
  ranges = @store.cache_fetch(uri, "textDocument/selectionRange") do |document|
331
- Requests::SelectionRanges.new(document).run
326
+ Requests::SelectionRanges.new(document).perform
332
327
  end
333
328
 
334
329
  # Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
@@ -355,68 +350,38 @@ module RubyLsp
355
350
  path = uri.to_standardized_path
356
351
  return unless path.nil? || path.start_with?(T.must(@store.workspace_uri.to_standardized_path))
357
352
 
358
- Requests::Formatting.new(@store.get(uri), formatter: @store.formatter).run
353
+ Requests::Formatting.new(@store.get(uri), formatter: @store.formatter).perform
359
354
  end
360
355
 
361
356
  sig do
362
357
  params(
363
358
  uri: URI::Generic,
364
- position: Document::PositionShape,
359
+ position: T::Hash[Symbol, T.untyped],
365
360
  character: String,
366
361
  ).returns(T::Array[Interface::TextEdit])
367
362
  end
368
363
  def on_type_formatting(uri, position, character)
369
- Requests::OnTypeFormatting.new(@store.get(uri), position, character).run
364
+ Requests::OnTypeFormatting.new(@store.get(uri), position, character).perform
370
365
  end
371
366
 
372
367
  sig do
373
368
  params(
374
369
  uri: URI::Generic,
375
- position: Document::PositionShape,
376
- ).returns(T.nilable(T::Array[Interface::DocumentHighlight]))
377
- end
378
- def document_highlight(uri, position)
379
- document = @store.get(uri)
380
-
381
- target, parent = document.locate_node(position)
382
- dispatcher = Prism::Dispatcher.new
383
- listener = Requests::DocumentHighlight.new(target, parent, dispatcher)
384
- dispatcher.visit(document.tree)
385
- listener.response
386
- end
387
-
388
- sig { params(uri: URI::Generic, range: Document::RangeShape).returns(T.nilable(T::Array[Interface::InlayHint])) }
389
- def inlay_hint(uri, range)
390
- document = @store.get(uri)
391
-
392
- start_line = range.dig(:start, :line)
393
- end_line = range.dig(:end, :line)
394
-
395
- dispatcher = Prism::Dispatcher.new
396
- hints_configurations = T.must(@store.features_configuration.dig(:inlayHint))
397
- listener = Requests::InlayHints.new(start_line..end_line, hints_configurations, dispatcher)
398
- dispatcher.visit(document.tree)
399
- listener.response
400
- end
401
-
402
- sig do
403
- params(
404
- uri: URI::Generic,
405
- range: Document::RangeShape,
370
+ range: T::Hash[Symbol, T.untyped],
406
371
  context: T::Hash[Symbol, T.untyped],
407
372
  ).returns(T.nilable(T::Array[Interface::CodeAction]))
408
373
  end
409
374
  def code_action(uri, range, context)
410
375
  document = @store.get(uri)
411
376
 
412
- Requests::CodeActions.new(document, range, context).run
377
+ Requests::CodeActions.new(document, range, context).perform
413
378
  end
414
379
 
415
380
  sig { params(params: T::Hash[Symbol, T.untyped]).returns(Interface::CodeAction) }
416
381
  def code_action_resolve(params)
417
382
  uri = URI(params.dig(:data, :uri))
418
383
  document = @store.get(uri)
419
- result = Requests::CodeActionResolve.new(document, params).run
384
+ result = Requests::CodeActionResolve.new(document, params).perform
420
385
 
421
386
  case result
422
387
  when Requests::CodeActionResolve::Error::EmptySelection
@@ -450,74 +415,23 @@ module RubyLsp
450
415
  return unless path.nil? || path.start_with?(T.must(@store.workspace_uri.to_standardized_path))
451
416
 
452
417
  response = @store.cache_fetch(uri, "textDocument/diagnostic") do |document|
453
- Requests::Diagnostics.new(document).run
418
+ Requests::Diagnostics.new(document).perform
454
419
  end
455
420
 
456
421
  Interface::FullDocumentDiagnosticReport.new(kind: "full", items: response) if response
457
422
  end
458
423
 
459
- sig { params(uri: URI::Generic, range: Document::RangeShape).returns(Interface::SemanticTokens) }
424
+ sig { params(uri: URI::Generic, range: T::Hash[Symbol, T.untyped]).returns(Interface::SemanticTokens) }
460
425
  def semantic_tokens_range(uri, range)
461
426
  document = @store.get(uri)
462
427
  start_line = range.dig(:start, :line)
463
428
  end_line = range.dig(:end, :line)
464
429
 
465
430
  dispatcher = Prism::Dispatcher.new
466
- listener = Requests::SemanticHighlighting.new(dispatcher, range: start_line..end_line)
431
+ request = Requests::SemanticHighlighting.new(dispatcher, range: start_line..end_line)
467
432
  dispatcher.visit(document.tree)
468
433
 
469
- Requests::Support::SemanticTokenEncoder.new.encode(listener.response)
470
- end
471
-
472
- sig do
473
- params(
474
- uri: URI::Generic,
475
- position: Document::PositionShape,
476
- ).returns(T.nilable(T::Array[Interface::CompletionItem]))
477
- end
478
- def completion(uri, position)
479
- document = @store.get(uri)
480
-
481
- # Completion always receives the position immediately after the character that was just typed. Here we adjust it
482
- # back by 1, so that we find the right node
483
- char_position = document.create_scanner.find_char_position(position) - 1
484
- matched, parent, nesting = document.locate(
485
- document.tree,
486
- char_position,
487
- node_types: [Prism::CallNode, Prism::ConstantReadNode, Prism::ConstantPathNode],
488
- )
489
- return unless matched && parent
490
-
491
- target = case matched
492
- when Prism::CallNode
493
- message = matched.message
494
-
495
- if message == "require"
496
- args = matched.arguments&.arguments
497
- return if args.nil? || args.is_a?(Prism::ForwardingArgumentsNode)
498
-
499
- argument = args.first
500
- return unless argument.is_a?(Prism::StringNode)
501
- return unless (argument.location.start_offset..argument.location.end_offset).cover?(char_position)
502
-
503
- argument
504
- else
505
- matched
506
- end
507
- when Prism::ConstantReadNode, Prism::ConstantPathNode
508
- if parent.is_a?(Prism::ConstantPathNode) && matched.is_a?(Prism::ConstantReadNode)
509
- parent
510
- else
511
- matched
512
- end
513
- end
514
-
515
- return unless target
516
-
517
- dispatcher = Prism::Dispatcher.new
518
- listener = Requests::Completion.new(@index, nesting, dispatcher)
519
- dispatcher.dispatch_once(target)
520
- listener.response
434
+ Requests::Support::SemanticTokenEncoder.new.encode(request.perform)
521
435
  end
522
436
 
523
437
  sig { params(id: String, title: String, percentage: Integer).void }
@@ -623,74 +537,18 @@ module RubyLsp
623
537
  Hash.new(true)
624
538
  end
625
539
 
626
- document_symbol_provider = if enabled_features["documentSymbols"]
627
- Interface::DocumentSymbolClientCapabilities.new(
628
- hierarchical_document_symbol_support: true,
629
- symbol_kind: {
630
- value_set: (Constant::SymbolKind::FILE..Constant::SymbolKind::TYPE_PARAMETER).to_a,
631
- },
632
- )
633
- end
634
-
635
- document_link_provider = if enabled_features["documentLink"]
636
- Interface::DocumentLinkOptions.new(resolve_provider: false)
637
- end
638
-
639
- code_lens_provider = if enabled_features["codeLens"]
640
- Interface::CodeLensOptions.new(resolve_provider: false)
641
- end
642
-
643
- hover_provider = if enabled_features["hover"]
644
- Interface::HoverClientCapabilities.new(dynamic_registration: false)
645
- end
646
-
647
- folding_ranges_provider = if enabled_features["foldingRanges"]
648
- Interface::FoldingRangeClientCapabilities.new(line_folding_only: true)
649
- end
650
-
651
- semantic_tokens_provider = if enabled_features["semanticHighlighting"]
652
- Interface::SemanticTokensRegistrationOptions.new(
653
- document_selector: { scheme: "file", language: "ruby" },
654
- legend: Interface::SemanticTokensLegend.new(
655
- token_types: Requests::SemanticHighlighting::TOKEN_TYPES.keys,
656
- token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys,
657
- ),
658
- range: true,
659
- full: { delta: false },
660
- )
661
- end
662
-
663
- diagnostics_provider = if enabled_features["diagnostics"]
664
- {
665
- interFileDependencies: false,
666
- workspaceDiagnostics: false,
667
- }
668
- end
669
-
670
- on_type_formatting_provider = if enabled_features["onTypeFormatting"]
671
- Interface::DocumentOnTypeFormattingOptions.new(
672
- first_trigger_character: "{",
673
- more_trigger_character: ["\n", "|", "d"],
674
- )
675
- end
676
-
677
- code_action_provider = if enabled_features["codeActions"]
678
- Interface::CodeActionOptions.new(resolve_provider: true)
679
- end
680
-
681
- inlay_hint_provider = if enabled_features["inlayHint"]
682
- Interface::InlayHintOptions.new(resolve_provider: false)
683
- end
684
-
685
- completion_provider = if enabled_features["completion"]
686
- Interface::CompletionOptions.new(
687
- resolve_provider: false,
688
- trigger_characters: ["/"],
689
- completion_item: {
690
- labelDetailsSupport: true,
691
- },
692
- )
693
- end
540
+ document_symbol_provider = Requests::DocumentSymbol.provider if enabled_features["documentSymbols"]
541
+ document_link_provider = Requests::DocumentLink.provider if enabled_features["documentLink"]
542
+ code_lens_provider = Requests::CodeLens.provider if enabled_features["codeLens"]
543
+ hover_provider = Requests::Hover.provider if enabled_features["hover"]
544
+ folding_ranges_provider = Requests::FoldingRanges.provider if enabled_features["foldingRanges"]
545
+ semantic_tokens_provider = Requests::SemanticHighlighting.provider if enabled_features["semanticHighlighting"]
546
+ diagnostics_provider = Requests::Diagnostics.provider if enabled_features["diagnostics"]
547
+ on_type_formatting_provider = Requests::OnTypeFormatting.provider if enabled_features["onTypeFormatting"]
548
+ code_action_provider = Requests::CodeActions.provider if enabled_features["codeActions"]
549
+ inlay_hint_provider = Requests::InlayHints.provider if enabled_features["inlayHint"]
550
+ completion_provider = Requests::Completion.provider if enabled_features["completion"]
551
+ signature_help_provider = Requests::SignatureHelp.provider if enabled_features["signatureHelp"]
694
552
 
695
553
  # Dynamically registered capabilities
696
554
  file_watching_caps = options.dig(:capabilities, :workspace, :didChangeWatchedFiles)
@@ -744,6 +602,7 @@ module RubyLsp
744
602
  code_lens_provider: code_lens_provider,
745
603
  definition_provider: enabled_features["definition"],
746
604
  workspace_symbol_provider: enabled_features["workspaceSymbol"],
605
+ signature_help_provider: signature_help_provider,
747
606
  ),
748
607
  serverInfo: {
749
608
  name: "Ruby LSP",