ruby-lsp 0.13.3 → 0.14.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp-doctor +2 -0
  5. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +4 -8
  6. data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +5 -1
  7. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +4 -2
  8. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +10 -5
  9. data/lib/ruby_indexer/test/classes_and_modules_test.rb +9 -0
  10. data/lib/ruby_indexer/test/index_test.rb +54 -3
  11. data/lib/ruby_lsp/addon.rb +34 -17
  12. data/lib/ruby_lsp/check_docs.rb +8 -8
  13. data/lib/ruby_lsp/executor.rb +28 -10
  14. data/lib/ruby_lsp/internal.rb +8 -6
  15. data/lib/ruby_lsp/listeners/code_lens.rb +54 -55
  16. data/lib/ruby_lsp/listeners/completion.rb +22 -18
  17. data/lib/ruby_lsp/listeners/definition.rb +31 -29
  18. data/lib/ruby_lsp/listeners/document_highlight.rb +6 -11
  19. data/lib/ruby_lsp/listeners/document_link.rb +6 -12
  20. data/lib/ruby_lsp/listeners/document_symbol.rb +194 -55
  21. data/lib/ruby_lsp/listeners/folding_ranges.rb +19 -23
  22. data/lib/ruby_lsp/listeners/hover.rb +36 -34
  23. data/lib/ruby_lsp/listeners/inlay_hints.rb +7 -13
  24. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -124
  25. data/lib/ruby_lsp/listeners/signature_help.rb +15 -14
  26. data/lib/ruby_lsp/requests/code_lens.rb +11 -19
  27. data/lib/ruby_lsp/requests/completion.rb +7 -9
  28. data/lib/ruby_lsp/requests/definition.rb +10 -22
  29. data/lib/ruby_lsp/requests/document_highlight.rb +7 -5
  30. data/lib/ruby_lsp/requests/document_link.rb +7 -6
  31. data/lib/ruby_lsp/requests/document_symbol.rb +5 -11
  32. data/lib/ruby_lsp/requests/folding_ranges.rb +11 -6
  33. data/lib/ruby_lsp/requests/hover.rb +18 -24
  34. data/lib/ruby_lsp/requests/inlay_hints.rb +7 -8
  35. data/lib/ruby_lsp/requests/on_type_formatting.rb +12 -2
  36. data/lib/ruby_lsp/requests/semantic_highlighting.rb +10 -8
  37. data/lib/ruby_lsp/requests/signature_help.rb +53 -18
  38. data/lib/ruby_lsp/requests/support/common.rb +38 -10
  39. data/lib/ruby_lsp/requests/support/dependency_detector.rb +5 -1
  40. data/lib/ruby_lsp/requests.rb +0 -1
  41. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +29 -0
  42. data/lib/ruby_lsp/response_builders/document_symbol.rb +57 -0
  43. data/lib/ruby_lsp/response_builders/hover.rb +49 -0
  44. data/lib/ruby_lsp/response_builders/response_builder.rb +16 -0
  45. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +199 -0
  46. data/lib/ruby_lsp/response_builders/signature_help.rb +28 -0
  47. data/lib/ruby_lsp/response_builders.rb +13 -0
  48. data/lib/ruby_lsp/server.rb +3 -3
  49. data/lib/ruby_lsp/setup_bundler.rb +64 -23
  50. data/lib/ruby_lsp/store.rb +4 -4
  51. metadata +17 -11
  52. data/lib/ruby_lsp/listener.rb +0 -33
  53. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +0 -73
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28e657dce7a85c270d1c647a158fd1a1c5f81dca211844defd817070fd264126
4
- data.tar.gz: f129245dd0e632916573c0b9dcf04bfaa2c7b942b39aaa6aa1618dd70f13e69e
3
+ metadata.gz: 293c03761c9b7d497045546e3bf7ca88a08ed5556ad0ba52c205a9798e820ce5
4
+ data.tar.gz: 38157f012f3f1dc944186ac1530dc660d8662cb59ca7b12ad3b117655e0c1709
5
5
  SHA512:
6
- metadata.gz: 3ab4afce37f672fd0d3c3ecc54c7b30247f893fc4b7b4f10549e13db4ab181c67a9b84da37dea9fbdd195e8d87ca2f2f794cbcce300c68b4709ee0ae3b3171b2
7
- data.tar.gz: ffdb3a1bdb2d5c4172f74c934da896bd6c19f09158effa137afd0443e79b8c2dfd392989997d5745616db58e1286191a9e35570bd69024779137e7aaf15bb987
6
+ metadata.gz: c4996e277088f015004df0f82e2cc47dc2f979f6658f9dfac19fe495c8c4deced3028b021e330ac0681dbfd79048e9033037c7ce93e6cc044c8ae6d91087e0df
7
+ data.tar.gz: 67c5c31c97c279f192b0b3d6c729c97a19f7aac4581eca037c0e5355cc0f3d3ed69fb4007a5f32985e046980324575e2e35a92ce81e8078b41ee5b6db711ac88
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  [![Build Status](https://github.com/Shopify/ruby-lsp/workflows/CI/badge.svg)](https://github.com/Shopify/ruby-lsp/actions/workflows/ci.yml)
2
2
  [![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)
3
- [![Ruby DX Slack](https://img.shields.io/badge/Slack-Ruby%20DX-success?logo=slack)](https://join.slack.com/t/ruby-dx/shared_invite/zt-1zjp7lmgk-zL7bGvze8gj5hFaYS~r5vg)
3
+ [![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)
4
4
 
5
5
  # Ruby LSP
6
6
 
@@ -9,7 +9,7 @@ for Ruby, used to improve rich features in editors. It is a part of a wider goal
9
9
  experience to Ruby developers using modern standards for cross-editor features, documentation and debugging.
10
10
 
11
11
  Want to discuss Ruby developer experience? Consider joining the public
12
- [Ruby DX Slack workspace](https://join.slack.com/t/ruby-dx/shared_invite/zt-1zjp7lmgk-zL7bGvze8gj5hFaYS~r5vg).
12
+ [Ruby DX Slack workspace](https://join.slack.com/t/ruby-dx/shared_invite/zt-2c8zjlir6-uUDJl8oIwcen_FS_aA~b6Q).
13
13
 
14
14
  ## Usage
15
15
 
@@ -83,6 +83,10 @@ features. This is the mechanism that powers addons like
83
83
 
84
84
  - [Ruby LSP Rails](https://github.com/Shopify/ruby-lsp-rails)
85
85
  - [Ruby LSP RSpec](https://github.com/st0012/ruby-lsp-rspec)
86
+ - [Ruby LSP rubyfmt](https://github.com/jscharf/ruby-lsp-rubyfmt)
87
+
88
+ Other community driven addons can be found in [rubygems](https://rubygems.org/search?query=name%3A+ruby-lsp) by
89
+ searching for the `ruby-lsp` prefix.
86
90
 
87
91
  For instructions on how to create addons, see the [addons documentation](ADDONS.md).
88
92
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.13.3
1
+ 0.14.2
data/exe/ruby-lsp-doctor CHANGED
@@ -6,6 +6,8 @@ require "ruby_lsp/internal"
6
6
 
7
7
  index = RubyIndexer::Index.new
8
8
 
9
+ puts "Globbing for indexable files"
10
+
9
11
  RubyIndexer.configuration.indexables.each do |indexable|
10
12
  puts "indexing: #{indexable.full_path}"
11
13
  content = File.read(indexable.full_path)
@@ -13,9 +13,8 @@ module RuboCop
13
13
  # # Register without handler method.
14
14
  #
15
15
  # # bad
16
- # class MyListener < Listener
16
+ # class MyListener
17
17
  # def initialize(dispatcher)
18
- # super()
19
18
  # dispatcher.register(
20
19
  # self,
21
20
  # :on_string_node_enter,
@@ -24,9 +23,8 @@ module RuboCop
24
23
  # end
25
24
  #
26
25
  # # good
27
- # class MyListener < Listener
26
+ # class MyListener
28
27
  # def initialize(dispatcher)
29
- # super()
30
28
  # dispatcher.register(
31
29
  # self,
32
30
  # :on_string_node_enter,
@@ -41,9 +39,8 @@ module RuboCop
41
39
  # # Handler method without register.
42
40
  #
43
41
  # # bad
44
- # class MyListener < Listener
42
+ # class MyListener
45
43
  # def initialize(dispatcher)
46
- # super()
47
44
  # dispatcher.register(
48
45
  # self,
49
46
  # )
@@ -54,9 +51,8 @@ module RuboCop
54
51
  # end
55
52
  #
56
53
  # # good
57
- # class MyListener < Listener
54
+ # class MyListener
58
55
  # def initialize(dispatcher)
59
- # super()
60
56
  # dispatcher.register(
61
57
  # self,
62
58
  # :on_string_node_enter,
@@ -304,7 +304,11 @@ module RubyIndexer
304
304
  break unless comment
305
305
 
306
306
  comment_content = comment.location.slice.chomp
307
- next if comment_content.match?(RubyIndexer.configuration.magic_comment_regex)
307
+
308
+ # invalid encodings would raise an "invalid byte sequence" exception
309
+ if !comment_content.valid_encoding? || comment_content.match?(RubyIndexer.configuration.magic_comment_regex)
310
+ next
311
+ end
308
312
 
309
313
  comment_content.delete_prefix!("#")
310
314
  comment_content.delete_prefix!(" ")
@@ -192,6 +192,9 @@ module RubyIndexer
192
192
 
193
193
  # When working on a gem, we need to make sure that its gemspec dependencies can't be excluded. This is necessary
194
194
  # because Bundler doesn't assign groups to gemspec dependencies
195
+ #
196
+ # If the dependency is prerelease, `to_spec` may return `nil` due to a bug in older version of Bundler/RubyGems:
197
+ # https://github.com/Shopify/ruby-lsp/issues/1246
195
198
  this_gem = Bundler.definition.dependencies.find do |d|
196
199
  d.to_spec&.full_gem_path == Dir.pwd
197
200
  rescue Gem::MissingSpecError
@@ -203,7 +206,6 @@ module RubyIndexer
203
206
  excluded.each do |dependency|
204
207
  next unless dependency.runtime?
205
208
 
206
- # If the dependency is prerelease, to_spec may return `nil`
207
209
  spec = dependency.to_spec
208
210
  next unless spec
209
211
 
@@ -213,7 +215,7 @@ module RubyIndexer
213
215
 
214
216
  # If the transitive dependency is included as a transitive dependency of a gem outside of the development
215
217
  # group, skip it
216
- next if others.any? { |d| d.to_spec.dependencies.include?(transitive_dependency) }
218
+ next if others.any? { |d| d.to_spec&.dependencies&.include?(transitive_dependency) }
217
219
 
218
220
  excluded << transitive_dependency
219
221
  end
@@ -237,16 +237,21 @@ module RubyIndexer
237
237
  real_parts.join("::")
238
238
  end
239
239
 
240
- # Attempts to find a given method for a resolved fully qualified receiver name. Returns `nil` if the method does not
241
- # exist on that receiver
242
- sig { params(method_name: String, receiver_name: String).returns(T.nilable(Entry::Method)) }
240
+ # Attempts to find methods for a resolved fully qualified receiver name.
241
+ # Returns `nil` if the method does not exist on that receiver
242
+ sig { params(method_name: String, receiver_name: String).returns(T.nilable(T::Array[Entry::Member])) }
243
243
  def resolve_method(method_name, receiver_name)
244
- method_entries = T.cast(self[method_name], T.nilable(T::Array[Entry::Method]))
244
+ method_entries = self[method_name]
245
245
  owner_entries = self[receiver_name]
246
246
  return unless owner_entries && method_entries
247
247
 
248
248
  owner_name = T.must(owner_entries.first).name
249
- method_entries.find { |entry| entry.owner&.name == owner_name }
249
+ T.cast(
250
+ method_entries.grep(Entry::Member).select do |entry|
251
+ T.cast(entry, Entry::Member).owner&.name == owner_name
252
+ end,
253
+ T::Array[Entry::Member],
254
+ )
250
255
  end
251
256
 
252
257
  private
@@ -168,6 +168,15 @@ module RubyIndexer
168
168
  assert_equal("This Bar comment has 1 line padding", bar_entry.comments.join("\n"))
169
169
  end
170
170
 
171
+ def test_skips_comments_containing_invalid_encodings
172
+ index(<<~RUBY)
173
+ # comment \xBA
174
+ class Foo
175
+ end
176
+ RUBY
177
+ assert(@index["Foo"].first)
178
+ end
179
+
171
180
  def test_comments_can_be_attached_to_a_namespaced_class
172
181
  index(<<~RUBY)
173
182
  # This is a Foo comment
@@ -226,9 +226,60 @@ module RubyIndexer
226
226
  end
227
227
  RUBY
228
228
 
229
- entry = T.must(@index.resolve_method("baz", "Foo::Bar"))
230
- assert_equal("baz", entry.name)
231
- assert_equal("Foo::Bar", T.must(entry.owner).name)
229
+ entries = T.must(@index.resolve_method("baz", "Foo::Bar"))
230
+ assert_equal("baz", entries.first.name)
231
+ assert_equal("Foo::Bar", T.must(entries.first.owner).name)
232
+ end
233
+
234
+ def test_resolve_method_with_class_name_conflict
235
+ index(<<~RUBY)
236
+ class Array
237
+ end
238
+
239
+ class Foo
240
+ def Array(*args); end
241
+ end
242
+ RUBY
243
+
244
+ entries = T.must(@index.resolve_method("Array", "Foo"))
245
+ assert_equal("Array", entries.first.name)
246
+ assert_equal("Foo", T.must(entries.first.owner).name)
247
+ end
248
+
249
+ def test_resolve_method_attribute
250
+ index(<<~RUBY)
251
+ class Foo
252
+ attr_reader :bar
253
+ end
254
+ RUBY
255
+
256
+ entries = T.must(@index.resolve_method("bar", "Foo"))
257
+ assert_equal("bar", entries.first.name)
258
+ assert_equal("Foo", T.must(entries.first.owner).name)
259
+ end
260
+
261
+ def test_resolve_method_with_two_definitions
262
+ index(<<~RUBY)
263
+ class Foo
264
+ # Hello from first `bar`
265
+ def bar; end
266
+ end
267
+
268
+ class Foo
269
+ # Hello from second `bar`
270
+ def bar; end
271
+ end
272
+ RUBY
273
+
274
+ first_entry, second_entry = T.must(@index.resolve_method("bar", "Foo"))
275
+
276
+ assert_equal("bar", first_entry.name)
277
+ assert_equal("Foo", T.must(first_entry.owner).name)
278
+ assert_includes(first_entry.comments, "Hello from first `bar`")
279
+
280
+ assert_equal("bar", second_entry.name)
281
+ assert_equal("Foo", T.must(second_entry.owner).name)
282
+ assert_includes(second_entry.comments, "Hello from second `bar`")
232
283
  end
233
284
 
234
285
  def test_prefix_search_for_methods
@@ -25,21 +25,25 @@ module RubyLsp
25
25
 
26
26
  abstract!
27
27
 
28
+ @addons = T.let([], T::Array[Addon])
29
+ @addon_classes = T.let([], T::Array[T.class_of(Addon)])
30
+
28
31
  class << self
29
32
  extend T::Sig
30
33
 
34
+ sig { returns(T::Array[Addon]) }
35
+ attr_accessor :addons
36
+
37
+ sig { returns(T::Array[T.class_of(Addon)]) }
38
+ attr_reader :addon_classes
39
+
31
40
  # Automatically track and instantiate addon classes
32
41
  sig { params(child_class: T.class_of(Addon)).void }
33
42
  def inherited(child_class)
34
- addons << child_class.new
43
+ addon_classes << child_class
35
44
  super
36
45
  end
37
46
 
38
- sig { returns(T::Array[Addon]) }
39
- def addons
40
- @addons ||= T.let([], T.nilable(T::Array[Addon]))
41
- end
42
-
43
47
  # Discovers and loads all addons. Returns the list of activated addons
44
48
  sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
45
49
  def load_addons(message_queue)
@@ -48,15 +52,16 @@ module RubyLsp
48
52
  Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
49
53
  require File.expand_path(addon)
50
54
  rescue => e
51
- warn(e.message)
52
- warn(e.backtrace.to_s) # rubocop:disable Lint/RedundantStringCoercion
55
+ $stderr.puts(e.full_message)
53
56
  end
54
57
 
58
+ # Instantiate all discovered addon classes
59
+ self.addons = addon_classes.map(&:new)
60
+
55
61
  # Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
56
62
  # fail to boot the server
57
63
  addons.each do |addon|
58
64
  addon.activate(message_queue)
59
- nil
60
65
  rescue => e
61
66
  addon.add_error(e)
62
67
  end
@@ -109,39 +114,51 @@ module RubyLsp
109
114
  # Creates a new CodeLens listener. This method is invoked on every CodeLens request
110
115
  sig do
111
116
  overridable.params(
117
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
112
118
  uri: URI::Generic,
113
119
  dispatcher: Prism::Dispatcher,
114
- ).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
120
+ ).void
115
121
  end
116
- def create_code_lens_listener(uri, dispatcher); end
122
+ def create_code_lens_listener(response_builder, uri, dispatcher); end
117
123
 
118
124
  # Creates a new Hover listener. This method is invoked on every Hover request
119
125
  sig do
120
126
  overridable.params(
127
+ response_builder: ResponseBuilders::Hover,
121
128
  nesting: T::Array[String],
122
129
  index: RubyIndexer::Index,
123
130
  dispatcher: Prism::Dispatcher,
124
- ).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
131
+ ).void
125
132
  end
126
- def create_hover_listener(nesting, index, dispatcher); end
133
+ def create_hover_listener(response_builder, nesting, index, dispatcher); end
127
134
 
128
135
  # Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
129
136
  sig do
130
137
  overridable.params(
138
+ response_builder: ResponseBuilders::DocumentSymbol,
139
+ dispatcher: Prism::Dispatcher,
140
+ ).void
141
+ end
142
+ def create_document_symbol_listener(response_builder, dispatcher); end
143
+
144
+ sig do
145
+ overridable.params(
146
+ response_builder: ResponseBuilders::SemanticHighlighting,
131
147
  dispatcher: Prism::Dispatcher,
132
- ).returns(T.nilable(Listener[T::Array[Interface::DocumentSymbol]]))
148
+ ).void
133
149
  end
134
- def create_document_symbol_listener(dispatcher); end
150
+ def create_semantic_highlighting_listener(response_builder, dispatcher); end
135
151
 
136
152
  # Creates a new Definition listener. This method is invoked on every Definition request
137
153
  sig do
138
154
  overridable.params(
155
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::Location],
139
156
  uri: URI::Generic,
140
157
  nesting: T::Array[String],
141
158
  index: RubyIndexer::Index,
142
159
  dispatcher: Prism::Dispatcher,
143
- ).returns(T.nilable(Listener[T.nilable(T.any(T::Array[Interface::Location], Interface::Location))]))
160
+ ).void
144
161
  end
145
- def create_definition_listener(uri, nesting, index, dispatcher); end
162
+ def create_definition_listener(response_builder, uri, nesting, index, dispatcher); end
146
163
  end
147
164
  end
@@ -6,7 +6,7 @@ require "objspace"
6
6
 
7
7
  module RubyLsp
8
8
  # This rake task checks that all requests or addons are fully documented. Add the rake task to your Rakefile and
9
- # specify the absolute path for all files that must be required in order to discover all listeners and their related
9
+ # specify the absolute path for all files that must be required in order to discover all requests and their related
10
10
  # GIFs
11
11
  #
12
12
  # # Rakefile
@@ -33,7 +33,7 @@ module RubyLsp
33
33
 
34
34
  sig { void }
35
35
  def define_task
36
- desc("Checks if all Ruby LSP listeners are documented")
36
+ desc("Checks if all Ruby LSP requests are documented")
37
37
  task(@name) { run_task }
38
38
  end
39
39
 
@@ -46,10 +46,10 @@ module RubyLsp
46
46
 
47
47
  sig { void }
48
48
  def run_task
49
- # Require all files configured to make sure all listeners are loaded
49
+ # Require all files configured to make sure all requests are loaded
50
50
  @file_list.each { |f| require(f.delete_suffix(".rb")) }
51
51
 
52
- # Find all classes that inherit from BaseRequest or Listener, which are the ones we want to make sure are
52
+ # Find all classes that inherit from BaseRequest, which are the ones we want to make sure are
53
53
  # documented
54
54
  features = ObjectSpace.each_object(Class).select do |k|
55
55
  klass = T.unsafe(k)
@@ -69,7 +69,7 @@ module RubyLsp
69
69
  lines = File.readlines(file_path)
70
70
  docs = []
71
71
 
72
- # Extract the documentation on top of the listener constant
72
+ # Extract the documentation on top of the request constant
73
73
  while (line = lines[line_number]&.strip) && line.start_with?("#")
74
74
  docs.unshift(line)
75
75
  line_number -= 1
@@ -115,8 +115,8 @@ module RubyLsp
115
115
  end
116
116
 
117
117
  if missing_docs.any?
118
- warn(<<~WARN)
119
- The following listeners are missing documentation:
118
+ $stderr.puts(<<~WARN)
119
+ The following requests are missing documentation:
120
120
 
121
121
  #{missing_docs.map { |k, v| "#{k}\n\n#{v.join("\n")}" }.join("\n\n")}
122
122
  WARN
@@ -124,7 +124,7 @@ module RubyLsp
124
124
  abort
125
125
  end
126
126
 
127
- puts "All listeners are documented!"
127
+ puts "All requests are documented!"
128
128
  end
129
129
  end
130
130
  end
@@ -25,7 +25,7 @@ module RubyLsp
25
25
  begin
26
26
  response = run(request)
27
27
  rescue StandardError, LoadError => e
28
- warn(e.message)
28
+ $stderr.puts(e.full_message)
29
29
  error = e
30
30
  end
31
31
 
@@ -55,7 +55,7 @@ module RubyLsp
55
55
  ),
56
56
  )
57
57
 
58
- warn(errored_addons.map(&:backtraces).join("\n\n"))
58
+ $stderr.puts(errored_addons.map(&:backtraces).join("\n\n"))
59
59
  end
60
60
 
61
61
  RubyVM::YJIT.enable if defined? RubyVM::YJIT.enable
@@ -63,7 +63,7 @@ module RubyLsp
63
63
  perform_initial_indexing
64
64
  check_formatter_is_available
65
65
 
66
- warn("Ruby LSP is ready")
66
+ $stderr.puts("Ruby LSP is ready")
67
67
  VOID
68
68
  when "textDocument/didOpen"
69
69
  text_document_did_open(
@@ -99,8 +99,7 @@ module RubyLsp
99
99
  folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher)
100
100
  document_symbol = Requests::DocumentSymbol.new(dispatcher)
101
101
  document_link = Requests::DocumentLink.new(uri, document.comments, dispatcher)
102
- lenses_configuration = T.must(@store.features_configuration.dig(:codeLens))
103
- code_lens = Requests::CodeLens.new(uri, lenses_configuration, dispatcher)
102
+ code_lens = Requests::CodeLens.new(uri, dispatcher)
104
103
 
105
104
  semantic_highlighting = Requests::SemanticHighlighting.new(dispatcher)
106
105
  dispatcher.dispatch(document.tree)
@@ -113,7 +112,7 @@ module RubyLsp
113
112
  document.cache_set("textDocument/codeLens", code_lens.perform)
114
113
  document.cache_set(
115
114
  "textDocument/semanticTokens/full",
116
- Requests::Support::SemanticTokenEncoder.new.encode(semantic_highlighting.perform),
115
+ semantic_highlighting.perform,
117
116
  )
118
117
  document.cache_get(request[:method])
119
118
  when "textDocument/semanticTokens/range"
@@ -222,6 +221,8 @@ module RubyLsp
222
221
  workspace_symbol(request.dig(:params, :query))
223
222
  when "rubyLsp/textDocument/showSyntaxTree"
224
223
  show_syntax_tree(uri, request.dig(:params, :range))
224
+ when "rubyLsp/workspace/dependencies"
225
+ workspace_dependencies
225
226
  else
226
227
  VOID
227
228
  end
@@ -252,6 +253,22 @@ module RubyLsp
252
253
  VOID
253
254
  end
254
255
 
256
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
257
+ def workspace_dependencies
258
+ definition = Bundler.definition
259
+ dep_keys = definition.locked_deps.keys.to_set
260
+ definition.specs.map do |spec|
261
+ {
262
+ name: spec.name,
263
+ version: spec.version,
264
+ path: spec.full_gem_path,
265
+ dependency: dep_keys.include?(spec.name),
266
+ }
267
+ end
268
+ rescue Bundler::GemfileNotFound
269
+ []
270
+ end
271
+
255
272
  sig { void }
256
273
  def perform_initial_indexing
257
274
  # The begin progress invocation happens during `initialize`, so that the notification is sent before we are
@@ -361,7 +378,7 @@ module RubyLsp
361
378
  ).returns(T::Array[Interface::TextEdit])
362
379
  end
363
380
  def on_type_formatting(uri, position, character)
364
- Requests::OnTypeFormatting.new(@store.get(uri), position, character).perform
381
+ Requests::OnTypeFormatting.new(@store.get(uri), position, character, @store.client_name).perform
365
382
  end
366
383
 
367
384
  sig do
@@ -431,7 +448,7 @@ module RubyLsp
431
448
  request = Requests::SemanticHighlighting.new(dispatcher, range: start_line..end_line)
432
449
  dispatcher.visit(document.tree)
433
450
 
434
- Requests::Support::SemanticTokenEncoder.new.encode(request.perform)
451
+ request.perform
435
452
  end
436
453
 
437
454
  sig { params(id: String, title: String, percentage: Integer).void }
@@ -497,6 +514,9 @@ module RubyLsp
497
514
  workspace_uri = options.dig(:workspaceFolders, 0, :uri)
498
515
  @store.workspace_uri = URI(workspace_uri) if workspace_uri
499
516
 
517
+ client_name = options.dig(:clientInfo, :name)
518
+ @store.client_name = client_name if client_name
519
+
500
520
  encodings = options.dig(:capabilities, :general, :positionEncodings)
501
521
  @store.encoding = if encodings.nil? || encodings.empty?
502
522
  Constant::PositionEncodingKind::UTF16
@@ -519,9 +539,7 @@ module RubyLsp
519
539
  @store.experimental_features = options.dig(:initializationOptions, :experimentalFeaturesEnabled) || false
520
540
 
521
541
  configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
522
- configured_lenses = options.dig(:initializationOptions, :featuresConfiguration, :codeLens)
523
542
  T.must(@store.features_configuration.dig(:inlayHint)).configuration.merge!(configured_hints) if configured_hints
524
- T.must(@store.features_configuration.dig(:codeLens)).configuration.merge!(configured_lenses) if configured_lenses
525
543
 
526
544
  enabled_features = case configured_features
527
545
  when Array
@@ -7,13 +7,17 @@ yarp_require_paths = Gem.loaded_specs["yarp"]&.full_require_paths
7
7
  $LOAD_PATH.delete_if { |path| yarp_require_paths.include?(path) } if yarp_require_paths
8
8
 
9
9
  require "sorbet-runtime"
10
- require "prism"
11
- require "prism/visitor"
12
- require "language_server-protocol"
10
+
11
+ # Set Bundler's UI level to silent as soon as possible to prevent any prints to STDOUT
13
12
  require "bundler"
13
+ Bundler.ui.level = :silent
14
+
14
15
  require "uri"
15
16
  require "cgi"
16
17
  require "set"
18
+ require "prism"
19
+ require "prism/visitor"
20
+ require "language_server-protocol"
17
21
 
18
22
  require "ruby-lsp"
19
23
  require "ruby_indexer/ruby_indexer"
@@ -23,11 +27,9 @@ require "ruby_lsp/parameter_scope"
23
27
  require "ruby_lsp/server"
24
28
  require "ruby_lsp/executor"
25
29
  require "ruby_lsp/requests"
26
- require "ruby_lsp/listener"
30
+ require "ruby_lsp/response_builders"
27
31
  require "ruby_lsp/document"
28
32
  require "ruby_lsp/ruby_document"
29
33
  require "ruby_lsp/store"
30
34
  require "ruby_lsp/addon"
31
35
  require "ruby_lsp/requests/support/rubocop_runner"
32
-
33
- Bundler.ui.level = :silent