ruby-lsp 0.23.10 → 0.23.11

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: 3a0d78055f2f6bf861e581a5b5a2d1321d3a8452b23d638becb6e64da925d842
4
- data.tar.gz: '0397aa5a123ed08757606db1be3690b50cba847a372f52da25fb64a6fb5816ce'
3
+ metadata.gz: b93894c0d2c2687def87d9e173c7a9e45e810088613cb902c2a4b1a9d93a8404
4
+ data.tar.gz: 9e92f360c8367cde864ac1a5dd2305170a975fa3164e6fc2c1d6f492396fbbc5
5
5
  SHA512:
6
- metadata.gz: a14d101646bd32467724aeedb60892c5c06e775a57d749623cc1e76dbc42ee6d82eca10e2fa1149900365eff59ee57c20300bb043a3fdcf1330961b6bbd94918
7
- data.tar.gz: 23b339c5854620771e7b505381dad64cf3e8d89ed2850a19c7a299e72d2363202e1e74327c05d27d8fb7fae508abb7141e5a858319b2841c8c914233e28e076e
6
+ metadata.gz: fc2172fba1c50192cb86d2dfc619c633cf756f3ebb574caaaeabb81fe23d283b7b896f48fe23981d29c472fce98248137171d119b33c75d1a7f6fafc73c7a775
7
+ data.tar.gz: 03b0b5987fc8dcc6c989ce6c5df55e16fff906836ef74aa993ddc445b50c5d3458775fee1a31b9e228710df44f80b8338390ef1fdf75d464deac4e38fe822644
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.23.10
1
+ 0.23.11
@@ -87,7 +87,7 @@ module RubyIndexer
87
87
  # Find the group that is either immediately or two lines above the current entry
88
88
  correct_group = grouped.find do |group|
89
89
  comment_end_line = group.last.location.start_line
90
- (comment_end_line - 1..comment_end_line).cover?(@location.start_line - 1)
90
+ (comment_end_line..comment_end_line + 1).cover?(@location.start_line - 1)
91
91
  end
92
92
 
93
93
  # If we found something, we join the comments together. Otherwise, the entry has no documentation and we don't
@@ -21,9 +21,9 @@ module RubyIndexer
21
21
  # Returns the real nesting of a constant name taking into account top level
22
22
  # references that may be included anywhere in the name or nesting where that
23
23
  # constant was found
24
- sig { params(stack: T::Array[String], name: String).returns(T::Array[String]) }
24
+ sig { params(stack: T::Array[String], name: T.nilable(String)).returns(T::Array[String]) }
25
25
  def actual_nesting(stack, name)
26
- nesting = stack + [name]
26
+ nesting = name ? stack + [name] : stack
27
27
  corrected_nesting = []
28
28
 
29
29
  nesting.reverse_each do |name|
@@ -43,11 +43,18 @@ module RubyIndexer
43
43
  Prism::ConstantPathNode,
44
44
  Prism::ConstantReadNode,
45
45
  Prism::ConstantPathTargetNode,
46
+ Prism::CallNode,
47
+ Prism::MissingNode,
46
48
  ),
47
49
  ).returns(T.nilable(String))
48
50
  end
49
51
  def constant_name(node)
50
- node.full_name
52
+ case node
53
+ when Prism::CallNode, Prism::MissingNode
54
+ nil
55
+ else
56
+ node.full_name
57
+ end
51
58
  rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
52
59
  Prism::ConstantPathNode::MissingNodesInConstantPathError
53
60
  nil
@@ -666,5 +666,80 @@ module RubyIndexer
666
666
  method = @index["baz"]&.first
667
667
  assert_equal("Foo::Bar::<Class:Bar>", method.owner.name)
668
668
  end
669
+
670
+ def test_lazy_comments_with_spaces_are_properly_attributed
671
+ path = File.join(Dir.pwd, "lib", "foo.rb")
672
+ source = <<~RUBY
673
+ require "whatever"
674
+
675
+ # These comments belong to the declaration below
676
+ # They have to be associated with it
677
+
678
+ class Foo
679
+ end
680
+ RUBY
681
+ File.write(path, source)
682
+ @index.index_single(URI::Generic.from_path(path: path), source, collect_comments: false)
683
+
684
+ entry = @index["Foo"].first
685
+
686
+ begin
687
+ assert_equal(<<~COMMENTS.chomp, entry.comments)
688
+ These comments belong to the declaration below
689
+ They have to be associated with it
690
+ COMMENTS
691
+ ensure
692
+ FileUtils.rm(path)
693
+ end
694
+ end
695
+
696
+ def test_lazy_comments_with_no_spaces_are_properly_attributed
697
+ path = File.join(Dir.pwd, "lib", "foo.rb")
698
+ source = <<~RUBY
699
+ require "whatever"
700
+
701
+ # These comments belong to the declaration below
702
+ # They have to be associated with it
703
+ class Foo
704
+ end
705
+ RUBY
706
+ File.write(path, source)
707
+ @index.index_single(URI::Generic.from_path(path: path), source, collect_comments: false)
708
+
709
+ entry = @index["Foo"].first
710
+
711
+ begin
712
+ assert_equal(<<~COMMENTS.chomp, entry.comments)
713
+ These comments belong to the declaration below
714
+ They have to be associated with it
715
+ COMMENTS
716
+ ensure
717
+ FileUtils.rm(path)
718
+ end
719
+ end
720
+
721
+ def test_lazy_comments_with_two_extra_spaces_are_properly_ignored
722
+ path = File.join(Dir.pwd, "lib", "foo.rb")
723
+ source = <<~RUBY
724
+ require "whatever"
725
+
726
+ # These comments don't belong to the declaration below
727
+ # They will not be associated with it
728
+
729
+
730
+ class Foo
731
+ end
732
+ RUBY
733
+ File.write(path, source)
734
+ @index.index_single(URI::Generic.from_path(path: path), source, collect_comments: false)
735
+
736
+ entry = @index["Foo"].first
737
+
738
+ begin
739
+ assert_empty(entry.comments)
740
+ ensure
741
+ FileUtils.rm(path)
742
+ end
743
+ end
669
744
  end
670
745
  end
@@ -2161,5 +2161,26 @@ module RubyIndexer
2161
2161
 
2162
2162
  assert_equal("@@hello", candidates.first&.name)
2163
2163
  end
2164
+
2165
+ def test_actual_nesting
2166
+ assert_equal(["Foo"], Index.actual_nesting([], "Foo"))
2167
+ assert_equal(["TopLevel", "Foo"], Index.actual_nesting(["First", "::TopLevel"], "Foo"))
2168
+ assert_equal(["TopLevel", "Another", "Foo"], Index.actual_nesting(["::TopLevel", "Another"], "Foo"))
2169
+ assert_equal(["TopLevel"], Index.actual_nesting(["First", "::TopLevel"], nil))
2170
+ end
2171
+
2172
+ def test_constant_name
2173
+ node = Prism.parse("class var::Foo; end").value.statements.body.first.constant_path
2174
+ assert_nil(Index.constant_name(node))
2175
+
2176
+ node = Prism.parse("class ; end").value.statements.body.first.constant_path
2177
+ assert_nil(Index.constant_name(node))
2178
+
2179
+ node = Prism.parse("class method_call; end").value.statements.body.first.constant_path
2180
+ assert_nil(Index.constant_name(node))
2181
+
2182
+ node = Prism.parse("class Foo; end").value.statements.body.first.constant_path
2183
+ assert_equal("Foo", Index.constant_name(node))
2184
+ end
2164
2185
  end
2165
2186
  end
@@ -90,7 +90,8 @@ 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"
93
+ when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange",
94
+ "rubyLsp/diagnoseState"
94
95
  process_message(message)
95
96
  when "shutdown"
96
97
  @global_state.synchronize do
@@ -24,6 +24,7 @@ require "rbs"
24
24
  require "fileutils"
25
25
  require "open3"
26
26
  require "securerandom"
27
+ require "shellwords"
27
28
 
28
29
  require "ruby-lsp"
29
30
  require "ruby_lsp/base_server"
@@ -50,6 +51,7 @@ require "ruby_lsp/response_builders/document_symbol"
50
51
  require "ruby_lsp/response_builders/hover"
51
52
  require "ruby_lsp/response_builders/semantic_highlighting"
52
53
  require "ruby_lsp/response_builders/signature_help"
54
+ require "ruby_lsp/response_builders/test_collection"
53
55
 
54
56
  # Request support
55
57
  require "ruby_lsp/requests/support/selection_range"
@@ -60,6 +62,7 @@ require "ruby_lsp/requests/support/formatter"
60
62
  require "ruby_lsp/requests/support/rubocop_runner"
61
63
  require "ruby_lsp/requests/support/rubocop_formatter"
62
64
  require "ruby_lsp/requests/support/syntax_tree_formatter"
65
+ require "ruby_lsp/requests/support/test_item"
63
66
 
64
67
  # Requests
65
68
  require "ruby_lsp/requests/request"
@@ -70,6 +73,7 @@ require "ruby_lsp/requests/completion_resolve"
70
73
  require "ruby_lsp/requests/completion"
71
74
  require "ruby_lsp/requests/definition"
72
75
  require "ruby_lsp/requests/diagnostics"
76
+ require "ruby_lsp/requests/discover_tests"
73
77
  require "ruby_lsp/requests/document_highlight"
74
78
  require "ruby_lsp/requests/document_link"
75
79
  require "ruby_lsp/requests/document_symbol"
@@ -0,0 +1,164 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Listeners
6
+ class TestStyle
7
+ extend T::Sig
8
+ include Requests::Support::Common
9
+
10
+ ACCESS_MODIFIERS = [:public, :private, :protected].freeze
11
+ DYNAMIC_REFERENCE_MARKER = "<dynamic_reference>"
12
+
13
+ sig do
14
+ params(
15
+ response_builder: ResponseBuilders::TestCollection,
16
+ global_state: GlobalState,
17
+ dispatcher: Prism::Dispatcher,
18
+ uri: URI::Generic,
19
+ ).void
20
+ end
21
+ def initialize(response_builder, global_state, dispatcher, uri)
22
+ @response_builder = response_builder
23
+ @uri = uri
24
+ @index = T.let(global_state.index, RubyIndexer::Index)
25
+ @visibility_stack = T.let([:public], T::Array[Symbol])
26
+ @nesting = T.let([], T::Array[String])
27
+
28
+ dispatcher.register(
29
+ self,
30
+ :on_class_node_enter,
31
+ :on_class_node_leave,
32
+ :on_module_node_enter,
33
+ :on_module_node_leave,
34
+ :on_def_node_enter,
35
+ :on_call_node_enter,
36
+ :on_call_node_leave,
37
+ )
38
+ end
39
+
40
+ sig { params(node: Prism::ClassNode).void }
41
+ def on_class_node_enter(node)
42
+ @visibility_stack << :public
43
+ name = constant_name(node.constant_path)
44
+ name ||= name_with_dynamic_reference(node.constant_path)
45
+
46
+ fully_qualified_name = RubyIndexer::Index.actual_nesting(@nesting, name).join("::")
47
+
48
+ attached_ancestors = begin
49
+ @index.linearized_ancestors_of(fully_qualified_name)
50
+ rescue RubyIndexer::Index::NonExistingNamespaceError
51
+ # When there are dynamic parts in the constant path, we will not have indexed the namespace. We can still
52
+ # provide test functionality if the class inherits directly from Test::Unit::TestCase or Minitest::Test
53
+ [node.superclass&.slice].compact
54
+ end
55
+
56
+ if attached_ancestors.include?("Test::Unit::TestCase") ||
57
+ non_declarative_minitest?(attached_ancestors, fully_qualified_name)
58
+
59
+ @response_builder.add(Requests::Support::TestItem.new(
60
+ fully_qualified_name,
61
+ fully_qualified_name,
62
+ @uri,
63
+ range_from_node(node),
64
+ ))
65
+ end
66
+
67
+ @nesting << name
68
+ end
69
+
70
+ sig { params(node: Prism::ModuleNode).void }
71
+ def on_module_node_enter(node)
72
+ @visibility_stack << :public
73
+
74
+ name = constant_name(node.constant_path)
75
+ name ||= name_with_dynamic_reference(node.constant_path)
76
+
77
+ @nesting << name
78
+ end
79
+
80
+ sig { params(node: Prism::ModuleNode).void }
81
+ def on_module_node_leave(node)
82
+ @visibility_stack.pop
83
+ @nesting.pop
84
+ end
85
+
86
+ sig { params(node: Prism::ClassNode).void }
87
+ def on_class_node_leave(node)
88
+ @visibility_stack.pop
89
+ @nesting.pop
90
+ end
91
+
92
+ sig { params(node: Prism::DefNode).void }
93
+ def on_def_node_enter(node)
94
+ return if @visibility_stack.last != :public
95
+
96
+ name = node.name.to_s
97
+ return unless name.start_with?("test_")
98
+
99
+ current_group_name = RubyIndexer::Index.actual_nesting(@nesting, nil).join("::")
100
+
101
+ # If we're finding a test method, but for the wrong framework, then the group test item will not have been
102
+ # previously pushed and thus we return early and avoid adding items for a framework this listener is not
103
+ # interested in
104
+ test_item = @response_builder[current_group_name]
105
+ return unless test_item
106
+
107
+ test_item.add(Requests::Support::TestItem.new(
108
+ "#{current_group_name}##{name}",
109
+ name,
110
+ @uri,
111
+ range_from_node(node),
112
+ ))
113
+ end
114
+
115
+ sig { params(node: Prism::CallNode).void }
116
+ def on_call_node_enter(node)
117
+ name = node.name
118
+ return unless ACCESS_MODIFIERS.include?(name)
119
+
120
+ @visibility_stack << name
121
+ end
122
+
123
+ sig { params(node: Prism::CallNode).void }
124
+ def on_call_node_leave(node)
125
+ name = node.name
126
+ return unless ACCESS_MODIFIERS.include?(name)
127
+ return unless node.arguments&.arguments
128
+
129
+ @visibility_stack.pop
130
+ end
131
+
132
+ private
133
+
134
+ sig { params(attached_ancestors: T::Array[String], fully_qualified_name: String).returns(T::Boolean) }
135
+ def non_declarative_minitest?(attached_ancestors, fully_qualified_name)
136
+ return false unless attached_ancestors.include?("Minitest::Test")
137
+
138
+ # We only support regular Minitest tests. The declarative syntax provided by ActiveSupport is handled by the
139
+ # Rails add-on
140
+ name_parts = fully_qualified_name.split("::")
141
+ singleton_name = "#{name_parts.join("::")}::<Class:#{name_parts.last}>"
142
+ !@index.linearized_ancestors_of(singleton_name).include?("ActiveSupport::Testing::Declarative")
143
+ rescue RubyIndexer::Index::NonExistingNamespaceError
144
+ true
145
+ end
146
+
147
+ sig do
148
+ params(
149
+ node: T.any(
150
+ Prism::ConstantPathNode,
151
+ Prism::ConstantReadNode,
152
+ Prism::ConstantPathTargetNode,
153
+ Prism::CallNode,
154
+ Prism::MissingNode,
155
+ ),
156
+ ).returns(String)
157
+ end
158
+ def name_with_dynamic_reference(node)
159
+ slice = node.slice
160
+ slice.gsub(/((?<=::)|^)[a-z]\w*/, DYNAMIC_REFERENCE_MARKER)
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,62 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "ruby_lsp/listeners/test_style"
5
+
6
+ module RubyLsp
7
+ module Requests
8
+ # This is a custom request to ask the server to parse a test file and discover all available examples in it. Add-ons
9
+ # can augment the behavior through listeners, allowing them to handle discovery for different frameworks
10
+ class DiscoverTests < Request
11
+ extend T::Sig
12
+ include Support::Common
13
+
14
+ sig { params(global_state: GlobalState, document: RubyDocument, dispatcher: Prism::Dispatcher).void }
15
+ def initialize(global_state, document, dispatcher)
16
+ super()
17
+ @global_state = global_state
18
+ @document = document
19
+ @dispatcher = dispatcher
20
+ @response_builder = T.let(ResponseBuilders::TestCollection.new, ResponseBuilders::TestCollection)
21
+ @index = T.let(global_state.index, RubyIndexer::Index)
22
+ end
23
+
24
+ sig { override.returns(T::Array[Support::TestItem]) }
25
+ def perform
26
+ uri = @document.uri
27
+
28
+ # We normally only index test files once they are opened in the editor to save memory and avoid doing
29
+ # unnecessary work. If the file is already opened and we already indexed it, then we can just discover the tests
30
+ # straight away.
31
+ #
32
+ # However, if the user navigates to a specific test file from the explorer with nothing opened in the UI, then
33
+ # we will not have indexed the test file yet and trying to linearize the ancestor of the class will fail. In
34
+ # this case, we have to instantiate the indexer listener first, so that we insert classes, modules and methods
35
+ # in the index first and then discover the tests, all in the same traversal.
36
+ if @index.entries_for(uri.to_s)
37
+ Listeners::TestStyle.new(@response_builder, @global_state, @dispatcher, @document.uri)
38
+ @dispatcher.visit(@document.parse_result.value)
39
+ else
40
+ @global_state.synchronize do
41
+ RubyIndexer::DeclarationListener.new(
42
+ @index,
43
+ @dispatcher,
44
+ @document.parse_result,
45
+ uri,
46
+ collect_comments: true,
47
+ )
48
+
49
+ Listeners::TestStyle.new(@response_builder, @global_state, @dispatcher, @document.uri)
50
+
51
+ # Dispatch the events both for indexing the test file and discovering the tests. The order here is
52
+ # important because we need the index to be aware of the existing classes/modules/methods before the test
53
+ # listeners can do their work
54
+ @dispatcher.visit(@document.parse_result.value)
55
+ end
56
+ end
57
+
58
+ @response_builder.response
59
+ end
60
+ end
61
+ end
62
+ end
@@ -141,6 +141,8 @@ module RubyLsp
141
141
  Prism::ConstantPathNode,
142
142
  Prism::ConstantReadNode,
143
143
  Prism::ConstantPathTargetNode,
144
+ Prism::CallNode,
145
+ Prism::MissingNode,
144
146
  ),
145
147
  ).returns(T.nilable(String))
146
148
  end
@@ -0,0 +1,59 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ module Support
7
+ # Represents a test item as defined by the VS Code interface to be used in the test explorer
8
+ # See https://code.visualstudio.com/api/references/vscode-api#TestItem
9
+ #
10
+ # Note: this test item object can only represent test groups or examples discovered inside files. It cannot be
11
+ # used to represent test files, directories or workspaces
12
+ class TestItem
13
+ extend T::Sig
14
+
15
+ sig { returns(String) }
16
+ attr_reader :id, :label
17
+
18
+ sig { params(id: String, label: String, uri: URI::Generic, range: Interface::Range).void }
19
+ def initialize(id, label, uri, range)
20
+ @id = id
21
+ @label = label
22
+ @uri = uri
23
+ @range = range
24
+ @children = T.let({}, T::Hash[String, TestItem])
25
+ end
26
+
27
+ sig { params(item: TestItem).void }
28
+ def add(item)
29
+ if @children.key?(item.id)
30
+ raise ResponseBuilders::TestCollection::DuplicateIdError, "TestItem ID is already in use"
31
+ end
32
+
33
+ @children[item.id] = item
34
+ end
35
+
36
+ sig { params(id: String).returns(T.nilable(TestItem)) }
37
+ def [](id)
38
+ @children[id]
39
+ end
40
+
41
+ sig { returns(T::Array[TestItem]) }
42
+ def children
43
+ @children.values
44
+ end
45
+
46
+ sig { returns(T::Hash[Symbol, T.untyped]) }
47
+ def to_hash
48
+ {
49
+ id: @id,
50
+ label: @label,
51
+ uri: @uri,
52
+ range: @range,
53
+ children: children.map(&:to_hash),
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module ResponseBuilders
6
+ class TestCollection < ResponseBuilder
7
+ class DuplicateIdError < StandardError; end
8
+
9
+ extend T::Sig
10
+ extend T::Generic
11
+
12
+ ResponseType = type_member { { fixed: Requests::Support::TestItem } }
13
+
14
+ sig { void }
15
+ def initialize
16
+ super
17
+ @items = T.let({}, T::Hash[String, ResponseType])
18
+ end
19
+
20
+ sig { params(item: ResponseType).void }
21
+ def add(item)
22
+ raise DuplicateIdError, "TestItem ID is already in use" if @items.key?(item.id)
23
+
24
+ @items[item.id] = item
25
+ end
26
+
27
+ sig { params(id: String).returns(T.nilable(ResponseType)) }
28
+ def [](id)
29
+ @items[id]
30
+ end
31
+
32
+ sig { override.returns(T::Array[ResponseType]) }
33
+ def response
34
+ @items.values
35
+ end
36
+ end
37
+ end
38
+ end
@@ -108,6 +108,10 @@ module RubyLsp
108
108
  )
109
109
  when "rubyLsp/composeBundle"
110
110
  compose_bundle(message)
111
+ when "rubyLsp/diagnoseState"
112
+ diagnose_state(message)
113
+ when "rubyLsp/discoverTests"
114
+ discover_tests(message)
111
115
  when "$/cancelRequest"
112
116
  @global_state.synchronize { @cancelled_requests << message[:params][:id] }
113
117
  when nil
@@ -1368,5 +1372,47 @@ module RubyLsp
1368
1372
  end
1369
1373
  end
1370
1374
  end
1375
+
1376
+ # Returns internal state information for debugging purposes
1377
+ sig { params(message: T::Hash[Symbol, T.untyped]).void }
1378
+ def diagnose_state(message)
1379
+ documents = {}
1380
+ @store.each { |uri, document| documents[uri] = document.source }
1381
+
1382
+ send_message(
1383
+ Result.new(
1384
+ id: message[:id],
1385
+ response: {
1386
+ workerAlive: @worker.alive?,
1387
+ backtrace: @worker.backtrace,
1388
+ documents: documents,
1389
+ incomingQueueSize: @incoming_queue.length,
1390
+ },
1391
+ ),
1392
+ )
1393
+ end
1394
+
1395
+ # Discovers all available test groups and examples in a given file taking into consideration the merged response of
1396
+ # all add-ons
1397
+ sig { params(message: T::Hash[Symbol, T.untyped]).void }
1398
+ def discover_tests(message)
1399
+ document = @store.get(message.dig(:params, :textDocument, :uri))
1400
+
1401
+ unless document.is_a?(RubyDocument)
1402
+ send_empty_response(message[:id])
1403
+ return
1404
+ end
1405
+
1406
+ cached_response = document.cache_get("rubyLsp/discoverTests")
1407
+ if cached_response != Document::EMPTY_CACHE
1408
+ send_message(Result.new(id: message[:id], response: cached_response.map(&:to_hash)))
1409
+ return
1410
+ end
1411
+
1412
+ items = Requests::DiscoverTests.new(@global_state, document, Prism::Dispatcher.new).perform
1413
+ document.cache_set("rubyLsp/discoverTests", items)
1414
+
1415
+ send_message(Result.new(id: message[:id], response: items.map(&:to_hash)))
1416
+ end
1371
1417
  end
1372
1418
  end
@@ -158,7 +158,8 @@ module RubyLsp
158
158
  # If there's a top level Gemfile, we want to evaluate from the composed bundle. We get the source from the top
159
159
  # level Gemfile, so if there isn't one we need to add a default source
160
160
  if @gemfile&.exist? && @lockfile&.exist?
161
- parts << "eval_gemfile(File.expand_path(\"../#{@gemfile_name}\", __dir__))"
161
+ gemfile_path = @gemfile.relative_path_from(@custom_dir.realpath)
162
+ parts << "eval_gemfile(File.expand_path(\"#{gemfile_path}\", __dir__))"
162
163
  else
163
164
  parts.unshift('source "https://rubygems.org"')
164
165
  end
@@ -360,7 +361,7 @@ module RubyLsp
360
361
  # setting name `e` is `path` with a value of `vendor/bundle`, then it will return `"BUNDLE_PATH" =>
361
362
  # "vendor/bundle"`
362
363
  settings.all.to_h do |e|
363
- key = Bundler::Settings.key_for(e)
364
+ key = settings.key_for(e)
364
365
  value = Array(settings[e]).join(":").tr(" ", ":")
365
366
 
366
367
  [key, value]
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.10
4
+ version: 0.23.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-02-10 00:00:00.000000000 Z
10
+ date: 2025-02-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: language_server-protocol
@@ -140,6 +140,7 @@ files:
140
140
  - lib/ruby_lsp/listeners/inlay_hints.rb
141
141
  - lib/ruby_lsp/listeners/semantic_highlighting.rb
142
142
  - lib/ruby_lsp/listeners/signature_help.rb
143
+ - lib/ruby_lsp/listeners/test_style.rb
143
144
  - lib/ruby_lsp/load_sorbet.rb
144
145
  - lib/ruby_lsp/node_context.rb
145
146
  - lib/ruby_lsp/rbs_document.rb
@@ -150,6 +151,7 @@ files:
150
151
  - lib/ruby_lsp/requests/completion_resolve.rb
151
152
  - lib/ruby_lsp/requests/definition.rb
152
153
  - lib/ruby_lsp/requests/diagnostics.rb
154
+ - lib/ruby_lsp/requests/discover_tests.rb
153
155
  - lib/ruby_lsp/requests/document_highlight.rb
154
156
  - lib/ruby_lsp/requests/document_link.rb
155
157
  - lib/ruby_lsp/requests/document_symbol.rb
@@ -178,6 +180,7 @@ files:
178
180
  - lib/ruby_lsp/requests/support/sorbet.rb
179
181
  - lib/ruby_lsp/requests/support/source_uri.rb
180
182
  - lib/ruby_lsp/requests/support/syntax_tree_formatter.rb
183
+ - lib/ruby_lsp/requests/support/test_item.rb
181
184
  - lib/ruby_lsp/requests/type_hierarchy_supertypes.rb
182
185
  - lib/ruby_lsp/requests/workspace_symbol.rb
183
186
  - lib/ruby_lsp/response_builders/collection_response_builder.rb
@@ -186,6 +189,7 @@ files:
186
189
  - lib/ruby_lsp/response_builders/response_builder.rb
187
190
  - lib/ruby_lsp/response_builders/semantic_highlighting.rb
188
191
  - lib/ruby_lsp/response_builders/signature_help.rb
192
+ - lib/ruby_lsp/response_builders/test_collection.rb
189
193
  - lib/ruby_lsp/ruby_document.rb
190
194
  - lib/ruby_lsp/scope.rb
191
195
  - lib/ruby_lsp/scripts/compose_bundle.rb