ruby-lsp 0.14.0 → 0.14.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: 846e8dec07f2ef860ee536f5031df7d38b43d60fa920edd8858d3231aea8dfdc
4
- data.tar.gz: 423fe5ec4630332897a9a691c5fb7349c1c2f31e017fa1d5bbdc07a95f0c616d
3
+ metadata.gz: 293c03761c9b7d497045546e3bf7ca88a08ed5556ad0ba52c205a9798e820ce5
4
+ data.tar.gz: 38157f012f3f1dc944186ac1530dc660d8662cb59ca7b12ad3b117655e0c1709
5
5
  SHA512:
6
- metadata.gz: aa20b2be3ee98080569821635324953270b40986c914c57737239e8879175ad3a31bb76094e27518249e6388d366575d0cef76a762cb108136fb54d1b47fe897
7
- data.tar.gz: 5e3cd7e882c998001234cce3b08124148c4bffbf6b223d57b6eca9cef5d9128c2b8d460161fb1b4bbf13e77c9f2360cb98a903a24b82e739b754bf9e08b1ca00
6
+ metadata.gz: c4996e277088f015004df0f82e2cc47dc2f979f6658f9dfac19fe495c8c4deced3028b021e330ac0681dbfd79048e9033037c7ce93e6cc044c8ae6d91087e0df
7
+ data.tar.gz: 67c5c31c97c279f192b0b3d6c729c97a19f7aac4581eca037c0e5355cc0f3d3ed69fb4007a5f32985e046980324575e2e35a92ce81e8078b41ee5b6db711ac88
data/README.md CHANGED
@@ -85,6 +85,9 @@ features. This is the mechanism that powers addons like
85
85
  - [Ruby LSP RSpec](https://github.com/st0012/ruby-lsp-rspec)
86
86
  - [Ruby LSP rubyfmt](https://github.com/jscharf/ruby-lsp-rubyfmt)
87
87
 
88
+ Other community driven addons can be found in [rubygems](https://rubygems.org/search?query=name%3A+ruby-lsp) by
89
+ searching for the `ruby-lsp` prefix.
90
+
88
91
  For instructions on how to create addons, see the [addons documentation](ADDONS.md).
89
92
 
90
93
  ## Learn More
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.0
1
+ 0.14.2
data/exe/ruby-lsp-doctor CHANGED
@@ -6,6 +6,8 @@ require "ruby_lsp/internal"
6
6
 
7
7
  index = RubyIndexer::Index.new
8
8
 
9
+ puts "Globbing for indexable files"
10
+
9
11
  RubyIndexer.configuration.indexables.each do |indexable|
10
12
  puts "indexing: #{indexable.full_path}"
11
13
  content = File.read(indexable.full_path)
@@ -237,9 +237,9 @@ module RubyIndexer
237
237
  real_parts.join("::")
238
238
  end
239
239
 
240
- # Attempts to find a given method for a resolved fully qualified receiver name. Returns `nil` if the method does not
241
- # exist on that receiver
242
- sig { params(method_name: String, receiver_name: String).returns(T.nilable(Entry::Member)) }
240
+ # Attempts to find methods for a resolved fully qualified receiver name.
241
+ # Returns `nil` if the method does not exist on that receiver
242
+ sig { params(method_name: String, receiver_name: String).returns(T.nilable(T::Array[Entry::Member])) }
243
243
  def resolve_method(method_name, receiver_name)
244
244
  method_entries = self[method_name]
245
245
  owner_entries = self[receiver_name]
@@ -247,10 +247,10 @@ module RubyIndexer
247
247
 
248
248
  owner_name = T.must(owner_entries.first).name
249
249
  T.cast(
250
- method_entries.grep(Entry::Member).find do |entry|
250
+ method_entries.grep(Entry::Member).select do |entry|
251
251
  T.cast(entry, Entry::Member).owner&.name == owner_name
252
252
  end,
253
- T.nilable(Entry::Member),
253
+ T::Array[Entry::Member],
254
254
  )
255
255
  end
256
256
 
@@ -226,9 +226,9 @@ module RubyIndexer
226
226
  end
227
227
  RUBY
228
228
 
229
- entry = T.must(@index.resolve_method("baz", "Foo::Bar"))
230
- assert_equal("baz", entry.name)
231
- assert_equal("Foo::Bar", T.must(entry.owner).name)
229
+ entries = T.must(@index.resolve_method("baz", "Foo::Bar"))
230
+ assert_equal("baz", entries.first.name)
231
+ assert_equal("Foo::Bar", T.must(entries.first.owner).name)
232
232
  end
233
233
 
234
234
  def test_resolve_method_with_class_name_conflict
@@ -241,9 +241,9 @@ module RubyIndexer
241
241
  end
242
242
  RUBY
243
243
 
244
- entry = T.must(@index.resolve_method("Array", "Foo"))
245
- assert_equal("Array", entry.name)
246
- assert_equal("Foo", T.must(entry.owner).name)
244
+ entries = T.must(@index.resolve_method("Array", "Foo"))
245
+ assert_equal("Array", entries.first.name)
246
+ assert_equal("Foo", T.must(entries.first.owner).name)
247
247
  end
248
248
 
249
249
  def test_resolve_method_attribute
@@ -253,9 +253,33 @@ module RubyIndexer
253
253
  end
254
254
  RUBY
255
255
 
256
- entry = T.must(@index.resolve_method("bar", "Foo"))
257
- assert_equal("bar", entry.name)
258
- assert_equal("Foo", T.must(entry.owner).name)
256
+ entries = T.must(@index.resolve_method("bar", "Foo"))
257
+ assert_equal("bar", entries.first.name)
258
+ assert_equal("Foo", T.must(entries.first.owner).name)
259
+ end
260
+
261
+ def test_resolve_method_with_two_definitions
262
+ index(<<~RUBY)
263
+ class Foo
264
+ # Hello from first `bar`
265
+ def bar; end
266
+ end
267
+
268
+ class Foo
269
+ # Hello from second `bar`
270
+ def bar; end
271
+ end
272
+ RUBY
273
+
274
+ first_entry, second_entry = T.must(@index.resolve_method("bar", "Foo"))
275
+
276
+ assert_equal("bar", first_entry.name)
277
+ assert_equal("Foo", T.must(first_entry.owner).name)
278
+ assert_includes(first_entry.comments, "Hello from first `bar`")
279
+
280
+ assert_equal("bar", second_entry.name)
281
+ assert_equal("Foo", T.must(second_entry.owner).name)
282
+ assert_includes(second_entry.comments, "Hello from second `bar`")
259
283
  end
260
284
 
261
285
  def test_prefix_search_for_methods
@@ -25,21 +25,25 @@ module RubyLsp
25
25
 
26
26
  abstract!
27
27
 
28
+ @addons = T.let([], T::Array[Addon])
29
+ @addon_classes = T.let([], T::Array[T.class_of(Addon)])
30
+
28
31
  class << self
29
32
  extend T::Sig
30
33
 
34
+ sig { returns(T::Array[Addon]) }
35
+ attr_accessor :addons
36
+
37
+ sig { returns(T::Array[T.class_of(Addon)]) }
38
+ attr_reader :addon_classes
39
+
31
40
  # Automatically track and instantiate addon classes
32
41
  sig { params(child_class: T.class_of(Addon)).void }
33
42
  def inherited(child_class)
34
- addons << child_class.new
43
+ addon_classes << child_class
35
44
  super
36
45
  end
37
46
 
38
- sig { returns(T::Array[Addon]) }
39
- def addons
40
- @addons ||= T.let([], T.nilable(T::Array[Addon]))
41
- end
42
-
43
47
  # Discovers and loads all addons. Returns the list of activated addons
44
48
  sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
45
49
  def load_addons(message_queue)
@@ -51,11 +55,13 @@ module RubyLsp
51
55
  $stderr.puts(e.full_message)
52
56
  end
53
57
 
58
+ # Instantiate all discovered addon classes
59
+ self.addons = addon_classes.map(&:new)
60
+
54
61
  # Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
55
62
  # fail to boot the server
56
63
  addons.each do |addon|
57
64
  addon.activate(message_queue)
58
- nil
59
65
  rescue => e
60
66
  addon.add_error(e)
61
67
  end
@@ -7,13 +7,17 @@ yarp_require_paths = Gem.loaded_specs["yarp"]&.full_require_paths
7
7
  $LOAD_PATH.delete_if { |path| yarp_require_paths.include?(path) } if yarp_require_paths
8
8
 
9
9
  require "sorbet-runtime"
10
- require "prism"
11
- require "prism/visitor"
12
- require "language_server-protocol"
10
+
11
+ # Set Bundler's UI level to silent as soon as possible to prevent any prints to STDOUT
13
12
  require "bundler"
13
+ Bundler.ui.level = :silent
14
+
14
15
  require "uri"
15
16
  require "cgi"
16
17
  require "set"
18
+ require "prism"
19
+ require "prism/visitor"
20
+ require "language_server-protocol"
17
21
 
18
22
  require "ruby-lsp"
19
23
  require "ruby_indexer/ruby_indexer"
@@ -29,5 +33,3 @@ require "ruby_lsp/ruby_document"
29
33
  require "ruby_lsp/store"
30
34
  require "ruby_lsp/addon"
31
35
  require "ruby_lsp/requests/support/rubocop_runner"
32
-
33
- Bundler.ui.level = :silent
@@ -43,7 +43,9 @@ module RubyLsp
43
43
  def on_constant_read_node_enter(node)
44
44
  return if DependencyDetector.instance.typechecker
45
45
 
46
- name = node.slice
46
+ name = constant_name(node)
47
+ return if name.nil?
48
+
47
49
  candidates = @index.prefix_search(name, @nesting)
48
50
  candidates.each do |entries|
49
51
  complete_name = T.must(entries.first).name
@@ -62,7 +64,8 @@ module RubyLsp
62
64
  def on_constant_path_node_enter(node)
63
65
  return if DependencyDetector.instance.typechecker
64
66
 
65
- name = node.slice
67
+ name = constant_name(node)
68
+ return if name.nil?
66
69
 
67
70
  top_level_reference = if name.start_with?("::")
68
71
  name = name.delete_prefix("::")
@@ -45,12 +45,18 @@ module RubyLsp
45
45
 
46
46
  sig { params(node: Prism::ConstantPathNode).void }
47
47
  def on_constant_path_node_enter(node)
48
- find_in_index(node.slice)
48
+ name = constant_name(node)
49
+ return if name.nil?
50
+
51
+ find_in_index(name)
49
52
  end
50
53
 
51
54
  sig { params(node: Prism::ConstantReadNode).void }
52
55
  def on_constant_read_node_enter(node)
53
- find_in_index(node.slice)
56
+ name = constant_name(node)
57
+ return if name.nil?
58
+
59
+ find_in_index(name)
54
60
  end
55
61
 
56
62
  private
@@ -62,20 +68,22 @@ module RubyLsp
62
68
  message = node.message
63
69
  return unless message
64
70
 
65
- target_method = @index.resolve_method(message, @nesting.join("::"))
66
- return unless target_method
71
+ methods = @index.resolve_method(message, @nesting.join("::"))
72
+ return unless methods
67
73
 
68
- location = target_method.location
69
- file_path = target_method.file_path
70
- return if @typechecker_enabled && not_in_dependencies?(file_path)
74
+ methods.each do |target_method|
75
+ location = target_method.location
76
+ file_path = target_method.file_path
77
+ next if @typechecker_enabled && not_in_dependencies?(file_path)
71
78
 
72
- @response_builder << Interface::Location.new(
73
- uri: URI::Generic.from_path(path: file_path).to_s,
74
- range: Interface::Range.new(
75
- start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
76
- end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
77
- ),
78
- )
79
+ @response_builder << Interface::Location.new(
80
+ uri: URI::Generic.from_path(path: file_path).to_s,
81
+ range: Interface::Range.new(
82
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
83
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
84
+ ),
85
+ )
86
+ end
79
87
  end
80
88
 
81
89
  sig { params(node: Prism::CallNode).void }
@@ -25,6 +25,14 @@ module RubyLsp
25
25
  :on_call_node_enter,
26
26
  :on_constant_path_write_node_enter,
27
27
  :on_constant_write_node_enter,
28
+ :on_constant_path_or_write_node_enter,
29
+ :on_constant_path_operator_write_node_enter,
30
+ :on_constant_path_and_write_node_enter,
31
+ :on_constant_or_write_node_enter,
32
+ :on_constant_operator_write_node_enter,
33
+ :on_constant_and_write_node_enter,
34
+ :on_constant_target_node_enter,
35
+ :on_constant_path_target_node_enter,
28
36
  :on_def_node_enter,
29
37
  :on_def_node_leave,
30
38
  :on_module_node_enter,
@@ -98,6 +106,86 @@ module RubyLsp
98
106
  )
99
107
  end
100
108
 
109
+ sig { params(node: Prism::ConstantPathAndWriteNode).void }
110
+ def on_constant_path_and_write_node_enter(node)
111
+ create_document_symbol(
112
+ name: node.target.location.slice,
113
+ kind: Constant::SymbolKind::CONSTANT,
114
+ range_location: node.location,
115
+ selection_range_location: node.target.location,
116
+ )
117
+ end
118
+
119
+ sig { params(node: Prism::ConstantPathOrWriteNode).void }
120
+ def on_constant_path_or_write_node_enter(node)
121
+ create_document_symbol(
122
+ name: node.target.location.slice,
123
+ kind: Constant::SymbolKind::CONSTANT,
124
+ range_location: node.location,
125
+ selection_range_location: node.target.location,
126
+ )
127
+ end
128
+
129
+ sig { params(node: Prism::ConstantPathOperatorWriteNode).void }
130
+ def on_constant_path_operator_write_node_enter(node)
131
+ create_document_symbol(
132
+ name: node.target.location.slice,
133
+ kind: Constant::SymbolKind::CONSTANT,
134
+ range_location: node.location,
135
+ selection_range_location: node.target.location,
136
+ )
137
+ end
138
+
139
+ sig { params(node: Prism::ConstantOrWriteNode).void }
140
+ def on_constant_or_write_node_enter(node)
141
+ create_document_symbol(
142
+ name: node.name.to_s,
143
+ kind: Constant::SymbolKind::CONSTANT,
144
+ range_location: node.location,
145
+ selection_range_location: node.name_loc,
146
+ )
147
+ end
148
+
149
+ sig { params(node: Prism::ConstantAndWriteNode).void }
150
+ def on_constant_and_write_node_enter(node)
151
+ create_document_symbol(
152
+ name: node.name.to_s,
153
+ kind: Constant::SymbolKind::CONSTANT,
154
+ range_location: node.location,
155
+ selection_range_location: node.name_loc,
156
+ )
157
+ end
158
+
159
+ sig { params(node: Prism::ConstantOperatorWriteNode).void }
160
+ def on_constant_operator_write_node_enter(node)
161
+ create_document_symbol(
162
+ name: node.name.to_s,
163
+ kind: Constant::SymbolKind::CONSTANT,
164
+ range_location: node.location,
165
+ selection_range_location: node.name_loc,
166
+ )
167
+ end
168
+
169
+ sig { params(node: Prism::ConstantTargetNode).void }
170
+ def on_constant_target_node_enter(node)
171
+ create_document_symbol(
172
+ name: node.name.to_s,
173
+ kind: Constant::SymbolKind::CONSTANT,
174
+ range_location: node.location,
175
+ selection_range_location: node.location,
176
+ )
177
+ end
178
+
179
+ sig { params(node: Prism::ConstantPathTargetNode).void }
180
+ def on_constant_path_target_node_enter(node)
181
+ create_document_symbol(
182
+ name: node.slice,
183
+ kind: Constant::SymbolKind::CONSTANT,
184
+ range_location: node.location,
185
+ selection_range_location: node.location,
186
+ )
187
+ end
188
+
101
189
  sig { params(node: Prism::DefNode).void }
102
190
  def on_def_node_leave(node)
103
191
  @response_builder.pop
@@ -206,23 +294,34 @@ module RubyLsp
206
294
 
207
295
  sig { params(node: Prism::CallNode).void }
208
296
  def handle_attr_accessor(node)
209
- return unless node.receiver.nil?
297
+ receiver = node.receiver
298
+ return if receiver && !receiver.is_a?(Prism::SelfNode)
210
299
 
211
300
  arguments = node.arguments
212
301
  return unless arguments
213
302
 
214
303
  arguments.arguments.each do |argument|
215
- next unless argument.is_a?(Prism::SymbolNode)
216
-
217
- name = argument.value
218
- next unless name
219
-
220
- create_document_symbol(
221
- name: name,
222
- kind: Constant::SymbolKind::FIELD,
223
- range_location: argument.location,
224
- selection_range_location: T.must(argument.value_loc),
225
- )
304
+ if argument.is_a?(Prism::SymbolNode)
305
+ name = argument.value
306
+ next unless name
307
+
308
+ create_document_symbol(
309
+ name: name,
310
+ kind: Constant::SymbolKind::FIELD,
311
+ range_location: argument.location,
312
+ selection_range_location: T.must(argument.value_loc),
313
+ )
314
+ elsif argument.is_a?(Prism::StringNode)
315
+ name = argument.content
316
+ next if name.empty?
317
+
318
+ create_document_symbol(
319
+ name: name,
320
+ kind: Constant::SymbolKind::FIELD,
321
+ range_location: argument.location,
322
+ selection_range_location: argument.content_loc,
323
+ )
324
+ end
226
325
  end
227
326
  end
228
327
 
@@ -55,7 +55,10 @@ module RubyLsp
55
55
  def on_constant_read_node_enter(node)
56
56
  return if @typechecker_enabled
57
57
 
58
- generate_hover(node.slice, node.location)
58
+ name = constant_name(node)
59
+ return if name.nil?
60
+
61
+ generate_hover(name, node.location)
59
62
  end
60
63
 
61
64
  sig { params(node: Prism::ConstantWriteNode).void }
@@ -69,7 +72,10 @@ module RubyLsp
69
72
  def on_constant_path_node_enter(node)
70
73
  return if DependencyDetector.instance.typechecker
71
74
 
72
- generate_hover(node.slice, node.location)
75
+ name = constant_name(node)
76
+ return if name.nil?
77
+
78
+ generate_hover(name, node.location)
73
79
  end
74
80
 
75
81
  sig { params(node: Prism::CallNode).void }
@@ -86,10 +92,10 @@ module RubyLsp
86
92
  message = node.message
87
93
  return unless message
88
94
 
89
- target_method = @index.resolve_method(message, @nesting.join("::"))
90
- return unless target_method
95
+ methods = @index.resolve_method(message, @nesting.join("::"))
96
+ return unless methods
91
97
 
92
- categorized_markdown_from_index_entries(message, target_method).each do |category, content|
98
+ categorized_markdown_from_index_entries(message, methods).each do |category, content|
93
99
  @response_builder.push(content, category: category)
94
100
  end
95
101
  end
@@ -30,7 +30,10 @@ module RubyLsp
30
30
  message = node.message
31
31
  return unless message
32
32
 
33
- target_method = @index.resolve_method(message, @nesting.join("::"))
33
+ methods = @index.resolve_method(message, @nesting.join("::"))
34
+ return unless methods
35
+
36
+ target_method = methods.first
34
37
  return unless target_method
35
38
 
36
39
  parameters = target_method.parameters
@@ -59,7 +62,7 @@ module RubyLsp
59
62
  parameters: parameters.map { |param| Interface::ParameterInformation.new(label: param.name) },
60
63
  documentation: Interface::MarkupContent.new(
61
64
  kind: "markdown",
62
- value: markdown_from_index_entries("", target_method),
65
+ value: markdown_from_index_entries("", methods),
63
66
  ),
64
67
  ),
65
68
  ],
@@ -11,12 +11,12 @@ module RubyLsp
11
11
  #
12
12
  # The
13
13
  # [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
14
- # request informs the editor of runnable commands such as tests
14
+ # request informs the editor of runnable commands such as testing and debugging
15
15
  #
16
16
  # # Example
17
17
  #
18
18
  # ```ruby
19
- # # Run
19
+ # # Run | Run in Terminal | Debug
20
20
  # class Test < Minitest::Test
21
21
  # end
22
22
  # ```
@@ -132,6 +132,21 @@ module RubyLsp
132
132
  #{categorized_markdown[:documentation]}
133
133
  MARKDOWN
134
134
  end
135
+
136
+ sig do
137
+ params(
138
+ node: T.any(
139
+ Prism::ConstantPathNode,
140
+ Prism::ConstantReadNode,
141
+ Prism::ConstantPathTargetNode,
142
+ ),
143
+ ).returns(T.nilable(String))
144
+ end
145
+ def constant_name(node)
146
+ node.full_name
147
+ rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError
148
+ nil
149
+ end
135
150
  end
136
151
  end
137
152
  end
@@ -57,15 +57,18 @@ module RubyLsp
57
57
  def setup!
58
58
  raise BundleNotLocked if @gemfile&.exist? && !@lockfile&.exist?
59
59
 
60
- # Do not setup a custom bundle if both `ruby-lsp` and `debug` are already in the Gemfile
61
- if @dependencies["ruby-lsp"] && @dependencies["debug"]
60
+ # Do not set up a custom bundle if LSP dependencies are already in the Gemfile
61
+ if @dependencies["ruby-lsp"] &&
62
+ @dependencies["debug"] &&
63
+ (@dependencies["rails"] ? @dependencies["ruby-lsp-rails"] : true)
62
64
  $stderr.puts(
63
- "Ruby LSP> Skipping custom bundle setup since both `ruby-lsp` and `debug` are already in #{@gemfile}",
65
+ "Ruby LSP> Skipping custom bundle setup since LSP dependencies are already in #{@gemfile}",
64
66
  )
65
67
 
66
- # If the user decided to add the `ruby-lsp` and `debug` to their Gemfile after having already run the Ruby LSP,
67
- # then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle install` for the top level and
68
- # try to execute the Ruby LSP using the custom bundle, which will fail since the gems are not installed there
68
+ # If the user decided to add `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) to their Gemfile after
69
+ # having already run the Ruby LSP, then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle
70
+ # install` for the top level and try to execute the Ruby LSP using the custom bundle, which will fail since the
71
+ # gems are not installed there
69
72
  @custom_dir.rmtree if @custom_dir.exist?
70
73
  return run_bundle_install
71
74
  end
@@ -143,6 +146,10 @@ module RubyLsp
143
146
  parts << 'gem "debug", require: false, group: :development, platforms: :mri'
144
147
  end
145
148
 
149
+ if @dependencies["rails"] && !@dependencies["ruby-lsp-rails"]
150
+ parts << 'gem "ruby-lsp-rails", require: false, group: :development'
151
+ end
152
+
146
153
  content = parts.join("\n")
147
154
  @custom_gemfile.write(content) unless @custom_gemfile.exist? && @custom_gemfile.read == content
148
155
  end
@@ -183,22 +190,24 @@ module RubyLsp
183
190
  local_config_path = File.join(Dir.pwd, ".bundle")
184
191
  env["BUNDLE_APP_CONFIG"] = local_config_path if Dir.exist?(local_config_path)
185
192
 
186
- # If both `ruby-lsp` and `debug` are already in the Gemfile, then we shouldn't try to upgrade them or else we'll
187
- # produce undesired source control changes. If the custom bundle was just created and either `ruby-lsp` or `debug`
188
- # weren't a part of the Gemfile, then we need to run `bundle install` for the first time to generate the
189
- # Gemfile.lock with them included or else Bundler will complain that they're missing. We can only update if the
190
- # custom `.ruby-lsp/Gemfile.lock` already exists and includes both gems
193
+ # If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
194
+ # to upgrade them or else we'll produce undesired source control changes. If the custom bundle was just created
195
+ # and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
196
+ # install` for the first time to generate the Gemfile.lock with them included or else Bundler will complain that
197
+ # they're missing. We can only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
191
198
 
192
199
  # When not updating, we run `(bundle check || bundle install)`
193
200
  # When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
194
201
  command = +"(bundle check"
195
202
 
196
203
  if should_bundle_update?
197
- # If ruby-lsp or debug are not in the Gemfile, try to update them to the latest version
204
+ # If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
205
+ # version
198
206
  command.prepend("(")
199
207
  command << " && bundle update "
200
208
  command << "ruby-lsp " unless @dependencies["ruby-lsp"]
201
209
  command << "debug " unless @dependencies["debug"]
210
+ command << "ruby-lsp-rails " if @dependencies["rails"] && !@dependencies["ruby-lsp-rails"]
202
211
  command << "--pre" if @experimental
203
212
  command.delete_suffix!(" ")
204
213
  command << ")"
@@ -221,13 +230,20 @@ module RubyLsp
221
230
 
222
231
  sig { returns(T::Boolean) }
223
232
  def should_bundle_update?
224
- # If both `ruby-lsp` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it will produce
225
- # version control changes
226
- return false if @dependencies["ruby-lsp"] && @dependencies["debug"]
233
+ # If `ruby-lsp`, `ruby-lsp-rails` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it
234
+ # will produce version control changes
235
+ if @dependencies["rails"]
236
+ return false if @dependencies.values_at("ruby-lsp", "ruby-lsp-rails", "debug").all?
237
+
238
+ # If the custom lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle install
239
+ # before updating
240
+ return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug", "ruby-lsp-rails").any?(&:nil?)
241
+ else
242
+ return false if @dependencies.values_at("ruby-lsp", "debug").all?
227
243
 
228
- # If the custom lockfile doesn't include either the `ruby-lsp` or `debug`, we need to run bundle install before
229
- # updating
230
- return false if custom_bundle_dependencies["ruby-lsp"].nil? || custom_bundle_dependencies["debug"].nil?
244
+ # If the custom lockfile doesn't include `ruby-lsp` or `debug`, we need to run bundle install before updating
245
+ return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug").any?(&:nil?)
246
+ end
231
247
 
232
248
  # If the last updated file doesn't exist or was updated more than 4 hours ago, we should update
233
249
  !@last_updated_path.exist? || Time.parse(@last_updated_path.read) < (Time.now - FOUR_HOURS)
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.14.0
4
+ version: 0.14.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-08 00:00:00.000000000 Z
11
+ date: 2024-02-22 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.19.0
33
+ version: 0.22.0
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '0.22'
36
+ version: '0.25'
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.19.0
43
+ version: 0.22.0
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.22'
46
+ version: '0.25'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sorbet-runtime
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +159,7 @@ licenses:
159
159
  - MIT
160
160
  metadata:
161
161
  allowed_push_host: https://rubygems.org
162
+ documentation_uri: https://shopify.github.io/ruby-lsp/
162
163
  post_install_message:
163
164
  rdoc_options: []
164
165
  require_paths: