ruby-lsp 0.12.5 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cb6c373890a19400025a75be13971ff5e5e33772bd74a178784a035ba94c168
4
- data.tar.gz: d52ad65673ea9f1dfde13cfa6beec0f8c860a75b7f08453238597d584227b56f
3
+ metadata.gz: d6bace664e1540c1333df9dabfb2e7bdd8bda0f910033b47b188e4a82ddacb15
4
+ data.tar.gz: be9e5da0492b26b5cb6e07074d01d7874104b70286c1578342b9639158fed147
5
5
  SHA512:
6
- metadata.gz: ba64686636c26776797fc6e7e70156f4c7f304dbe27e98c73c2a60a7255ae7260159838d68c0364e98bc58d26c404118ad9e3d1cfe13766a2221cbc4d2ac6a7c
7
- data.tar.gz: fcf587173133668739ddc639d913ce34877cc1c0d3451b2ddc49254940ef8ba49815cae57dce2c6de423d3d3fb0db1059f1b8d2d19cd9d1de3af72fb26819759
6
+ metadata.gz: 7d8e61433686271a68dafe8db79765ed509a115ab6f06060d7669d279f48218fe2eada2c12e3b45f155d27a41774771681cdab92700d27f426e75ed89287ca03
7
+ data.tar.gz: 611c050b751050934d0fd93e9e52089fe63fc4d947be75a440dfa0465933814d2682268a10135d036c2cee83fa739156d2b11e42e679ecbed7de62acfee9d621
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.12.5
1
+ 0.13.0
data/exe/ruby-lsp-check CHANGED
@@ -17,8 +17,6 @@ end
17
17
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
18
18
  require "ruby_lsp/internal"
19
19
 
20
- RubyLsp::Addon.load_addons
21
-
22
20
  T::Utils.run_all_sig_blocks
23
21
 
24
22
  files = Dir.glob("#{Dir.pwd}/**/*.rb")
@@ -28,6 +26,7 @@ puts "Verifying that all automatic LSP requests execute successfully. This may t
28
26
  errors = {}
29
27
  store = RubyLsp::Store.new
30
28
  message_queue = Thread::Queue.new
29
+ RubyLsp::Addon.load_addons(message_queue)
31
30
  executor = RubyLsp::Executor.new(store, message_queue)
32
31
 
33
32
  files.each_with_index do |file, index|
@@ -50,13 +49,30 @@ end
50
49
  puts "\n"
51
50
  message_queue.close
52
51
 
52
+ # Indexing
53
+ puts "Verifying that indexing executes successfully. This may take a while..."
54
+
55
+ index = RubyIndexer::Index.new
56
+ indexables = RubyIndexer.configuration.indexables
57
+
58
+ indexables.each_with_index do |indexable, i|
59
+ result = Prism.parse(File.read(indexable.full_path))
60
+ collector = RubyIndexer::Collector.new(index, result, indexable.full_path)
61
+ collector.collect(result.value)
62
+ rescue => e
63
+ errors[indexable.full_path] = e
64
+ ensure
65
+ print("\033[M\033[0KIndexed #{i + 1}/#{indexables.length}") unless ENV["CI"]
66
+ end
67
+ puts "\n"
68
+
53
69
  if errors.empty?
54
- puts "All automatic LSP requests executed successfully"
70
+ puts "All operations completed successfully!"
55
71
  exit
56
72
  end
57
73
 
58
74
  puts <<~ERRORS
59
- Errors while executing requests:
75
+ Errors while executing:
60
76
 
61
77
  #{errors.map { |file, error| "#{file}: #{error.message}" }.join("\n")}
62
78
  ERRORS
@@ -141,8 +141,18 @@ module RubyIndexer
141
141
 
142
142
  sig { params(node: Prism::CallNode).void }
143
143
  def handle_call_node(node)
144
- message = node.message
145
- handle_private_constant(node) if message == "private_constant"
144
+ message = node.name
145
+
146
+ case message
147
+ when :private_constant
148
+ handle_private_constant(node)
149
+ when :attr_reader
150
+ handle_attribute(node, reader: true, writer: false)
151
+ when :attr_writer
152
+ handle_attribute(node, reader: false, writer: true)
153
+ when :attr_accessor
154
+ handle_attribute(node, reader: true, writer: true)
155
+ end
146
156
  end
147
157
 
148
158
  sig { params(node: Prism::DefNode).void }
@@ -312,5 +322,29 @@ module RubyIndexer
312
322
  "#{@stack.join("::")}::#{name}"
313
323
  end.delete_prefix("::")
314
324
  end
325
+
326
+ sig { params(node: Prism::CallNode, reader: T::Boolean, writer: T::Boolean).void }
327
+ def handle_attribute(node, reader:, writer:)
328
+ arguments = node.arguments&.arguments
329
+ return unless arguments
330
+
331
+ receiver = node.receiver
332
+ return unless receiver.nil? || receiver.is_a?(Prism::SelfNode)
333
+
334
+ comments = collect_comments(node)
335
+ arguments.each do |argument|
336
+ name, loc = case argument
337
+ when Prism::SymbolNode
338
+ [argument.value, argument.value_loc]
339
+ when Prism::StringNode
340
+ [argument.content, argument.content_loc]
341
+ end
342
+
343
+ next unless name && loc
344
+
345
+ @index << Entry::Accessor.new(name, @file_path, loc, comments, @current_owner) if reader
346
+ @index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @current_owner) if writer
347
+ end
348
+ end
315
349
  end
316
350
  end
@@ -120,7 +120,7 @@ module RubyIndexer
120
120
  IndexablePath.new(RbConfig::CONFIG["rubylibdir"], path)
121
121
  end,
122
122
  )
123
- else
123
+ elsif pathname.extname == ".rb"
124
124
  # If the default_path is a Ruby file, we index it
125
125
  indexables << IndexablePath.new(RbConfig::CONFIG["rubylibdir"], default_path)
126
126
  end
@@ -90,20 +90,69 @@ module RubyIndexer
90
90
  end
91
91
  end
92
92
 
93
+ # A required method parameter, e.g. `def foo(a)`
93
94
  class RequiredParameter < Parameter
94
95
  end
95
96
 
96
- class Method < Entry
97
+ # An optional method parameter, e.g. `def foo(a = 123)`
98
+ class OptionalParameter < Parameter
99
+ end
100
+
101
+ # An required keyword method parameter, e.g. `def foo(a:)`
102
+ class KeywordParameter < Parameter
103
+ end
104
+
105
+ # An optional keyword method parameter, e.g. `def foo(a: 123)`
106
+ class OptionalKeywordParameter < Parameter
107
+ end
108
+
109
+ class Member < Entry
97
110
  extend T::Sig
98
111
  extend T::Helpers
99
- abstract!
100
112
 
101
- sig { returns(T::Array[Parameter]) }
102
- attr_reader :parameters
113
+ abstract!
103
114
 
104
115
  sig { returns(T.nilable(Entry::Namespace)) }
105
116
  attr_reader :owner
106
117
 
118
+ sig do
119
+ params(
120
+ name: String,
121
+ file_path: String,
122
+ location: Prism::Location,
123
+ comments: T::Array[String],
124
+ owner: T.nilable(Entry::Namespace),
125
+ ).void
126
+ end
127
+ def initialize(name, file_path, location, comments, owner)
128
+ super(name, file_path, location, comments)
129
+ @owner = owner
130
+ end
131
+
132
+ sig { abstract.returns(T::Array[Parameter]) }
133
+ def parameters; end
134
+ end
135
+
136
+ class Accessor < Member
137
+ extend T::Sig
138
+
139
+ sig { override.returns(T::Array[Parameter]) }
140
+ def parameters
141
+ params = []
142
+ params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
143
+ params
144
+ end
145
+ end
146
+
147
+ class Method < Member
148
+ extend T::Sig
149
+ extend T::Helpers
150
+
151
+ abstract!
152
+
153
+ sig { override.returns(T::Array[Parameter]) }
154
+ attr_reader :parameters
155
+
107
156
  sig do
108
157
  params(
109
158
  name: String,
@@ -115,9 +164,9 @@ module RubyIndexer
115
164
  ).void
116
165
  end
117
166
  def initialize(name, file_path, location, comments, parameters_node, owner) # rubocop:disable Metrics/ParameterLists
118
- super(name, file_path, location, comments)
167
+ super(name, file_path, location, comments, owner)
168
+
119
169
  @parameters = T.let(list_params(parameters_node), T::Array[Parameter])
120
- @owner = owner
121
170
  end
122
171
 
123
172
  private
@@ -126,20 +175,42 @@ module RubyIndexer
126
175
  def list_params(parameters_node)
127
176
  return [] unless parameters_node
128
177
 
129
- parameters_node.requireds.filter_map do |required|
178
+ parameters = []
179
+
180
+ parameters_node.requireds.each do |required|
130
181
  name = parameter_name(required)
131
182
  next unless name
132
183
 
133
- RequiredParameter.new(name: name)
184
+ parameters << RequiredParameter.new(name: name)
134
185
  end
135
- end
136
186
 
137
- sig do
138
- params(node: Prism::Node).returns(T.nilable(Symbol))
187
+ parameters_node.optionals.each do |optional|
188
+ name = parameter_name(optional)
189
+ next unless name
190
+
191
+ parameters << OptionalParameter.new(name: name)
192
+ end
193
+
194
+ parameters_node.keywords.each do |keyword|
195
+ name = parameter_name(keyword)
196
+ next unless name
197
+
198
+ case keyword
199
+ when Prism::RequiredKeywordParameterNode
200
+ parameters << KeywordParameter.new(name: name)
201
+ when Prism::OptionalKeywordParameterNode
202
+ parameters << OptionalKeywordParameter.new(name: name)
203
+ end
204
+ end
205
+
206
+ parameters
139
207
  end
208
+
209
+ sig { params(node: Prism::Node).returns(T.nilable(Symbol)) }
140
210
  def parameter_name(node)
141
211
  case node
142
- when Prism::RequiredParameterNode
212
+ when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
213
+ Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode
143
214
  node.name
144
215
  when Prism::MultiTargetNode
145
216
  names = [*node.lefts, *node.rest, *node.rights].map { |parameter_node| parameter_name(parameter_node) }
@@ -84,6 +84,16 @@ module RubyIndexer
84
84
  )
85
85
  end
86
86
 
87
+ def test_indexables_does_not_include_non_ruby_files_inside_rubylibdir
88
+ path = Pathname.new(RbConfig::CONFIG["rubylibdir"]).join("extra_file.txt").to_s
89
+ FileUtils.touch(path)
90
+ indexables = @config.indexables
91
+
92
+ assert(indexables.none? { |indexable| indexable.full_path == path })
93
+ ensure
94
+ FileUtils.rm(T.must(path))
95
+ end
96
+
87
97
  def test_paths_are_unique
88
98
  @config.load_config
89
99
  indexables = @config.indexables
@@ -246,5 +246,16 @@ module RubyIndexer
246
246
  entry = T.must(entries.first).first
247
247
  assert_equal("baz", entry.name)
248
248
  end
249
+
250
+ def test_indexing_prism_fixtures_succeeds
251
+ fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
252
+
253
+ fixtures.each do |fixture|
254
+ indexable_path = IndexablePath.new("", fixture)
255
+ @index.index_single(indexable_path)
256
+ end
257
+
258
+ refute_empty(@index.instance_variable_get(:@entries))
259
+ end
249
260
  end
250
261
  end
@@ -70,6 +70,42 @@ module RubyIndexer
70
70
  assert_instance_of(Entry::RequiredParameter, parameter)
71
71
  end
72
72
 
73
+ def test_method_with_optional_parameters
74
+ index(<<~RUBY)
75
+ class Foo
76
+ def bar(a = 123)
77
+ end
78
+ end
79
+ RUBY
80
+
81
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
82
+ entry = T.must(@index["bar"].first)
83
+ assert_equal(1, entry.parameters.length)
84
+ parameter = entry.parameters.first
85
+ assert_equal(:a, parameter.name)
86
+ assert_instance_of(Entry::OptionalParameter, parameter)
87
+ end
88
+
89
+ def test_method_with_keyword_parameters
90
+ index(<<~RUBY)
91
+ class Foo
92
+ def bar(a:, b: 123)
93
+ end
94
+ end
95
+ RUBY
96
+
97
+ assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
98
+ entry = T.must(@index["bar"].first)
99
+ assert_equal(2, entry.parameters.length)
100
+ a, b = entry.parameters
101
+
102
+ assert_equal(:a, a.name)
103
+ assert_instance_of(Entry::KeywordParameter, a)
104
+
105
+ assert_equal(:b, b.name)
106
+ assert_instance_of(Entry::OptionalKeywordParameter, b)
107
+ end
108
+
73
109
  def test_keeps_track_of_method_owner
74
110
  index(<<~RUBY)
75
111
  class Foo
@@ -83,5 +119,35 @@ module RubyIndexer
83
119
 
84
120
  assert_equal("Foo", owner_name)
85
121
  end
122
+
123
+ def test_keeps_track_of_attributes
124
+ index(<<~RUBY)
125
+ class Foo
126
+ # Hello there
127
+ attr_reader :bar, :other
128
+ attr_writer :baz
129
+ attr_accessor :qux
130
+ end
131
+ RUBY
132
+
133
+ assert_entry("bar", Entry::Accessor, "/fake/path/foo.rb:2-15:2-18")
134
+ assert_equal("Hello there", @index["bar"].first.comments.join("\n"))
135
+ assert_entry("other", Entry::Accessor, "/fake/path/foo.rb:2-21:2-26")
136
+ assert_equal("Hello there", @index["other"].first.comments.join("\n"))
137
+ assert_entry("baz=", Entry::Accessor, "/fake/path/foo.rb:3-15:3-18")
138
+ assert_entry("qux", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
139
+ assert_entry("qux=", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
140
+ end
141
+
142
+ def test_ignores_attributes_invoked_on_constant
143
+ index(<<~RUBY)
144
+ class Foo
145
+ end
146
+
147
+ Foo.attr_reader :bar
148
+ RUBY
149
+
150
+ assert_no_entry("bar")
151
+ end
86
152
  end
87
153
  end
@@ -41,8 +41,8 @@ module RubyLsp
41
41
  end
42
42
 
43
43
  # Discovers and loads all addons. Returns the list of activated addons
44
- sig { returns(T::Array[Addon]) }
45
- def load_addons
44
+ sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
45
+ def load_addons(message_queue)
46
46
  # Require all addons entry points, which should be placed under
47
47
  # `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
48
48
  Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
@@ -55,7 +55,7 @@ module RubyLsp
55
55
  # Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
56
56
  # fail to boot the server
57
57
  addons.each do |addon|
58
- addon.activate
58
+ addon.activate(message_queue)
59
59
  nil
60
60
  rescue => e
61
61
  addon.add_error(e)
@@ -94,8 +94,8 @@ module RubyLsp
94
94
 
95
95
  # Each addon should implement `MyAddon#activate` and use to perform any sort of initialization, such as
96
96
  # reading information into memory or even spawning a separate process
97
- sig { abstract.void }
98
- def activate; end
97
+ sig { abstract.params(message_queue: Thread::Queue).void }
98
+ def activate(message_queue); end
99
99
 
100
100
  # Each addon should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
101
101
  # child process
@@ -111,10 +111,9 @@ module RubyLsp
111
111
  overridable.params(
112
112
  uri: URI::Generic,
113
113
  dispatcher: Prism::Dispatcher,
114
- message_queue: Thread::Queue,
115
114
  ).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
116
115
  end
117
- def create_code_lens_listener(uri, dispatcher, message_queue); end
116
+ def create_code_lens_listener(uri, dispatcher); end
118
117
 
119
118
  # Creates a new Hover listener. This method is invoked on every Hover request
120
119
  sig do
@@ -122,19 +121,17 @@ module RubyLsp
122
121
  nesting: T::Array[String],
123
122
  index: RubyIndexer::Index,
124
123
  dispatcher: Prism::Dispatcher,
125
- message_queue: Thread::Queue,
126
124
  ).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
127
125
  end
128
- def create_hover_listener(nesting, index, dispatcher, message_queue); end
126
+ def create_hover_listener(nesting, index, dispatcher); end
129
127
 
130
128
  # Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
131
129
  sig do
132
130
  overridable.params(
133
131
  dispatcher: Prism::Dispatcher,
134
- message_queue: Thread::Queue,
135
132
  ).returns(T.nilable(Listener[T::Array[Interface::DocumentSymbol]]))
136
133
  end
137
- def create_document_symbol_listener(dispatcher, message_queue); end
134
+ def create_document_symbol_listener(dispatcher); end
138
135
 
139
136
  # Creates a new Definition listener. This method is invoked on every Definition request
140
137
  sig do
@@ -143,9 +140,8 @@ module RubyLsp
143
140
  nesting: T::Array[String],
144
141
  index: RubyIndexer::Index,
145
142
  dispatcher: Prism::Dispatcher,
146
- message_queue: Thread::Queue,
147
143
  ).returns(T.nilable(Listener[T.nilable(T.any(T::Array[Interface::Location], Interface::Location))]))
148
144
  end
149
- def create_definition_listener(uri, nesting, index, dispatcher, message_queue); end
145
+ def create_definition_listener(uri, nesting, index, dispatcher); end
150
146
  end
151
147
  end
@@ -41,7 +41,7 @@ module RubyLsp
41
41
  when "initialize"
42
42
  initialize_request(request.dig(:params))
43
43
  when "initialized"
44
- Addon.load_addons
44
+ Addon.load_addons(@message_queue)
45
45
 
46
46
  errored_addons = Addon.addons.select(&:error?)
47
47
 
@@ -95,12 +95,12 @@ module RubyLsp
95
95
 
96
96
  # Run listeners for the document
97
97
  dispatcher = Prism::Dispatcher.new
98
- folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher, @message_queue)
99
- document_symbol = Requests::DocumentSymbol.new(dispatcher, @message_queue)
100
- document_link = Requests::DocumentLink.new(uri, document.comments, dispatcher, @message_queue)
101
- code_lens = Requests::CodeLens.new(uri, dispatcher, @message_queue)
98
+ folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher)
99
+ document_symbol = Requests::DocumentSymbol.new(dispatcher)
100
+ document_link = Requests::DocumentLink.new(uri, document.comments, dispatcher)
101
+ code_lens = Requests::CodeLens.new(uri, dispatcher)
102
102
 
103
- semantic_highlighting = Requests::SemanticHighlighting.new(dispatcher, @message_queue)
103
+ semantic_highlighting = Requests::SemanticHighlighting.new(dispatcher)
104
104
  dispatcher.dispatch(document.tree)
105
105
 
106
106
  # Store all responses retrieve in this round of visits in the cache and then return the response for the request
@@ -265,13 +265,7 @@ module RubyLsp
265
265
  target = parent if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
266
266
 
267
267
  dispatcher = Prism::Dispatcher.new
268
- base_listener = Requests::Definition.new(
269
- uri,
270
- nesting,
271
- @index,
272
- dispatcher,
273
- @message_queue,
274
- )
268
+ base_listener = Requests::Definition.new(uri, nesting, @index, dispatcher)
275
269
  dispatcher.dispatch_once(target)
276
270
  base_listener.response
277
271
  end
@@ -297,7 +291,7 @@ module RubyLsp
297
291
 
298
292
  # Instantiate all listeners
299
293
  dispatcher = Prism::Dispatcher.new
300
- hover = Requests::Hover.new(@index, nesting, dispatcher, @message_queue)
294
+ hover = Requests::Hover.new(@index, nesting, dispatcher)
301
295
 
302
296
  # Emit events for all listeners
303
297
  dispatcher.dispatch_once(target)
@@ -355,6 +349,11 @@ module RubyLsp
355
349
  # If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
356
350
  return if @store.formatter == "none"
357
351
 
352
+ # Do not format files outside of the workspace. For example, if someone is looking at a gem's source code, we
353
+ # don't want to format it
354
+ path = uri.to_standardized_path
355
+ return unless path.nil? || path.start_with?(T.must(@store.workspace_uri.to_standardized_path))
356
+
358
357
  Requests::Formatting.new(@store.get(uri), formatter: @store.formatter).run
359
358
  end
360
359
 
@@ -380,7 +379,7 @@ module RubyLsp
380
379
 
381
380
  target, parent = document.locate_node(position)
382
381
  dispatcher = Prism::Dispatcher.new
383
- listener = Requests::DocumentHighlight.new(target, parent, dispatcher, @message_queue)
382
+ listener = Requests::DocumentHighlight.new(target, parent, dispatcher)
384
383
  dispatcher.visit(document.tree)
385
384
  listener.response
386
385
  end
@@ -393,7 +392,7 @@ module RubyLsp
393
392
  end_line = range.dig(:end, :line)
394
393
 
395
394
  dispatcher = Prism::Dispatcher.new
396
- listener = Requests::InlayHints.new(start_line..end_line, dispatcher, @message_queue)
395
+ listener = Requests::InlayHints.new(start_line..end_line, dispatcher)
397
396
  dispatcher.visit(document.tree)
398
397
  listener.response
399
398
  end
@@ -443,6 +442,11 @@ module RubyLsp
443
442
 
444
443
  sig { params(uri: URI::Generic).returns(T.nilable(Interface::FullDocumentDiagnosticReport)) }
445
444
  def diagnostic(uri)
445
+ # Do not compute diagnostics for files outside of the workspace. For example, if someone is looking at a gem's
446
+ # source code, we don't want to show diagnostics for it
447
+ path = uri.to_standardized_path
448
+ return unless path.nil? || path.start_with?(T.must(@store.workspace_uri.to_standardized_path))
449
+
446
450
  response = @store.cache_fetch(uri, "textDocument/diagnostic") do |document|
447
451
  Requests::Diagnostics.new(document).run
448
452
  end
@@ -457,11 +461,7 @@ module RubyLsp
457
461
  end_line = range.dig(:end, :line)
458
462
 
459
463
  dispatcher = Prism::Dispatcher.new
460
- listener = Requests::SemanticHighlighting.new(
461
- dispatcher,
462
- @message_queue,
463
- range: start_line..end_line,
464
- )
464
+ listener = Requests::SemanticHighlighting.new(dispatcher, range: start_line..end_line)
465
465
  dispatcher.visit(document.tree)
466
466
 
467
467
  Requests::Support::SemanticTokenEncoder.new.encode(listener.response)
@@ -513,12 +513,7 @@ module RubyLsp
513
513
  return unless target
514
514
 
515
515
  dispatcher = Prism::Dispatcher.new
516
- listener = Requests::Completion.new(
517
- @index,
518
- nesting,
519
- dispatcher,
520
- @message_queue,
521
- )
516
+ listener = Requests::Completion.new(@index, nesting, dispatcher)
522
517
  dispatcher.dispatch_once(target)
523
518
  listener.response
524
519
  end
@@ -583,6 +578,9 @@ module RubyLsp
583
578
  def initialize_request(options)
584
579
  @store.clear
585
580
 
581
+ workspace_uri = options.dig(:workspaceFolders, 0, :uri)
582
+ @store.workspace_uri = URI(workspace_uri) if workspace_uri
583
+
586
584
  encodings = options.dig(:capabilities, :general, :positionEncodings)
587
585
  @store.encoding = if encodings.nil? || encodings.empty?
588
586
  Constant::PositionEncodingKind::UTF16
@@ -14,10 +14,9 @@ module RubyLsp
14
14
 
15
15
  abstract!
16
16
 
17
- sig { params(dispatcher: Prism::Dispatcher, message_queue: Thread::Queue).void }
18
- def initialize(dispatcher, message_queue)
17
+ sig { params(dispatcher: Prism::Dispatcher).void }
18
+ def initialize(dispatcher)
19
19
  @dispatcher = dispatcher
20
- @message_queue = message_queue
21
20
  end
22
21
 
23
22
  sig { returns(ResponseType) }
@@ -43,8 +42,8 @@ module RubyLsp
43
42
  # When inheriting from ExtensibleListener, the `super` of constructor must be called **after** the subclass's own
44
43
  # ivars have been initialized. This is because the constructor of ExtensibleListener calls
45
44
  # `initialize_external_listener` which may depend on the subclass's ivars.
46
- sig { params(dispatcher: Prism::Dispatcher, message_queue: Thread::Queue).void }
47
- def initialize(dispatcher, message_queue)
45
+ sig { params(dispatcher: Prism::Dispatcher).void }
46
+ def initialize(dispatcher)
48
47
  super
49
48
  @response_merged = T.let(false, T::Boolean)
50
49
  @external_listeners = T.let(
@@ -47,16 +47,18 @@ module RubyLsp
47
47
  sig { override.returns(ResponseType) }
48
48
  attr_reader :_response
49
49
 
50
- sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher, message_queue: Thread::Queue).void }
51
- def initialize(uri, dispatcher, message_queue)
50
+ sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher).void }
51
+ def initialize(uri, dispatcher)
52
52
  @uri = T.let(uri, URI::Generic)
53
53
  @_response = T.let([], ResponseType)
54
54
  @path = T.let(uri.to_standardized_path, T.nilable(String))
55
55
  # visibility_stack is a stack of [current_visibility, previous_visibility]
56
56
  @visibility_stack = T.let([[:public, :public]], T::Array[T::Array[T.nilable(Symbol)]])
57
57
  @class_stack = T.let([], T::Array[String])
58
+ @group_id = T.let(1, Integer)
59
+ @group_id_stack = T.let([], T::Array[Integer])
58
60
 
59
- super(dispatcher, message_queue)
61
+ super(dispatcher)
60
62
 
61
63
  dispatcher.register(
62
64
  self,
@@ -82,12 +84,16 @@ module RubyLsp
82
84
  kind: :group,
83
85
  )
84
86
  end
87
+
88
+ @group_id_stack.push(@group_id)
89
+ @group_id += 1
85
90
  end
86
91
 
87
92
  sig { params(node: Prism::ClassNode).void }
88
93
  def on_class_node_leave(node)
89
94
  @visibility_stack.pop
90
95
  @class_stack.pop
96
+ @group_id_stack.pop
91
97
  end
92
98
 
93
99
  sig { params(node: Prism::DefNode).void }
@@ -146,7 +152,7 @@ module RubyLsp
146
152
 
147
153
  sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
148
154
  def initialize_external_listener(addon)
149
- addon.create_code_lens_listener(@uri, @dispatcher, @message_queue)
155
+ addon.create_code_lens_listener(@uri, @dispatcher)
150
156
  end
151
157
 
152
158
  sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
@@ -174,12 +180,15 @@ module RubyLsp
174
180
  },
175
181
  ]
176
182
 
183
+ grouping_data = { group_id: @group_id_stack.last, kind: kind }
184
+ grouping_data[:id] = @group_id if kind == :group
185
+
177
186
  @_response << create_code_lens(
178
187
  node,
179
188
  title: "Run",
180
189
  command_name: "rubyLsp.runTest",
181
190
  arguments: arguments,
182
- data: { type: "test", kind: kind },
191
+ data: { type: "test", **grouping_data },
183
192
  )
184
193
 
185
194
  @_response << create_code_lens(
@@ -187,7 +196,7 @@ module RubyLsp
187
196
  title: "Run In Terminal",
188
197
  command_name: "rubyLsp.runTestInTerminal",
189
198
  arguments: arguments,
190
- data: { type: "test_in_terminal", kind: kind },
199
+ data: { type: "test_in_terminal", **grouping_data },
191
200
  )
192
201
 
193
202
  @_response << create_code_lens(
@@ -195,7 +204,7 @@ module RubyLsp
195
204
  title: "Debug",
196
205
  command_name: "rubyLsp.debugTest",
197
206
  arguments: arguments,
198
- data: { type: "debug", kind: kind },
207
+ data: { type: "debug", **grouping_data },
199
208
  )
200
209
  end
201
210
 
@@ -36,11 +36,10 @@ module RubyLsp
36
36
  index: RubyIndexer::Index,
37
37
  nesting: T::Array[String],
38
38
  dispatcher: Prism::Dispatcher,
39
- message_queue: Thread::Queue,
40
39
  ).void
41
40
  end
42
- def initialize(index, nesting, dispatcher, message_queue)
43
- super(dispatcher, message_queue)
41
+ def initialize(index, nesting, dispatcher)
42
+ super(dispatcher)
44
43
  @_response = T.let([], ResponseType)
45
44
  @index = index
46
45
  @nesting = nesting
@@ -137,18 +136,22 @@ module RubyLsp
137
136
 
138
137
  receiver = T.must(receiver_entries.first)
139
138
 
140
- candidates = T.cast(@index.prefix_search(name), T::Array[T::Array[RubyIndexer::Entry::Method]])
141
- candidates.each do |entries|
142
- entry = entries.find { |e| e.owner&.name == receiver.name }
139
+ @index.prefix_search(name).each do |entries|
140
+ entry = entries.find { |e| e.is_a?(RubyIndexer::Entry::Member) && e.owner&.name == receiver.name }
143
141
  next unless entry
144
142
 
145
- @_response << build_method_completion(entry, node)
143
+ @_response << build_method_completion(T.cast(entry, RubyIndexer::Entry::Member), node)
146
144
  end
147
145
  end
148
146
 
149
147
  private
150
148
 
151
- sig { params(entry: RubyIndexer::Entry::Method, node: Prism::CallNode).returns(Interface::CompletionItem) }
149
+ sig do
150
+ params(
151
+ entry: RubyIndexer::Entry::Member,
152
+ node: Prism::CallNode,
153
+ ).returns(Interface::CompletionItem)
154
+ end
152
155
  def build_method_completion(entry, node)
153
156
  name = entry.name
154
157
  parameters = entry.parameters
@@ -37,16 +37,15 @@ module RubyLsp
37
37
  nesting: T::Array[String],
38
38
  index: RubyIndexer::Index,
39
39
  dispatcher: Prism::Dispatcher,
40
- message_queue: Thread::Queue,
41
40
  ).void
42
41
  end
43
- def initialize(uri, nesting, index, dispatcher, message_queue)
42
+ def initialize(uri, nesting, index, dispatcher)
44
43
  @uri = uri
45
44
  @nesting = nesting
46
45
  @index = index
47
46
  @_response = T.let(nil, ResponseType)
48
47
 
49
- super(dispatcher, message_queue)
48
+ super(dispatcher)
50
49
 
51
50
  dispatcher.register(
52
51
  self,
@@ -58,7 +57,7 @@ module RubyLsp
58
57
 
59
58
  sig { override.params(addon: Addon).returns(T.nilable(RubyLsp::Listener[ResponseType])) }
60
59
  def initialize_external_listener(addon)
61
- addon.create_definition_listener(@uri, @nesting, @index, @dispatcher, @message_queue)
60
+ addon.create_definition_listener(@uri, @nesting, @index, @dispatcher)
62
61
  end
63
62
 
64
63
  sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
@@ -32,13 +32,8 @@ module RubyLsp
32
32
  def run
33
33
  # Running RuboCop is slow, so to avoid excessive runs we only do so if the file is syntactically valid
34
34
  return syntax_error_diagnostics if @document.syntax_error?
35
-
36
35
  return unless defined?(Support::RuboCopDiagnosticsRunner)
37
36
 
38
- # Don't try to run RuboCop diagnostics for files outside the current working directory
39
- path = @uri.to_standardized_path
40
- return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
41
-
42
37
  Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document).map!(&:to_lsp_diagnostic)
43
38
  end
44
39
 
@@ -114,11 +114,10 @@ module RubyLsp
114
114
  target: T.nilable(Prism::Node),
115
115
  parent: T.nilable(Prism::Node),
116
116
  dispatcher: Prism::Dispatcher,
117
- message_queue: Thread::Queue,
118
117
  ).void
119
118
  end
120
- def initialize(target, parent, dispatcher, message_queue)
121
- super(dispatcher, message_queue)
119
+ def initialize(target, parent, dispatcher)
120
+ super(dispatcher)
122
121
 
123
122
  @_response = T.let([], T::Array[Interface::DocumentHighlight])
124
123
 
@@ -80,11 +80,10 @@ module RubyLsp
80
80
  uri: URI::Generic,
81
81
  comments: T::Array[Prism::Comment],
82
82
  dispatcher: Prism::Dispatcher,
83
- message_queue: Thread::Queue,
84
83
  ).void
85
84
  end
86
- def initialize(uri, comments, dispatcher, message_queue)
87
- super(dispatcher, message_queue)
85
+ def initialize(uri, comments, dispatcher)
86
+ super(dispatcher)
88
87
 
89
88
  # Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
90
89
  # in the URI
@@ -49,8 +49,8 @@ module RubyLsp
49
49
  sig { override.returns(T::Array[Interface::DocumentSymbol]) }
50
50
  attr_reader :_response
51
51
 
52
- sig { params(dispatcher: Prism::Dispatcher, message_queue: Thread::Queue).void }
53
- def initialize(dispatcher, message_queue)
52
+ sig { params(dispatcher: Prism::Dispatcher).void }
53
+ def initialize(dispatcher)
54
54
  @root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
55
55
  @_response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
56
56
  @stack = T.let(
@@ -80,7 +80,7 @@ module RubyLsp
80
80
 
81
81
  sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
82
82
  def initialize_external_listener(addon)
83
- addon.create_document_symbol_listener(@dispatcher, @message_queue)
83
+ addon.create_document_symbol_listener(@dispatcher)
84
84
  end
85
85
 
86
86
  # Merges responses from other listeners
@@ -21,9 +21,9 @@ module RubyLsp
21
21
 
22
22
  ResponseType = type_member { { fixed: T::Array[Interface::FoldingRange] } }
23
23
 
24
- sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher, queue: Thread::Queue).void }
25
- def initialize(comments, dispatcher, queue)
26
- super(dispatcher, queue)
24
+ sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
25
+ def initialize(comments, dispatcher)
26
+ super(dispatcher)
27
27
 
28
28
  @_response = T.let([], ResponseType)
29
29
  @requires = T.let([], T::Array[Prism::CallNode])
@@ -40,6 +40,7 @@ module RubyLsp
40
40
  :on_array_node_enter,
41
41
  :on_block_node_enter,
42
42
  :on_case_node_enter,
43
+ :on_case_match_node_enter,
43
44
  :on_class_node_enter,
44
45
  :on_module_node_enter,
45
46
  :on_for_node_enter,
@@ -51,7 +52,6 @@ module RubyLsp
51
52
  :on_else_node_enter,
52
53
  :on_ensure_node_enter,
53
54
  :on_begin_node_enter,
54
- :on_string_concat_node_enter,
55
55
  :on_def_node_enter,
56
56
  :on_call_node_enter,
57
57
  :on_lambda_node_enter,
@@ -91,10 +91,10 @@ module RubyLsp
91
91
 
92
92
  sig { params(node: Prism::InterpolatedStringNode).void }
93
93
  def on_interpolated_string_node_enter(node)
94
- opening_loc = node.opening_loc
95
- closing_loc = node.closing_loc
94
+ opening_loc = node.opening_loc || node.location
95
+ closing_loc = node.closing_loc || node.parts.last&.location || node.location
96
96
 
97
- add_lines_range(opening_loc.start_line, closing_loc.start_line - 1) if opening_loc && closing_loc
97
+ add_lines_range(opening_loc.start_line, closing_loc.start_line - 1)
98
98
  end
99
99
 
100
100
  sig { params(node: Prism::ArrayNode).void }
@@ -112,6 +112,11 @@ module RubyLsp
112
112
  add_simple_range(node)
113
113
  end
114
114
 
115
+ sig { params(node: Prism::CaseMatchNode).void }
116
+ def on_case_match_node_enter(node)
117
+ add_simple_range(node)
118
+ end
119
+
115
120
  sig { params(node: Prism::ClassNode).void }
116
121
  def on_class_node_enter(node)
117
122
  add_simple_range(node)
@@ -167,14 +172,6 @@ module RubyLsp
167
172
  add_simple_range(node)
168
173
  end
169
174
 
170
- sig { params(node: Prism::StringConcatNode).void }
171
- def on_string_concat_node_enter(node)
172
- left = T.let(node.left, Prism::Node)
173
- left = left.left while left.is_a?(Prism::StringConcatNode)
174
-
175
- add_lines_range(left.location.start_line, node.right.location.end_line - 1)
176
- end
177
-
178
175
  sig { params(node: Prism::DefNode).void }
179
176
  def on_def_node_enter(node)
180
177
  params = node.parameters
@@ -64,11 +64,6 @@ module RubyLsp
64
64
  sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
65
65
  def run
66
66
  return if @formatter == "none"
67
-
68
- # Don't try to format files outside the current working directory
69
- path = @uri.to_standardized_path
70
- return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
71
-
72
67
  return if @document.syntax_error?
73
68
 
74
69
  formatted_text = formatted_file
@@ -37,15 +37,14 @@ module RubyLsp
37
37
  index: RubyIndexer::Index,
38
38
  nesting: T::Array[String],
39
39
  dispatcher: Prism::Dispatcher,
40
- message_queue: Thread::Queue,
41
40
  ).void
42
41
  end
43
- def initialize(index, nesting, dispatcher, message_queue)
42
+ def initialize(index, nesting, dispatcher)
44
43
  @index = index
45
44
  @nesting = nesting
46
45
  @_response = T.let(nil, ResponseType)
47
46
 
48
- super(dispatcher, message_queue)
47
+ super(dispatcher)
49
48
  dispatcher.register(
50
49
  self,
51
50
  :on_constant_read_node_enter,
@@ -57,7 +56,7 @@ module RubyLsp
57
56
 
58
57
  sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
59
58
  def initialize_external_listener(addon)
60
- addon.create_hover_listener(@nesting, @index, @dispatcher, @message_queue)
59
+ addon.create_hover_listener(@nesting, @index, @dispatcher)
61
60
  end
62
61
 
63
62
  # Merges responses from other hover listeners
@@ -39,9 +39,9 @@ module RubyLsp
39
39
  sig { override.returns(ResponseType) }
40
40
  attr_reader :_response
41
41
 
42
- sig { params(range: T::Range[Integer], dispatcher: Prism::Dispatcher, message_queue: Thread::Queue).void }
43
- def initialize(range, dispatcher, message_queue)
44
- super(dispatcher, message_queue)
42
+ sig { params(range: T::Range[Integer], dispatcher: Prism::Dispatcher).void }
43
+ def initialize(range, dispatcher)
44
+ super(dispatcher)
45
45
 
46
46
  @_response = T.let([], ResponseType)
47
47
  @range = range
@@ -20,8 +20,8 @@ module RubyLsp
20
20
 
21
21
  END_REGEXES = T.let(
22
22
  [
23
- /(if|unless|for|while|class|module|until|def|case).*/,
24
- /.*\sdo/,
23
+ /\b(if|unless|for|while|class|module|until|def|case)\b.*/,
24
+ /.*\s\bdo\b/,
25
25
  ],
26
26
  T::Array[Regexp],
27
27
  )
@@ -139,7 +139,6 @@ module RubyLsp
139
139
  sig { params(spaces: String).void }
140
140
  def handle_comment_line(spaces)
141
141
  add_edit_with_text("##{spaces}")
142
- move_cursor_to(@position[:line], @indentation + spaces.size + 1)
143
142
  end
144
143
 
145
144
  sig { params(text: String, position: Document::PositionShape).void }
@@ -107,20 +107,15 @@ module RubyLsp
107
107
  sig { override.returns(ResponseType) }
108
108
  attr_reader :_response
109
109
 
110
- sig do
111
- params(
112
- dispatcher: Prism::Dispatcher,
113
- message_queue: Thread::Queue,
114
- range: T.nilable(T::Range[Integer]),
115
- ).void
116
- end
117
- def initialize(dispatcher, message_queue, range: nil)
118
- super(dispatcher, message_queue)
110
+ sig { params(dispatcher: Prism::Dispatcher, range: T.nilable(T::Range[Integer])).void }
111
+ def initialize(dispatcher, range: nil)
112
+ super(dispatcher)
119
113
 
120
114
  @_response = T.let([], ResponseType)
121
115
  @range = range
122
116
  @special_methods = T.let(nil, T.nilable(T::Array[String]))
123
117
  @current_scope = T.let(ParameterScope.new, ParameterScope)
118
+ @inside_regex_capture = T.let(false, T::Boolean)
124
119
 
125
120
  dispatcher.register(
126
121
  self,
@@ -152,6 +147,8 @@ module RubyLsp
152
147
  :on_local_variable_or_write_node_enter,
153
148
  :on_local_variable_target_node_enter,
154
149
  :on_block_local_variable_node_enter,
150
+ :on_match_write_node_enter,
151
+ :on_match_write_node_leave,
155
152
  )
156
153
  end
157
154
 
@@ -165,14 +162,28 @@ module RubyLsp
165
162
  # We can't push a semantic token for [] and []= because the argument inside the brackets is a part of
166
163
  # the message_loc
167
164
  return if message.start_with?("[") && (message.end_with?("]") || message.end_with?("]="))
168
-
169
- return process_regexp_locals(node) if message == "=~"
165
+ return if message == "=~"
170
166
  return if special_method?(message)
171
167
 
172
168
  type = Support::Sorbet.annotation?(node) ? :type : :method
173
169
  add_token(T.must(node.message_loc), type)
174
170
  end
175
171
 
172
+ sig { params(node: Prism::MatchWriteNode).void }
173
+ def on_match_write_node_enter(node)
174
+ call = node.call
175
+
176
+ if call.message == "=~"
177
+ @inside_regex_capture = true
178
+ process_regexp_locals(call)
179
+ end
180
+ end
181
+
182
+ sig { params(node: Prism::MatchWriteNode).void }
183
+ def on_match_write_node_leave(node)
184
+ @inside_regex_capture = true if node.call.message == "=~"
185
+ end
186
+
176
187
  sig { params(node: Prism::ConstantReadNode).void }
177
188
  def on_constant_read_node_enter(node)
178
189
  return unless visible?(node, @range)
@@ -359,6 +370,12 @@ module RubyLsp
359
370
 
360
371
  sig { params(node: Prism::LocalVariableTargetNode).void }
361
372
  def on_local_variable_target_node_enter(node)
373
+ # If we're inside a regex capture, Prism will add LocalVariableTarget nodes for each captured variable.
374
+ # Unfortunately, if the regex contains a backslash, the location will be incorrect and we'll end up highlighting
375
+ # the entire regex as a local variable. We process these captures in process_regexp_locals instead and then
376
+ # prevent pushing local variable target tokens. See https://github.com/ruby/prism/issues/1912
377
+ return if @inside_regex_capture
378
+
362
379
  return unless visible?(node, @range)
363
380
 
364
381
  add_token(node.location, @current_scope.type_for(node.name))
@@ -34,15 +34,10 @@ module RubyLsp
34
34
 
35
35
  sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
36
36
  def run(uri, document)
37
- relative_path = Pathname.new(T.must(uri.to_standardized_path || uri.opaque))
38
- .relative_path_from(T.must(WORKSPACE_URI.to_standardized_path))
39
- return if @options.ignore_files.any? { |pattern| File.fnmatch(pattern, relative_path) }
37
+ path = uri.to_standardized_path
38
+ return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
40
39
 
41
- SyntaxTree.format(
42
- document.source,
43
- @options.print_width,
44
- options: @options.formatter_options,
45
- )
40
+ SyntaxTree.format(document.source, @options.print_width, options: @options.formatter_options)
46
41
  end
47
42
  end
48
43
  end
@@ -75,6 +75,8 @@ module RubyLsp
75
75
  Constant::SymbolKind::CONSTANT
76
76
  when RubyIndexer::Entry::Method
77
77
  entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
78
+ when RubyIndexer::Entry::Accessor
79
+ Constant::SymbolKind::PROPERTY
78
80
  end
79
81
  end
80
82
  end
@@ -17,6 +17,9 @@ module RubyLsp
17
17
  sig { returns(T::Boolean) }
18
18
  attr_accessor :experimental_features
19
19
 
20
+ sig { returns(URI::Generic) }
21
+ attr_accessor :workspace_uri
22
+
20
23
  sig { void }
21
24
  def initialize
22
25
  @state = T.let({}, T::Hash[String, Document])
@@ -24,6 +27,7 @@ module RubyLsp
24
27
  @formatter = T.let("auto", String)
25
28
  @supports_progress = T.let(true, T::Boolean)
26
29
  @experimental_features = T.let(false, T::Boolean)
30
+ @workspace_uri = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
27
31
  end
28
32
 
29
33
  sig { params(uri: URI::Generic).returns(Document) }
@@ -4,10 +4,6 @@
4
4
  module RubyLsp
5
5
  # Used to indicate that a request shouldn't return a response
6
6
  VOID = T.let(Object.new.freeze, Object)
7
-
8
- # This freeze is not redundant since the interpolated string is mutable
9
- WORKSPACE_URI = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
10
-
11
7
  BUNDLE_PATH = T.let(
12
8
  begin
13
9
  Bundler.bundle_path.to_s
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.12.5
4
+ version: 0.13.0
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-24 00:00:00.000000000 Z
11
+ date: 2023-11-30 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.17.1
33
+ version: 0.18.0
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '0.18'
36
+ version: '0.19'
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.17.1
43
+ version: 0.18.0
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.18'
46
+ version: '0.19'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sorbet-runtime
49
49
  requirement: !ruby/object:Gem::Requirement