ruby-lsp 0.23.2 → 0.23.3

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: 5d295233e64f7b79aa061f243c61c6d5bfb69cbdc5dac64474106473d7033bc8
4
- data.tar.gz: 559fbc2fb40b2a8043fefbf332cb4bf94ce8e3953299d6740d1d21034b79e92b
3
+ metadata.gz: 95642b8034d20684e2596755f391591d6dfffc9021e23a6e2efd0b9a0e500eb0
4
+ data.tar.gz: 6db469fda24144ce71eb0c2d8434251b3bf01a800035d85bea5e8e6801cf5120
5
5
  SHA512:
6
- metadata.gz: 52e0176c0e9516801f94d9bd387ad6acfcd640c500443527448b69f3b55e2627aafa3bea75a60e131c21c0b06b309aba28a98b263344d20ce6406e1e66b69a37
7
- data.tar.gz: 52b47878d9c5a71dadd618a5562a30901abf3fe167f71e08d92f1a5418710a4e360043ae08d553975ad7008d7f1fb657a9b650d05a311ddcfc92157a7283ec6c
6
+ metadata.gz: 69365797e36c6597b43b5067da2e10b6c634cdb9121081db0e7c16c657fe12e2aa72042ba7beb07480b1cbb4a24c9a37a7a71f5a49a1be42923adb7a85a80715
7
+ data.tar.gz: 22695e4a4fd4e72738b43c32e9a693ed9895033e82240317700cde5583537b0ad6e7d8ce530a110624c57278d5a08c4eeb207ae010a4db99b3885bc241c5caa4
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.23.2
1
+ 0.23.3
@@ -45,6 +45,12 @@ rescue Errno::ECHILD
45
45
  # In theory, the child process can finish before we even get to the wait call, but that is not an error
46
46
  end
47
47
 
48
+ error_path = File.join(".ruby-lsp", "install_error")
49
+
50
+ install_error = if File.exist?(error_path)
51
+ Marshal.load(File.read(error_path))
52
+ end
53
+
48
54
  begin
49
55
  bundle_env_path = File.join(".ruby-lsp", "bundle_env")
50
56
  # We can't require `bundler/setup` because that file prematurely exits the process if setup fails. However, we can't
@@ -67,21 +73,21 @@ begin
67
73
  rescue StandardError => e
68
74
  # If installing gems failed for any reason, we don't want to exit the process prematurely. We can still provide most
69
75
  # features in a degraded mode. We simply save the error so that we can report to the user that certain gems might be
70
- # missing, but we respect the LSP life cycle
71
- setup_error = e
72
- $stderr.puts("Failed to set up composed Bundle\n#{e.full_message}")
76
+ # missing, but we respect the LSP life cycle.
77
+ #
78
+ # If an install error occurred and one of the gems is not installed, Bundler.setup is guaranteed to fail with
79
+ # `Bundler::GemNotFound`. We don't set `setup_error` here because that would essentially report the same problem twice
80
+ # to telemetry, which is not useful
81
+ unless install_error && e.is_a?(Bundler::GemNotFound)
82
+ setup_error = e
83
+ $stderr.puts("Failed to set up composed Bundle\n#{e.full_message}")
84
+ end
73
85
 
74
86
  # If Bundler.setup fails, we need to restore the original $LOAD_PATH so that we can still require the Ruby LSP server
75
87
  # in degraded mode
76
88
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
77
89
  end
78
90
 
79
- error_path = File.join(".ruby-lsp", "install_error")
80
-
81
- install_error = if File.exist?(error_path)
82
- Marshal.load(File.read(error_path))
83
- end
84
-
85
91
  # Now that the bundle is set up, we can begin actually launching the server. Note that `Bundler.setup` will have already
86
92
  # configured the load path using the version of the Ruby LSP present in the composed bundle. Do not push any Ruby LSP
87
93
  # paths into the load path manually or we may end up requiring the wrong version of the gem
@@ -287,7 +287,6 @@ module RubyIndexer
287
287
  when :module_function
288
288
  handle_module_function(node)
289
289
  when :private_class_method
290
- @visibility_stack.push(VisibilityScope.new(visibility: Entry::Visibility::PRIVATE))
291
290
  handle_private_class_method(node)
292
291
  end
293
292
 
@@ -975,39 +974,42 @@ module RubyIndexer
975
974
 
976
975
  sig { params(node: Prism::CallNode).void }
977
976
  def handle_private_class_method(node)
978
- node.arguments&.arguments&.each do |argument|
979
- string_or_symbol_nodes = case argument
980
- when Prism::StringNode, Prism::SymbolNode
981
- [argument]
982
- when Prism::ArrayNode
983
- argument.elements
984
- else
985
- []
986
- end
977
+ arguments = node.arguments&.arguments
978
+ return unless arguments
987
979
 
988
- unless string_or_symbol_nodes.empty?
989
- # pop the visibility off since there isn't a method definition following `private_class_method`
990
- @visibility_stack.pop
991
- end
980
+ # If we're passing a method definition directly to `private_class_method`, push a new private scope. That will be
981
+ # applied when the indexer finds the method definition and then popped on `call_node_leave`
982
+ if arguments.first.is_a?(Prism::DefNode)
983
+ @visibility_stack.push(VisibilityScope.new(visibility: Entry::Visibility::PRIVATE))
984
+ return
985
+ end
992
986
 
993
- string_or_symbol_nodes.each do |string_or_symbol_node|
994
- method_name = case string_or_symbol_node
995
- when Prism::StringNode
996
- string_or_symbol_node.content
997
- when Prism::SymbolNode
998
- string_or_symbol_node.value
999
- end
1000
- next unless method_name
987
+ owner_name = @owner_stack.last&.name
988
+ return unless owner_name
1001
989
 
1002
- owner_name = @owner_stack.last&.name
1003
- next unless owner_name
990
+ # private_class_method accepts strings, symbols or arrays of strings and symbols as arguments. Here we build a
991
+ # single list of all of the method names that have to be made private
992
+ arrays, others = T.cast(
993
+ arguments.partition { |argument| argument.is_a?(Prism::ArrayNode) },
994
+ [T::Array[Prism::ArrayNode], T::Array[Prism::Node]],
995
+ )
996
+ arrays.each { |array| others.concat(array.elements) }
1004
997
 
1005
- entries = @index.resolve_method(method_name, @index.existing_or_new_singleton_class(owner_name).name)
1006
- next unless entries
998
+ names = others.filter_map do |argument|
999
+ case argument
1000
+ when Prism::StringNode
1001
+ argument.unescaped
1002
+ when Prism::SymbolNode
1003
+ argument.value
1004
+ end
1005
+ end
1007
1006
 
1008
- entries.each do |entry|
1009
- entry.visibility = Entry::Visibility::PRIVATE
1010
- end
1007
+ names.each do |name|
1008
+ entries = @index.resolve_method(name, @index.existing_or_new_singleton_class(owner_name).name)
1009
+ next unless entries
1010
+
1011
+ entries.each do |entry|
1012
+ entry.visibility = Entry::Visibility::PRIVATE
1011
1013
  end
1012
1014
  end
1013
1015
  end
@@ -909,6 +909,21 @@ module RubyIndexer
909
909
  assert_equal("Foo", T.must(entry.owner).name)
910
910
  end
911
911
 
912
+ def test_making_several_class_methods_private
913
+ index(<<~RUBY)
914
+ class Foo
915
+ def self.bar; end
916
+ def self.baz; end
917
+ def self.qux; end
918
+
919
+ private_class_method :bar, :baz, :qux
920
+
921
+ def initialize
922
+ end
923
+ end
924
+ RUBY
925
+ end
926
+
912
927
  private
913
928
 
914
929
  sig { params(entry: Entry::Method, call_string: String).void }
@@ -90,8 +90,7 @@ module RubyLsp
90
90
  # The following requests need to be executed in the main thread directly to avoid concurrency issues. Everything
91
91
  # else is pushed into the incoming queue
92
92
  case method
93
- when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange",
94
- "$/cancelRequest"
93
+ when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
95
94
  process_message(message)
96
95
  when "shutdown"
97
96
  @global_state.synchronize do
@@ -97,33 +97,31 @@ module RubyLsp
97
97
 
98
98
  sig { params(edits: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).void }
99
99
  def push_edits(edits, version:)
100
- @global_state.synchronize do
101
- edits.each do |edit|
102
- range = edit[:range]
103
- scanner = create_scanner
100
+ edits.each do |edit|
101
+ range = edit[:range]
102
+ scanner = create_scanner
104
103
 
105
- start_position = scanner.find_char_position(range[:start])
106
- end_position = scanner.find_char_position(range[:end])
104
+ start_position = scanner.find_char_position(range[:start])
105
+ end_position = scanner.find_char_position(range[:end])
107
106
 
108
- @source[start_position...end_position] = edit[:text]
109
- end
107
+ @source[start_position...end_position] = edit[:text]
108
+ end
110
109
 
111
- @version = version
112
- @needs_parsing = true
113
- @cache.clear
110
+ @version = version
111
+ @needs_parsing = true
112
+ @cache.clear
114
113
 
115
- last_edit = edits.last
116
- return unless last_edit
114
+ last_edit = edits.last
115
+ return unless last_edit
117
116
 
118
- last_edit_range = last_edit[:range]
117
+ last_edit_range = last_edit[:range]
119
118
 
120
- @last_edit = if last_edit_range[:start] == last_edit_range[:end]
121
- Insert.new(last_edit_range)
122
- elsif last_edit[:text].empty?
123
- Delete.new(last_edit_range)
124
- else
125
- Replace.new(last_edit_range)
126
- end
119
+ @last_edit = if last_edit_range[:start] == last_edit_range[:end]
120
+ Insert.new(last_edit_range)
121
+ elsif last_edit[:text].empty?
122
+ Delete.new(last_edit_range)
123
+ else
124
+ Replace.new(last_edit_range)
127
125
  end
128
126
  end
129
127
 
@@ -330,7 +330,8 @@ module RubyLsp
330
330
 
331
331
  methods.each do |target_method|
332
332
  uri = target_method.uri
333
- next if sorbet_level_true_or_higher?(@sorbet_level) && not_in_dependencies?(T.must(uri.full_path))
333
+ full_path = uri.full_path
334
+ next if sorbet_level_true_or_higher?(@sorbet_level) && (!full_path || not_in_dependencies?(full_path))
334
335
 
335
336
  @response_builder << Interface::LocationLink.new(
336
337
  target_uri: uri.to_s,
@@ -403,7 +404,11 @@ module RubyLsp
403
404
  # additional behavior on top of jumping to RBIs. The only sigil where Sorbet cannot handle constants is typed
404
405
  # ignore
405
406
  uri = entry.uri
406
- next if @sorbet_level != RubyDocument::SorbetLevel::Ignore && not_in_dependencies?(T.must(uri.full_path))
407
+ full_path = uri.full_path
408
+
409
+ if @sorbet_level != RubyDocument::SorbetLevel::Ignore && (!full_path || not_in_dependencies?(full_path))
410
+ next
411
+ end
407
412
 
408
413
  @response_builder << Interface::LocationLink.new(
409
414
  target_uri: uri.to_s,
@@ -116,8 +116,8 @@ module RubyLsp
116
116
  T.must(@global_state.index[fully_qualified_name]).each do |entry|
117
117
  # Do not rename files that are not part of the workspace
118
118
  uri = entry.uri
119
- file_path = T.must(uri.full_path)
120
- next unless file_path.start_with?(@global_state.workspace_path)
119
+ file_path = uri.full_path
120
+ next unless file_path&.start_with?(@global_state.workspace_path)
121
121
 
122
122
  case entry
123
123
  when RubyIndexer::Entry::Class, RubyIndexer::Entry::Module, RubyIndexer::Entry::Constant,
@@ -22,10 +22,10 @@ module RubyLsp
22
22
  def perform
23
23
  @index.fuzzy_search(@query).filter_map do |entry|
24
24
  uri = entry.uri
25
- file_path = T.must(uri.full_path)
25
+ file_path = uri.full_path
26
26
 
27
27
  # We only show symbols declared in the workspace
28
- in_dependencies = !not_in_dependencies?(file_path)
28
+ in_dependencies = file_path && !not_in_dependencies?(file_path)
29
29
  next if in_dependencies
30
30
 
31
31
  # We should never show private symbols when searching the entire workspace
@@ -359,48 +359,52 @@ module RubyLsp
359
359
 
360
360
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
361
361
  def text_document_did_open(message)
362
- text_document = message.dig(:params, :textDocument)
363
- language_id = case text_document[:languageId]
364
- when "erb", "eruby"
365
- Document::LanguageId::ERB
366
- when "rbs"
367
- Document::LanguageId::RBS
368
- else
369
- Document::LanguageId::Ruby
370
- end
362
+ @global_state.synchronize do
363
+ text_document = message.dig(:params, :textDocument)
364
+ language_id = case text_document[:languageId]
365
+ when "erb", "eruby"
366
+ Document::LanguageId::ERB
367
+ when "rbs"
368
+ Document::LanguageId::RBS
369
+ else
370
+ Document::LanguageId::Ruby
371
+ end
371
372
 
372
- document = @store.set(
373
- uri: text_document[:uri],
374
- source: text_document[:text],
375
- version: text_document[:version],
376
- language_id: language_id,
377
- )
373
+ document = @store.set(
374
+ uri: text_document[:uri],
375
+ source: text_document[:text],
376
+ version: text_document[:version],
377
+ language_id: language_id,
378
+ )
378
379
 
379
- if document.past_expensive_limit? && text_document[:uri].scheme == "file"
380
- log_message = <<~MESSAGE
381
- The file #{text_document[:uri].path} is too long. For performance reasons, semantic highlighting and
382
- diagnostics will be disabled.
383
- MESSAGE
380
+ if document.past_expensive_limit? && text_document[:uri].scheme == "file"
381
+ log_message = <<~MESSAGE
382
+ The file #{text_document[:uri].path} is too long. For performance reasons, semantic highlighting and
383
+ diagnostics will be disabled.
384
+ MESSAGE
384
385
 
385
- send_message(
386
- Notification.new(
387
- method: "window/logMessage",
388
- params: Interface::LogMessageParams.new(
389
- type: Constant::MessageType::WARNING,
390
- message: log_message,
386
+ send_message(
387
+ Notification.new(
388
+ method: "window/logMessage",
389
+ params: Interface::LogMessageParams.new(
390
+ type: Constant::MessageType::WARNING,
391
+ message: log_message,
392
+ ),
391
393
  ),
392
- ),
393
- )
394
+ )
395
+ end
394
396
  end
395
397
  end
396
398
 
397
399
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
398
400
  def text_document_did_close(message)
399
- uri = message.dig(:params, :textDocument, :uri)
400
- @store.delete(uri)
401
+ @global_state.synchronize do
402
+ uri = message.dig(:params, :textDocument, :uri)
403
+ @store.delete(uri)
401
404
 
402
- # Clear diagnostics for the closed file, so that they no longer appear in the problems tab
403
- send_message(Notification.publish_diagnostics(uri.to_s, []))
405
+ # Clear diagnostics for the closed file, so that they no longer appear in the problems tab
406
+ send_message(Notification.publish_diagnostics(uri.to_s, []))
407
+ end
404
408
  end
405
409
 
406
410
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
@@ -408,7 +412,9 @@ module RubyLsp
408
412
  params = message[:params]
409
413
  text_document = params[:textDocument]
410
414
 
411
- @store.push_edits(uri: text_document[:uri], edits: params[:contentChanges], version: text_document[:version])
415
+ @global_state.synchronize do
416
+ @store.push_edits(uri: text_document[:uri], edits: params[:contentChanges], version: text_document[:version])
417
+ end
412
418
  end
413
419
 
414
420
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
@@ -1254,10 +1260,10 @@ module RubyLsp
1254
1260
  return
1255
1261
  end
1256
1262
 
1257
- return unless indexing_options
1258
-
1259
1263
  configuration = @global_state.index.configuration
1260
1264
  configuration.workspace_path = @global_state.workspace_path
1265
+ return unless indexing_options
1266
+
1261
1267
  # The index expects snake case configurations, but VS Code standardizes on camel case settings
1262
1268
  configuration.apply_config(indexing_options.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase })
1263
1269
  end
@@ -65,15 +65,13 @@ module RubyLsp
65
65
  ).returns(Document[T.untyped])
66
66
  end
67
67
  def set(uri:, source:, version:, language_id:)
68
- @global_state.synchronize do
69
- @state[uri.to_s] = case language_id
70
- when Document::LanguageId::ERB
71
- ERBDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
72
- when Document::LanguageId::RBS
73
- RBSDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
74
- else
75
- RubyDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
76
- end
68
+ @state[uri.to_s] = case language_id
69
+ when Document::LanguageId::ERB
70
+ ERBDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
71
+ when Document::LanguageId::RBS
72
+ RBSDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
73
+ else
74
+ RubyDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
77
75
  end
78
76
  end
79
77
 
@@ -94,9 +92,7 @@ module RubyLsp
94
92
 
95
93
  sig { params(uri: URI::Generic).void }
96
94
  def delete(uri)
97
- @global_state.synchronize do
98
- @state.delete(uri.to_s)
99
- end
95
+ @state.delete(uri.to_s)
100
96
  end
101
97
 
102
98
  sig { params(uri: URI::Generic).returns(T::Boolean) }
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.2
4
+ version: 0.23.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-08 00:00:00.000000000 Z
10
+ date: 2025-01-09 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: language_server-protocol