ruby-lsp 0.15.0 → 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9749ddfd5f25d0f6e3c0636a070d8977c19af973943e33deba4e49cba9b473d6
4
- data.tar.gz: 1c3f663fd6487e8517154a2595be253659e2f2f9bd6a4df23c8b16a91e159c4d
3
+ metadata.gz: b52249bb9ff4600edc041d0ac28d961c7670f5dad2475b632fa5ea87c02e1657
4
+ data.tar.gz: c15ed4c4cd012c64f526ce3c31ca0f70a248467a44034dc6ffeed50cda94d9ad
5
5
  SHA512:
6
- metadata.gz: '039fc58aa31af82930cc2852819208fdd9045ed493cf368702f87e9ffd814487bf63fe522124fa3210336cfc72d806b828e2e338114a66913dbd688ed85980c3'
7
- data.tar.gz: bb4d62e3ce21fe07cda085f0284b69c356a10694125454b8160bd0c5e87789481b2d4f8036cdb4cdc2b0667c8a78c7e7a1409307722a532122172fcff8c5450c
6
+ metadata.gz: bf9936e23669e947cc802e5efe4fc5466528dff0e290d3daf255522cdca7e41d08802737da2f93b0690ca3abf3916a726926b454964f21a67bb661e902494390
7
+ data.tar.gz: 6d6b39a1dfe90b54e4e20a1a4eda471a71418b85c94ee305c5e9b1a77be8251a304d0da9f4c72fae28773e14bdb1f316da12ce41ef436c2bc72d78903a647fb1
data/README.md CHANGED
@@ -29,7 +29,7 @@ The Ruby LSP features include
29
29
  - Debugging support
30
30
  - Running and debugging tests through VS Code's UI
31
31
  - Go to definition for classes, modules, constants and required files
32
- - Showing documentaton on hover for classes, modules and constants
32
+ - Showing documentation on hover for classes, modules and constants
33
33
  - Completion for classes, modules, constants and require paths
34
34
  - Fuzzy search classes, modules and constants anywhere in the project and its dependencies (workspace symbol)
35
35
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.15.0
1
+ 0.16.1
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 }
@@ -52,17 +63,17 @@ module RubyLsp
52
63
 
53
64
  sig { returns(String) }
54
65
  def detect_test_library
66
+ if direct_dependency?(/^rspec/)
67
+ "rspec"
55
68
  # A Rails app may have a dependency on minitest, but we would instead want to use the Rails test runner provided
56
69
  # by ruby-lsp-rails.
57
- if direct_dependency?(/^rails$/)
70
+ elsif direct_dependency?(/^rails$/)
58
71
  "rails"
59
72
  # NOTE: Intentionally ends with $ to avoid mis-matching minitest-reporters, etc. in a Rails app.
60
73
  elsif direct_dependency?(/^minitest$/)
61
74
  "minitest"
62
75
  elsif direct_dependency?(/^test-unit/)
63
76
  "test-unit"
64
- elsif direct_dependency?(/^rspec/)
65
- "rspec"
66
77
  else
67
78
  "unknown"
68
79
  end
@@ -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.1
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-04 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