ruby-lsp 0.17.12 → 0.17.14

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 (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)