ruby-lsp 0.26.1 → 0.26.2

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: c80f549675508ffbb28d649de04506adabec01eac9aa4c6eee057ec848adf858
4
- data.tar.gz: 71ea1a4d628444b98bc1173748f5aecf0d71bdc8d3dc80f33b2779c9c78d9de0
3
+ metadata.gz: a3c596f1104438061fe9ee2b890b980a7048e2137c10d34783d55defa0f17354
4
+ data.tar.gz: b9f328146d02d36436a48385f1156a3a94ce9f321123220a2316a794ab253695
5
5
  SHA512:
6
- metadata.gz: 7261bf15c095154ff36152492aa252cbd84b84f6e83eb458623c7bb9790a57957885a855c2ee10683b7035267177e323c013988befc02e96f3fdf0274d2312ca
7
- data.tar.gz: 74bcea4844e876230713400776bf7def1db44492bcf913526195b5d01919efd24ac69b517594ce2499e332184bf7ef4881e17e7694574bf4d35afabeda25b8c4
6
+ metadata.gz: 21c6b94baa433cf5c944a96f2ef8829f36ec81b0a093fb1e6fb5c53537698df6adc936f71ff2856bc68411d9ccefbd143cb75ee703d8d2b5a171e940faada191
7
+ data.tar.gz: 7e84f101f485088c24e2afccaaa779f8cfdae3bb91798ec24f30199402bc3bbd5e142ece40a86de7845cb342b31d68be5c953383b0a0b081bf388b0574b25ab9
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.26.1
1
+ 0.26.2
@@ -424,7 +424,10 @@ module RubyIndexer
424
424
  (parts.length - 1).downto(0) do |i|
425
425
  current_name = parts[0..i] #: as !nil
426
426
  .join("::")
427
- entry = @entries[current_name]&.first
427
+
428
+ entry = unless seen_names.include?(current_name)
429
+ @entries[current_name]&.first
430
+ end
428
431
 
429
432
  case entry
430
433
  when Entry::ConstantAlias
@@ -904,6 +907,9 @@ module RubyIndexer
904
907
  target = resolve(entry.target, entry.nesting, seen_names)
905
908
  return entry unless target
906
909
 
910
+ # Self referential alias can be unresolved we should bail out from resolving
911
+ return entry if target.first == entry
912
+
907
913
  target_name = target.first #: as !nil
908
914
  .name
909
915
  resolved_alias = Entry::ConstantAlias.new(target_name, entry)
@@ -1023,11 +1029,19 @@ module RubyIndexer
1023
1029
  name_parts.join("::")
1024
1030
  end
1025
1031
 
1032
+ # Tries to return direct entry from index then non seen canonicalized alias or nil
1026
1033
  #: (String full_name, Array[String] seen_names) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
1027
1034
  def direct_or_aliased_constant(full_name, seen_names)
1028
- entries = @entries[full_name] || @entries[follow_aliased_namespace(full_name)]
1035
+ if (entries = @entries[full_name])
1036
+ return entries.map do |e|
1037
+ e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e
1038
+ end #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias])?
1039
+ end
1040
+
1041
+ aliased = follow_aliased_namespace(full_name, seen_names)
1042
+ return if full_name == aliased || seen_names.include?(aliased)
1029
1043
 
1030
- entries&.map do |e|
1044
+ @entries[aliased]&.map do |e|
1031
1045
  e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e
1032
1046
  end #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias])?
1033
1047
  end
@@ -1152,6 +1152,46 @@ module RubyIndexer
1152
1152
  assert_equal(2, foo_entry.location.start_line)
1153
1153
  end
1154
1154
 
1155
+ def test_resolving_self_referential_constant_alias
1156
+ index(<<~RUBY)
1157
+ module A
1158
+ module B
1159
+ class C
1160
+ end
1161
+ end
1162
+ end
1163
+
1164
+ module A
1165
+ module D
1166
+ B = B::C
1167
+ end
1168
+ end
1169
+ RUBY
1170
+
1171
+ entry = @index.resolve("A::D::B", [])&.first #: as Entry::ConstantAlias
1172
+
1173
+ assert_kind_of(RubyIndexer::Entry::ConstantAlias, entry)
1174
+ assert_equal(10, entry.location.start_line)
1175
+ assert_equal("A::B::C", entry.target)
1176
+ end
1177
+
1178
+ def test_resolving_non_existing_self_referential_constant_alias
1179
+ index(<<~RUBY)
1180
+ module Foo
1181
+ SomeClass = ::SomeClass
1182
+ UNRESOLVED = SomeClass::CONSTANT
1183
+ end
1184
+ RUBY
1185
+
1186
+ entry = @index.resolve("Foo::UNRESOLVED", [])&.first #: as Entry::UnresolvedConstantAlias
1187
+ assert_kind_of(Entry::UnresolvedConstantAlias, entry)
1188
+ assert_equal(3, entry.location.start_line)
1189
+ assert_equal("SomeClass::CONSTANT", entry.target)
1190
+
1191
+ entry = @index.resolve("SomeClass::CONSTANT", ["Foo"])
1192
+ refute(entry)
1193
+ end
1194
+
1155
1195
  def test_resolving_qualified_references
1156
1196
  index(<<~RUBY)
1157
1197
  module Namespace
@@ -103,7 +103,7 @@ module RubyLsp
103
103
  # This method is only intended to be used in tests! Pops the latest response that would be sent to the client
104
104
  #: -> untyped
105
105
  def pop_response
106
- @outgoing_queue.pop
106
+ @outgoing_queue.pop(timeout: 20) || raise("No message received from server")
107
107
  end
108
108
 
109
109
  # This method is only intended to be used in tests! Pushes a message to the incoming queue directly
@@ -92,7 +92,8 @@ module RubyLsp
92
92
  Prism::RequiredParameterNode, Prism::RestParameterNode
93
93
  [target, node_value(target)]
94
94
  when Prism::ModuleNode, Prism::ClassNode, Prism::SingletonClassNode, Prism::DefNode, Prism::CaseNode,
95
- Prism::WhileNode, Prism::UntilNode, Prism::ForNode, Prism::IfNode, Prism::UnlessNode
95
+ Prism::WhileNode, Prism::UntilNode, Prism::ForNode, Prism::IfNode, Prism::UnlessNode, Prism::BlockNode,
96
+ Prism::LambdaNode, Prism::BeginNode
96
97
  [target, nil]
97
98
  end
98
99
 
@@ -157,6 +158,9 @@ module RubyLsp
157
158
  :on_for_node_enter,
158
159
  :on_if_node_enter,
159
160
  :on_unless_node_enter,
161
+ :on_block_node_enter,
162
+ :on_lambda_node_enter,
163
+ :on_begin_node_enter,
160
164
  )
161
165
  end
162
166
  end
@@ -551,6 +555,27 @@ module RubyLsp
551
555
  add_matching_end_highlights(node.keyword_loc, node.end_keyword_loc)
552
556
  end
553
557
 
558
+ #: (Prism::BlockNode node) -> void
559
+ def on_block_node_enter(node)
560
+ return unless @target.is_a?(Prism::BlockNode)
561
+
562
+ add_matching_end_highlights(node.opening_loc, node.closing_loc)
563
+ end
564
+
565
+ #: (Prism::LambdaNode node) -> void
566
+ def on_lambda_node_enter(node)
567
+ return unless @target.is_a?(Prism::LambdaNode)
568
+
569
+ add_matching_end_highlights(node.opening_loc, node.closing_loc)
570
+ end
571
+
572
+ #: (Prism::BeginNode node) -> void
573
+ def on_begin_node_enter(node)
574
+ return unless @target.is_a?(Prism::BeginNode)
575
+
576
+ add_matching_end_highlights(node.begin_keyword_loc, node.end_keyword_loc)
577
+ end
578
+
554
579
  private
555
580
 
556
581
  #: (Prism::Node node, Array[singleton(Prism::Node)] classes) -> bool?
@@ -58,13 +58,11 @@ module RubyLsp
58
58
 
59
59
  #: (Prism::CallNode) -> void
60
60
  def on_call_node_enter(node) # rubocop:disable RubyLsp/UseRegisterWithHandlerMethod
61
- return unless in_spec_context?
62
-
63
61
  case node.name
64
62
  when :describe
65
63
  handle_describe(node)
66
64
  when :it, :specify
67
- handle_example(node)
65
+ handle_example(node) if in_spec_context?
68
66
  end
69
67
  end
70
68
 
@@ -117,10 +115,7 @@ module RubyLsp
117
115
 
118
116
  #: (Prism::CallNode) -> void
119
117
  def handle_example(node)
120
- # Minitest formats the descriptions into test method names by using the count of examples with the description
121
- # We are not guaranteed to discover examples in the exact order using static analysis, so we use the line number
122
- # instead. Note that anonymous examples mixed with meta-programming will not be handled correctly
123
- description = extract_description(node) || "anonymous"
118
+ description = extract_it_description(node)
124
119
  line = node.location.start_line - 1
125
120
  parent = latest_group
126
121
  return unless parent.is_a?(Requests::Support::TestItem)
@@ -141,16 +136,37 @@ module RubyLsp
141
136
 
142
137
  #: (Prism::CallNode) -> String?
143
138
  def extract_description(node)
139
+ arguments = node.arguments&.arguments
140
+ return unless arguments
141
+
142
+ parts = arguments.map { |arg| extract_argument_content(arg) }
143
+ return if parts.empty?
144
+
145
+ parts.join("::")
146
+ end
147
+
148
+ #: (Prism::CallNode) -> String
149
+ def extract_it_description(node)
150
+ # Minitest formats the descriptions into test method names by using the count of examples with the description
151
+ # We are not guaranteed to discover examples in the exact order using static analysis, so we use the line number
152
+ # instead. Note that anonymous examples mixed with meta-programming will not be handled correctly
144
153
  first_argument = node.arguments&.arguments&.first
145
- return unless first_argument
154
+ return "anonymous" unless first_argument
155
+
156
+ extract_argument_content(first_argument) || "anonymous"
157
+ end
146
158
 
147
- case first_argument
159
+ #: (Prism::Node) -> String?
160
+ def extract_argument_content(arg)
161
+ case arg
148
162
  when Prism::StringNode
149
- first_argument.content
163
+ arg.content
164
+ when Prism::SymbolNode
165
+ arg.value
150
166
  when Prism::ConstantReadNode, Prism::ConstantPathNode
151
- constant_name(first_argument)
167
+ constant_name(arg)
152
168
  else
153
- first_argument.slice
169
+ arg.slice
154
170
  end
155
171
  end
156
172
 
@@ -190,12 +206,13 @@ module RubyLsp
190
206
  end
191
207
 
192
208
  # Specs only using describes
193
- first_group = @spec_group_id_stack.find { |i| i.is_a?(DescribeGroup) }
194
- return unless first_group
209
+ first_group_index = @spec_group_id_stack.index { |i| i.is_a?(DescribeGroup) }
210
+ return unless first_group_index
195
211
 
212
+ first_group = @spec_group_id_stack[first_group_index] #: as !nil
196
213
  item = @response_builder[first_group.id] #: as !nil
197
214
 
198
- @spec_group_id_stack[1..] #: as !nil
215
+ @spec_group_id_stack[first_group_index + 1..] #: as !nil
199
216
  .each do |group|
200
217
  next unless group.is_a?(DescribeGroup)
201
218
 
@@ -61,11 +61,26 @@ module RubyLsp
61
61
 
62
62
  #: (Prism::ClassNode node, String fully_qualified_name) -> Array[String]
63
63
  def calc_attached_ancestors(node, fully_qualified_name)
64
- @index.linearized_ancestors_of(fully_qualified_name)
65
- rescue RubyIndexer::Index::NonExistingNamespaceError
66
- # When there are dynamic parts in the constant path, we will not have indexed the namespace. We can still
67
- # provide test functionality if the class inherits directly from Test::Unit::TestCase or Minitest::Test
68
- [node.superclass&.slice].compact
64
+ superclass = node.superclass
65
+
66
+ begin
67
+ ancestors = @index.linearized_ancestors_of(fully_qualified_name)
68
+ # If the project has no bundle and a test class inherits from `Minitest::Test`, the linearized ancestors will
69
+ # not include the parent class because we never indexed it in the first place. Here we add the superclass
70
+ # directly, so that we can support running tests in projects without a bundle
71
+ return ancestors if ancestors.length > 1
72
+
73
+ # If all we found is the class itself, then manually include the parent class
74
+ if ancestors.first == fully_qualified_name && superclass
75
+ return [*ancestors, superclass.slice]
76
+ end
77
+
78
+ ancestors
79
+ rescue RubyIndexer::Index::NonExistingNamespaceError
80
+ # When there are dynamic parts in the constant path, we will not have indexed the namespace. We can still
81
+ # provide test functionality if the class inherits directly from Test::Unit::TestCase or Minitest::Test
82
+ [superclass&.slice].compact
83
+ end
69
84
  end
70
85
 
71
86
  #: (Prism::ConstantPathNode | Prism::ConstantReadNode | Prism::ConstantPathTargetNode | Prism::CallNode | Prism::MissingNode node) -> String
@@ -33,13 +33,15 @@ module RubyLsp
33
33
 
34
34
  if tags.include?("test_dir")
35
35
  if children.empty?
36
- full_files.concat(Dir.glob(
37
- "#{path}/**/{*_test,test_*,*_spec}.rb",
38
- File::Constants::FNM_EXTGLOB | File::Constants::FNM_PATHNAME,
39
- ))
36
+ full_files.concat(
37
+ Dir.glob(
38
+ "#{path}/**/{*_test,test_*,*_spec}.rb",
39
+ File::Constants::FNM_EXTGLOB | File::Constants::FNM_PATHNAME,
40
+ ).map! { |p| Shellwords.escape(p) },
41
+ )
40
42
  end
41
43
  elsif tags.include?("test_file")
42
- full_files << path if children.empty?
44
+ full_files << Shellwords.escape(path) if children.empty?
43
45
  elsif tags.include?("test_group")
44
46
  # If all of the children of the current test group are other groups, then there's no need to add it to the
45
47
  # aggregated examples
@@ -114,7 +116,7 @@ module RubyLsp
114
116
  end
115
117
 
116
118
  load_path = spec?(file_path) ? "-Ispec" : "-Itest"
117
- "#{COMMAND} #{load_path} #{file_path} --name \"/#{regex}/\""
119
+ "#{COMMAND} #{load_path} #{Shellwords.escape(file_path)} --name \"/#{regex}/\""
118
120
  end
119
121
 
120
122
  #: (String, Hash[String, Hash[Symbol, untyped]]) -> Array[String]
@@ -125,7 +127,7 @@ module RubyLsp
125
127
  Shellwords.escape(TestDiscovery::DYNAMIC_REFERENCE_MARKER),
126
128
  ".*",
127
129
  )
128
- command = +"#{COMMAND} -Itest #{file_path} --testcase \"/^#{group_regex}\\$/\""
130
+ command = +"#{COMMAND} -Itest #{Shellwords.escape(file_path)} --testcase \"/^#{group_regex}\\$/\""
129
131
 
130
132
  unless examples.empty?
131
133
  command << if examples.length == 1
@@ -145,7 +147,7 @@ module RubyLsp
145
147
  MINITEST_REPORTER_PATH = File.expand_path("../test_reporters/minitest_reporter.rb", __dir__) #: String
146
148
  TEST_UNIT_REPORTER_PATH = File.expand_path("../test_reporters/test_unit_reporter.rb", __dir__) #: String
147
149
  BASE_COMMAND = begin
148
- Bundler.with_original_env { Bundler.default_lockfile }
150
+ Bundler.with_unbundled_env { Bundler.default_lockfile }
149
151
  "bundle exec ruby"
150
152
  rescue Bundler::GemfileNotFound
151
153
  "ruby"
@@ -35,24 +35,78 @@ module RubyLsp
35
35
 
36
36
  #: -> Array[String]
37
37
  def find_relevant_paths
38
- candidate_paths = Dir.glob(File.join("**", relevant_filename_pattern))
38
+ patterns = relevant_filename_patterns
39
+
40
+ candidate_paths = patterns.flat_map do |pattern|
41
+ Dir.glob(File.join(search_root, "**", pattern))
42
+ end
43
+
39
44
  return [] if candidate_paths.empty?
40
45
 
41
- find_most_similar_with_jaccard(candidate_paths).map { File.join(@workspace_path, _1) }
46
+ find_most_similar_with_jaccard(candidate_paths).map { |path| File.expand_path(path, @workspace_path) }
42
47
  end
43
48
 
49
+ # Determine the search roots based on the closest test directories.
50
+ # This scopes the search to reduce the number of files that need to be checked.
44
51
  #: -> String
45
- def relevant_filename_pattern
46
- input_basename = File.basename(@path, File.extname(@path))
52
+ def search_root
53
+ current_path = File.join(".", @path)
54
+ current_dir = File.dirname(current_path)
55
+ while current_dir != "."
56
+ dir_basename = File.basename(current_dir)
57
+
58
+ # If current directory is a test directory, return its parent as search root
59
+ if TEST_KEYWORDS.include?(dir_basename)
60
+ return File.dirname(current_dir)
61
+ end
47
62
 
48
- relevant_basename_pattern =
49
- if input_basename.match?(TEST_PATTERN)
50
- input_basename.gsub(TEST_PATTERN, "")
51
- else
52
- "{{#{TEST_PREFIX_GLOB}}#{input_basename},#{input_basename}{#{TEST_SUFFIX_GLOB}}}"
63
+ # Search the test directories by walking up the directory tree
64
+ begin
65
+ contains_test_dir = Dir
66
+ .entries(current_dir)
67
+ .filter { |entry| TEST_KEYWORDS.include?(entry) }
68
+ .any? { |entry| File.directory?(File.join(current_dir, entry)) }
69
+
70
+ return current_dir if contains_test_dir
71
+ rescue Errno::EACCES, Errno::ENOENT
72
+ # Skip directories we can't read
53
73
  end
54
74
 
55
- "#{relevant_basename_pattern}#{File.extname(@path)}"
75
+ # Move up one level
76
+ parent_dir = File.dirname(current_dir)
77
+ current_dir = parent_dir
78
+ end
79
+
80
+ "."
81
+ end
82
+
83
+ #: -> Array[String]
84
+ def relevant_filename_patterns
85
+ extension = File.extname(@path)
86
+ input_basename = File.basename(@path, extension)
87
+
88
+ if input_basename.match?(TEST_PATTERN)
89
+ # Test file -> find implementation
90
+ base = input_basename.gsub(TEST_PATTERN, "")
91
+ parent_dir = File.basename(File.dirname(@path))
92
+
93
+ # If test file is in a directory matching the implementation name
94
+ # (e.g., go_to_relevant_file/test_go_to_relevant_file_a.rb)
95
+ # return patterns for both the base file name and the parent directory name
96
+ if base.include?(parent_dir) && base != parent_dir
97
+ ["#{base}#{extension}", "#{parent_dir}#{extension}"]
98
+ else
99
+ ["#{base}#{extension}"]
100
+ end
101
+ else
102
+ # Implementation file -> find tests (including in matching directory)
103
+ [
104
+ "{#{TEST_PREFIX_GLOB}}#{input_basename}#{extension}",
105
+ "#{input_basename}{#{TEST_SUFFIX_GLOB}}#{extension}",
106
+ "#{input_basename}/{#{TEST_PREFIX_GLOB}}*#{extension}",
107
+ "#{input_basename}/*{#{TEST_SUFFIX_GLOB}}#{extension}",
108
+ ]
109
+ end
56
110
  end
57
111
 
58
112
  # Using the Jaccard algorithm to determine the similarity between the
@@ -140,21 +140,25 @@ module RubyLsp
140
140
  end
141
141
  end
142
142
 
143
- #: (RubyIndexer::Entry entry) -> Integer?
143
+ #: (RubyIndexer::Entry entry) -> Integer
144
144
  def kind_for_entry(entry)
145
145
  case entry
146
146
  when RubyIndexer::Entry::Class
147
147
  Constant::SymbolKind::CLASS
148
148
  when RubyIndexer::Entry::Module
149
149
  Constant::SymbolKind::NAMESPACE
150
- when RubyIndexer::Entry::Constant
150
+ when RubyIndexer::Entry::Constant, RubyIndexer::Entry::UnresolvedConstantAlias, RubyIndexer::Entry::ConstantAlias
151
151
  Constant::SymbolKind::CONSTANT
152
- when RubyIndexer::Entry::Method
152
+ when RubyIndexer::Entry::Method, RubyIndexer::Entry::UnresolvedMethodAlias, RubyIndexer::Entry::MethodAlias
153
153
  entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
154
154
  when RubyIndexer::Entry::Accessor
155
155
  Constant::SymbolKind::PROPERTY
156
- when RubyIndexer::Entry::InstanceVariable
156
+ when RubyIndexer::Entry::InstanceVariable, RubyIndexer::Entry::ClassVariable
157
157
  Constant::SymbolKind::FIELD
158
+ when RubyIndexer::Entry::GlobalVariable
159
+ Constant::SymbolKind::VARIABLE
160
+ else
161
+ Constant::SymbolKind::NULL
158
162
  end
159
163
  end
160
164
  end
@@ -61,6 +61,14 @@ module RubyLsp
61
61
  "RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
62
62
  ] #: Array[String]
63
63
 
64
+ # Functionality was introduced in 1.75.0 but had issues with autocorrect
65
+ REUSE_PRISM_RESULT = begin
66
+ gem("rubocop", ">= 1.80.1")
67
+ true
68
+ rescue LoadError
69
+ false
70
+ end #: bool
71
+
64
72
  #: Array[::RuboCop::Cop::Offense]
65
73
  attr_reader :offenses
66
74
 
@@ -81,7 +89,7 @@ module RubyLsp
81
89
  @offenses = [] #: Array[::RuboCop::Cop::Offense]
82
90
  @errors = [] #: Array[String]
83
91
  @warnings = [] #: Array[String]
84
- # @prism_result = nil #: Prism::ParseLexResult?
92
+ @prism_result = nil #: Prism::ParseLexResult?
85
93
 
86
94
  args += DEFAULT_ARGS
87
95
  rubocop_options = ::RuboCop::Options.new.parse(args).first
@@ -101,11 +109,7 @@ module RubyLsp
101
109
  @warnings = []
102
110
  @offenses = []
103
111
  @options[:stdin] = contents
104
-
105
- # Setting the Prism result before running the RuboCop runner makes it reuse the existing AST and avoids
106
- # double-parsing. Unfortunately, this leads to a bunch of cops failing to execute properly under LSP mode.
107
- # Uncomment this once reusing the Prism result is more stable
108
- # @prism_result = prism_result
112
+ @prism_result = prism_result if REUSE_PRISM_RESULT
109
113
 
110
114
  super([path])
111
115
 
@@ -303,7 +303,7 @@ module RubyLsp
303
303
  @current_request_id,
304
304
  Interface::RelativePattern.new(
305
305
  base_uri: @global_state.workspace_uri.to_s,
306
- pattern: "{.rubocop.yml,.rubocop}",
306
+ pattern: "{.rubocop.yml,.rubocop,.rubocop_todo.yml}",
307
307
  ),
308
308
  registration_id: "rubocop-watcher",
309
309
  ))
@@ -1045,7 +1045,7 @@ module RubyLsp
1045
1045
 
1046
1046
  file_name = File.basename(file_path)
1047
1047
 
1048
- if file_name == ".rubocop.yml" || file_name == ".rubocop"
1048
+ if file_name == ".rubocop.yml" || file_name == ".rubocop" || file_name == ".rubocop_todo.yml"
1049
1049
  handle_rubocop_config_change(uri)
1050
1050
  end
1051
1051
  end
@@ -234,13 +234,14 @@ module RubyLsp
234
234
  # If no error occurred, then clear previous errors
235
235
  @error_path.delete if @error_path.exist?
236
236
  $stderr.puts("Ruby LSP> Composed bundle installation complete")
237
- rescue Errno::EPIPE
238
- # If the $stderr pipe was closed by the client, for example when closing the editor during running bundle
239
- # install, we don't want to write the error to a file or else we will report to telemetry on the next launch and
240
- # it does not represent an actual error.
237
+ rescue Errno::EPIPE, Bundler::HTTPError
238
+ # There are cases where we expect certain errors to happen occasionally, and we don't want to write them to
239
+ # a file, which would report to telemetry on the next launch.
241
240
  #
242
- # This situation may happen because while running bundle install, the server is not yet ready to receive
243
- # shutdown requests and we may continue doing work until the process is killed.
241
+ # - The $stderr pipe might be closed by the client, for example when closing the editor during running bundle
242
+ # install. This situation may happen because, while running bundle install, the server is not yet ready to
243
+ # receive shutdown requests and we may continue doing work until the process is killed.
244
+ # - Bundler might also encounter a network error.
244
245
  @error_path.delete if @error_path.exist?
245
246
  rescue => e
246
247
  # Write the error object to a file so that we can read it from the parent process
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.1
4
+ version: 0.26.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
@@ -216,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
216
  - !ruby/object:Gem::Version
217
217
  version: '0'
218
218
  requirements: []
219
- rubygems_version: 3.6.9
219
+ rubygems_version: 3.7.2
220
220
  specification_version: 4
221
221
  summary: An opinionated language server for Ruby
222
222
  test_files: []