ruby-lsp 0.23.6 → 0.23.8

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: 563db8ddc06dc53f37db5ea4a42a48b7af8ed5bb2639c42e87e3c2bdd7fe38d1
4
- data.tar.gz: a1820031a007e14c42600fd897e43fad044f26e05f02e117c806821cdc46e9d7
3
+ metadata.gz: 918079e906832b0289a053cd4bfe849422082c25bd0f4bdada25cab3a532005f
4
+ data.tar.gz: 7935b2bdc52a2bb83264376fb98f7ef8d3bfc3c5cb9dadd23642a1ebafbca013
5
5
  SHA512:
6
- metadata.gz: 2d28983a474a7b32486f20df65ec2a808ddf2be31bc0c4d7d62ae1c3fa24448b28699917d23b6f4f00045ff45e25aeff1e27c6a27d40c6a7dc6887be630f8828
7
- data.tar.gz: d10bd35268476cd2b2d319405dd58433d32df48a621cf4d45555cafb6e293d3bc4b3844afe7bf6dc0d39e68a5f5a7be70b935874796a3852a68ac5c61c592709
6
+ metadata.gz: 9fb084d322308bb2e69c2c0d5cfed2d275fe53f5df40aa2a49a848aab4c771858dfa1b5d5df913516c1f1c90ce5101b2f461865093f5e6787c79886cadc40bdb
7
+ data.tar.gz: 06206026d180e9d044edda0a83018ae31895cce3e6d91cb9ae4bdb3c365565a27881dd17ffd6d8861d8126441e327cb8fdf91c41e6003c1d84a4038c8b9003ea
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Build Status](https://github.com/Shopify/ruby-lsp/workflows/CI/badge.svg)](https://github.com/Shopify/ruby-lsp/actions/workflows/ci.yml)
6
6
  [![Ruby LSP extension](https://img.shields.io/badge/VS%20Code-Ruby%20LSP-success?logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp)
7
- [![Ruby DX Slack](https://img.shields.io/badge/Slack-Ruby%20DX-success?logo=slack)](https://join.slack.com/t/ruby-dx/shared_invite/zt-2c8zjlir6-uUDJl8oIwcen_FS_aA~b6Q)
7
+ [![Ruby DX Slack](https://img.shields.io/badge/Slack-Ruby%20DX-success?logo=slack)](https://join.slack.com/t/ruby-dx/shared_invite/zt-2yd77ayis-yAiVc1TX_kH0mHMBbi89dA)
8
8
 
9
9
  # Ruby LSP
10
10
 
@@ -13,7 +13,7 @@ for Ruby, used to improve rich features in editors. It is a part of a wider goal
13
13
  experience to Ruby developers using modern standards for cross-editor features, documentation and debugging.
14
14
 
15
15
  Want to discuss Ruby developer experience? Consider joining the public
16
- [Ruby DX Slack workspace](https://join.slack.com/t/ruby-dx/shared_invite/zt-2c8zjlir6-uUDJl8oIwcen_FS_aA~b6Q).
16
+ [Ruby DX Slack workspace](https://join.slack.com/t/ruby-dx/shared_invite/zt-2yd77ayis-yAiVc1TX_kH0mHMBbi89dA).
17
17
 
18
18
  ## Getting Started
19
19
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.23.6
1
+ 0.23.8
data/exe/ruby-lsp CHANGED
@@ -64,9 +64,9 @@ if ENV["BUNDLE_GEMFILE"].nil?
64
64
  # which gives us the opportunity to control which specs are activated and enter degraded mode if any gems failed to
65
65
  # install rather than failing to boot the server completely
66
66
  if options[:launcher]
67
- command = +"#{Gem.ruby} #{File.expand_path("ruby-lsp-launcher", __dir__)}"
68
- command << " --debug" if options[:debug]
69
- exit exec(command)
67
+ flags = []
68
+ flags << "--debug" if options[:debug]
69
+ exit exec(Gem.ruby, File.expand_path("ruby-lsp-launcher", __dir__), *flags)
70
70
  end
71
71
 
72
72
  require_relative "../lib/ruby_lsp/setup_bundler"
@@ -8,14 +8,24 @@
8
8
 
9
9
  setup_error = nil
10
10
  install_error = nil
11
+ reboot = false
11
12
 
12
- # Read the initialize request before even starting the server. We need to do this to figure out the workspace URI.
13
- # Editors are not required to spawn the language server process on the same directory as the workspace URI, so we need
14
- # to ensure that we're setting up the bundle in the right place
15
- $stdin.binmode
16
- headers = $stdin.gets("\r\n\r\n")
17
- content_length = headers[/Content-Length: (\d+)/i, 1].to_i
18
- raw_initialize = $stdin.read(content_length)
13
+ workspace_uri = ARGV.first
14
+
15
+ raw_initialize = if workspace_uri && !workspace_uri.start_with?("--")
16
+ # If there's an argument without `--`, then it's the server asking to compose the bundle and passing to this
17
+ # executable the workspace URI. We can't require gems at this point, so we built a fake initialize request manually
18
+ reboot = true
19
+ "{\"params\":{\"workspaceFolders\":[{\"uri\":\"#{workspace_uri}\"}]}}"
20
+ else
21
+ # Read the initialize request before even starting the server. We need to do this to figure out the workspace URI.
22
+ # Editors are not required to spawn the language server process on the same directory as the workspace URI, so we need
23
+ # to ensure that we're setting up the bundle in the right place
24
+ $stdin.binmode
25
+ headers = $stdin.gets("\r\n\r\n")
26
+ content_length = headers[/Content-Length: (\d+)/i, 1].to_i
27
+ $stdin.read(content_length)
28
+ end
19
29
 
20
30
  # Compose the Ruby LSP bundle in a forked process so that we can require gems without polluting the main process
21
31
  # `$LOAD_PATH` and `Gem.loaded_specs`. Windows doesn't support forking, so we need a separate path to support it
@@ -41,7 +51,7 @@ end
41
51
 
42
52
  begin
43
53
  # Wait until the composed Bundle is finished
44
- Process.wait(pid)
54
+ _, status = Process.wait2(pid)
45
55
  rescue Errno::ECHILD
46
56
  # In theory, the child process can finish before we even get to the wait call, but that is not an error
47
57
  end
@@ -91,6 +101,13 @@ rescue StandardError => e
91
101
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
92
102
  end
93
103
 
104
+ # When performing a lockfile re-boot, this executable is invoked to set up the composed bundle ahead of time. In this
105
+ # flow, we are not booting the LSP yet, just checking if the bundle is valid before rebooting
106
+ if reboot
107
+ # Use the exit status to signal to the server if composing the bundle succeeded
108
+ exit(install_error || setup_error ? 1 : status&.exitstatus || 0)
109
+ end
110
+
94
111
  # Now that the bundle is set up, we can begin actually launching the server. Note that `Bundler.setup` will have already
95
112
  # configured the load path using the version of the Ruby LSP present in the composed bundle. Do not push any Ruby LSP
96
113
  # paths into the load path manually or we may end up requiring the wrong version of the gem
@@ -120,8 +120,16 @@ module RubyIndexer
120
120
  )]))
121
121
  end
122
122
  def first_unqualified_const(name)
123
+ # Look for an exact match first
123
124
  _name, entries = @entries.find do |const_name, _entries|
124
- const_name.end_with?(name)
125
+ const_name == name || const_name.end_with?("::#{name}")
126
+ end
127
+
128
+ # If an exact match is not found, then try to find a constant that ends with the name
129
+ unless entries
130
+ _name, entries = @entries.find do |const_name, _entries|
131
+ const_name.end_with?(name)
132
+ end
125
133
  end
126
134
 
127
135
  T.cast(
@@ -593,7 +601,7 @@ module RubyIndexer
593
601
  entries = self[variable_name]&.grep(Entry::ClassVariable)
594
602
  return unless entries&.any?
595
603
 
596
- ancestors = linearized_ancestors_of(owner_name)
604
+ ancestors = linearized_attached_ancestors(owner_name)
597
605
  return if ancestors.empty?
598
606
 
599
607
  entries.select { |e| ancestors.include?(e.owner&.name) }
@@ -601,12 +609,33 @@ module RubyIndexer
601
609
 
602
610
  # Returns a list of possible candidates for completion of instance variables for a given owner name. The name must
603
611
  # include the `@` prefix
604
- sig { params(name: String, owner_name: String).returns(T::Array[Entry::InstanceVariable]) }
612
+ sig do
613
+ params(name: String, owner_name: String).returns(T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
614
+ end
605
615
  def instance_variable_completion_candidates(name, owner_name)
606
- entries = T.cast(prefix_search(name).flatten, T::Array[Entry::InstanceVariable])
616
+ entries = T.cast(prefix_search(name).flatten, T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
617
+ # Avoid wasting time linearizing ancestors if we didn't find anything
618
+ return entries if entries.empty?
619
+
607
620
  ancestors = linearized_ancestors_of(owner_name)
608
621
 
609
- variables = entries.select { |e| ancestors.any?(e.owner&.name) }
622
+ instance_variables, class_variables = entries.partition { |e| e.is_a?(Entry::InstanceVariable) }
623
+ variables = instance_variables.select { |e| ancestors.any?(e.owner&.name) }
624
+
625
+ # Class variables are only owned by the attached class in our representation. If the owner is in a singleton
626
+ # context, we have to search for ancestors of the attached class
627
+ if class_variables.any?
628
+ name_parts = owner_name.split("::")
629
+
630
+ if name_parts.last&.start_with?("<Class:")
631
+ attached_name = T.must(name_parts[0..-2]).join("::")
632
+ attached_ancestors = linearized_ancestors_of(attached_name)
633
+ variables.concat(class_variables.select { |e| attached_ancestors.any?(e.owner&.name) })
634
+ else
635
+ variables.concat(class_variables.select { |e| ancestors.any?(e.owner&.name) })
636
+ end
637
+ end
638
+
610
639
  variables.uniq!(&:name)
611
640
  variables
612
641
  end
@@ -614,8 +643,10 @@ module RubyIndexer
614
643
  sig { params(name: String, owner_name: String).returns(T::Array[Entry::ClassVariable]) }
615
644
  def class_variable_completion_candidates(name, owner_name)
616
645
  entries = T.cast(prefix_search(name).flatten, T::Array[Entry::ClassVariable])
617
- ancestors = linearized_ancestors_of(owner_name)
646
+ # Avoid wasting time linearizing ancestors if we didn't find anything
647
+ return entries if entries.empty?
618
648
 
649
+ ancestors = linearized_attached_ancestors(owner_name)
619
650
  variables = entries.select { |e| ancestors.any?(e.owner&.name) }
620
651
  variables.uniq!(&:name)
621
652
  variables
@@ -717,6 +748,20 @@ module RubyIndexer
717
748
 
718
749
  private
719
750
 
751
+ # Always returns the linearized ancestors for the attached class, regardless of whether `name` refers to a singleton
752
+ # or attached namespace
753
+ sig { params(name: String).returns(T::Array[String]) }
754
+ def linearized_attached_ancestors(name)
755
+ name_parts = name.split("::")
756
+
757
+ if name_parts.last&.start_with?("<Class:")
758
+ attached_name = T.must(name_parts[0..-2]).join("::")
759
+ linearized_ancestors_of(attached_name)
760
+ else
761
+ linearized_ancestors_of(name)
762
+ end
763
+ end
764
+
720
765
  # Runs the registered included hooks
721
766
  sig { params(fully_qualified_name: String, nesting: T::Array[String]).void }
722
767
  def run_included_hooks(fully_qualified_name, nesting)
@@ -1561,6 +1561,23 @@ module RubyIndexer
1561
1561
  assert_equal("Foo::Bar", entry.name)
1562
1562
  end
1563
1563
 
1564
+ def test_first_unqualified_const_prefers_exact_matches
1565
+ index(<<~RUBY)
1566
+ module Foo
1567
+ class ParseResultType
1568
+ end
1569
+ end
1570
+
1571
+ module Namespace
1572
+ class Type
1573
+ end
1574
+ end
1575
+ RUBY
1576
+
1577
+ entry = T.must(@index.first_unqualified_const("Type")&.first)
1578
+ assert_equal("Namespace::Type", entry.name)
1579
+ end
1580
+
1564
1581
  def test_completion_does_not_duplicate_overridden_methods
1565
1582
  index(<<~RUBY)
1566
1583
  class Foo
@@ -2092,5 +2109,57 @@ module RubyIndexer
2092
2109
  refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
2093
2110
  assert_equal("I added this comment!", entry.comments)
2094
2111
  end
2112
+
2113
+ def test_instance_variable_completion_returns_class_variables_too
2114
+ index(<<~RUBY)
2115
+ class Parent
2116
+ @@abc = 123
2117
+ end
2118
+
2119
+ class Child < Parent
2120
+ @@adf = 123
2121
+
2122
+ def self.do
2123
+ end
2124
+ end
2125
+ RUBY
2126
+
2127
+ abc, adf = @index.instance_variable_completion_candidates("@", "Child::<Class:Child>")
2128
+
2129
+ refute_nil(abc)
2130
+ refute_nil(adf)
2131
+
2132
+ assert_equal("@@abc", abc.name)
2133
+ assert_equal("@@adf", adf.name)
2134
+ end
2135
+
2136
+ def test_class_variable_completion_from_singleton_context
2137
+ index(<<~RUBY)
2138
+ class Foo
2139
+ @@hello = 123
2140
+
2141
+ def self.do
2142
+ end
2143
+ end
2144
+ RUBY
2145
+
2146
+ candidates = @index.class_variable_completion_candidates("@@", "Foo::<Class:Foo>")
2147
+ refute_empty(candidates)
2148
+
2149
+ assert_equal("@@hello", candidates.first&.name)
2150
+ end
2151
+
2152
+ def test_resolve_class_variable_in_singleton_context
2153
+ index(<<~RUBY)
2154
+ class Foo
2155
+ @@hello = 123
2156
+ end
2157
+ RUBY
2158
+
2159
+ candidates = @index.resolve_class_variable("@@hello", "Foo::<Class:Foo>")
2160
+ refute_empty(candidates)
2161
+
2162
+ assert_equal("@@hello", candidates.first&.name)
2163
+ end
2095
2164
  end
2096
2165
  end
@@ -22,6 +22,7 @@ require "prism/visitor"
22
22
  require "language_server-protocol"
23
23
  require "rbs"
24
24
  require "fileutils"
25
+ require "open3"
25
26
 
26
27
  require "ruby-lsp"
27
28
  require "ruby_lsp/base_server"
@@ -19,7 +19,7 @@ module RubyLsp
19
19
  sig { returns(Interface::CodeActionRegistrationOptions) }
20
20
  def provider
21
21
  Interface::CodeActionRegistrationOptions.new(
22
- document_selector: [Interface::DocumentFilter.new(language: "ruby")],
22
+ document_selector: nil,
23
23
  resolve_provider: true,
24
24
  )
25
25
  end
@@ -15,7 +15,7 @@ module RubyLsp
15
15
  sig { returns(Interface::DiagnosticRegistrationOptions) }
16
16
  def provider
17
17
  Interface::DiagnosticRegistrationOptions.new(
18
- document_selector: [Interface::DocumentFilter.new(language: "ruby")],
18
+ document_selector: nil,
19
19
  inter_file_dependencies: false,
20
20
  workspace_diagnostics: false,
21
21
  )
@@ -13,13 +13,9 @@ module RubyLsp
13
13
  class << self
14
14
  extend T::Sig
15
15
 
16
- sig { returns(Interface::FoldingRangeRegistrationOptions) }
16
+ sig { returns(TrueClass) }
17
17
  def provider
18
- Interface::FoldingRangeRegistrationOptions.new(
19
- document_selector: [
20
- Interface::DocumentFilter.new(language: "ruby"),
21
- ],
22
- )
18
+ true
23
19
  end
24
20
  end
25
21
 
@@ -14,13 +14,9 @@ module RubyLsp
14
14
  class << self
15
15
  extend T::Sig
16
16
 
17
- sig { returns(Interface::DocumentFormattingRegistrationOptions) }
17
+ sig { returns(TrueClass) }
18
18
  def provider
19
- Interface::DocumentFormattingRegistrationOptions.new(
20
- document_selector: [
21
- Interface::DocumentFilter.new(language: "ruby"),
22
- ],
23
- )
19
+ true
24
20
  end
25
21
  end
26
22
 
@@ -14,7 +14,7 @@ module RubyLsp
14
14
  sig { returns(Interface::DocumentOnTypeFormattingRegistrationOptions) }
15
15
  def provider
16
16
  Interface::DocumentOnTypeFormattingRegistrationOptions.new(
17
- document_selector: [Interface::DocumentFilter.new(language: "ruby")],
17
+ document_selector: nil,
18
18
  first_trigger_character: "{",
19
19
  more_trigger_character: ["\n", "|", "d"],
20
20
  )
@@ -170,7 +170,7 @@ module RubyLsp
170
170
 
171
171
  sig { params(line: Integer, character: Integer).void }
172
172
  def move_cursor_to(line, character)
173
- return unless @client_name.start_with?("Visual Studio Code")
173
+ return unless /Visual Studio Code|Cursor/.match?(@client_name)
174
174
 
175
175
  position = Interface::Position.new(
176
176
  line: line,
@@ -17,7 +17,7 @@ module RubyLsp
17
17
  sig { returns(Interface::SemanticTokensRegistrationOptions) }
18
18
  def provider
19
19
  Interface::SemanticTokensRegistrationOptions.new(
20
- document_selector: [{ language: "ruby" }, { language: "erb" }],
20
+ document_selector: nil,
21
21
  legend: Interface::SemanticTokensLegend.new(
22
22
  token_types: ResponseBuilders::SemanticHighlighting::TOKEN_TYPES.keys,
23
23
  token_modifiers: ResponseBuilders::SemanticHighlighting::TOKEN_MODIFIERS.keys,
@@ -106,6 +106,8 @@ module RubyLsp
106
106
  end,
107
107
  ),
108
108
  )
109
+ when "rubyLsp/composeBundle"
110
+ compose_bundle(message)
109
111
  when "$/cancelRequest"
110
112
  @global_state.synchronize { @cancelled_requests << message[:params][:id] }
111
113
  when nil
@@ -283,6 +285,7 @@ module RubyLsp
283
285
  document_range_formatting_provider: true,
284
286
  experimental: {
285
287
  addon_detection: true,
288
+ compose_bundle: true,
286
289
  },
287
290
  ),
288
291
  serverInfo: {
@@ -1033,6 +1036,10 @@ module RubyLsp
1033
1036
  when Constant::FileChangeType::DELETED
1034
1037
  index.delete(uri)
1035
1038
  end
1039
+ rescue Errno::ENOENT
1040
+ # If a file is created and then delete immediately afterwards, we will process the created notification before we
1041
+ # receive the deleted one, but the file no longer exists. This may happen when running a test suite that creates
1042
+ # and deletes files automatically.
1036
1043
  end
1037
1044
 
1038
1045
  sig { params(uri: URI::Generic).void }
@@ -1282,5 +1289,54 @@ module RubyLsp
1282
1289
 
1283
1290
  addon.handle_window_show_message_response(result[:title])
1284
1291
  end
1292
+
1293
+ # NOTE: all servers methods are void because they can produce several messages for the client. The only reason this
1294
+ # method returns the created thread is to that we can join it in tests and avoid flakiness. The implementation is
1295
+ # not supposed to rely on the return of this method
1296
+ sig { params(message: T::Hash[Symbol, T.untyped]).returns(T.nilable(Thread)) }
1297
+ def compose_bundle(message)
1298
+ already_composed_path = File.join(@global_state.workspace_path, ".ruby-lsp", "bundle_is_composed")
1299
+ id = message[:id]
1300
+
1301
+ begin
1302
+ Bundler.with_original_env do
1303
+ Bundler::LockfileParser.new(Bundler.default_lockfile.read)
1304
+ end
1305
+ rescue Bundler::LockfileError => e
1306
+ send_message(Error.new(id: id, code: BUNDLE_COMPOSE_FAILED_CODE, message: e.message))
1307
+ return
1308
+ rescue Bundler::GemfileNotFound, Errno::ENOENT
1309
+ # We still compose the bundle if there's no Gemfile or if the lockfile got deleted
1310
+ end
1311
+
1312
+ # We compose the bundle in a thread so that the LSP continues to work while we're checking for its validity. Once
1313
+ # we return the response back to the editor, then the restart is triggered
1314
+ Thread.new do
1315
+ send_log_message("Recomposing the bundle ahead of restart")
1316
+
1317
+ _stdout, stderr, status = Bundler.with_unbundled_env do
1318
+ Open3.capture3(
1319
+ Gem.ruby,
1320
+ "-I",
1321
+ File.dirname(T.must(__dir__)),
1322
+ File.expand_path("../../exe/ruby-lsp-launcher", __dir__),
1323
+ @global_state.workspace_uri.to_s,
1324
+ chdir: @global_state.workspace_path,
1325
+ )
1326
+ end
1327
+
1328
+ if status&.exitstatus == 0
1329
+ # Create a signal for the restart that it can skip composing the bundle and launch directly
1330
+ FileUtils.touch(already_composed_path)
1331
+ send_message(Result.new(id: id, response: { success: true }))
1332
+ else
1333
+ # This special error code makes the extension avoid restarting in case we already know that the composed
1334
+ # bundle is not valid
1335
+ send_message(
1336
+ Error.new(id: id, code: BUNDLE_COMPOSE_FAILED_CODE, message: "Failed to compose bundle\n#{stderr}"),
1337
+ )
1338
+ end
1339
+ end
1340
+ end
1285
1341
  end
1286
1342
  end
@@ -57,6 +57,7 @@ module RubyLsp
57
57
  @lockfile_hash_path = T.let(@custom_dir + "main_lockfile_hash", Pathname)
58
58
  @last_updated_path = T.let(@custom_dir + "last_updated", Pathname)
59
59
  @error_path = T.let(@custom_dir + "install_error", Pathname)
60
+ @already_composed_path = T.let(@custom_dir + "bundle_is_composed", Pathname)
60
61
 
61
62
  dependencies, bundler_version = load_dependencies
62
63
  @dependencies = T.let(dependencies, T::Hash[String, T.untyped])
@@ -71,6 +72,23 @@ module RubyLsp
71
72
  def setup!
72
73
  raise BundleNotLocked if !@launcher && @gemfile&.exist? && !@lockfile&.exist?
73
74
 
75
+ # If the bundle was composed ahead of time using our custom `rubyLsp/composeBundle` request, then we can skip the
76
+ # entire process and just return the composed environment
77
+ if @already_composed_path.exist?
78
+ $stderr.puts("Ruby LSP> Composed bundle was set up ahead of time. Skipping...")
79
+ @already_composed_path.delete
80
+
81
+ env = bundler_settings_as_env
82
+ env["BUNDLE_GEMFILE"] = @custom_gemfile.exist? ? @custom_gemfile.to_s : @gemfile.to_s
83
+
84
+ if env["BUNDLE_PATH"]
85
+ env["BUNDLE_PATH"] = File.expand_path(env["BUNDLE_PATH"], @project_path)
86
+ end
87
+
88
+ env["BUNDLER_VERSION"] = @bundler_version.to_s if @bundler_version
89
+ return env
90
+ end
91
+
74
92
  # Automatically create and ignore the .ruby-lsp folder for users
75
93
  @custom_dir.mkpath unless @custom_dir.exist?
76
94
  ignore_file = @custom_dir + ".gitignore"
@@ -223,8 +241,7 @@ module RubyLsp
223
241
 
224
242
  # If either the Gemfile or the lockfile have been modified during the process of setting up the bundle, retry
225
243
  # composing the bundle from scratch
226
-
227
- if @gemfile && @lockfile
244
+ if @gemfile&.exist? && @lockfile&.exist?
228
245
  current_gemfile_hash = Digest::SHA256.hexdigest(@gemfile.read)
229
246
  current_lockfile_hash = Digest::SHA256.hexdigest(@lockfile.read)
230
247
 
@@ -37,6 +37,8 @@ module RubyLsp
37
37
  CODE = -32900
38
38
  end
39
39
 
40
+ BUNDLE_COMPOSE_FAILED_CODE = -33000
41
+
40
42
  # A notification to be sent to the client
41
43
  class Message
42
44
  extend T::Sig
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.6
4
+ version: 0.23.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-16 00:00:00.000000000 Z
10
+ date: 2025-01-31 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: language_server-protocol
@@ -218,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
218
  - !ruby/object:Gem::Version
219
219
  version: '0'
220
220
  requirements: []
221
- rubygems_version: 3.6.2
221
+ rubygems_version: 3.6.3
222
222
  specification_version: 4
223
223
  summary: An opinionated language server for Ruby
224
224
  test_files: []