ruby-lsp 0.14.5 → 0.15.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 +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp +1 -16
- data/exe/ruby-lsp-check +13 -22
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +21 -0
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +12 -24
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +16 -0
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +3 -2
- 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_indexer/test/index_test.rb +5 -0
- data/lib/ruby_lsp/addon.rb +18 -5
- 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} +30 -9
- data/lib/ruby_lsp/internal.rb +2 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +66 -18
- 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 +4 -3
- 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 +18 -5
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/hover.rb +9 -5
- data/lib/ruby_lsp/requests/request.rb +51 -0
- data/lib/ruby_lsp/requests/signature_help.rb +4 -3
- data/lib/ruby_lsp/requests/support/common.rb +25 -5
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/server.rb +756 -142
- data/lib/ruby_lsp/store.rb +0 -8
- data/lib/ruby_lsp/test_helper.rb +45 -0
- data/lib/ruby_lsp/utils.rb +68 -33
- metadata +8 -5
- data/lib/ruby_lsp/executor.rb +0 -612
@@ -31,13 +31,13 @@ module RubyLsp
|
|
31
31
|
sig do
|
32
32
|
params(
|
33
33
|
document: Document,
|
34
|
-
|
34
|
+
global_state: GlobalState,
|
35
35
|
position: T::Hash[Symbol, T.untyped],
|
36
36
|
dispatcher: Prism::Dispatcher,
|
37
37
|
typechecker_enabled: T::Boolean,
|
38
38
|
).void
|
39
39
|
end
|
40
|
-
def initialize(document,
|
40
|
+
def initialize(document, global_state, position, dispatcher, typechecker_enabled)
|
41
41
|
super()
|
42
42
|
@response_builder = T.let(
|
43
43
|
ResponseBuilders::CollectionResponseBuilder[Interface::Location].new,
|
@@ -49,12 +49,25 @@ module RubyLsp
|
|
49
49
|
node_types: [Prism::CallNode, Prism::ConstantReadNode, Prism::ConstantPathNode],
|
50
50
|
)
|
51
51
|
|
52
|
-
|
52
|
+
if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
|
53
|
+
target = determine_target(
|
54
|
+
target,
|
55
|
+
parent,
|
56
|
+
position,
|
57
|
+
)
|
58
|
+
end
|
53
59
|
|
54
|
-
Listeners::Definition.new(
|
60
|
+
Listeners::Definition.new(
|
61
|
+
@response_builder,
|
62
|
+
global_state,
|
63
|
+
document.uri,
|
64
|
+
nesting,
|
65
|
+
dispatcher,
|
66
|
+
typechecker_enabled,
|
67
|
+
)
|
55
68
|
|
56
69
|
Addon.addons.each do |addon|
|
57
|
-
addon.create_definition_listener(@response_builder, document.uri, nesting,
|
70
|
+
addon.create_definition_listener(@response_builder, global_state, document.uri, nesting, dispatcher)
|
58
71
|
end
|
59
72
|
|
60
73
|
@target = T.let(target, T.nilable(Prism::Node))
|
@@ -45,11 +45,11 @@ module RubyLsp
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
sig { params(dispatcher: Prism::Dispatcher).void }
|
49
|
-
def initialize(dispatcher)
|
48
|
+
sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher).void }
|
49
|
+
def initialize(uri, dispatcher)
|
50
50
|
super()
|
51
51
|
@response_builder = T.let(ResponseBuilders::DocumentSymbol.new, ResponseBuilders::DocumentSymbol)
|
52
|
-
Listeners::DocumentSymbol.new(@response_builder, dispatcher)
|
52
|
+
Listeners::DocumentSymbol.new(@response_builder, uri, dispatcher)
|
53
53
|
|
54
54
|
Addon.addons.each do |addon|
|
55
55
|
addon.create_document_symbol_listener(@response_builder, dispatcher)
|
@@ -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(
|
@@ -50,7 +50,11 @@ module RubyLsp
|
|
50
50
|
if (Listeners::Hover::ALLOWED_TARGETS.include?(parent.class) &&
|
51
51
|
!Listeners::Hover::ALLOWED_TARGETS.include?(@target.class)) ||
|
52
52
|
(parent.is_a?(Prism::ConstantPathNode) && @target.is_a?(Prism::ConstantReadNode))
|
53
|
-
@target =
|
53
|
+
@target = determine_target(
|
54
|
+
T.must(@target),
|
55
|
+
T.must(parent),
|
56
|
+
position,
|
57
|
+
)
|
54
58
|
end
|
55
59
|
|
56
60
|
# Don't need to instantiate any listeners if there's no target
|
@@ -58,9 +62,9 @@ module RubyLsp
|
|
58
62
|
|
59
63
|
uri = document.uri
|
60
64
|
@response_builder = T.let(ResponseBuilders::Hover.new, ResponseBuilders::Hover)
|
61
|
-
Listeners::Hover.new(@response_builder, uri, nesting,
|
65
|
+
Listeners::Hover.new(@response_builder, global_state, uri, nesting, dispatcher, typechecker_enabled)
|
62
66
|
Addon.addons.each do |addon|
|
63
|
-
addon.create_hover_listener(@response_builder,
|
67
|
+
addon.create_hover_listener(@response_builder, global_state, nesting, dispatcher)
|
64
68
|
end
|
65
69
|
|
66
70
|
@dispatcher = dispatcher
|
@@ -12,6 +12,57 @@ module RubyLsp
|
|
12
12
|
|
13
13
|
sig { abstract.returns(T.anything) }
|
14
14
|
def perform; end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Checks if a location covers a position
|
19
|
+
sig { params(location: Prism::Location, position: T.untyped).returns(T::Boolean) }
|
20
|
+
def cover?(location, position)
|
21
|
+
start_covered =
|
22
|
+
location.start_line - 1 < position[:line] ||
|
23
|
+
(
|
24
|
+
location.start_line - 1 == position[:line] &&
|
25
|
+
location.start_column <= position[:character]
|
26
|
+
)
|
27
|
+
end_covered =
|
28
|
+
location.end_line - 1 > position[:line] ||
|
29
|
+
(
|
30
|
+
location.end_line - 1 == position[:line] &&
|
31
|
+
location.end_column >= position[:character]
|
32
|
+
)
|
33
|
+
start_covered && end_covered
|
34
|
+
end
|
35
|
+
|
36
|
+
# Based on a constant node target, a constant path node parent and a position, this method will find the exact
|
37
|
+
# portion of the constant path that matches the requested position, for higher precision in hover and
|
38
|
+
# definition. For example:
|
39
|
+
#
|
40
|
+
# ```ruby
|
41
|
+
# Foo::Bar::Baz
|
42
|
+
# # ^ Going to definition here should go to Foo::Bar::Baz
|
43
|
+
# # ^ Going to definition here should go to Foo::Bar
|
44
|
+
# #^ Going to definition here should go to Foo
|
45
|
+
# ```
|
46
|
+
sig do
|
47
|
+
params(
|
48
|
+
target: Prism::Node,
|
49
|
+
parent: Prism::Node,
|
50
|
+
position: T::Hash[Symbol, Integer],
|
51
|
+
).returns(Prism::Node)
|
52
|
+
end
|
53
|
+
def determine_target(target, parent, position)
|
54
|
+
return target unless parent.is_a?(Prism::ConstantPathNode)
|
55
|
+
|
56
|
+
target = T.let(parent, Prism::Node)
|
57
|
+
parent = T.let(T.cast(target, Prism::ConstantPathNode).parent, T.nilable(Prism::Node))
|
58
|
+
|
59
|
+
while parent && cover?(parent.location, position)
|
60
|
+
target = parent
|
61
|
+
parent = target.is_a?(Prism::ConstantPathNode) ? target.parent : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
target
|
65
|
+
end
|
15
66
|
end
|
16
67
|
end
|
17
68
|
end
|
@@ -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]}
|
@@ -147,6 +158,15 @@ module RubyLsp
|
|
147
158
|
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError
|
148
159
|
nil
|
149
160
|
end
|
161
|
+
|
162
|
+
sig { params(node: T.any(Prism::ModuleNode, Prism::ClassNode)).returns(T.nilable(String)) }
|
163
|
+
def namespace_constant_name(node)
|
164
|
+
path = node.constant_path
|
165
|
+
case path
|
166
|
+
when Prism::ConstantPathNode, Prism::ConstantReadNode, Prism::ConstantPathTargetNode
|
167
|
+
constant_name(path)
|
168
|
+
end
|
169
|
+
end
|
150
170
|
end
|
151
171
|
end
|
152
172
|
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
|
@@ -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"
|