ruby-lsp 0.13.0 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6bace664e1540c1333df9dabfb2e7bdd8bda0f910033b47b188e4a82ddacb15
4
- data.tar.gz: be9e5da0492b26b5cb6e07074d01d7874104b70286c1578342b9639158fed147
3
+ metadata.gz: 2329129b74c75a0bb4113d1f1489463f666b74ef495d0ac65bad675fbd83d1d3
4
+ data.tar.gz: 2f31f495b9ca0b1a9f909758dabce816411d0b64a006577c93c7a80a253791e5
5
5
  SHA512:
6
- metadata.gz: 7d8e61433686271a68dafe8db79765ed509a115ab6f06060d7669d279f48218fe2eada2c12e3b45f155d27a41774771681cdab92700d27f426e75ed89287ca03
7
- data.tar.gz: 611c050b751050934d0fd93e9e52089fe63fc4d947be75a440dfa0465933814d2682268a10135d036c2cee83fa739156d2b11e42e679ecbed7de62acfee9d621
6
+ metadata.gz: 9c3ab34cb3e7877105ca21df3f521589d9838bd15e77a3d17cc4df91ca1f93221ef845e514a902a03a63a1f82ad6b5cf90fa4f9a93037fbfb57af5f7a48b0ebe
7
+ data.tar.gz: d4867c86eb238abf039f40592d7ff48acd85749fcf9349ab72fdea218ff5201156fc0d511987ed768b1fb2dcc9fd55a76bfac611f3fc565b7b2ba8c8d1054a72
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.13.0
1
+ 0.13.2
@@ -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,10 +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
119
+ end
120
+
121
+ # A rest method parameter, e.g. `def foo(*a)`
122
+ class RestParameter < Parameter
123
+ DEFAULT_NAME = T.let(:"<anonymous splat>", Symbol)
124
+
125
+ sig { override.returns(Symbol) }
126
+ def decorated_name
127
+ :"*#{@name}"
128
+ end
129
+ end
130
+
131
+ # A keyword rest method parameter, e.g. `def foo(**a)`
132
+ class KeywordRestParameter < Parameter
133
+ DEFAULT_NAME = T.let(:"<anonymous keyword splat>", Symbol)
134
+
135
+ sig { override.returns(Symbol) }
136
+ def decorated_name
137
+ :"**#{@name}"
138
+ end
139
+ end
140
+
141
+ # A block method parameter, e.g. `def foo(&block)`
142
+ class BlockParameter < Parameter
143
+ DEFAULT_NAME = T.let(:"<anonymous block>", Symbol)
144
+
145
+ sig { override.returns(Symbol) }
146
+ def decorated_name
147
+ :"&#{@name}"
148
+ end
107
149
  end
108
150
 
109
151
  class Member < Entry
@@ -203,17 +245,52 @@ module RubyIndexer
203
245
  end
204
246
  end
205
247
 
248
+ rest = parameters_node.rest
249
+
250
+ if rest.is_a?(Prism::RestParameterNode)
251
+ rest_name = rest.name || RestParameter::DEFAULT_NAME
252
+ parameters << RestParameter.new(name: rest_name)
253
+ end
254
+
255
+ keyword_rest = parameters_node.keyword_rest
256
+
257
+ if keyword_rest.is_a?(Prism::KeywordRestParameterNode)
258
+ keyword_rest_name = parameter_name(keyword_rest) || KeywordRestParameter::DEFAULT_NAME
259
+ parameters << KeywordRestParameter.new(name: keyword_rest_name)
260
+ end
261
+
262
+ parameters_node.posts.each do |post|
263
+ name = parameter_name(post)
264
+ next unless name
265
+
266
+ parameters << RequiredParameter.new(name: name)
267
+ end
268
+
269
+ block = parameters_node.block
270
+ parameters << BlockParameter.new(name: block.name || BlockParameter::DEFAULT_NAME) if block
271
+
206
272
  parameters
207
273
  end
208
274
 
209
- sig { params(node: Prism::Node).returns(T.nilable(Symbol)) }
275
+ sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(Symbol)) }
210
276
  def parameter_name(node)
211
277
  case node
212
278
  when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
213
- Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode
279
+ Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode,
280
+ Prism::RestParameterNode, Prism::KeywordRestParameterNode
214
281
  node.name
215
282
  when Prism::MultiTargetNode
216
- names = [*node.lefts, *node.rest, *node.rights].map { |parameter_node| parameter_name(parameter_node) }
283
+ names = node.lefts.map { |parameter_node| parameter_name(parameter_node) }
284
+
285
+ rest = node.rest
286
+ if rest.is_a?(Prism::SplatNode)
287
+ name = rest.expression&.slice
288
+ names << (rest.operator == "*" ? "*#{name}".to_sym : name&.to_sym)
289
+ end
290
+
291
+ names << nil if rest.is_a?(Prism::ImplicitRestNode)
292
+
293
+ names.concat(node.rights.map { |parameter_node| parameter_name(parameter_node) })
217
294
 
218
295
  names_with_commas = names.join(", ")
219
296
  :"(#{names_with_commas})"
@@ -106,6 +106,142 @@ module RubyIndexer
106
106
  assert_instance_of(Entry::OptionalKeywordParameter, b)
107
107
  end
108
108
 
109
+ def test_method_with_rest_and_keyword_rest_parameters
110
+ index(<<~RUBY)
111
+ class Foo
112
+ def bar(*a, **b)
113
+ end
114
+ end
115
+ RUBY
116
+
117
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
118
+ entry = T.must(@index["bar"].first)
119
+ assert_equal(2, entry.parameters.length)
120
+ a, b = entry.parameters
121
+
122
+ assert_equal(:a, a.name)
123
+ assert_instance_of(Entry::RestParameter, a)
124
+
125
+ assert_equal(:b, b.name)
126
+ assert_instance_of(Entry::KeywordRestParameter, b)
127
+ end
128
+
129
+ def test_method_with_post_parameters
130
+ index(<<~RUBY)
131
+ class Foo
132
+ def bar(*a, b)
133
+ end
134
+
135
+ def baz(**a, b)
136
+ end
137
+
138
+ def qux(*a, (b, c))
139
+ end
140
+ RUBY
141
+
142
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
143
+ entry = T.must(@index["bar"].first)
144
+ assert_equal(2, entry.parameters.length)
145
+ a, b = entry.parameters
146
+
147
+ assert_equal(:a, a.name)
148
+ assert_instance_of(Entry::RestParameter, a)
149
+
150
+ assert_equal(:b, b.name)
151
+ assert_instance_of(Entry::RequiredParameter, b)
152
+
153
+ entry = T.must(@index["baz"].first)
154
+ assert_equal(2, entry.parameters.length)
155
+ a, b = entry.parameters
156
+
157
+ assert_equal(:a, a.name)
158
+ assert_instance_of(Entry::KeywordRestParameter, a)
159
+
160
+ assert_equal(:b, b.name)
161
+ assert_instance_of(Entry::RequiredParameter, b)
162
+
163
+ entry = T.must(@index["qux"].first)
164
+ assert_equal(2, entry.parameters.length)
165
+ _a, second = entry.parameters
166
+
167
+ assert_equal(:"(b, c)", second.name)
168
+ assert_instance_of(Entry::RequiredParameter, second)
169
+ end
170
+
171
+ def test_method_with_destructured_rest_parameters
172
+ index(<<~RUBY)
173
+ class Foo
174
+ def bar((a, *b))
175
+ end
176
+ end
177
+ RUBY
178
+
179
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
180
+ entry = T.must(@index["bar"].first)
181
+ assert_equal(1, entry.parameters.length)
182
+ param = entry.parameters.first
183
+
184
+ assert_equal(:"(a, *b)", param.name)
185
+ assert_instance_of(Entry::RequiredParameter, param)
186
+ end
187
+
188
+ def test_method_with_block_parameters
189
+ index(<<~RUBY)
190
+ class Foo
191
+ def bar(&block)
192
+ end
193
+
194
+ def baz(&)
195
+ end
196
+ end
197
+ RUBY
198
+
199
+ entry = T.must(@index["bar"].first)
200
+ param = entry.parameters.first
201
+ assert_equal(:block, param.name)
202
+ assert_instance_of(Entry::BlockParameter, param)
203
+
204
+ entry = T.must(@index["baz"].first)
205
+ assert_equal(1, entry.parameters.length)
206
+
207
+ param = entry.parameters.first
208
+ assert_equal(Entry::BlockParameter::DEFAULT_NAME, param.name)
209
+ assert_instance_of(Entry::BlockParameter, param)
210
+ end
211
+
212
+ def test_method_with_anonymous_rest_parameters
213
+ index(<<~RUBY)
214
+ class Foo
215
+ def bar(*, **)
216
+ end
217
+ end
218
+ RUBY
219
+
220
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
221
+ entry = T.must(@index["bar"].first)
222
+ assert_equal(2, entry.parameters.length)
223
+ first, second = entry.parameters
224
+
225
+ assert_equal(Entry::RestParameter::DEFAULT_NAME, first.name)
226
+ assert_instance_of(Entry::RestParameter, first)
227
+
228
+ assert_equal(Entry::KeywordRestParameter::DEFAULT_NAME, second.name)
229
+ assert_instance_of(Entry::KeywordRestParameter, second)
230
+ end
231
+
232
+ def test_method_with_forbidden_keyword_splat_parameter
233
+ index(<<~RUBY)
234
+ class Foo
235
+ def bar(**nil)
236
+ end
237
+ end
238
+ RUBY
239
+
240
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
241
+ entry = T.must(@index["bar"].first)
242
+ assert_empty(entry.parameters)
243
+ end
244
+
109
245
  def test_keeps_track_of_method_owner
110
246
  index(<<~RUBY)
111
247
  class Foo
@@ -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
 
@@ -24,6 +20,9 @@ module RubyLsp
24
20
  sig { returns(URI::Generic) }
25
21
  attr_reader :uri
26
22
 
23
+ sig { returns(String) }
24
+ attr_reader :encoding
25
+
27
26
  sig { params(source: String, version: Integer, uri: URI::Generic, encoding: String).void }
28
27
  def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind::UTF8)
29
28
  @cache = T.let({}, T::Hash[String, T.untyped])
@@ -77,7 +76,7 @@ module RubyLsp
77
76
  @cache[request_name]
78
77
  end
79
78
 
80
- sig { params(edits: T::Array[EditShape], version: Integer).void }
79
+ sig { params(edits: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).void }
81
80
  def push_edits(edits, version:)
82
81
  edits.each do |edit|
83
82
  range = edit[:range]
@@ -109,7 +108,7 @@ module RubyLsp
109
108
 
110
109
  sig do
111
110
  params(
112
- position: PositionShape,
111
+ position: T::Hash[Symbol, T.untyped],
113
112
  node_types: T::Array[T.class_of(Prism::Node)],
114
113
  ).returns([T.nilable(Prism::Node), T.nilable(Prism::Node), T::Array[String]])
115
114
  end
@@ -190,7 +189,7 @@ module RubyLsp
190
189
  end
191
190
 
192
191
  # Finds the character index inside the source string for a given line and column
193
- sig { params(position: PositionShape).returns(Integer) }
192
+ sig { params(position: T::Hash[Symbol, T.untyped]).returns(Integer) }
194
193
  def find_char_position(position)
195
194
  # Find the character index for the beginning of the requested line
196
195
  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
 
@@ -98,7 +99,8 @@ module RubyLsp
98
99
  folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher)
99
100
  document_symbol = Requests::DocumentSymbol.new(dispatcher)
100
101
  document_link = Requests::DocumentLink.new(uri, document.comments, dispatcher)
101
- code_lens = Requests::CodeLens.new(uri, dispatcher)
102
+ lenses_configuration = T.must(@store.features_configuration.dig(:codeLens))
103
+ code_lens = Requests::CodeLens.new(uri, lenses_configuration, dispatcher)
102
104
 
103
105
  semantic_highlighting = Requests::SemanticHighlighting.new(dispatcher)
104
106
  dispatcher.dispatch(document.tree)
@@ -170,6 +172,8 @@ module RubyLsp
170
172
  completion(uri, request.dig(:params, :position))
171
173
  when "textDocument/definition"
172
174
  definition(uri, request.dig(:params, :position))
175
+ when "textDocument/signatureHelp"
176
+ signature_help(uri, request.dig(:params, :position), request.dig(:params, :context))
173
177
  when "workspace/didChangeWatchedFiles"
174
178
  did_change_watched_files(request.dig(:params, :changes))
175
179
  when "workspace/symbol"
@@ -239,12 +243,44 @@ module RubyLsp
239
243
  end
240
244
  end
241
245
 
246
+ sig do
247
+ params(
248
+ uri: URI::Generic,
249
+ position: T::Hash[Symbol, T.untyped],
250
+ context: T::Hash[Symbol, T.untyped],
251
+ ).returns(T.any(T.nilable(Interface::SignatureHelp), T::Hash[Symbol, T.untyped]))
252
+ end
253
+ def signature_help(uri, position, context)
254
+ current_signature = context[:activeSignatureHelp]
255
+ document = @store.get(uri)
256
+ target, parent, nesting = document.locate_node(
257
+ { line: position[:line], character: position[:character] - 2 },
258
+ node_types: [Prism::CallNode],
259
+ )
260
+
261
+ # If we're typing a nested method call (e.g.: `foo(bar)`), then we may end up locating `bar` as the target method
262
+ # call incorrectly. To correct that, we check if there's an active signature with the same name as the parent node
263
+ # and then replace the target
264
+ if current_signature && parent.is_a?(Prism::CallNode)
265
+ active_signature = current_signature[:activeSignature] || 0
266
+
267
+ if current_signature.dig(:signatures, active_signature, :label)&.start_with?(parent.message)
268
+ target = parent
269
+ end
270
+ end
271
+
272
+ dispatcher = Prism::Dispatcher.new
273
+ listener = Requests::SignatureHelp.new(context, nesting, @index, dispatcher)
274
+ dispatcher.dispatch_once(target)
275
+ listener.response
276
+ end
277
+
242
278
  sig { params(query: T.nilable(String)).returns(T::Array[Interface::WorkspaceSymbol]) }
243
279
  def workspace_symbol(query)
244
280
  Requests::WorkspaceSymbol.new(query, @index).run
245
281
  end
246
282
 
247
- sig { params(uri: URI::Generic, range: T.nilable(Document::RangeShape)).returns({ ast: String }) }
283
+ sig { params(uri: URI::Generic, range: T.nilable(T::Hash[Symbol, T.untyped])).returns({ ast: String }) }
248
284
  def show_syntax_tree(uri, range)
249
285
  { ast: Requests::ShowSyntaxTree.new(@store.get(uri), range).run }
250
286
  end
@@ -252,7 +288,7 @@ module RubyLsp
252
288
  sig do
253
289
  params(
254
290
  uri: URI::Generic,
255
- position: Document::PositionShape,
291
+ position: T::Hash[Symbol, T.untyped],
256
292
  ).returns(T.nilable(T.any(T::Array[Interface::Location], Interface::Location)))
257
293
  end
258
294
  def definition(uri, position)
@@ -273,7 +309,7 @@ module RubyLsp
273
309
  sig do
274
310
  params(
275
311
  uri: URI::Generic,
276
- position: Document::PositionShape,
312
+ position: T::Hash[Symbol, T.untyped],
277
313
  ).returns(T.nilable(Interface::Hover))
278
314
  end
279
315
  def hover(uri, position)
@@ -300,7 +336,7 @@ module RubyLsp
300
336
  end
301
337
 
302
338
  sig do
303
- params(uri: URI::Generic, content_changes: T::Array[Document::EditShape], version: Integer).returns(Object)
339
+ params(uri: URI::Generic, content_changes: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).returns(Object)
304
340
  end
305
341
  def text_document_did_change(uri, content_changes, version)
306
342
  @store.push_edits(uri: uri, edits: content_changes, version: version)
@@ -322,7 +358,7 @@ module RubyLsp
322
358
  sig do
323
359
  params(
324
360
  uri: URI::Generic,
325
- positions: T::Array[Document::PositionShape],
361
+ positions: T::Array[T::Hash[Symbol, T.untyped]],
326
362
  ).returns(T.nilable(T::Array[T.nilable(Requests::Support::SelectionRange)]))
327
363
  end
328
364
  def selection_range(uri, positions)
@@ -360,7 +396,7 @@ module RubyLsp
360
396
  sig do
361
397
  params(
362
398
  uri: URI::Generic,
363
- position: Document::PositionShape,
399
+ position: T::Hash[Symbol, T.untyped],
364
400
  character: String,
365
401
  ).returns(T::Array[Interface::TextEdit])
366
402
  end
@@ -371,7 +407,7 @@ module RubyLsp
371
407
  sig do
372
408
  params(
373
409
  uri: URI::Generic,
374
- position: Document::PositionShape,
410
+ position: T::Hash[Symbol, T.untyped],
375
411
  ).returns(T.nilable(T::Array[Interface::DocumentHighlight]))
376
412
  end
377
413
  def document_highlight(uri, position)
@@ -384,7 +420,12 @@ module RubyLsp
384
420
  listener.response
385
421
  end
386
422
 
387
- sig { params(uri: URI::Generic, range: Document::RangeShape).returns(T.nilable(T::Array[Interface::InlayHint])) }
423
+ sig do
424
+ params(
425
+ uri: URI::Generic,
426
+ range: T::Hash[Symbol, T.untyped],
427
+ ).returns(T.nilable(T::Array[Interface::InlayHint]))
428
+ end
388
429
  def inlay_hint(uri, range)
389
430
  document = @store.get(uri)
390
431
 
@@ -392,7 +433,8 @@ module RubyLsp
392
433
  end_line = range.dig(:end, :line)
393
434
 
394
435
  dispatcher = Prism::Dispatcher.new
395
- listener = Requests::InlayHints.new(start_line..end_line, dispatcher)
436
+ hints_configurations = T.must(@store.features_configuration.dig(:inlayHint))
437
+ listener = Requests::InlayHints.new(start_line..end_line, hints_configurations, dispatcher)
396
438
  dispatcher.visit(document.tree)
397
439
  listener.response
398
440
  end
@@ -400,7 +442,7 @@ module RubyLsp
400
442
  sig do
401
443
  params(
402
444
  uri: URI::Generic,
403
- range: Document::RangeShape,
445
+ range: T::Hash[Symbol, T.untyped],
404
446
  context: T::Hash[Symbol, T.untyped],
405
447
  ).returns(T.nilable(T::Array[Interface::CodeAction]))
406
448
  end
@@ -454,7 +496,7 @@ module RubyLsp
454
496
  Interface::FullDocumentDiagnosticReport.new(kind: "full", items: response) if response
455
497
  end
456
498
 
457
- sig { params(uri: URI::Generic, range: Document::RangeShape).returns(Interface::SemanticTokens) }
499
+ sig { params(uri: URI::Generic, range: T::Hash[Symbol, T.untyped]).returns(Interface::SemanticTokens) }
458
500
  def semantic_tokens_range(uri, range)
459
501
  document = @store.get(uri)
460
502
  start_line = range.dig(:start, :line)
@@ -470,7 +512,7 @@ module RubyLsp
470
512
  sig do
471
513
  params(
472
514
  uri: URI::Generic,
473
- position: Document::PositionShape,
515
+ position: T::Hash[Symbol, T.untyped],
474
516
  ).returns(T.nilable(T::Array[Interface::CompletionItem]))
475
517
  end
476
518
  def completion(uri, position)
@@ -602,6 +644,11 @@ module RubyLsp
602
644
  configured_features = options.dig(:initializationOptions, :enabledFeatures)
603
645
  @store.experimental_features = options.dig(:initializationOptions, :experimentalFeaturesEnabled) || false
604
646
 
647
+ configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
648
+ configured_lenses = options.dig(:initializationOptions, :featuresConfiguration, :codeLens)
649
+ T.must(@store.features_configuration.dig(:inlayHint)).configuration.merge!(configured_hints) if configured_hints
650
+ T.must(@store.features_configuration.dig(:codeLens)).configuration.merge!(configured_lenses) if configured_lenses
651
+
605
652
  enabled_features = case configured_features
606
653
  when Array
607
654
  # If the configuration is using an array, then absent features are disabled and present ones are enabled. That's
@@ -663,7 +710,7 @@ module RubyLsp
663
710
  on_type_formatting_provider = if enabled_features["onTypeFormatting"]
664
711
  Interface::DocumentOnTypeFormattingOptions.new(
665
712
  first_trigger_character: "{",
666
- more_trigger_character: ["\n", "|"],
713
+ more_trigger_character: ["\n", "|", "d"],
667
714
  )
668
715
  end
669
716
 
@@ -685,6 +732,13 @@ module RubyLsp
685
732
  )
686
733
  end
687
734
 
735
+ signature_help_provider = if enabled_features["signatureHelp"]
736
+ # Identifier characters are automatically included, such as A-Z, a-z, 0-9, _, * or :
737
+ Interface::SignatureHelpOptions.new(
738
+ trigger_characters: ["(", " ", ","],
739
+ )
740
+ end
741
+
688
742
  # Dynamically registered capabilities
689
743
  file_watching_caps = options.dig(:capabilities, :workspace, :didChangeWatchedFiles)
690
744
 
@@ -737,6 +791,7 @@ module RubyLsp
737
791
  code_lens_provider: code_lens_provider,
738
792
  definition_provider: enabled_features["definition"],
739
793
  workspace_symbol_provider: enabled_features["workspaceSymbol"],
794
+ signature_help_provider: signature_help_provider,
740
795
  ),
741
796
  serverInfo: {
742
797
  name: "Ruby LSP",
@@ -137,7 +137,7 @@ module RubyLsp
137
137
 
138
138
  private
139
139
 
140
- sig { params(range: Document::RangeShape, new_text: String).returns(Interface::TextEdit) }
140
+ sig { params(range: T::Hash[Symbol, T.untyped], new_text: String).returns(Interface::TextEdit) }
141
141
  def create_text_edit(range, new_text)
142
142
  Interface::TextEdit.new(
143
143
  range: Interface::Range.new(
@@ -22,7 +22,7 @@ module RubyLsp
22
22
  sig do
23
23
  params(
24
24
  document: Document,
25
- range: Document::RangeShape,
25
+ range: T::Hash[Symbol, T.untyped],
26
26
  context: T::Hash[Symbol, T.untyped],
27
27
  ).void
28
28
  end
@@ -38,14 +38,8 @@ module RubyLsp
38
38
  def run
39
39
  diagnostics = @context[:diagnostics]
40
40
 
41
- code_actions = diagnostics.filter_map do |diagnostic|
42
- code_action = diagnostic.dig(:data, :code_action)
43
- next if code_action.nil?
44
-
45
- # We want to return only code actions that are within range or that do not have any edits, such as refactor
46
- # code actions
47
- range = code_action.dig(:edit, :documentChanges, 0, :edits, 0, :range)
48
- code_action if diagnostic.dig(:data, :correctable) && cover?(range)
41
+ code_actions = diagnostics.flat_map do |diagnostic|
42
+ diagnostic.dig(:data, :code_actions) || []
49
43
  end
50
44
 
51
45
  # Only add refactor actions if there's a non empty selection in the editor
@@ -55,15 +49,7 @@ module RubyLsp
55
49
 
56
50
  private
57
51
 
58
- sig { params(range: T.nilable(Document::RangeShape)).returns(T::Boolean) }
59
- def cover?(range)
60
- range.nil? ||
61
- ((@range.dig(:start, :line))..(@range.dig(:end, :line))).cover?(
62
- (range.dig(:start, :line))..(range.dig(:end, :line)),
63
- )
64
- end
65
-
66
- sig { params(range: Document::RangeShape, uri: URI::Generic).returns(Interface::CodeAction) }
52
+ sig { params(range: T::Hash[Symbol, T.untyped], uri: URI::Generic).returns(Interface::CodeAction) }
67
53
  def refactor_code_action(range, uri)
68
54
  Interface::CodeAction.new(
69
55
  title: "Refactor: Extract Variable",
@@ -11,6 +11,10 @@ module RubyLsp
11
11
  # [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
12
12
  # request informs the editor of runnable commands such as tests
13
13
  #
14
+ # # Configuration
15
+ #
16
+ # To disable gem code lenses, set `rubyLsp.featuresConfiguration.codeLens.gemfileLinks` to `false`.
17
+ #
14
18
  # # Example
15
19
  #
16
20
  # ```ruby
@@ -47,8 +51,14 @@ module RubyLsp
47
51
  sig { override.returns(ResponseType) }
48
52
  attr_reader :_response
49
53
 
50
- sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher).void }
51
- def initialize(uri, dispatcher)
54
+ sig do
55
+ params(
56
+ uri: URI::Generic,
57
+ lenses_configuration: RequestConfig,
58
+ dispatcher: Prism::Dispatcher,
59
+ ).void
60
+ end
61
+ def initialize(uri, lenses_configuration, dispatcher)
52
62
  @uri = T.let(uri, URI::Generic)
53
63
  @_response = T.let([], ResponseType)
54
64
  @path = T.let(uri.to_standardized_path, T.nilable(String))
@@ -57,6 +67,7 @@ module RubyLsp
57
67
  @class_stack = T.let([], T::Array[String])
58
68
  @group_id = T.let(1, Integer)
59
69
  @group_id_stack = T.let([], T::Array[Integer])
70
+ @lenses_configuration = lenses_configuration
60
71
 
61
72
  super(dispatcher)
62
73
 
@@ -134,6 +145,8 @@ module RubyLsp
134
145
  end
135
146
 
136
147
  if @path&.include?(GEMFILE_NAME) && name == :gem && arguments
148
+ return unless @lenses_configuration.enabled?(:gemfileLinks)
149
+
137
150
  first_argument = arguments.arguments.first
138
151
  return unless first_argument.is_a?(Prism::StringNode)
139
152
 
@@ -154,13 +154,11 @@ module RubyLsp
154
154
  end
155
155
  def build_method_completion(entry, node)
156
156
  name = entry.name
157
- parameters = entry.parameters
158
- new_text = parameters.empty? ? name : "#{name}(#{parameters.map(&:name).join(", ")})"
159
157
 
160
158
  Interface::CompletionItem.new(
161
159
  label: name,
162
160
  filter_text: name,
163
- text_edit: Interface::TextEdit.new(range: range_from_node(node), new_text: new_text),
161
+ text_edit: Interface::TextEdit.new(range: range_from_node(node), new_text: name),
164
162
  kind: Constant::CompletionItemKind::METHOD,
165
163
  label_details: Interface::CompletionItemLabelDetails.new(
166
164
  description: entry.file_name,
@@ -9,6 +9,14 @@ module RubyLsp
9
9
  # are labels added directly in the code that explicitly show the user something that might
10
10
  # otherwise just be implied.
11
11
  #
12
+ # # Configuration
13
+ #
14
+ # To enable rescue hints, set `rubyLsp.featuresConfiguration.inlayHint.implicitRescue` to `true`.
15
+ #
16
+ # To enable hash value hints, set `rubyLsp.featuresConfiguration.inlayHint.implicitHashValue` to `true`.
17
+ #
18
+ # To enable all hints, set `rubyLsp.featuresConfiguration.inlayHint.enableAll` to `true`.
19
+ #
12
20
  # # Example
13
21
  #
14
22
  # ```ruby
@@ -39,18 +47,26 @@ module RubyLsp
39
47
  sig { override.returns(ResponseType) }
40
48
  attr_reader :_response
41
49
 
42
- sig { params(range: T::Range[Integer], dispatcher: Prism::Dispatcher).void }
43
- def initialize(range, dispatcher)
50
+ sig do
51
+ params(
52
+ range: T::Range[Integer],
53
+ hints_configuration: RequestConfig,
54
+ dispatcher: Prism::Dispatcher,
55
+ ).void
56
+ end
57
+ def initialize(range, hints_configuration, dispatcher)
44
58
  super(dispatcher)
45
59
 
46
60
  @_response = T.let([], ResponseType)
47
61
  @range = range
62
+ @hints_configuration = hints_configuration
48
63
 
49
64
  dispatcher.register(self, :on_rescue_node_enter, :on_implicit_node_enter)
50
65
  end
51
66
 
52
67
  sig { params(node: Prism::RescueNode).void }
53
68
  def on_rescue_node_enter(node)
69
+ return unless @hints_configuration.enabled?(:implicitRescue)
54
70
  return unless node.exceptions.empty?
55
71
 
56
72
  loc = node.location
@@ -66,6 +82,7 @@ module RubyLsp
66
82
 
67
83
  sig { params(node: Prism::ImplicitNode).void }
68
84
  def on_implicit_node_enter(node)
85
+ return unless @hints_configuration.enabled?(:implicitHashValue)
69
86
  return unless visible?(node, @range)
70
87
 
71
88
  node_value = node.value
@@ -26,7 +26,7 @@ module RubyLsp
26
26
  T::Array[Regexp],
27
27
  )
28
28
 
29
- sig { params(document: Document, position: Document::PositionShape, trigger_character: String).void }
29
+ sig { params(document: Document, position: T::Hash[Symbol, T.untyped], trigger_character: String).void }
30
30
  def initialize(document, position, trigger_character)
31
31
  super(document)
32
32
 
@@ -60,6 +60,8 @@ module RubyLsp
60
60
  handle_statement_end
61
61
  end
62
62
  end
63
+ when "d"
64
+ auto_indent_after_end_keyword
63
65
  end
64
66
 
65
67
  @edits
@@ -118,7 +120,7 @@ module RubyLsp
118
120
  current_line = @lines[@position[:line]]
119
121
  next_line = @lines[@position[:line] + 1]
120
122
 
121
- if current_line.nil? || current_line.strip.empty?
123
+ if current_line.nil? || current_line.strip.empty? || current_line.include?(")") || current_line.include?("]")
122
124
  add_edit_with_text("\n")
123
125
  add_edit_with_text("#{indents}end")
124
126
  move_cursor_to(@position[:line], @indentation + 2)
@@ -141,7 +143,7 @@ module RubyLsp
141
143
  add_edit_with_text("##{spaces}")
142
144
  end
143
145
 
144
- sig { params(text: String, position: Document::PositionShape).void }
146
+ sig { params(text: String, position: T::Hash[Symbol, T.untyped]).void }
145
147
  def add_edit_with_text(text, position = @position)
146
148
  pos = Interface::Position.new(
147
149
  line: position[:line],
@@ -185,6 +187,32 @@ module RubyLsp
185
187
 
186
188
  count
187
189
  end
190
+
191
+ sig { void }
192
+ def auto_indent_after_end_keyword
193
+ current_line = @lines[@position[:line]]
194
+ return unless current_line&.strip == "end"
195
+
196
+ target, _parent, _nesting = @document.locate_node({
197
+ line: @position[:line],
198
+ character: @position[:character] - 1,
199
+ })
200
+
201
+ statements = case target
202
+ when Prism::IfNode, Prism::UnlessNode, Prism::ForNode, Prism::WhileNode, Prism::UntilNode
203
+ target.statements
204
+ end
205
+ return unless statements
206
+
207
+ statements.body.each do |node|
208
+ loc = node.location
209
+ next unless loc.start_column == @indentation
210
+
211
+ add_edit_with_text(" ", { line: loc.start_line - 1, character: 0 })
212
+ end
213
+
214
+ move_cursor_to(@position[:line], @position[:character])
215
+ end
188
216
  end
189
217
  end
190
218
  end
@@ -20,7 +20,7 @@ module RubyLsp
20
20
  class ShowSyntaxTree < BaseRequest
21
21
  extend T::Sig
22
22
 
23
- sig { params(document: Document, range: T.nilable(Document::RangeShape)).void }
23
+ sig { params(document: Document, range: T.nilable(T::Hash[Symbol, T.untyped])).void }
24
24
  def initialize(document, range)
25
25
  super(document)
26
26
 
@@ -0,0 +1,95 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # ![Signature help demo](../../signature_help.gif)
7
+ #
8
+ # The [signature help
9
+ # request](https://microsoft.github.io/language-server-protocol/specification#textDocument_signatureHelp) displays
10
+ # information about the parameters of a method as you type an invocation.
11
+ #
12
+ # Currently only supports methods invoked directly on `self` without taking inheritance into account.
13
+ #
14
+ # # Example
15
+ #
16
+ # ```ruby
17
+ # class Foo
18
+ # def bar(a, b, c)
19
+ # end
20
+ #
21
+ # def baz
22
+ # bar( # -> Signature help will show the parameters of `bar`
23
+ # end
24
+ # ```
25
+ class SignatureHelp < Listener
26
+ extend T::Sig
27
+ extend T::Generic
28
+
29
+ ResponseType = type_member { { fixed: T.nilable(T.any(Interface::SignatureHelp, T::Hash[Symbol, T.untyped])) } }
30
+
31
+ sig { override.returns(ResponseType) }
32
+ attr_reader :_response
33
+
34
+ sig do
35
+ params(
36
+ context: T::Hash[Symbol, T.untyped],
37
+ nesting: T::Array[String],
38
+ index: RubyIndexer::Index,
39
+ dispatcher: Prism::Dispatcher,
40
+ ).void
41
+ end
42
+ def initialize(context, nesting, index, dispatcher)
43
+ @context = context
44
+ @nesting = nesting
45
+ @index = index
46
+ @_response = T.let(nil, ResponseType)
47
+
48
+ super(dispatcher)
49
+ dispatcher.register(self, :on_call_node_enter)
50
+ end
51
+
52
+ sig { params(node: Prism::CallNode).void }
53
+ def on_call_node_enter(node)
54
+ return if DependencyDetector.instance.typechecker
55
+ return unless self_receiver?(node)
56
+
57
+ message = node.message
58
+ return unless message
59
+
60
+ target_method = @index.resolve_method(message, @nesting.join("::"))
61
+ return unless target_method
62
+
63
+ parameters = target_method.parameters
64
+ name = target_method.name
65
+
66
+ # If the method doesn't have any parameters, there's no need to show signature help
67
+ return if parameters.empty?
68
+
69
+ label = "#{name}(#{parameters.map(&:decorated_name).join(", ")})"
70
+
71
+ arguments_node = node.arguments
72
+ arguments = arguments_node&.arguments || []
73
+ active_parameter = (arguments.length - 1).clamp(0, parameters.length - 1)
74
+
75
+ # If there are arguments, then we need to check if there's a trailing comma after the end of the last argument
76
+ # to advance the active parameter to the next one
77
+ if arguments_node &&
78
+ node.slice.byteslice(arguments_node.location.end_offset - node.location.start_offset) == ","
79
+ active_parameter += 1
80
+ end
81
+
82
+ @_response = Interface::SignatureHelp.new(
83
+ signatures: [
84
+ Interface::SignatureInformation.new(
85
+ label: label,
86
+ parameters: parameters.map { |param| Interface::ParameterInformation.new(label: param.name) },
87
+ documentation: markdown_from_index_entries("", target_method),
88
+ ),
89
+ ],
90
+ active_parameter: active_parameter,
91
+ )
92
+ end
93
+ end
94
+ end
95
+ end
@@ -19,30 +19,23 @@ module RubyLsp
19
19
  T::Hash[Symbol, Integer],
20
20
  )
21
21
 
22
- sig { params(offense: RuboCop::Cop::Offense, uri: URI::Generic).void }
23
- def initialize(offense, uri)
22
+ # TODO: avoid passing document once we have alternative ways to get at
23
+ # encoding and file source
24
+ sig { params(document: Document, offense: RuboCop::Cop::Offense, uri: URI::Generic).void }
25
+ def initialize(document, offense, uri)
26
+ @document = document
24
27
  @offense = offense
25
28
  @uri = uri
26
29
  end
27
30
 
28
- sig { returns(Interface::CodeAction) }
29
- def to_lsp_code_action
30
- Interface::CodeAction.new(
31
- title: "Autocorrect #{@offense.cop_name}",
32
- kind: Constant::CodeActionKind::QUICK_FIX,
33
- edit: Interface::WorkspaceEdit.new(
34
- document_changes: [
35
- Interface::TextDocumentEdit.new(
36
- text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
37
- uri: @uri.to_s,
38
- version: nil,
39
- ),
40
- edits: @offense.correctable? ? offense_replacements : [],
41
- ),
42
- ],
43
- ),
44
- is_preferred: true,
45
- )
31
+ sig { returns(T::Array[Interface::CodeAction]) }
32
+ def to_lsp_code_actions
33
+ code_actions = []
34
+
35
+ code_actions << autocorrect_action if @offense.correctable?
36
+ code_actions << disable_line_action
37
+
38
+ code_actions
46
39
  end
47
40
 
48
41
  sig { returns(Interface::Diagnostic) }
@@ -65,7 +58,7 @@ module RubyLsp
65
58
  ),
66
59
  data: {
67
60
  correctable: @offense.correctable?,
68
- code_action: to_lsp_code_action,
61
+ code_actions: to_lsp_code_actions,
69
62
  },
70
63
  )
71
64
  end
@@ -90,6 +83,26 @@ module RubyLsp
90
83
  Interface::CodeDescription.new(href: doc_url) if doc_url
91
84
  end
92
85
 
86
+ sig { returns(Interface::CodeAction) }
87
+ def autocorrect_action
88
+ Interface::CodeAction.new(
89
+ title: "Autocorrect #{@offense.cop_name}",
90
+ kind: Constant::CodeActionKind::QUICK_FIX,
91
+ edit: Interface::WorkspaceEdit.new(
92
+ document_changes: [
93
+ Interface::TextDocumentEdit.new(
94
+ text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
95
+ uri: @uri.to_s,
96
+ version: nil,
97
+ ),
98
+ edits: @offense.correctable? ? offense_replacements : [],
99
+ ),
100
+ ],
101
+ ),
102
+ is_preferred: true,
103
+ )
104
+ end
105
+
93
106
  sig { returns(T::Array[Interface::TextEdit]) }
94
107
  def offense_replacements
95
108
  @offense.corrector.as_replacements.map do |range, replacement|
@@ -102,6 +115,64 @@ module RubyLsp
102
115
  )
103
116
  end
104
117
  end
118
+
119
+ sig { returns(Interface::CodeAction) }
120
+ def disable_line_action
121
+ Interface::CodeAction.new(
122
+ title: "Disable #{@offense.cop_name} for this line",
123
+ kind: Constant::CodeActionKind::QUICK_FIX,
124
+ edit: Interface::WorkspaceEdit.new(
125
+ document_changes: [
126
+ Interface::TextDocumentEdit.new(
127
+ text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
128
+ uri: @uri.to_s,
129
+ version: nil,
130
+ ),
131
+ edits: line_disable_comment,
132
+ ),
133
+ ],
134
+ ),
135
+ )
136
+ end
137
+
138
+ sig { returns(T::Array[Interface::TextEdit]) }
139
+ def line_disable_comment
140
+ new_text = if @offense.source_line.include?(" # rubocop:disable ")
141
+ ",#{@offense.cop_name}"
142
+ else
143
+ " # rubocop:disable #{@offense.cop_name}"
144
+ end
145
+
146
+ eol = Interface::Position.new(
147
+ line: @offense.line - 1,
148
+ character: length_of_line(@offense.source_line),
149
+ )
150
+
151
+ # TODO: fails for multiline strings - may be preferable to use block
152
+ # comments to disable some offenses
153
+ inline_comment = Interface::TextEdit.new(
154
+ range: Interface::Range.new(start: eol, end: eol),
155
+ new_text: new_text,
156
+ )
157
+
158
+ [inline_comment]
159
+ end
160
+
161
+ sig { params(line: String).returns(Integer) }
162
+ def length_of_line(line)
163
+ if @document.encoding == Constant::PositionEncodingKind::UTF16
164
+ line_length = 0
165
+ line.codepoints.each do |codepoint|
166
+ line_length += 1
167
+ if codepoint > RubyLsp::Document::Scanner::SURROGATE_PAIR_START
168
+ line_length += 1
169
+ end
170
+ end
171
+ line_length
172
+ else
173
+ line.length
174
+ end
175
+ end
105
176
  end
106
177
  end
107
178
  end
@@ -25,7 +25,7 @@ module RubyLsp
25
25
  @runner.run(filename, document.source)
26
26
 
27
27
  @runner.offenses.map do |offense|
28
- Support::RuboCopDiagnostic.new(offense, uri)
28
+ Support::RuboCopDiagnostic.new(document, offense, uri)
29
29
  end
30
30
  end
31
31
  end
@@ -7,7 +7,7 @@ module RubyLsp
7
7
  class SelectionRange < Interface::SelectionRange
8
8
  extend T::Sig
9
9
 
10
- sig { params(position: Document::PositionShape).returns(T::Boolean) }
10
+ sig { params(position: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
11
11
  def cover?(position)
12
12
  start_covered = range.start.line < position[:line] ||
13
13
  (range.start.line == position[:line] && range.start.character <= position[:character])
@@ -22,6 +22,7 @@ module RubyLsp
22
22
  # - [Definition](rdoc-ref:RubyLsp::Requests::Definition)
23
23
  # - [ShowSyntaxTree](rdoc-ref:RubyLsp::Requests::ShowSyntaxTree)
24
24
  # - [WorkspaceSymbol](rdoc-ref:RubyLsp::Requests::WorkspaceSymbol)
25
+ # - [SignatureHelp](rdoc-ref:RubyLsp::Requests::SignatureHelp)
25
26
 
26
27
  module Requests
27
28
  autoload :BaseRequest, "ruby_lsp/requests/base_request"
@@ -43,6 +44,7 @@ module RubyLsp
43
44
  autoload :Definition, "ruby_lsp/requests/definition"
44
45
  autoload :ShowSyntaxTree, "ruby_lsp/requests/show_syntax_tree"
45
46
  autoload :WorkspaceSymbol, "ruby_lsp/requests/workspace_symbol"
47
+ autoload :SignatureHelp, "ruby_lsp/requests/signature_help"
46
48
 
47
49
  # :nodoc:
48
50
  module Support
@@ -20,6 +20,9 @@ module RubyLsp
20
20
  sig { returns(URI::Generic) }
21
21
  attr_accessor :workspace_uri
22
22
 
23
+ sig { returns(T::Hash[Symbol, RequestConfig]) }
24
+ attr_accessor :features_configuration
25
+
23
26
  sig { void }
24
27
  def initialize
25
28
  @state = T.let({}, T::Hash[String, Document])
@@ -28,6 +31,20 @@ module RubyLsp
28
31
  @supports_progress = T.let(true, T::Boolean)
29
32
  @experimental_features = T.let(false, T::Boolean)
30
33
  @workspace_uri = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
34
+ @features_configuration = T.let(
35
+ {
36
+ codeLens: RequestConfig.new({
37
+ enableAll: false,
38
+ gemfileLinks: true,
39
+ }),
40
+ inlayHint: RequestConfig.new({
41
+ enableAll: false,
42
+ implicitRescue: false,
43
+ implicitHashValue: false,
44
+ }),
45
+ },
46
+ T::Hash[Symbol, RequestConfig],
47
+ )
31
48
  end
32
49
 
33
50
  sig { params(uri: URI::Generic).returns(Document) }
@@ -46,7 +63,7 @@ module RubyLsp
46
63
  @state[uri.to_s] = document
47
64
  end
48
65
 
49
- sig { params(uri: URI::Generic, edits: T::Array[Document::EditShape], version: Integer).void }
66
+ sig { params(uri: URI::Generic, edits: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).void }
50
67
  def push_edits(uri:, edits:, version:)
51
68
  T.must(@state[uri.to_s]).push_edits(edits, version: version)
52
69
  end
@@ -74,4 +74,22 @@ module RubyLsp
74
74
  @cancelled = true
75
75
  end
76
76
  end
77
+
78
+ # A request configuration, to turn on/off features
79
+ class RequestConfig
80
+ extend T::Sig
81
+
82
+ sig { returns(T::Hash[Symbol, T::Boolean]) }
83
+ attr_accessor :configuration
84
+
85
+ sig { params(configuration: T::Hash[Symbol, T::Boolean]).void }
86
+ def initialize(configuration)
87
+ @configuration = configuration
88
+ end
89
+
90
+ sig { params(feature: Symbol).returns(T.nilable(T::Boolean)) }
91
+ def enabled?(feature)
92
+ @configuration[:enableAll] || @configuration[feature]
93
+ end
94
+ end
77
95
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-30 00:00:00.000000000 Z
11
+ date: 2023-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: language_server-protocol
@@ -30,20 +30,20 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.18.0
33
+ version: 0.19.0
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '0.19'
36
+ version: '0.20'
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.18.0
43
+ version: 0.19.0
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.19'
46
+ version: '0.20'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sorbet-runtime
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -118,6 +118,7 @@ files:
118
118
  - lib/ruby_lsp/requests/selection_ranges.rb
119
119
  - lib/ruby_lsp/requests/semantic_highlighting.rb
120
120
  - lib/ruby_lsp/requests/show_syntax_tree.rb
121
+ - lib/ruby_lsp/requests/signature_help.rb
121
122
  - lib/ruby_lsp/requests/support/annotation.rb
122
123
  - lib/ruby_lsp/requests/support/common.rb
123
124
  - lib/ruby_lsp/requests/support/dependency_detector.rb
@@ -157,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
158
  - !ruby/object:Gem::Version
158
159
  version: '0'
159
160
  requirements: []
160
- rubygems_version: 3.4.21
161
+ rubygems_version: 3.4.22
161
162
  signing_key:
162
163
  specification_version: 4
163
164
  summary: An opinionated language server for Ruby