ruby-lsp 0.14.6 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp +1 -16
- data/exe/ruby-lsp-check +13 -22
- data/exe/ruby-lsp-doctor +9 -0
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +14 -1
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +11 -23
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +4 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +46 -0
- data/lib/ruby_indexer/test/configuration_test.rb +2 -11
- data/lib/ruby_lsp/addon.rb +18 -9
- data/lib/ruby_lsp/base_server.rb +147 -0
- data/lib/ruby_lsp/document.rb +0 -5
- data/lib/ruby_lsp/{requests/support/dependency_detector.rb → global_state.rb} +41 -9
- data/lib/ruby_lsp/internal.rb +4 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +13 -9
- data/lib/ruby_lsp/listeners/completion.rb +13 -14
- data/lib/ruby_lsp/listeners/definition.rb +4 -3
- data/lib/ruby_lsp/listeners/document_symbol.rb +91 -3
- data/lib/ruby_lsp/listeners/hover.rb +6 -5
- data/lib/ruby_lsp/listeners/signature_help.rb +7 -4
- data/lib/ruby_lsp/load_sorbet.rb +62 -0
- data/lib/ruby_lsp/requests/code_lens.rb +3 -2
- data/lib/ruby_lsp/requests/completion.rb +15 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +56 -0
- data/lib/ruby_lsp/requests/definition.rb +11 -4
- data/lib/ruby_lsp/requests/diagnostics.rb +6 -12
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/formatting.rb +7 -43
- data/lib/ruby_lsp/requests/hover.rb +4 -4
- data/lib/ruby_lsp/requests/request.rb +2 -0
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/signature_help.rb +4 -3
- data/lib/ruby_lsp/requests/support/common.rb +16 -5
- data/lib/ruby_lsp/requests/support/formatter.rb +26 -0
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +50 -0
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
- data/lib/ruby_lsp/requests/support/{syntax_tree_formatting_runner.rb → syntax_tree_formatter.rb} +13 -3
- data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
- data/lib/ruby_lsp/requests.rb +3 -1
- data/lib/ruby_lsp/server.rb +770 -142
- data/lib/ruby_lsp/store.rb +0 -8
- data/lib/ruby_lsp/test_helper.rb +52 -0
- data/lib/ruby_lsp/utils.rb +68 -33
- metadata +11 -9
- data/lib/ruby_lsp/executor.rb +0 -614
- data/lib/ruby_lsp/requests/support/formatter_runner.rb +0 -18
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +0 -34
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +0 -35
@@ -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
|
-
|
57
|
-
|
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
|
40
|
+
return unless @active_formatter
|
67
41
|
return if @document.syntax_error?
|
68
42
|
|
69
|
-
formatted_text =
|
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
|
@@ -33,13 +33,13 @@ module RubyLsp
|
|
33
33
|
sig do
|
34
34
|
params(
|
35
35
|
document: Document,
|
36
|
-
|
36
|
+
global_state: GlobalState,
|
37
37
|
position: T::Hash[Symbol, T.untyped],
|
38
38
|
dispatcher: Prism::Dispatcher,
|
39
39
|
typechecker_enabled: T::Boolean,
|
40
40
|
).void
|
41
41
|
end
|
42
|
-
def initialize(document,
|
42
|
+
def initialize(document, global_state, position, dispatcher, typechecker_enabled)
|
43
43
|
super()
|
44
44
|
@target = T.let(nil, T.nilable(Prism::Node))
|
45
45
|
@target, parent, nesting = document.locate_node(
|
@@ -62,9 +62,9 @@ module RubyLsp
|
|
62
62
|
|
63
63
|
uri = document.uri
|
64
64
|
@response_builder = T.let(ResponseBuilders::Hover.new, ResponseBuilders::Hover)
|
65
|
-
Listeners::Hover.new(@response_builder, uri, nesting,
|
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, nesting,
|
67
|
+
addon.create_hover_listener(@response_builder, nesting, dispatcher)
|
68
68
|
end
|
69
69
|
|
70
70
|
@dispatcher = dispatcher
|
@@ -29,7 +29,7 @@ module RubyLsp
|
|
29
29
|
sig { returns(Interface::SemanticTokensRegistrationOptions) }
|
30
30
|
def provider
|
31
31
|
Interface::SemanticTokensRegistrationOptions.new(
|
32
|
-
document_selector: {
|
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,
|
@@ -42,13 +42,14 @@ module RubyLsp
|
|
42
42
|
sig do
|
43
43
|
params(
|
44
44
|
document: Document,
|
45
|
-
|
45
|
+
global_state: GlobalState,
|
46
46
|
position: T::Hash[Symbol, T.untyped],
|
47
47
|
context: T.nilable(T::Hash[Symbol, T.untyped]),
|
48
48
|
dispatcher: Prism::Dispatcher,
|
49
|
+
typechecker_enabled: T::Boolean,
|
49
50
|
).void
|
50
51
|
end
|
51
|
-
def initialize(document,
|
52
|
+
def initialize(document, global_state, position, context, dispatcher, typechecker_enabled) # rubocop:disable Metrics/ParameterLists
|
52
53
|
super()
|
53
54
|
target, parent, nesting = document.locate_node(
|
54
55
|
{ line: position[:line], character: position[:character] },
|
@@ -60,7 +61,7 @@ module RubyLsp
|
|
60
61
|
@target = T.let(target, T.nilable(Prism::Node))
|
61
62
|
@dispatcher = dispatcher
|
62
63
|
@response_builder = T.let(ResponseBuilders::SignatureHelp.new, ResponseBuilders::SignatureHelp)
|
63
|
-
Listeners::SignatureHelp.new(@response_builder, nesting,
|
64
|
+
Listeners::SignatureHelp.new(@response_builder, global_state, nesting, dispatcher, typechecker_enabled)
|
64
65
|
end
|
65
66
|
|
66
67
|
sig { override.returns(T.nilable(Interface::SignatureHelp)) }
|
@@ -86,13 +86,16 @@ module RubyLsp
|
|
86
86
|
params(
|
87
87
|
title: String,
|
88
88
|
entries: T.any(T::Array[RubyIndexer::Entry], RubyIndexer::Entry),
|
89
|
+
max_entries: T.nilable(Integer),
|
89
90
|
).returns(T::Hash[Symbol, String])
|
90
91
|
end
|
91
|
-
def categorized_markdown_from_index_entries(title, entries)
|
92
|
+
def categorized_markdown_from_index_entries(title, entries, max_entries = nil)
|
92
93
|
markdown_title = "```ruby\n#{title}\n```"
|
93
94
|
definitions = []
|
94
95
|
content = +""
|
95
|
-
Array(entries)
|
96
|
+
entries = Array(entries)
|
97
|
+
entries_to_format = max_entries ? entries.take(max_entries) : entries
|
98
|
+
entries_to_format.each do |entry|
|
96
99
|
loc = entry.location
|
97
100
|
|
98
101
|
# We always handle locations as zero based. However, for file links in Markdown we need them to be one
|
@@ -108,9 +111,16 @@ module RubyLsp
|
|
108
111
|
content << "\n\n#{entry.comments.join("\n")}" unless entry.comments.empty?
|
109
112
|
end
|
110
113
|
|
114
|
+
additional_entries_text = if max_entries && entries.length > max_entries
|
115
|
+
additional = entries.length - max_entries
|
116
|
+
" | #{additional} other#{additional > 1 ? "s" : ""}"
|
117
|
+
else
|
118
|
+
""
|
119
|
+
end
|
120
|
+
|
111
121
|
{
|
112
122
|
title: markdown_title,
|
113
|
-
links: "**Definitions**: #{definitions.join(" | ")}",
|
123
|
+
links: "**Definitions**: #{definitions.join(" | ")}#{additional_entries_text}",
|
114
124
|
documentation: content,
|
115
125
|
}
|
116
126
|
end
|
@@ -119,10 +129,11 @@ module RubyLsp
|
|
119
129
|
params(
|
120
130
|
title: String,
|
121
131
|
entries: T.any(T::Array[RubyIndexer::Entry], RubyIndexer::Entry),
|
132
|
+
max_entries: T.nilable(Integer),
|
122
133
|
).returns(String)
|
123
134
|
end
|
124
|
-
def markdown_from_index_entries(title, entries)
|
125
|
-
categorized_markdown = categorized_markdown_from_index_entries(title, entries)
|
135
|
+
def markdown_from_index_entries(title, entries, max_entries = nil)
|
136
|
+
categorized_markdown = categorized_markdown_from_index_entries(title, entries, max_entries)
|
126
137
|
|
127
138
|
<<~MARKDOWN.chomp
|
128
139
|
#{categorized_markdown[:title]}
|
@@ -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
|
@@ -92,6 +92,10 @@ module RubyLsp
|
|
92
92
|
@options[:stdin] = contents
|
93
93
|
|
94
94
|
super([path])
|
95
|
+
|
96
|
+
# RuboCop rescues interrupts and then sets the `@aborting` variable to true. We don't want them to be rescued,
|
97
|
+
# so here we re-raise in case RuboCop received an interrupt.
|
98
|
+
raise Interrupt if aborting?
|
95
99
|
rescue RuboCop::Runner::InfiniteCorrectionLoop => error
|
96
100
|
raise Formatting::Error, error.message
|
97
101
|
rescue RuboCop::ValidationError => error
|
data/lib/ruby_lsp/requests/support/{syntax_tree_formatting_runner.rb → syntax_tree_formatter.rb}
RENAMED
@@ -14,10 +14,10 @@ module RubyLsp
|
|
14
14
|
module Requests
|
15
15
|
module Support
|
16
16
|
# :nodoc:
|
17
|
-
class
|
17
|
+
class SyntaxTreeFormatter
|
18
18
|
extend T::Sig
|
19
19
|
include Singleton
|
20
|
-
include Support::
|
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
|
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
|
@@ -22,11 +22,12 @@ module RubyLsp
|
|
22
22
|
extend T::Sig
|
23
23
|
include Support::Common
|
24
24
|
|
25
|
-
sig { params(query: T.nilable(String)
|
26
|
-
def initialize(
|
25
|
+
sig { params(global_state: GlobalState, query: T.nilable(String)).void }
|
26
|
+
def initialize(global_state, query)
|
27
27
|
super()
|
28
|
+
@global_state = global_state
|
28
29
|
@query = query
|
29
|
-
@index = index
|
30
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
30
31
|
end
|
31
32
|
|
32
33
|
sig { override.returns(T::Array[Interface::WorkspaceSymbol]) }
|
@@ -35,7 +36,7 @@ module RubyLsp
|
|
35
36
|
# If the project is using Sorbet, we let Sorbet handle symbols defined inside the project itself and RBIs, but
|
36
37
|
# we still return entries defined in gems to allow developers to jump directly to the source
|
37
38
|
file_path = entry.file_path
|
38
|
-
next if
|
39
|
+
next if @global_state.typechecker && not_in_dependencies?(file_path)
|
39
40
|
|
40
41
|
# We should never show private symbols when searching the entire workspace
|
41
42
|
next if entry.visibility == :private
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -18,6 +18,7 @@ module RubyLsp
|
|
18
18
|
# - [DocumentHighlight](rdoc-ref:RubyLsp::Requests::DocumentHighlight)
|
19
19
|
# - [InlayHint](rdoc-ref:RubyLsp::Requests::InlayHints)
|
20
20
|
# - [Completion](rdoc-ref:RubyLsp::Requests::Completion)
|
21
|
+
# - [CompletionResolve](rdoc-ref:RubyLsp::Requests::CompletionResolve)
|
21
22
|
# - [CodeLens](rdoc-ref:RubyLsp::Requests::CodeLens)
|
22
23
|
# - [Definition](rdoc-ref:RubyLsp::Requests::Definition)
|
23
24
|
# - [ShowSyntaxTree](rdoc-ref:RubyLsp::Requests::ShowSyntaxTree)
|
@@ -40,6 +41,7 @@ module RubyLsp
|
|
40
41
|
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
41
42
|
autoload :InlayHints, "ruby_lsp/requests/inlay_hints"
|
42
43
|
autoload :Completion, "ruby_lsp/requests/completion"
|
44
|
+
autoload :CompletionResolve, "ruby_lsp/requests/completion_resolve"
|
43
45
|
autoload :CodeLens, "ruby_lsp/requests/code_lens"
|
44
46
|
autoload :Definition, "ruby_lsp/requests/definition"
|
45
47
|
autoload :ShowSyntaxTree, "ruby_lsp/requests/show_syntax_tree"
|
@@ -54,7 +56,7 @@ module RubyLsp
|
|
54
56
|
autoload :Sorbet, "ruby_lsp/requests/support/sorbet"
|
55
57
|
autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
|
56
58
|
autoload :Common, "ruby_lsp/requests/support/common"
|
57
|
-
autoload :
|
59
|
+
autoload :Formatter, "ruby_lsp/requests/support/formatter"
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|