ruby-lsp 0.17.12 → 0.17.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +6 -4
  4. data/exe/ruby-lsp-check +1 -1
  5. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +1 -1
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +6 -1
  7. data/lib/ruby_indexer/ruby_indexer.rb +0 -8
  8. data/lib/ruby_indexer/test/configuration_test.rb +1 -1
  9. data/lib/ruby_lsp/addon.rb +9 -4
  10. data/lib/ruby_lsp/base_server.rb +7 -2
  11. data/lib/ruby_lsp/document.rb +9 -178
  12. data/lib/ruby_lsp/erb_document.rb +16 -2
  13. data/lib/ruby_lsp/global_state.rb +34 -14
  14. data/lib/ruby_lsp/internal.rb +1 -0
  15. data/lib/ruby_lsp/listeners/completion.rb +5 -5
  16. data/lib/ruby_lsp/listeners/definition.rb +3 -3
  17. data/lib/ruby_lsp/listeners/hover.rb +5 -5
  18. data/lib/ruby_lsp/listeners/signature_help.rb +1 -1
  19. data/lib/ruby_lsp/rbs_document.rb +41 -0
  20. data/lib/ruby_lsp/requests/code_action_resolve.rb +37 -21
  21. data/lib/ruby_lsp/requests/code_actions.rb +3 -3
  22. data/lib/ruby_lsp/requests/completion.rb +3 -3
  23. data/lib/ruby_lsp/requests/definition.rb +2 -2
  24. data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
  25. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  26. data/lib/ruby_lsp/requests/formatting.rb +1 -1
  27. data/lib/ruby_lsp/requests/hover.rb +2 -2
  28. data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
  29. data/lib/ruby_lsp/requests/on_type_formatting.rb +1 -1
  30. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
  31. data/lib/ruby_lsp/requests/selection_ranges.rb +2 -1
  32. data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -1
  33. data/lib/ruby_lsp/requests/signature_help.rb +2 -2
  34. data/lib/ruby_lsp/requests/support/common.rb +2 -2
  35. data/lib/ruby_lsp/requests/support/formatter.rb +2 -2
  36. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -1
  37. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +2 -2
  38. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +2 -2
  39. data/lib/ruby_lsp/ruby_document.rb +183 -1
  40. data/lib/ruby_lsp/server.rb +125 -15
  41. data/lib/ruby_lsp/setup_bundler.rb +15 -4
  42. data/lib/ruby_lsp/store.rb +10 -6
  43. data/lib/ruby_lsp/utils.rb +12 -0
  44. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34cae8b53cfb0811cb26d3b3dd4198a72585d1f15a98a7d8f656fd1676886630
4
- data.tar.gz: f4868222c46c4cbad9a099fce69562838b5dda567f1666a82752f45fe3f501c5
3
+ metadata.gz: 17c576dbc88c8c4012eb777b15df7df630a827d7692f6bceec06b68178b25357
4
+ data.tar.gz: f023f22a818616b1c8c6fb1de77d0637e7bdae37b60b46e941b297aaa95729a9
5
5
  SHA512:
6
- metadata.gz: db8e991497aa6e9388b2778fb9a417adbef07c6bb29165ff9a1718ab7cf1db6d2a6586453320d72adf0cffe78b846b553c3a0ba24b63807c52170f02f1b7d2e3
7
- data.tar.gz: 80aac045ca6aaf7dbb9344f947a9b1419eaac4711448d997c902f0fb9da68e7c2338e0a5b1d81a30c0a2609defe1b656457d1a4a23b0ba5288162d142cf7c9e9
6
+ metadata.gz: e0848d63fef1677ccf276182cdea5a8304e4a1e04a7ec4936f8f083c27bc62f575fe3f0a207f75805cf3c8eb106e43d5d1afe2df366028980cb5eee6ed97c14b
7
+ data.tar.gz: d57869c1ee7dcec65becd9ee4fc225c91e946e697c3aab8a42d2453c1a85bcc91cd8e0a6364d810f8109c2b97102f101d24bf8986d2e4b3905b56368e260b0d3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.17.12
1
+ 0.17.14
data/exe/ruby-lsp CHANGED
@@ -81,6 +81,8 @@ require "ruby_lsp/load_sorbet"
81
81
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
82
82
  require "ruby_lsp/internal"
83
83
 
84
+ T::Utils.run_all_sig_blocks
85
+
84
86
  if options[:debug]
85
87
  if ["x64-mingw-ucrt", "x64-mingw32"].include?(RUBY_PLATFORM)
86
88
  $stderr.puts "Debugging is not supported on Windows"
@@ -112,20 +114,20 @@ if options[:time_index]
112
114
  end
113
115
 
114
116
  if options[:doctor]
117
+ index = RubyIndexer::Index.new
118
+
115
119
  if File.exist?(".index.yml")
116
120
  begin
117
121
  config = YAML.parse_file(".index.yml").to_ruby
118
122
  rescue => e
119
123
  abort("Error parsing config: #{e.message}")
120
124
  end
121
- RubyIndexer.configuration.apply_config(config)
125
+ index.configuration.apply_config(config)
122
126
  end
123
127
 
124
- index = RubyIndexer::Index.new
125
-
126
128
  puts "Globbing for indexable files"
127
129
 
128
- RubyIndexer.configuration.indexables.each do |indexable|
130
+ index.configuration.indexables.each do |indexable|
129
131
  puts "indexing: #{indexable.full_path}"
130
132
  index.index_single(indexable)
131
133
  end
data/exe/ruby-lsp-check CHANGED
@@ -44,7 +44,7 @@ puts "\n"
44
44
  puts "Verifying that indexing executes successfully. This may take a while..."
45
45
 
46
46
  index = RubyIndexer::Index.new
47
- indexables = RubyIndexer.configuration.indexables
47
+ indexables = index.configuration.indexables
48
48
 
49
49
  indexables.each_with_index do |indexable, i|
50
50
  index.index_single(indexable)
@@ -552,7 +552,7 @@ module RubyIndexer
552
552
  comment_content = comment.location.slice.chomp
553
553
 
554
554
  # invalid encodings would raise an "invalid byte sequence" exception
555
- if !comment_content.valid_encoding? || comment_content.match?(RubyIndexer.configuration.magic_comment_regex)
555
+ if !comment_content.valid_encoding? || comment_content.match?(@index.configuration.magic_comment_regex)
556
556
  next
557
557
  end
558
558
 
@@ -11,6 +11,9 @@ module RubyIndexer
11
11
  # The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query
12
12
  ENTRY_SIMILARITY_THRESHOLD = 0.7
13
13
 
14
+ sig { returns(Configuration) }
15
+ attr_reader :configuration
16
+
14
17
  sig { void }
15
18
  def initialize
16
19
  # Holds all entries in the index using the following format:
@@ -44,6 +47,8 @@ module RubyIndexer
44
47
  {},
45
48
  T::Hash[String, T::Array[T.proc.params(index: Index, base: Entry::Namespace).void]],
46
49
  )
50
+
51
+ @configuration = T.let(RubyIndexer::Configuration.new, Configuration)
47
52
  end
48
53
 
49
54
  # Register an enhancement to the index. Enhancements must conform to the `Enhancement` interface
@@ -296,7 +301,7 @@ module RubyIndexer
296
301
  block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
297
302
  ).void
298
303
  end
299
- def index_all(indexable_paths: RubyIndexer.configuration.indexables, &block)
304
+ def index_all(indexable_paths: @configuration.indexables, &block)
300
305
  RBSIndexer.new(self).index_ruby_core
301
306
  # Calculate how many paths are worth 1% of progress
302
307
  progress_step = (indexable_paths.length / 100.0).ceil
@@ -15,12 +15,4 @@ require "ruby_indexer/lib/ruby_indexer/location"
15
15
  require "ruby_indexer/lib/ruby_indexer/rbs_indexer"
16
16
 
17
17
  module RubyIndexer
18
- @configuration = T.let(Configuration.new, Configuration)
19
-
20
- class << self
21
- extend T::Sig
22
-
23
- sig { returns(Configuration) }
24
- attr_reader :configuration
25
- end
26
18
  end
@@ -108,7 +108,7 @@ module RubyIndexer
108
108
  end
109
109
 
110
110
  def test_magic_comments_regex
111
- regex = RubyIndexer.configuration.magic_comment_regex
111
+ regex = @config.magic_comment_regex
112
112
 
113
113
  [
114
114
  "# frozen_string_literal:",
@@ -49,15 +49,18 @@ module RubyLsp
49
49
  super
50
50
  end
51
51
 
52
- # Discovers and loads all addons. Returns the list of activated addons
53
- sig { params(global_state: GlobalState, outgoing_queue: Thread::Queue).returns(T::Array[Addon]) }
52
+ # Discovers and loads all addons. Returns a list of errors when trying to require addons
53
+ sig do
54
+ params(global_state: GlobalState, outgoing_queue: Thread::Queue).returns(T::Array[StandardError])
55
+ end
54
56
  def load_addons(global_state, outgoing_queue)
55
57
  # Require all addons entry points, which should be placed under
56
58
  # `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
57
- Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
59
+ errors = Gem.find_files("ruby_lsp/**/addon.rb").filter_map do |addon|
58
60
  require File.expand_path(addon)
61
+ nil
59
62
  rescue => e
60
- $stderr.puts(e.full_message)
63
+ e
61
64
  end
62
65
 
63
66
  # Instantiate all discovered addon classes
@@ -71,6 +74,8 @@ module RubyLsp
71
74
  rescue => e
72
75
  addon.add_error(e)
73
76
  end
77
+
78
+ errors
74
79
  end
75
80
 
76
81
  # Intended for use by tests for addons
@@ -65,7 +65,7 @@ module RubyLsp
65
65
  when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
66
66
  process_message(message)
67
67
  when "shutdown"
68
- $stderr.puts("Shutting down Ruby LSP...")
68
+ send_log_message("Shutting down Ruby LSP...")
69
69
 
70
70
  shutdown
71
71
 
@@ -76,7 +76,7 @@ module RubyLsp
76
76
  when "exit"
77
77
  @mutex.synchronize do
78
78
  status = @incoming_queue.closed? ? 0 : 1
79
- $stderr.puts("Shutdown complete with status #{status}")
79
+ send_log_message("Shutdown complete with status #{status}")
80
80
  exit(status)
81
81
  end
82
82
  else
@@ -145,5 +145,10 @@ module RubyLsp
145
145
  def send_empty_response(id)
146
146
  send_message(Result.new(id: id, response: nil))
147
147
  end
148
+
149
+ sig { params(message: String, type: Integer).void }
150
+ def send_log_message(message, type: Constant::MessageType::LOG)
151
+ send_message(Notification.window_log_message(message, type: Constant::MessageType::LOG))
152
+ end
148
153
  end
149
154
  end
@@ -7,25 +7,19 @@ module RubyLsp
7
7
  enums do
8
8
  Ruby = new("ruby")
9
9
  ERB = new("erb")
10
- end
11
- end
12
-
13
- class SorbetLevel < T::Enum
14
- enums do
15
- None = new("none")
16
- Ignore = new("ignore")
17
- False = new("false")
18
- True = new("true")
19
- Strict = new("strict")
10
+ RBS = new("rbs")
20
11
  end
21
12
  end
22
13
 
23
14
  extend T::Sig
24
15
  extend T::Helpers
16
+ extend T::Generic
17
+
18
+ ParseResultType = type_member
25
19
 
26
20
  abstract!
27
21
 
28
- sig { returns(Prism::ParseResult) }
22
+ sig { returns(ParseResultType) }
29
23
  attr_reader :parse_result
30
24
 
31
25
  sig { returns(String) }
@@ -48,10 +42,10 @@ module RubyLsp
48
42
  @version = T.let(version, Integer)
49
43
  @uri = T.let(uri, URI::Generic)
50
44
  @needs_parsing = T.let(true, T::Boolean)
51
- @parse_result = T.let(parse, Prism::ParseResult)
45
+ @parse_result = T.let(parse, ParseResultType)
52
46
  end
53
47
 
54
- sig { params(other: Document).returns(T::Boolean) }
48
+ sig { params(other: Document[T.untyped]).returns(T::Boolean) }
55
49
  def ==(other)
56
50
  self.class == other.class && uri == other.uri && @source == other.source
57
51
  end
@@ -64,7 +58,7 @@ module RubyLsp
64
58
  type_parameters(:T)
65
59
  .params(
66
60
  request_name: String,
67
- block: T.proc.params(document: Document).returns(T.type_parameter(:T)),
61
+ block: T.proc.params(document: Document[ParseResultType]).returns(T.type_parameter(:T)),
68
62
  ).returns(T.type_parameter(:T))
69
63
  end
70
64
  def cache_fetch(request_name, &block)
@@ -103,7 +97,7 @@ module RubyLsp
103
97
  @cache.clear
104
98
  end
105
99
 
106
- sig { abstract.returns(Prism::ParseResult) }
100
+ sig { abstract.returns(ParseResultType) }
107
101
  def parse; end
108
102
 
109
103
  sig { abstract.returns(T::Boolean) }
@@ -114,169 +108,6 @@ module RubyLsp
114
108
  Scanner.new(@source, @encoding)
115
109
  end
116
110
 
117
- sig do
118
- params(
119
- position: T::Hash[Symbol, T.untyped],
120
- node_types: T::Array[T.class_of(Prism::Node)],
121
- ).returns(NodeContext)
122
- end
123
- def locate_node(position, node_types: [])
124
- locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
125
- end
126
-
127
- sig do
128
- params(
129
- node: Prism::Node,
130
- char_position: Integer,
131
- node_types: T::Array[T.class_of(Prism::Node)],
132
- ).returns(NodeContext)
133
- end
134
- def locate(node, char_position, node_types: [])
135
- queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
136
- closest = node
137
- parent = T.let(nil, T.nilable(Prism::Node))
138
- nesting_nodes = T.let(
139
- [],
140
- T::Array[T.any(
141
- Prism::ClassNode,
142
- Prism::ModuleNode,
143
- Prism::SingletonClassNode,
144
- Prism::DefNode,
145
- Prism::BlockNode,
146
- Prism::LambdaNode,
147
- Prism::ProgramNode,
148
- )],
149
- )
150
-
151
- nesting_nodes << node if node.is_a?(Prism::ProgramNode)
152
- call_node = T.let(nil, T.nilable(Prism::CallNode))
153
-
154
- until queue.empty?
155
- candidate = queue.shift
156
-
157
- # Skip nil child nodes
158
- next if candidate.nil?
159
-
160
- # Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
161
- # same order as the visiting mechanism, which means searching the child nodes before moving on to the next
162
- # sibling
163
- T.unsafe(queue).unshift(*candidate.child_nodes)
164
-
165
- # Skip if the current node doesn't cover the desired position
166
- loc = candidate.location
167
- next unless (loc.start_offset...loc.end_offset).cover?(char_position)
168
-
169
- # If the node's start character is already past the position, then we should've found the closest node
170
- # already
171
- break if char_position < loc.start_offset
172
-
173
- # If the candidate starts after the end of the previous nesting level, then we've exited that nesting level and
174
- # need to pop the stack
175
- previous_level = nesting_nodes.last
176
- nesting_nodes.pop if previous_level && loc.start_offset > previous_level.location.end_offset
177
-
178
- # Keep track of the nesting where we found the target. This is used to determine the fully qualified name of the
179
- # target when it is a constant
180
- case candidate
181
- when Prism::ClassNode, Prism::ModuleNode, Prism::SingletonClassNode, Prism::DefNode, Prism::BlockNode,
182
- Prism::LambdaNode
183
- nesting_nodes << candidate
184
- end
185
-
186
- if candidate.is_a?(Prism::CallNode)
187
- arg_loc = candidate.arguments&.location
188
- blk_loc = candidate.block&.location
189
- if (arg_loc && (arg_loc.start_offset...arg_loc.end_offset).cover?(char_position)) ||
190
- (blk_loc && (blk_loc.start_offset...blk_loc.end_offset).cover?(char_position))
191
- call_node = candidate
192
- end
193
- end
194
-
195
- # If there are node types to filter by, and the current node is not one of those types, then skip it
196
- next if node_types.any? && node_types.none? { |type| candidate.class == type }
197
-
198
- # If the current node is narrower than or equal to the previous closest node, then it is more precise
199
- closest_loc = closest.location
200
- if loc.end_offset - loc.start_offset <= closest_loc.end_offset - closest_loc.start_offset
201
- parent = closest
202
- closest = candidate
203
- end
204
- end
205
-
206
- # When targeting the constant part of a class/module definition, we do not want the nesting to be duplicated. That
207
- # is, when targeting Bar in the following example:
208
- #
209
- # ```ruby
210
- # class Foo::Bar; end
211
- # ```
212
- # The correct target is `Foo::Bar` with an empty nesting. `Foo::Bar` should not appear in the nesting stack, even
213
- # though the class/module node does indeed enclose the target, because it would lead to incorrect behavior
214
- if closest.is_a?(Prism::ConstantReadNode) || closest.is_a?(Prism::ConstantPathNode)
215
- last_level = nesting_nodes.last
216
-
217
- if (last_level.is_a?(Prism::ModuleNode) || last_level.is_a?(Prism::ClassNode)) &&
218
- last_level.constant_path == closest
219
- nesting_nodes.pop
220
- end
221
- end
222
-
223
- NodeContext.new(closest, parent, nesting_nodes, call_node)
224
- end
225
-
226
- sig do
227
- params(
228
- range: T::Hash[Symbol, T.untyped],
229
- node_types: T::Array[T.class_of(Prism::Node)],
230
- ).returns(T.nilable(Prism::Node))
231
- end
232
- def locate_first_within_range(range, node_types: [])
233
- scanner = create_scanner
234
- start_position = scanner.find_char_position(range[:start])
235
- end_position = scanner.find_char_position(range[:end])
236
- desired_range = (start_position...end_position)
237
- queue = T.let(@parse_result.value.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
238
-
239
- until queue.empty?
240
- candidate = queue.shift
241
-
242
- # Skip nil child nodes
243
- next if candidate.nil?
244
-
245
- # Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
246
- # same order as the visiting mechanism, which means searching the child nodes before moving on to the next
247
- # sibling
248
- T.unsafe(queue).unshift(*candidate.child_nodes)
249
-
250
- # Skip if the current node doesn't cover the desired position
251
- loc = candidate.location
252
-
253
- if desired_range.cover?(loc.start_offset...loc.end_offset) &&
254
- (node_types.empty? || node_types.any? { |type| candidate.class == type })
255
- return candidate
256
- end
257
- end
258
- end
259
-
260
- sig { returns(SorbetLevel) }
261
- def sorbet_level
262
- sigil = parse_result.magic_comments.find do |comment|
263
- comment.key == "typed"
264
- end&.value
265
-
266
- case sigil
267
- when "ignore"
268
- SorbetLevel::Ignore
269
- when "false"
270
- SorbetLevel::False
271
- when "true"
272
- SorbetLevel::True
273
- when "strict", "strong"
274
- SorbetLevel::Strict
275
- else
276
- SorbetLevel::None
277
- end
278
- end
279
-
280
111
  class Scanner
281
112
  extend T::Sig
282
113
 
@@ -4,15 +4,19 @@
4
4
  module RubyLsp
5
5
  class ERBDocument < Document
6
6
  extend T::Sig
7
+ extend T::Generic
7
8
 
8
- sig { override.returns(Prism::ParseResult) }
9
+ ParseResultType = type_member { { fixed: Prism::ParseResult } }
10
+
11
+ sig { override.returns(ParseResultType) }
9
12
  def parse
10
13
  return @parse_result unless @needs_parsing
11
14
 
12
15
  @needs_parsing = false
13
16
  scanner = ERBScanner.new(@source)
14
17
  scanner.scan
15
- @parse_result = Prism.parse(scanner.ruby)
18
+ # assigning empty scopes to turn Prism into eval mode
19
+ @parse_result = Prism.parse(scanner.ruby, scopes: [[]])
16
20
  end
17
21
 
18
22
  sig { override.returns(T::Boolean) }
@@ -25,6 +29,16 @@ module RubyLsp
25
29
  LanguageId::ERB
26
30
  end
27
31
 
32
+ sig do
33
+ params(
34
+ position: T::Hash[Symbol, T.untyped],
35
+ node_types: T::Array[T.class_of(Prism::Node)],
36
+ ).returns(NodeContext)
37
+ end
38
+ def locate_node(position, node_types: [])
39
+ RubyDocument.locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
40
+ end
41
+
28
42
  class ERBScanner
29
43
  extend T::Sig
30
44
 
@@ -57,21 +57,48 @@ module RubyLsp
57
57
  @linters.filter_map { |name| @supported_formatters[name] }
58
58
  end
59
59
 
60
- sig { params(options: T::Hash[Symbol, T.untyped]).void }
60
+ # Applies the options provided by the editor and returns an array of notifications to send back to the client
61
+ sig { params(options: T::Hash[Symbol, T.untyped]).returns(T::Array[Notification]) }
61
62
  def apply_options(options)
63
+ notifications = []
62
64
  direct_dependencies = gather_direct_dependencies
63
65
  all_dependencies = gather_direct_and_indirect_dependencies
64
66
  workspace_uri = options.dig(:workspaceFolders, 0, :uri)
65
67
  @workspace_uri = URI(workspace_uri) if workspace_uri
66
68
 
67
69
  specified_formatter = options.dig(:initializationOptions, :formatter)
68
- @formatter = specified_formatter if specified_formatter
69
- @formatter = detect_formatter(direct_dependencies, all_dependencies) if @formatter == "auto"
70
+
71
+ if specified_formatter
72
+ @formatter = specified_formatter
73
+
74
+ if specified_formatter != "auto"
75
+ notifications << Notification.window_log_message("Using formatter specified by user: #{@formatter}")
76
+ end
77
+ end
78
+
79
+ if @formatter == "auto"
80
+ @formatter = detect_formatter(direct_dependencies, all_dependencies)
81
+ notifications << Notification.window_log_message("Auto detected formatter: #{@formatter}")
82
+ end
70
83
 
71
84
  specified_linters = options.dig(:initializationOptions, :linters)
72
85
  @linters = specified_linters || detect_linters(direct_dependencies, all_dependencies)
86
+
87
+ notifications << if specified_linters
88
+ Notification.window_log_message("Using linters specified by user: #{@linters.join(", ")}")
89
+ else
90
+ Notification.window_log_message("Auto detected linters: #{@linters.join(", ")}")
91
+ end
92
+
73
93
  @test_library = detect_test_library(direct_dependencies)
74
- @has_type_checker = detect_typechecker(direct_dependencies)
94
+ notifications << Notification.window_log_message("Detected test library: #{@test_library}")
95
+
96
+ @has_type_checker = detect_typechecker(all_dependencies)
97
+ if @has_type_checker
98
+ notifications << Notification.window_log_message(
99
+ "Ruby LSP detected this is a Sorbet project and will defer to the Sorbet LSP for some functionality",
100
+ )
101
+ end
75
102
 
76
103
  encodings = options.dig(:capabilities, :general, :positionEncodings)
77
104
  @encoding = if !encodings || encodings.empty?
@@ -91,6 +118,8 @@ module RubyLsp
91
118
 
92
119
  @experimental_features = options.dig(:initializationOptions, :experimentalFeaturesEnabled) || false
93
120
  @type_inferrer.experimental_features = @experimental_features
121
+
122
+ notifications
94
123
  end
95
124
 
96
125
  sig { returns(String) }
@@ -163,16 +192,7 @@ module RubyLsp
163
192
  def detect_typechecker(dependencies)
164
193
  return false if ENV["RUBY_LSP_BYPASS_TYPECHECKER"]
165
194
 
166
- # We can't read the env from within `Bundle.with_original_env` so we need to set it here.
167
- ruby_lsp_env_is_test = (ENV["RUBY_LSP_ENV"] == "test")
168
- Bundler.with_original_env do
169
- sorbet_static_detected = dependencies.any?(/^sorbet-static/)
170
- # Don't show message while running tests, since it's noisy
171
- if sorbet_static_detected && !ruby_lsp_env_is_test
172
- $stderr.puts("Ruby LSP detected this is a Sorbet project so will defer to Sorbet LSP for some functionality")
173
- end
174
- sorbet_static_detected
175
- end
195
+ dependencies.any?(/^sorbet-static/)
176
196
  rescue Bundler::GemfileNotFound
177
197
  false
178
198
  end
@@ -36,6 +36,7 @@ require "ruby_lsp/node_context"
36
36
  require "ruby_lsp/document"
37
37
  require "ruby_lsp/ruby_document"
38
38
  require "ruby_lsp/erb_document"
39
+ require "ruby_lsp/rbs_document"
39
40
  require "ruby_lsp/store"
40
41
  require "ruby_lsp/addon"
41
42
  require "ruby_lsp/requests/support/rubocop_runner"
@@ -56,7 +56,7 @@ module RubyLsp
56
56
  response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
57
57
  global_state: GlobalState,
58
58
  node_context: NodeContext,
59
- sorbet_level: Document::SorbetLevel,
59
+ sorbet_level: RubyDocument::SorbetLevel,
60
60
  dispatcher: Prism::Dispatcher,
61
61
  uri: URI::Generic,
62
62
  trigger_character: T.nilable(String),
@@ -99,7 +99,7 @@ module RubyLsp
99
99
  def on_constant_read_node_enter(node)
100
100
  # The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
101
101
  # no sigil, Sorbet will still provide completion for constants
102
- return if @sorbet_level != Document::SorbetLevel::Ignore
102
+ return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
103
103
 
104
104
  name = constant_name(node)
105
105
  return if name.nil?
@@ -122,7 +122,7 @@ module RubyLsp
122
122
  def on_constant_path_node_enter(node)
123
123
  # The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
124
124
  # no sigil, Sorbet will still provide completion for constants
125
- return if @sorbet_level != Document::SorbetLevel::Ignore
125
+ return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
126
126
 
127
127
  name = constant_name(node)
128
128
  return if name.nil?
@@ -134,7 +134,7 @@ module RubyLsp
134
134
  def on_call_node_enter(node)
135
135
  # The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
136
136
  # no sigil, Sorbet will still provide completion for constants
137
- if @sorbet_level == Document::SorbetLevel::Ignore
137
+ if @sorbet_level == RubyDocument::SorbetLevel::Ignore
138
138
  receiver = node.receiver
139
139
 
140
140
  # When writing `Foo::`, the AST assigns a method call node (because you can use that syntax to invoke
@@ -257,7 +257,7 @@ module RubyLsp
257
257
  def handle_instance_variable_completion(name, location)
258
258
  # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
259
259
  # to provide all features for them
260
- return if @sorbet_level == Document::SorbetLevel::Strict
260
+ return if @sorbet_level == RubyDocument::SorbetLevel::Strict
261
261
 
262
262
  type = @type_inferrer.infer_receiver_type(@node_context)
263
263
  return unless type
@@ -20,7 +20,7 @@ module RubyLsp
20
20
  uri: URI::Generic,
21
21
  node_context: NodeContext,
22
22
  dispatcher: Prism::Dispatcher,
23
- sorbet_level: Document::SorbetLevel,
23
+ sorbet_level: RubyDocument::SorbetLevel,
24
24
  ).void
25
25
  end
26
26
  def initialize(response_builder, global_state, language_id, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
@@ -181,7 +181,7 @@ module RubyLsp
181
181
  def handle_instance_variable_definition(name)
182
182
  # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
183
183
  # to provide all features for them
184
- return if @sorbet_level == Document::SorbetLevel::Strict
184
+ return if @sorbet_level == RubyDocument::SorbetLevel::Strict
185
185
 
186
186
  type = @type_inferrer.infer_receiver_type(@node_context)
187
187
  return unless type
@@ -289,7 +289,7 @@ module RubyLsp
289
289
  # additional behavior on top of jumping to RBIs. The only sigil where Sorbet cannot handle constants is typed
290
290
  # ignore
291
291
  file_path = entry.file_path
292
- next if @sorbet_level != Document::SorbetLevel::Ignore && not_in_dependencies?(file_path)
292
+ next if @sorbet_level != RubyDocument::SorbetLevel::Ignore && not_in_dependencies?(file_path)
293
293
 
294
294
  @response_builder << Interface::LocationLink.new(
295
295
  target_uri: URI::Generic.from_path(path: file_path).to_s,
@@ -42,7 +42,7 @@ module RubyLsp
42
42
  uri: URI::Generic,
43
43
  node_context: NodeContext,
44
44
  dispatcher: Prism::Dispatcher,
45
- sorbet_level: Document::SorbetLevel,
45
+ sorbet_level: RubyDocument::SorbetLevel,
46
46
  ).void
47
47
  end
48
48
  def initialize(response_builder, global_state, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
@@ -73,7 +73,7 @@ module RubyLsp
73
73
 
74
74
  sig { params(node: Prism::ConstantReadNode).void }
75
75
  def on_constant_read_node_enter(node)
76
- return if @sorbet_level != Document::SorbetLevel::Ignore
76
+ return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
77
77
 
78
78
  name = constant_name(node)
79
79
  return if name.nil?
@@ -83,14 +83,14 @@ module RubyLsp
83
83
 
84
84
  sig { params(node: Prism::ConstantWriteNode).void }
85
85
  def on_constant_write_node_enter(node)
86
- return if @sorbet_level != Document::SorbetLevel::Ignore
86
+ return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
87
87
 
88
88
  generate_hover(node.name.to_s, node.name_loc)
89
89
  end
90
90
 
91
91
  sig { params(node: Prism::ConstantPathNode).void }
92
92
  def on_constant_path_node_enter(node)
93
- return if @sorbet_level != Document::SorbetLevel::Ignore
93
+ return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
94
94
 
95
95
  name = constant_name(node)
96
96
  return if name.nil?
@@ -193,7 +193,7 @@ module RubyLsp
193
193
  def handle_instance_variable_hover(name)
194
194
  # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
195
195
  # to provide all features for them
196
- return if @sorbet_level == Document::SorbetLevel::Strict
196
+ return if @sorbet_level == RubyDocument::SorbetLevel::Strict
197
197
 
198
198
  type = @type_inferrer.infer_receiver_type(@node_context)
199
199
  return unless type
@@ -13,7 +13,7 @@ module RubyLsp
13
13
  global_state: GlobalState,
14
14
  node_context: NodeContext,
15
15
  dispatcher: Prism::Dispatcher,
16
- sorbet_level: Document::SorbetLevel,
16
+ sorbet_level: RubyDocument::SorbetLevel,
17
17
  ).void
18
18
  end
19
19
  def initialize(response_builder, global_state, node_context, dispatcher, sorbet_level)