ruby-lsp 0.13.1 → 0.13.3

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 (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",