ruby-lsp 0.13.3 → 0.14.0

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/VERSION +1 -1
  4. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +4 -8
  5. data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +5 -1
  6. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +4 -2
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +8 -3
  8. data/lib/ruby_indexer/test/classes_and_modules_test.rb +9 -0
  9. data/lib/ruby_indexer/test/index_test.rb +27 -0
  10. data/lib/ruby_lsp/addon.rb +21 -10
  11. data/lib/ruby_lsp/check_docs.rb +8 -8
  12. data/lib/ruby_lsp/executor.rb +28 -10
  13. data/lib/ruby_lsp/internal.rb +1 -1
  14. data/lib/ruby_lsp/listeners/code_lens.rb +54 -55
  15. data/lib/ruby_lsp/listeners/completion.rb +17 -16
  16. data/lib/ruby_lsp/listeners/definition.rb +10 -16
  17. data/lib/ruby_lsp/listeners/document_highlight.rb +6 -11
  18. data/lib/ruby_lsp/listeners/document_link.rb +6 -12
  19. data/lib/ruby_lsp/listeners/document_symbol.rb +95 -55
  20. data/lib/ruby_lsp/listeners/folding_ranges.rb +19 -23
  21. data/lib/ruby_lsp/listeners/hover.rb +26 -30
  22. data/lib/ruby_lsp/listeners/inlay_hints.rb +7 -13
  23. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -124
  24. data/lib/ruby_lsp/listeners/signature_help.rb +11 -13
  25. data/lib/ruby_lsp/requests/code_lens.rb +9 -17
  26. data/lib/ruby_lsp/requests/completion.rb +7 -9
  27. data/lib/ruby_lsp/requests/definition.rb +10 -22
  28. data/lib/ruby_lsp/requests/document_highlight.rb +7 -5
  29. data/lib/ruby_lsp/requests/document_link.rb +7 -6
  30. data/lib/ruby_lsp/requests/document_symbol.rb +5 -11
  31. data/lib/ruby_lsp/requests/folding_ranges.rb +11 -6
  32. data/lib/ruby_lsp/requests/hover.rb +18 -24
  33. data/lib/ruby_lsp/requests/inlay_hints.rb +7 -8
  34. data/lib/ruby_lsp/requests/on_type_formatting.rb +12 -2
  35. data/lib/ruby_lsp/requests/semantic_highlighting.rb +10 -8
  36. data/lib/ruby_lsp/requests/signature_help.rb +53 -18
  37. data/lib/ruby_lsp/requests/support/common.rb +23 -10
  38. data/lib/ruby_lsp/requests/support/dependency_detector.rb +5 -1
  39. data/lib/ruby_lsp/requests.rb +0 -1
  40. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +29 -0
  41. data/lib/ruby_lsp/response_builders/document_symbol.rb +57 -0
  42. data/lib/ruby_lsp/response_builders/hover.rb +49 -0
  43. data/lib/ruby_lsp/response_builders/response_builder.rb +16 -0
  44. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +199 -0
  45. data/lib/ruby_lsp/response_builders/signature_help.rb +28 -0
  46. data/lib/ruby_lsp/response_builders.rb +13 -0
  47. data/lib/ruby_lsp/server.rb +3 -3
  48. data/lib/ruby_lsp/setup_bundler.rb +30 -5
  49. data/lib/ruby_lsp/store.rb +4 -4
  50. metadata +14 -9
  51. data/lib/ruby_lsp/listener.rb +0 -33
  52. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +0 -73
@@ -2,13 +2,12 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "shellwords"
5
- require_relative "../listener"
6
5
 
7
6
  module RubyLsp
8
7
  module Listeners
9
- class CodeLens < Listener
8
+ class CodeLens
10
9
  extend T::Sig
11
- extend T::Generic
10
+ include Requests::Support::Common
12
11
 
13
12
  BASE_COMMAND = T.let(
14
13
  begin
@@ -21,31 +20,25 @@ module RubyLsp
21
20
  )
22
21
  ACCESS_MODIFIERS = T.let([:public, :private, :protected], T::Array[Symbol])
23
22
  SUPPORTED_TEST_LIBRARIES = T.let(["minitest", "test-unit"], T::Array[String])
24
-
25
- ResponseType = type_member { { fixed: T::Array[Interface::CodeLens] } }
26
-
27
- sig { override.returns(ResponseType) }
28
- attr_reader :_response
23
+ DESCRIBE_KEYWORD = T.let(:describe, Symbol)
24
+ IT_KEYWORD = T.let(:it, Symbol)
29
25
 
30
26
  sig do
31
27
  params(
28
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
32
29
  uri: URI::Generic,
33
- lenses_configuration: RequestConfig,
34
30
  dispatcher: Prism::Dispatcher,
35
31
  ).void
36
32
  end
37
- def initialize(uri, lenses_configuration, dispatcher)
33
+ def initialize(response_builder, uri, dispatcher)
34
+ @response_builder = response_builder
38
35
  @uri = T.let(uri, URI::Generic)
39
- @_response = T.let([], ResponseType)
40
36
  @path = T.let(uri.to_standardized_path, T.nilable(String))
41
37
  # visibility_stack is a stack of [current_visibility, previous_visibility]
42
38
  @visibility_stack = T.let([[:public, :public]], T::Array[T::Array[T.nilable(Symbol)]])
43
- @class_stack = T.let([], T::Array[String])
39
+ @group_stack = T.let([], T::Array[String])
44
40
  @group_id = T.let(1, Integer)
45
41
  @group_id_stack = T.let([], T::Array[Integer])
46
- @lenses_configuration = lenses_configuration
47
-
48
- super(dispatcher)
49
42
 
50
43
  dispatcher.register(
51
44
  self,
@@ -61,13 +54,13 @@ module RubyLsp
61
54
  def on_class_node_enter(node)
62
55
  @visibility_stack.push([:public, :public])
63
56
  class_name = node.constant_path.slice
64
- @class_stack.push(class_name)
57
+ @group_stack.push(class_name)
65
58
 
66
59
  if @path && class_name.end_with?("Test")
67
60
  add_test_code_lens(
68
61
  node,
69
62
  name: class_name,
70
- command: generate_test_command(class_name: class_name),
63
+ command: generate_test_command(group_name: class_name),
71
64
  kind: :group,
72
65
  )
73
66
  end
@@ -79,13 +72,13 @@ module RubyLsp
79
72
  sig { params(node: Prism::ClassNode).void }
80
73
  def on_class_node_leave(node)
81
74
  @visibility_stack.pop
82
- @class_stack.pop
75
+ @group_stack.pop
83
76
  @group_id_stack.pop
84
77
  end
85
78
 
86
79
  sig { params(node: Prism::DefNode).void }
87
80
  def on_def_node_enter(node)
88
- class_name = @class_stack.last
81
+ class_name = @group_stack.last
89
82
  return unless class_name&.end_with?("Test")
90
83
 
91
84
  visibility, _ = @visibility_stack.last
@@ -95,7 +88,7 @@ module RubyLsp
95
88
  add_test_code_lens(
96
89
  node,
97
90
  name: method_name,
98
- command: generate_test_command(method_name: method_name, class_name: class_name),
91
+ command: generate_test_command(method_name: method_name, group_name: class_name),
99
92
  kind: :example,
100
93
  )
101
94
  end
@@ -120,16 +113,15 @@ module RubyLsp
120
113
  return
121
114
  end
122
115
 
123
- if @path&.include?(GEMFILE_NAME) && name == :gem && arguments
124
- return unless @lenses_configuration.enabled?(:gemfileLinks)
125
-
126
- first_argument = arguments.arguments.first
127
- return unless first_argument.is_a?(Prism::StringNode)
128
-
129
- remote = resolve_gem_remote(first_argument)
130
- return unless remote
131
-
132
- add_open_gem_remote_code_lens(node, remote)
116
+ if [DESCRIBE_KEYWORD, IT_KEYWORD].include?(name)
117
+ case name
118
+ when DESCRIBE_KEYWORD
119
+ add_spec_code_lens(node, kind: :group)
120
+ @group_id_stack.push(@group_id)
121
+ @group_id += 1
122
+ when IT_KEYWORD
123
+ add_spec_code_lens(node, kind: :example)
124
+ end
133
125
  end
134
126
  end
135
127
 
@@ -137,6 +129,9 @@ module RubyLsp
137
129
  def on_call_node_leave(node)
138
130
  _, prev_visibility = @visibility_stack.pop
139
131
  @visibility_stack.push([prev_visibility, prev_visibility])
132
+ if node.name == DESCRIBE_KEYWORD
133
+ @group_id_stack.pop
134
+ end
140
135
  end
141
136
 
142
137
  private
@@ -161,7 +156,7 @@ module RubyLsp
161
156
  grouping_data = { group_id: @group_id_stack.last, kind: kind }
162
157
  grouping_data[:id] = @group_id if kind == :group
163
158
 
164
- @_response << create_code_lens(
159
+ @response_builder << create_code_lens(
165
160
  node,
166
161
  title: "Run",
167
162
  command_name: "rubyLsp.runTest",
@@ -169,7 +164,7 @@ module RubyLsp
169
164
  data: { type: "test", **grouping_data },
170
165
  )
171
166
 
172
- @_response << create_code_lens(
167
+ @response_builder << create_code_lens(
173
168
  node,
174
169
  title: "Run In Terminal",
175
170
  command_name: "rubyLsp.runTestInTerminal",
@@ -177,7 +172,7 @@ module RubyLsp
177
172
  data: { type: "test_in_terminal", **grouping_data },
178
173
  )
179
174
 
180
- @_response << create_code_lens(
175
+ @response_builder << create_code_lens(
181
176
  node,
182
177
  title: "Debug",
183
178
  command_name: "rubyLsp.debugTest",
@@ -186,29 +181,19 @@ module RubyLsp
186
181
  )
187
182
  end
188
183
 
189
- sig { params(gem_name: Prism::StringNode).returns(T.nilable(String)) }
190
- def resolve_gem_remote(gem_name)
191
- spec = Gem::Specification.stubs.find { |gem| gem.name == gem_name.content }&.to_spec
192
- return if spec.nil?
193
-
194
- [spec.homepage, spec.metadata["source_code_uri"]].compact.find do |page|
195
- page.start_with?("https://github.com", "https://gitlab.com")
196
- end
197
- end
198
-
199
- sig { params(class_name: String, method_name: T.nilable(String)).returns(String) }
200
- def generate_test_command(class_name:, method_name: nil)
184
+ sig { params(group_name: String, method_name: T.nilable(String)).returns(String) }
185
+ def generate_test_command(group_name:, method_name: nil)
201
186
  command = BASE_COMMAND + T.must(@path)
202
187
 
203
188
  case DependencyDetector.instance.detected_test_library
204
189
  when "minitest"
205
190
  command += if method_name
206
- " --name " + "/#{Shellwords.escape(class_name + "#" + method_name)}/"
191
+ " --name " + "/#{Shellwords.escape(group_name + "#" + method_name)}/"
207
192
  else
208
- " --name " + "/#{Shellwords.escape(class_name)}/"
193
+ " --name " + "/#{Shellwords.escape(group_name)}/"
209
194
  end
210
195
  when "test-unit"
211
- command += " --testcase " + "/#{Shellwords.escape(class_name)}/"
196
+ command += " --testcase " + "/#{Shellwords.escape(group_name)}/"
212
197
 
213
198
  if method_name
214
199
  command += " --name " + Shellwords.escape(method_name)
@@ -218,14 +203,28 @@ module RubyLsp
218
203
  command
219
204
  end
220
205
 
221
- sig { params(node: Prism::CallNode, remote: String).void }
222
- def add_open_gem_remote_code_lens(node, remote)
223
- @_response << create_code_lens(
206
+ sig { params(node: Prism::CallNode, kind: Symbol).void }
207
+ def add_spec_code_lens(node, kind:)
208
+ arguments = node.arguments
209
+ return unless arguments
210
+
211
+ first_argument = arguments.arguments.first
212
+ return unless first_argument
213
+
214
+ name = case first_argument
215
+ when Prism::StringNode
216
+ first_argument.content
217
+ when Prism::ConstantReadNode
218
+ first_argument.full_name
219
+ end
220
+
221
+ return unless name
222
+
223
+ add_test_code_lens(
224
224
  node,
225
- title: "Open remote",
226
- command_name: "rubyLsp.openLink",
227
- arguments: [remote],
228
- data: { type: "link" },
225
+ name: name,
226
+ command: generate_test_command(group_name: name),
227
+ kind: kind,
229
228
  )
230
229
  end
231
230
  end
@@ -3,26 +3,21 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Listeners
6
- class Completion < Listener
6
+ class Completion
7
7
  extend T::Sig
8
- extend T::Generic
9
-
10
- ResponseType = type_member { { fixed: T::Array[Interface::CompletionItem] } }
11
-
12
- sig { override.returns(ResponseType) }
13
- attr_reader :_response
8
+ include Requests::Support::Common
14
9
 
15
10
  sig do
16
11
  params(
12
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
17
13
  index: RubyIndexer::Index,
18
14
  nesting: T::Array[String],
19
15
  typechecker_enabled: T::Boolean,
20
16
  dispatcher: Prism::Dispatcher,
21
17
  ).void
22
18
  end
23
- def initialize(index, nesting, typechecker_enabled, dispatcher)
24
- super(dispatcher)
25
- @_response = T.let([], ResponseType)
19
+ def initialize(response_builder, index, nesting, typechecker_enabled, dispatcher)
20
+ @response_builder = response_builder
26
21
  @index = index
27
22
  @nesting = nesting
28
23
  @typechecker_enabled = typechecker_enabled
@@ -39,7 +34,7 @@ module RubyLsp
39
34
  sig { params(node: Prism::StringNode).void }
40
35
  def on_string_node_enter(node)
41
36
  @index.search_require_paths(node.content).map!(&:require_path).sort!.each do |path|
42
- @_response << build_completion(T.must(path), node)
37
+ @response_builder << build_completion(T.must(path), node)
43
38
  end
44
39
  end
45
40
 
@@ -52,7 +47,7 @@ module RubyLsp
52
47
  candidates = @index.prefix_search(name, @nesting)
53
48
  candidates.each do |entries|
54
49
  complete_name = T.must(entries.first).name
55
- @_response << build_entry_completion(
50
+ @response_builder << build_entry_completion(
56
51
  complete_name,
57
52
  name,
58
53
  node,
@@ -96,7 +91,7 @@ module RubyLsp
96
91
 
97
92
  full_name = aliased_namespace.empty? ? constant_name : "#{aliased_namespace}::#{constant_name}"
98
93
 
99
- @_response << build_entry_completion(
94
+ @response_builder << build_entry_completion(
100
95
  full_name,
101
96
  name,
102
97
  node,
@@ -123,7 +118,7 @@ module RubyLsp
123
118
  entry = entries.find { |e| e.is_a?(RubyIndexer::Entry::Member) && e.owner&.name == receiver.name }
124
119
  next unless entry
125
120
 
126
- @_response << build_method_completion(T.cast(entry, RubyIndexer::Entry::Member), node)
121
+ @response_builder << build_method_completion(T.cast(entry, RubyIndexer::Entry::Member), node)
127
122
  end
128
123
  end
129
124
 
@@ -147,7 +142,10 @@ module RubyLsp
147
142
  detail: "(#{entry.parameters.map(&:decorated_name).join(", ")})",
148
143
  description: entry.file_name,
149
144
  ),
150
- documentation: markdown_from_index_entries(name, entry),
145
+ documentation: Interface::MarkupContent.new(
146
+ kind: "markdown",
147
+ value: markdown_from_index_entries(name, entry),
148
+ ),
151
149
  )
152
150
  end
153
151
 
@@ -240,7 +238,10 @@ module RubyLsp
240
238
  label_details: Interface::CompletionItemLabelDetails.new(
241
239
  description: entries.map(&:file_name).join(","),
242
240
  ),
243
- documentation: markdown_from_index_entries(real_name, entries),
241
+ documentation: Interface::MarkupContent.new(
242
+ kind: "markdown",
243
+ value: markdown_from_index_entries(real_name, entries),
244
+ ),
244
245
  )
245
246
  end
246
247
 
@@ -3,17 +3,13 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Listeners
6
- class Definition < Listener
6
+ class Definition
7
7
  extend T::Sig
8
- extend T::Generic
9
-
10
- ResponseType = type_member { { fixed: T.nilable(T.any(T::Array[Interface::Location], Interface::Location)) } }
11
-
12
- sig { override.returns(ResponseType) }
13
- attr_reader :_response
8
+ include Requests::Support::Common
14
9
 
15
10
  sig do
16
11
  params(
12
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::Location],
17
13
  uri: URI::Generic,
18
14
  nesting: T::Array[String],
19
15
  index: RubyIndexer::Index,
@@ -21,14 +17,12 @@ module RubyLsp
21
17
  typechecker_enabled: T::Boolean,
22
18
  ).void
23
19
  end
24
- def initialize(uri, nesting, index, dispatcher, typechecker_enabled)
20
+ def initialize(response_builder, uri, nesting, index, dispatcher, typechecker_enabled) # rubocop:disable Metrics/ParameterLists
21
+ @response_builder = response_builder
25
22
  @uri = uri
26
23
  @nesting = nesting
27
24
  @index = index
28
25
  @typechecker_enabled = typechecker_enabled
29
- @_response = T.let(nil, ResponseType)
30
-
31
- super(dispatcher)
32
26
 
33
27
  dispatcher.register(
34
28
  self,
@@ -75,7 +69,7 @@ module RubyLsp
75
69
  file_path = target_method.file_path
76
70
  return if @typechecker_enabled && not_in_dependencies?(file_path)
77
71
 
78
- @_response = Interface::Location.new(
72
+ @response_builder << Interface::Location.new(
79
73
  uri: URI::Generic.from_path(path: file_path).to_s,
80
74
  range: Interface::Range.new(
81
75
  start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
@@ -102,7 +96,7 @@ module RubyLsp
102
96
  if entry
103
97
  candidate = entry.full_path
104
98
 
105
- @_response = Interface::Location.new(
99
+ @response_builder << Interface::Location.new(
106
100
  uri: URI::Generic.from_path(path: candidate).to_s,
107
101
  range: Interface::Range.new(
108
102
  start: Interface::Position.new(line: 0, character: 0),
@@ -116,7 +110,7 @@ module RubyLsp
116
110
  current_folder = path ? Pathname.new(CGI.unescape(path)).dirname : Dir.pwd
117
111
  candidate = File.expand_path(File.join(current_folder, required_file))
118
112
 
119
- @_response = Interface::Location.new(
113
+ @response_builder << Interface::Location.new(
120
114
  uri: URI::Generic.from_path(path: candidate).to_s,
121
115
  range: Interface::Range.new(
122
116
  start: Interface::Position.new(line: 0, character: 0),
@@ -136,7 +130,7 @@ module RubyLsp
136
130
  first_entry = T.must(entries.first)
137
131
  return if first_entry.visibility == :private && first_entry.name != "#{@nesting.join("::")}::#{value}"
138
132
 
139
- @_response = entries.filter_map do |entry|
133
+ entries.each do |entry|
140
134
  location = entry.location
141
135
  # If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
142
136
  # additional behavior on top of jumping to RBIs. Sorbet can already handle go to definition for all constants
@@ -144,7 +138,7 @@ module RubyLsp
144
138
  file_path = entry.file_path
145
139
  next if @typechecker_enabled && not_in_dependencies?(file_path)
146
140
 
147
- Interface::Location.new(
141
+ @response_builder << Interface::Location.new(
148
142
  uri: URI::Generic.from_path(path: file_path).to_s,
149
143
  range: Interface::Range.new(
150
144
  start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
@@ -3,10 +3,9 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Listeners
6
- class DocumentHighlight < Listener
6
+ class DocumentHighlight
7
7
  extend T::Sig
8
-
9
- ResponseType = type_member { { fixed: T::Array[Interface::DocumentHighlight] } }
8
+ include Requests::Support::Common
10
9
 
11
10
  GLOBAL_VARIABLE_NODES = T.let(
12
11
  [
@@ -87,20 +86,16 @@ module RubyLsp
87
86
  T::Array[T.class_of(Prism::Node)],
88
87
  )
89
88
 
90
- sig { override.returns(ResponseType) }
91
- attr_reader :_response
92
-
93
89
  sig do
94
90
  params(
91
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight],
95
92
  target: T.nilable(Prism::Node),
96
93
  parent: T.nilable(Prism::Node),
97
94
  dispatcher: Prism::Dispatcher,
98
95
  ).void
99
96
  end
100
- def initialize(target, parent, dispatcher)
101
- super(dispatcher)
102
-
103
- @_response = T.let([], T::Array[Interface::DocumentHighlight])
97
+ def initialize(response_builder, target, parent, dispatcher)
98
+ @response_builder = response_builder
104
99
 
105
100
  return unless target && parent
106
101
 
@@ -521,7 +516,7 @@ module RubyLsp
521
516
 
522
517
  sig { params(kind: Integer, location: Prism::Location).void }
523
518
  def add_highlight(kind, location)
524
- @_response << Interface::DocumentHighlight.new(range: range_from_location(location), kind: kind)
519
+ @response_builder << Interface::DocumentHighlight.new(range: range_from_location(location), kind: kind)
525
520
  end
526
521
 
527
522
  sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(String)) }
@@ -5,11 +5,9 @@ require "ruby_lsp/requests/support/source_uri"
5
5
 
6
6
  module RubyLsp
7
7
  module Listeners
8
- class DocumentLink < Listener
8
+ class DocumentLink
9
9
  extend T::Sig
10
- extend T::Generic
11
-
12
- ResponseType = type_member { { fixed: T::Array[Interface::DocumentLink] } }
10
+ include Requests::Support::Common
13
11
 
14
12
  GEM_TO_VERSION_MAP = T.let(
15
13
  [*::Gem::Specification.default_stubs, *::Gem::Specification.stubs].map! do |s|
@@ -59,25 +57,21 @@ module RubyLsp
59
57
  end
60
58
  end
61
59
 
62
- sig { override.returns(ResponseType) }
63
- attr_reader :_response
64
-
65
60
  sig do
66
61
  params(
62
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::DocumentLink],
67
63
  uri: URI::Generic,
68
64
  comments: T::Array[Prism::Comment],
69
65
  dispatcher: Prism::Dispatcher,
70
66
  ).void
71
67
  end
72
- def initialize(uri, comments, dispatcher)
73
- super(dispatcher)
74
-
68
+ def initialize(response_builder, uri, comments, dispatcher)
75
69
  # Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
76
70
  # in the URI
71
+ @response_builder = response_builder
77
72
  path = uri.to_standardized_path
78
73
  version_match = path ? /(?<=%40)[\d.]+(?=\.rbi$)/.match(path) : nil
79
74
  @gem_version = T.let(version_match && version_match[0], T.nilable(String))
80
- @_response = T.let([], T::Array[Interface::DocumentLink])
81
75
  @lines_to_comments = T.let(
82
76
  comments.to_h do |comment|
83
77
  [comment.location.end_line, comment]
@@ -137,7 +131,7 @@ module RubyLsp
137
131
  file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, CGI.unescape(uri.path))
138
132
  return if file_path.nil?
139
133
 
140
- @_response << Interface::DocumentLink.new(
134
+ @response_builder << Interface::DocumentLink.new(
141
135
  range: range_from_location(comment.location),
142
136
  target: "file://#{file_path}##{uri.line_number}",
143
137
  tooltip: "Jump to #{file_path}##{uri.line_number}",