ruby-lsp 0.15.0 → 0.16.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9749ddfd5f25d0f6e3c0636a070d8977c19af973943e33deba4e49cba9b473d6
4
- data.tar.gz: 1c3f663fd6487e8517154a2595be253659e2f2f9bd6a4df23c8b16a91e159c4d
3
+ metadata.gz: faf267ef6ce1eb7c9471d0a63b07c8da3d60ae1aeb656b63eedb64c493746e18
4
+ data.tar.gz: 56cd98100e674d8e3de391cb107efb7c4b713715494f212f879e687d2c26cda4
5
5
  SHA512:
6
- metadata.gz: '039fc58aa31af82930cc2852819208fdd9045ed493cf368702f87e9ffd814487bf63fe522124fa3210336cfc72d806b828e2e338114a66913dbd688ed85980c3'
7
- data.tar.gz: bb4d62e3ce21fe07cda085f0284b69c356a10694125454b8160bd0c5e87789481b2d4f8036cdb4cdc2b0667c8a78c7e7a1409307722a532122172fcff8c5450c
6
+ metadata.gz: 75077a56844015e9915c1232102eca5e5bcc40687207579367b9ce836525a369e4d87e2a3e89223ca4af3bad1b8fdf09648d2839a756d171fefdc2c7d38c9df4
7
+ data.tar.gz: '025321865d6799a4ca874296d2552d8ec71f7ffa3023a104f74633ae9b858ab757dd5babee429aa38b04c1820ce64c4f7416aa626267189ac43d262744698369'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.15.0
1
+ 0.16.0
data/exe/ruby-lsp-doctor CHANGED
@@ -4,6 +4,15 @@
4
4
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
5
  require "ruby_lsp/internal"
6
6
 
7
+ if File.exist?(".index.yml")
8
+ begin
9
+ config = YAML.parse_file(".index.yml").to_ruby
10
+ rescue => e
11
+ abort("Error parsing config: #{e.message}")
12
+ end
13
+ RubyIndexer.configuration.apply_config(config)
14
+ end
15
+
7
16
  index = RubyIndexer::Index.new
8
17
 
9
18
  puts "Globbing for indexable files"
@@ -154,6 +154,8 @@ module RubyIndexer
154
154
  handle_attribute(node, reader: true, writer: true)
155
155
  when :include
156
156
  handle_include(node)
157
+ when :prepend
158
+ handle_prepend(node)
157
159
  end
158
160
  end
159
161
 
@@ -355,6 +357,16 @@ module RubyIndexer
355
357
 
356
358
  sig { params(node: Prism::CallNode).void }
357
359
  def handle_include(node)
360
+ handle_module_operation(node, :included_modules)
361
+ end
362
+
363
+ sig { params(node: Prism::CallNode).void }
364
+ def handle_prepend(node)
365
+ handle_module_operation(node, :prepended_modules)
366
+ end
367
+
368
+ sig { params(node: Prism::CallNode, operation: Symbol).void }
369
+ def handle_module_operation(node, operation)
358
370
  return unless @current_owner
359
371
 
360
372
  arguments = node.arguments&.arguments
@@ -369,7 +381,8 @@ module RubyIndexer
369
381
  # If a constant path reference is dynamic or missing parts, we can't
370
382
  # index it
371
383
  end
372
- @current_owner.included_modules.concat(names)
384
+ collection = operation == :included_modules ? @current_owner.included_modules : @current_owner.prepended_modules
385
+ collection.concat(names)
373
386
  end
374
387
  end
375
388
  end
@@ -43,6 +43,9 @@ module RubyIndexer
43
43
  sig { returns(T::Array[String]) }
44
44
  attr_accessor :included_modules
45
45
 
46
+ sig { returns(T::Array[String]) }
47
+ attr_accessor :prepended_modules
48
+
46
49
  sig do
47
50
  params(
48
51
  name: String,
@@ -54,6 +57,7 @@ module RubyIndexer
54
57
  def initialize(name, file_path, location, comments)
55
58
  super(name, file_path, location, comments)
56
59
  @included_modules = T.let([], T::Array[String])
60
+ @prepended_modules = T.let([], T::Array[String])
57
61
  end
58
62
 
59
63
  sig { returns(String) }
@@ -327,5 +327,51 @@ module RubyIndexer
327
327
  constant_path_references = T.must(@index["ConstantPathReferences"][0])
328
328
  assert_equal(["Foo::Bar", "Foo::Bar2"], constant_path_references.included_modules)
329
329
  end
330
+
331
+ def test_keeping_track_of_prepended_modules
332
+ index(<<~RUBY)
333
+ class Foo
334
+ # valid syntaxes that we can index
335
+ prepend A1
336
+ self.prepend A2
337
+ prepend A3, A4
338
+ self.prepend A5, A6
339
+
340
+ # valid syntaxes that we cannot index because of their dynamic nature
341
+ prepend some_variable_or_method_call
342
+ self.prepend some_variable_or_method_call
343
+
344
+ def something
345
+ prepend A7 # We should not index this because of this dynamic nature
346
+ end
347
+
348
+ # Valid inner class syntax definition with its own modules prepended
349
+ class Qux
350
+ prepend Corge
351
+ self.prepend Corge
352
+ prepend Baz
353
+
354
+ prepend some_variable_or_method_call
355
+ end
356
+ end
357
+
358
+ class ConstantPathReferences
359
+ prepend Foo::Bar
360
+ self.prepend Foo::Bar2
361
+
362
+ prepend dynamic::Bar
363
+ prepend Foo::
364
+ end
365
+ RUBY
366
+
367
+ foo = T.must(@index["Foo"][0])
368
+ assert_equal(["A1", "A2", "A3", "A4", "A5", "A6"], foo.prepended_modules)
369
+
370
+ qux = T.must(@index["Foo::Qux"][0])
371
+ assert_equal(["Corge", "Corge", "Baz"], qux.prepended_modules)
372
+
373
+ constant_path_references = T.must(@index["ConstantPathReferences"][0])
374
+ assert_equal(["Foo::Bar", "Foo::Bar2"], constant_path_references.prepended_modules)
375
+ end
330
376
  end
331
377
  end
@@ -50,8 +50,8 @@ module RubyLsp
50
50
  end
51
51
 
52
52
  # Discovers and loads all addons. Returns the list of activated addons
53
- sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
54
- def load_addons(message_queue)
53
+ sig { params(global_state: GlobalState, outgoing_queue: Thread::Queue).returns(T::Array[Addon]) }
54
+ def load_addons(global_state, outgoing_queue)
55
55
  # Require all addons entry points, which should be placed under
56
56
  # `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
57
57
  Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
@@ -67,7 +67,7 @@ module RubyLsp
67
67
  # Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
68
68
  # fail to boot the server
69
69
  addons.each do |addon|
70
- addon.activate(message_queue)
70
+ addon.activate(global_state, outgoing_queue)
71
71
  rescue => e
72
72
  addon.add_error(e)
73
73
  end
@@ -105,8 +105,8 @@ module RubyLsp
105
105
 
106
106
  # Each addon should implement `MyAddon#activate` and use to perform any sort of initialization, such as
107
107
  # reading information into memory or even spawning a separate process
108
- sig { abstract.params(message_queue: Thread::Queue).void }
109
- def activate(message_queue); end
108
+ sig { abstract.params(global_state: GlobalState, outgoing_queue: Thread::Queue).void }
109
+ def activate(global_state, outgoing_queue); end
110
110
 
111
111
  # Each addon should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
112
112
  # child process
@@ -121,23 +121,21 @@ module RubyLsp
121
121
  sig do
122
122
  overridable.params(
123
123
  response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
124
- global_state: GlobalState,
125
124
  uri: URI::Generic,
126
125
  dispatcher: Prism::Dispatcher,
127
126
  ).void
128
127
  end
129
- def create_code_lens_listener(response_builder, global_state, uri, dispatcher); end
128
+ def create_code_lens_listener(response_builder, uri, dispatcher); end
130
129
 
131
130
  # Creates a new Hover listener. This method is invoked on every Hover request
132
131
  sig do
133
132
  overridable.params(
134
133
  response_builder: ResponseBuilders::Hover,
135
- global_state: GlobalState,
136
134
  nesting: T::Array[String],
137
135
  dispatcher: Prism::Dispatcher,
138
136
  ).void
139
137
  end
140
- def create_hover_listener(response_builder, global_state, nesting, dispatcher); end
138
+ def create_hover_listener(response_builder, nesting, dispatcher); end
141
139
 
142
140
  # Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
143
141
  sig do
@@ -160,24 +158,22 @@ module RubyLsp
160
158
  sig do
161
159
  overridable.params(
162
160
  response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::Location],
163
- global_state: GlobalState,
164
161
  uri: URI::Generic,
165
162
  nesting: T::Array[String],
166
163
  dispatcher: Prism::Dispatcher,
167
164
  ).void
168
165
  end
169
- def create_definition_listener(response_builder, global_state, uri, nesting, dispatcher); end
166
+ def create_definition_listener(response_builder, uri, nesting, dispatcher); end
170
167
 
171
168
  # Creates a new Completion listener. This method is invoked on every Completion request
172
169
  sig do
173
170
  overridable.params(
174
171
  response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
175
- global_state: GlobalState,
176
172
  nesting: T::Array[String],
177
173
  dispatcher: Prism::Dispatcher,
178
174
  uri: URI::Generic,
179
175
  ).void
180
176
  end
181
- def create_completion_listener(response_builder, global_state, nesting, dispatcher, uri); end
177
+ def create_completion_listener(response_builder, nesting, dispatcher, uri); end
182
178
  end
183
179
  end
@@ -25,6 +25,17 @@ module RubyLsp
25
25
  @test_library = T.let(detect_test_library, String)
26
26
  @typechecker = T.let(detect_typechecker, T::Boolean)
27
27
  @index = T.let(RubyIndexer::Index.new, RubyIndexer::Index)
28
+ @supported_formatters = T.let({}, T::Hash[String, Requests::Support::Formatter])
29
+ end
30
+
31
+ sig { params(identifier: String, instance: Requests::Support::Formatter).void }
32
+ def register_formatter(identifier, instance)
33
+ @supported_formatters[identifier] = instance
34
+ end
35
+
36
+ sig { returns(T.nilable(Requests::Support::Formatter)) }
37
+ def active_formatter
38
+ @supported_formatters[@formatter]
28
39
  end
29
40
 
30
41
  sig { params(options: T::Hash[Symbol, T.untyped]).void }
@@ -34,3 +34,5 @@ require "ruby_lsp/ruby_document"
34
34
  require "ruby_lsp/store"
35
35
  require "ruby_lsp/addon"
36
36
  require "ruby_lsp/requests/support/rubocop_runner"
37
+ require "ruby_lsp/requests/support/rubocop_formatter"
38
+ require "ruby_lsp/requests/support/syntax_tree_formatter"
@@ -48,7 +48,7 @@ module RubyLsp
48
48
  Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
49
49
 
50
50
  Addon.addons.each do |addon|
51
- addon.create_code_lens_listener(@response_builder, global_state, uri, dispatcher)
51
+ addon.create_code_lens_listener(@response_builder, uri, dispatcher)
52
52
  end
53
53
  end
54
54
 
@@ -78,7 +78,7 @@ module RubyLsp
78
78
  )
79
79
 
80
80
  Addon.addons.each do |addon|
81
- addon.create_completion_listener(@response_builder, global_state, nesting, dispatcher, document.uri)
81
+ addon.create_completion_listener(@response_builder, nesting, dispatcher, document.uri)
82
82
  end
83
83
 
84
84
  return unless matched && parent
@@ -67,7 +67,7 @@ module RubyLsp
67
67
  )
68
68
 
69
69
  Addon.addons.each do |addon|
70
- addon.create_definition_listener(@response_builder, global_state, document.uri, nesting, dispatcher)
70
+ addon.create_definition_listener(@response_builder, document.uri, nesting, dispatcher)
71
71
  end
72
72
 
73
73
  @target = T.let(target, T.nilable(Prism::Node))
@@ -1,8 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "ruby_lsp/requests/support/rubocop_diagnostics_runner"
5
-
6
4
  module RubyLsp
7
5
  module Requests
8
6
  # ![Diagnostics demo](../../diagnostics.gif)
@@ -33,9 +31,10 @@ module RubyLsp
33
31
  end
34
32
  end
35
33
 
36
- sig { params(document: Document).void }
37
- def initialize(document)
34
+ sig { params(global_state: GlobalState, document: Document).void }
35
+ def initialize(global_state, document)
38
36
  super()
37
+ @active_formatter = T.let(global_state.active_formatter, T.nilable(Support::Formatter))
39
38
  @document = document
40
39
  @uri = T.let(document.uri, URI::Generic)
41
40
  end
@@ -46,15 +45,10 @@ module RubyLsp
46
45
  diagnostics.concat(syntax_error_diagnostics, syntax_warning_diagnostics)
47
46
 
48
47
  # Running RuboCop is slow, so to avoid excessive runs we only do so if the file is syntactically valid
49
- return diagnostics if @document.syntax_error?
50
-
51
- diagnostics.concat(
52
- Support::RuboCopDiagnosticsRunner.instance.run(
53
- @uri,
54
- @document,
55
- ).map!(&:to_lsp_diagnostic),
56
- ) if defined?(Support::RuboCopDiagnosticsRunner)
48
+ return diagnostics if @document.syntax_error? || !@active_formatter
57
49
 
50
+ formatter_diagnostics = @active_formatter.run_diagnostic(@uri, @document)
51
+ diagnostics.concat(formatter_diagnostics) if formatter_diagnostics
58
52
  diagnostics
59
53
  end
60
54
 
@@ -1,9 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "ruby_lsp/requests/support/rubocop_formatting_runner"
5
- require "ruby_lsp/requests/support/syntax_tree_formatting_runner"
6
-
7
4
  module RubyLsp
8
5
  module Requests
9
6
  # ![Formatting symbol demo](../../formatting.gif)
@@ -26,47 +23,24 @@ module RubyLsp
26
23
  # end
27
24
  # ```
28
25
  class Formatting < Request
29
- class Error < StandardError; end
30
- class InvalidFormatter < StandardError; end
31
-
32
- @formatters = T.let({}, T::Hash[String, Support::FormatterRunner])
33
-
34
- class << self
35
- extend T::Sig
36
-
37
- sig { returns(T::Hash[String, Support::FormatterRunner]) }
38
- attr_reader :formatters
39
-
40
- sig { params(identifier: String, instance: Support::FormatterRunner).void }
41
- def register_formatter(identifier, instance)
42
- @formatters[identifier] = instance
43
- end
44
- end
45
-
46
- if defined?(Support::RuboCopFormattingRunner)
47
- register_formatter("rubocop", Support::RuboCopFormattingRunner.instance)
48
- end
49
-
50
- if defined?(Support::SyntaxTreeFormattingRunner)
51
- register_formatter("syntax_tree", Support::SyntaxTreeFormattingRunner.instance)
52
- end
53
-
54
26
  extend T::Sig
55
27
 
56
- sig { params(document: Document, formatter: String).void }
57
- def initialize(document, formatter: "auto")
28
+ class Error < StandardError; end
29
+
30
+ sig { params(global_state: GlobalState, document: Document).void }
31
+ def initialize(global_state, document)
58
32
  super()
59
33
  @document = document
34
+ @active_formatter = T.let(global_state.active_formatter, T.nilable(Support::Formatter))
60
35
  @uri = T.let(document.uri, URI::Generic)
61
- @formatter = formatter
62
36
  end
63
37
 
64
38
  sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
65
39
  def perform
66
- return if @formatter == "none"
40
+ return unless @active_formatter
67
41
  return if @document.syntax_error?
68
42
 
69
- formatted_text = formatted_file
43
+ formatted_text = @active_formatter.run_formatting(@uri, @document)
70
44
  return unless formatted_text
71
45
 
72
46
  size = @document.source.size
@@ -82,16 +56,6 @@ module RubyLsp
82
56
  ),
83
57
  ]
84
58
  end
85
-
86
- private
87
-
88
- sig { returns(T.nilable(String)) }
89
- def formatted_file
90
- formatter_runner = Formatting.formatters[@formatter]
91
- raise InvalidFormatter, "Formatter is not available: #{@formatter}" unless formatter_runner
92
-
93
- formatter_runner.run(@uri, @document)
94
- end
95
59
  end
96
60
  end
97
61
  end
@@ -64,7 +64,7 @@ module RubyLsp
64
64
  @response_builder = T.let(ResponseBuilders::Hover.new, ResponseBuilders::Hover)
65
65
  Listeners::Hover.new(@response_builder, global_state, uri, nesting, dispatcher, typechecker_enabled)
66
66
  Addon.addons.each do |addon|
67
- addon.create_hover_listener(@response_builder, global_state, nesting, dispatcher)
67
+ addon.create_hover_listener(@response_builder, nesting, dispatcher)
68
68
  end
69
69
 
70
70
  @dispatcher = dispatcher
@@ -8,6 +8,8 @@ module RubyLsp
8
8
  extend T::Sig
9
9
  extend T::Generic
10
10
 
11
+ class InvalidFormatter < StandardError; end
12
+
11
13
  abstract!
12
14
 
13
15
  sig { abstract.returns(T.anything) }
@@ -29,7 +29,7 @@ module RubyLsp
29
29
  sig { returns(Interface::SemanticTokensRegistrationOptions) }
30
30
  def provider
31
31
  Interface::SemanticTokensRegistrationOptions.new(
32
- document_selector: { scheme: "file", language: "ruby" },
32
+ document_selector: [{ language: "ruby" }],
33
33
  legend: Interface::SemanticTokensLegend.new(
34
34
  token_types: ResponseBuilders::SemanticHighlighting::TOKEN_TYPES.keys,
35
35
  token_modifiers: ResponseBuilders::SemanticHighlighting::TOKEN_MODIFIERS.keys,
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ module Support
7
+ module Formatter
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ interface!
12
+
13
+ sig { abstract.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
14
+ def run_formatting(uri, document); end
15
+
16
+ sig do
17
+ abstract.params(
18
+ uri: URI::Generic,
19
+ document: Document,
20
+ ).returns(T.nilable(T::Array[Interface::Diagnostic]))
21
+ end
22
+ def run_diagnostic(uri, document); end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
5
+
6
+ require "singleton"
7
+
8
+ module RubyLsp
9
+ module Requests
10
+ module Support
11
+ class RuboCopFormatter
12
+ extend T::Sig
13
+ include Formatter
14
+ include Singleton
15
+
16
+ sig { void }
17
+ def initialize
18
+ @diagnostic_runner = T.let(RuboCopRunner.new, RuboCopRunner)
19
+ # -a is for "--auto-correct" (or "--autocorrect" on newer versions of RuboCop)
20
+ @format_runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
21
+ end
22
+
23
+ sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
24
+ def run_formatting(uri, document)
25
+ filename = T.must(uri.to_standardized_path || uri.opaque)
26
+
27
+ # Invoke RuboCop with just this file in `paths`
28
+ @format_runner.run(filename, document.source)
29
+ @format_runner.formatted_source
30
+ end
31
+
32
+ sig do
33
+ override.params(
34
+ uri: URI::Generic,
35
+ document: Document,
36
+ ).returns(T.nilable(T::Array[Interface::Diagnostic]))
37
+ end
38
+ def run_diagnostic(uri, document)
39
+ filename = T.must(uri.to_standardized_path || uri.opaque)
40
+ # Invoke RuboCop with just this file in `paths`
41
+ @diagnostic_runner.run(filename, document.source)
42
+
43
+ @diagnostic_runner.offenses.map do |offense|
44
+ Support::RuboCopDiagnostic.new(document, offense, uri).to_lsp_diagnostic
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -14,10 +14,10 @@ module RubyLsp
14
14
  module Requests
15
15
  module Support
16
16
  # :nodoc:
17
- class SyntaxTreeFormattingRunner
17
+ class SyntaxTreeFormatter
18
18
  extend T::Sig
19
19
  include Singleton
20
- include Support::FormatterRunner
20
+ include Support::Formatter
21
21
 
22
22
  sig { void }
23
23
  def initialize
@@ -33,12 +33,22 @@ module RubyLsp
33
33
  end
34
34
 
35
35
  sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
36
- def run(uri, document)
36
+ def run_formatting(uri, document)
37
37
  path = uri.to_standardized_path
38
38
  return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
39
39
 
40
40
  SyntaxTree.format(document.source, @options.print_width, options: @options.formatter_options)
41
41
  end
42
+
43
+ sig do
44
+ override.params(
45
+ uri: URI::Generic,
46
+ document: Document,
47
+ ).returns(T.nilable(T::Array[Interface::Diagnostic]))
48
+ end
49
+ def run_diagnostic(uri, document)
50
+ nil
51
+ end
42
52
  end
43
53
  end
44
54
  end
@@ -56,7 +56,7 @@ module RubyLsp
56
56
  autoload :Sorbet, "ruby_lsp/requests/support/sorbet"
57
57
  autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
58
58
  autoload :Common, "ruby_lsp/requests/support/common"
59
- autoload :FormatterRunner, "ruby_lsp/requests/support/formatter_runner"
59
+ autoload :Formatter, "ruby_lsp/requests/support/formatter"
60
60
  end
61
61
  end
62
62
  end
@@ -88,6 +88,26 @@ module RubyLsp
88
88
  $stderr.puts("Error processing #{message[:method]}: #{e.full_message}")
89
89
  end
90
90
 
91
+ sig { void }
92
+ def load_addons
93
+ Addon.load_addons(@global_state, @outgoing_queue)
94
+ errored_addons = Addon.addons.select(&:error?)
95
+
96
+ if errored_addons.any?
97
+ send_message(
98
+ Notification.new(
99
+ method: "window/showMessage",
100
+ params: Interface::ShowMessageParams.new(
101
+ type: Constant::MessageType::WARNING,
102
+ message: "Error loading addons:\n\n#{errored_addons.map(&:formatted_errors).join("\n\n")}",
103
+ ),
104
+ ),
105
+ )
106
+
107
+ $stderr.puts(errored_addons.map(&:backtraces).join("\n\n"))
108
+ end
109
+ end
110
+
91
111
  private
92
112
 
93
113
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
@@ -213,23 +233,7 @@ module RubyLsp
213
233
 
214
234
  sig { void }
215
235
  def run_initialized
216
- Addon.load_addons(@outgoing_queue)
217
- errored_addons = Addon.addons.select(&:error?)
218
-
219
- if errored_addons.any?
220
- send_message(
221
- Notification.new(
222
- method: "window/showMessage",
223
- params: Interface::ShowMessageParams.new(
224
- type: Constant::MessageType::WARNING,
225
- message: "Error loading addons:\n\n#{errored_addons.map(&:formatted_errors).join("\n\n")}",
226
- ),
227
- ),
228
- )
229
-
230
- $stderr.puts(errored_addons.map(&:backtraces).join("\n\n"))
231
- end
232
-
236
+ load_addons
233
237
  RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
234
238
 
235
239
  indexing_config = {}
@@ -254,6 +258,13 @@ module RubyLsp
254
258
  end
255
259
  end
256
260
 
261
+ if defined?(Requests::Support::RuboCopFormatter)
262
+ @global_state.register_formatter("rubocop", Requests::Support::RuboCopFormatter.instance)
263
+ end
264
+ if defined?(Requests::Support::SyntaxTreeFormatter)
265
+ @global_state.register_formatter("syntax_tree", Requests::Support::SyntaxTreeFormatter.instance)
266
+ end
267
+
257
268
  perform_initial_indexing(indexing_config)
258
269
  check_formatter_is_available
259
270
  end
@@ -387,9 +398,9 @@ module RubyLsp
387
398
  return
388
399
  end
389
400
 
390
- response = Requests::Formatting.new(@store.get(uri), formatter: @global_state.formatter).perform
401
+ response = Requests::Formatting.new(@global_state, @store.get(uri)).perform
391
402
  send_message(Result.new(id: message[:id], response: response))
392
- rescue Requests::Formatting::InvalidFormatter => error
403
+ rescue Requests::Request::InvalidFormatter => error
393
404
  send_message(Notification.window_show_error("Configuration error: #{error.message}"))
394
405
  send_empty_response(message[:id])
395
406
  rescue StandardError, LoadError => error
@@ -512,7 +523,7 @@ module RubyLsp
512
523
  end
513
524
 
514
525
  response = @store.cache_fetch(uri, "textDocument/diagnostic") do |document|
515
- Requests::Diagnostics.new(document).perform
526
+ Requests::Diagnostics.new(@global_state, document).perform
516
527
  end
517
528
 
518
529
  send_message(
@@ -521,6 +532,9 @@ module RubyLsp
521
532
  response: response && Interface::FullDocumentDiagnosticReport.new(kind: "full", items: response),
522
533
  ),
523
534
  )
535
+ rescue Requests::Request::InvalidFormatter => error
536
+ send_message(Notification.window_show_error("Configuration error: #{error.message}"))
537
+ send_empty_response(message[:id])
524
538
  rescue StandardError, LoadError => error
525
539
  send_message(Notification.window_show_error("Error running diagnostics: #{error.message}"))
526
540
  send_empty_response(message[:id])
@@ -13,10 +13,12 @@ module RubyLsp
13
13
  source: T.nilable(String),
14
14
  uri: URI::Generic,
15
15
  stub_no_typechecker: T::Boolean,
16
+ load_addons: T::Boolean,
16
17
  block: T.proc.params(server: RubyLsp::Server, uri: URI::Generic).returns(T.type_parameter(:T)),
17
18
  ).returns(T.type_parameter(:T))
18
19
  end
19
- def with_server(source = nil, uri = Kernel.URI("file:///fake.rb"), stub_no_typechecker: false, &block)
20
+ def with_server(source = nil, uri = Kernel.URI("file:///fake.rb"), stub_no_typechecker: false, load_addons: true,
21
+ &block)
20
22
  server = RubyLsp::Server.new(test_mode: true)
21
23
  server.global_state.stubs(:typechecker).returns(false) if stub_no_typechecker
22
24
 
@@ -37,8 +39,13 @@ module RubyLsp
37
39
  RubyIndexer::IndexablePath.new(nil, T.must(uri.to_standardized_path)),
38
40
  source,
39
41
  )
42
+ server.load_addons if load_addons
40
43
  block.call(server, uri)
41
44
  ensure
45
+ if load_addons
46
+ RubyLsp::Addon.addons.each(&:deactivate)
47
+ RubyLsp::Addon.addons.clear
48
+ end
42
49
  T.must(server).run_shutdown
43
50
  end
44
51
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-27 00:00:00.000000000 Z
11
+ date: 2024-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: language_server-protocol
@@ -134,15 +134,14 @@ files:
134
134
  - lib/ruby_lsp/requests/signature_help.rb
135
135
  - lib/ruby_lsp/requests/support/annotation.rb
136
136
  - lib/ruby_lsp/requests/support/common.rb
137
- - lib/ruby_lsp/requests/support/formatter_runner.rb
137
+ - lib/ruby_lsp/requests/support/formatter.rb
138
138
  - lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
139
- - lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb
140
- - lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb
139
+ - lib/ruby_lsp/requests/support/rubocop_formatter.rb
141
140
  - lib/ruby_lsp/requests/support/rubocop_runner.rb
142
141
  - lib/ruby_lsp/requests/support/selection_range.rb
143
142
  - lib/ruby_lsp/requests/support/sorbet.rb
144
143
  - lib/ruby_lsp/requests/support/source_uri.rb
145
- - lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb
144
+ - lib/ruby_lsp/requests/support/syntax_tree_formatter.rb
146
145
  - lib/ruby_lsp/requests/workspace_symbol.rb
147
146
  - lib/ruby_lsp/response_builders.rb
148
147
  - lib/ruby_lsp/response_builders/collection_response_builder.rb
@@ -1,18 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module RubyLsp
5
- module Requests
6
- module Support
7
- module FormatterRunner
8
- extend T::Sig
9
- extend T::Helpers
10
-
11
- interface!
12
-
13
- sig { abstract.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
14
- def run(uri, document); end
15
- end
16
- end
17
- end
18
- end
@@ -1,34 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
5
-
6
- require "singleton"
7
-
8
- module RubyLsp
9
- module Requests
10
- module Support
11
- # :nodoc:
12
- class RuboCopDiagnosticsRunner
13
- extend T::Sig
14
- include Singleton
15
-
16
- sig { void }
17
- def initialize
18
- @runner = T.let(RuboCopRunner.new, RuboCopRunner)
19
- end
20
-
21
- sig { params(uri: URI::Generic, document: Document).returns(T::Array[Support::RuboCopDiagnostic]) }
22
- def run(uri, document)
23
- filename = T.must(uri.to_standardized_path || uri.opaque)
24
- # Invoke RuboCop with just this file in `paths`
25
- @runner.run(filename, document.source)
26
-
27
- @runner.offenses.map do |offense|
28
- Support::RuboCopDiagnostic.new(document, offense, uri)
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,35 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
5
-
6
- require "singleton"
7
-
8
- module RubyLsp
9
- module Requests
10
- module Support
11
- # :nodoc:
12
- class RuboCopFormattingRunner
13
- extend T::Sig
14
- include Singleton
15
- include Support::FormatterRunner
16
-
17
- sig { void }
18
- def initialize
19
- # -a is for "--auto-correct" (or "--autocorrect" on newer versions of RuboCop)
20
- @runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
21
- end
22
-
23
- sig { override.params(uri: URI::Generic, document: Document).returns(String) }
24
- def run(uri, document)
25
- filename = T.must(uri.to_standardized_path || uri.opaque)
26
-
27
- # Invoke RuboCop with just this file in `paths`
28
- @runner.run(filename, document.source)
29
-
30
- @runner.formatted_source
31
- end
32
- end
33
- end
34
- end
35
- end