ruby-lsp 0.17.3 → 0.17.5
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/README.md +4 -0
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +251 -100
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +173 -114
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +337 -77
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +43 -14
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +79 -3
- data/lib/ruby_indexer/test/index_test.rb +563 -29
- data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
- data/lib/ruby_indexer/test/method_test.rb +75 -25
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +38 -2
- data/lib/ruby_indexer/test/test_case.rb +1 -5
- data/lib/ruby_lsp/addon.rb +13 -1
- data/lib/ruby_lsp/document.rb +50 -23
- data/lib/ruby_lsp/erb_document.rb +125 -0
- data/lib/ruby_lsp/global_state.rb +11 -4
- data/lib/ruby_lsp/internal.rb +3 -0
- data/lib/ruby_lsp/listeners/completion.rb +69 -34
- data/lib/ruby_lsp/listeners/definition.rb +34 -23
- data/lib/ruby_lsp/listeners/hover.rb +14 -7
- data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
- data/lib/ruby_lsp/node_context.rb +6 -1
- data/lib/ruby_lsp/requests/code_action_resolve.rb +2 -2
- data/lib/ruby_lsp/requests/completion.rb +6 -5
- data/lib/ruby_lsp/requests/completion_resolve.rb +7 -4
- data/lib/ruby_lsp/requests/definition.rb +4 -3
- data/lib/ruby_lsp/requests/formatting.rb +2 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
- data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -2
- data/lib/ruby_lsp/requests/support/common.rb +19 -1
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +87 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/ruby_document.rb +10 -0
- data/lib/ruby_lsp/server.rb +95 -26
- data/lib/ruby_lsp/store.rb +23 -8
- data/lib/ruby_lsp/test_helper.rb +3 -1
- data/lib/ruby_lsp/type_inferrer.rb +86 -0
- metadata +10 -6
@@ -40,7 +40,8 @@ module RubyLsp
|
|
40
40
|
def perform
|
41
41
|
# Based on the spec https://microsoft.github.io/language-server-protocol/specification#textDocument_completion,
|
42
42
|
# a completion resolve request must always return the original completion item without modifying ANY fields
|
43
|
-
# other than
|
43
|
+
# other than detail and documentation (NOT labelDetails). If we modify anything, the completion behaviour might
|
44
|
+
# be broken.
|
44
45
|
#
|
45
46
|
# For example, forgetting to return the `insertText` included in the original item will make the editor use the
|
46
47
|
# `label` for the text edit instead
|
@@ -56,9 +57,11 @@ module RubyLsp
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
)
|
60
|
+
first_entry = T.must(entries.first)
|
61
|
+
|
62
|
+
if first_entry.is_a?(RubyIndexer::Entry::Member)
|
63
|
+
label = "#{label}#{first_entry.decorated_parameters}"
|
64
|
+
end
|
62
65
|
|
63
66
|
@item[:documentation] = Interface::MarkupContent.new(
|
64
67
|
kind: "markdown",
|
@@ -42,8 +42,8 @@ module RubyLsp
|
|
42
42
|
def initialize(document, global_state, position, dispatcher, typechecker_enabled)
|
43
43
|
super()
|
44
44
|
@response_builder = T.let(
|
45
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::Location].new,
|
46
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::Location],
|
45
|
+
ResponseBuilders::CollectionResponseBuilder[T.any(Interface::Location, Interface::LocationLink)].new,
|
46
|
+
ResponseBuilders::CollectionResponseBuilder[T.any(Interface::Location, Interface::LocationLink)],
|
47
47
|
)
|
48
48
|
@dispatcher = dispatcher
|
49
49
|
|
@@ -90,6 +90,7 @@ module RubyLsp
|
|
90
90
|
Listeners::Definition.new(
|
91
91
|
@response_builder,
|
92
92
|
global_state,
|
93
|
+
document.language_id,
|
93
94
|
document.uri,
|
94
95
|
node_context,
|
95
96
|
dispatcher,
|
@@ -104,7 +105,7 @@ module RubyLsp
|
|
104
105
|
@target = T.let(target, T.nilable(Prism::Node))
|
105
106
|
end
|
106
107
|
|
107
|
-
sig { override.returns(T::Array[Interface::Location]) }
|
108
|
+
sig { override.returns(T::Array[T.any(Interface::Location, Interface::LocationLink)]) }
|
108
109
|
def perform
|
109
110
|
@dispatcher.dispatch_once(@target) if @target
|
110
111
|
@response_builder.response
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# 
|
7
|
+
#
|
8
|
+
# The [prepare type hierarchy
|
9
|
+
# request](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareTypeHierarchy)
|
10
|
+
# displays the list of ancestors (supertypes) and descendants (subtypes) for the selected type.
|
11
|
+
#
|
12
|
+
# Currently only supports supertypes due to a limitation of the index.
|
13
|
+
#
|
14
|
+
# # Example
|
15
|
+
#
|
16
|
+
# ```ruby
|
17
|
+
# class Foo; end
|
18
|
+
# class Bar < Foo; end
|
19
|
+
#
|
20
|
+
# puts Bar # <-- right click on `Bar` and select "Show Type Hierarchy"
|
21
|
+
# ```
|
22
|
+
class PrepareTypeHierarchy < Request
|
23
|
+
extend T::Sig
|
24
|
+
|
25
|
+
include Support::Common
|
26
|
+
|
27
|
+
class << self
|
28
|
+
extend T::Sig
|
29
|
+
|
30
|
+
sig { returns(Interface::TypeHierarchyOptions) }
|
31
|
+
def provider
|
32
|
+
Interface::TypeHierarchyOptions.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
sig do
|
37
|
+
params(
|
38
|
+
document: Document,
|
39
|
+
index: RubyIndexer::Index,
|
40
|
+
position: T::Hash[Symbol, T.untyped],
|
41
|
+
).void
|
42
|
+
end
|
43
|
+
def initialize(document, index, position)
|
44
|
+
super()
|
45
|
+
|
46
|
+
@document = document
|
47
|
+
@index = index
|
48
|
+
@position = position
|
49
|
+
end
|
50
|
+
|
51
|
+
sig { override.returns(T.nilable(T::Array[Interface::TypeHierarchyItem])) }
|
52
|
+
def perform
|
53
|
+
context = @document.locate_node(
|
54
|
+
@position,
|
55
|
+
node_types: [
|
56
|
+
Prism::ConstantReadNode,
|
57
|
+
Prism::ConstantWriteNode,
|
58
|
+
Prism::ConstantPathNode,
|
59
|
+
],
|
60
|
+
)
|
61
|
+
|
62
|
+
node = context.node
|
63
|
+
parent = context.parent
|
64
|
+
return unless node && parent
|
65
|
+
|
66
|
+
target = determine_target(node, parent, @position)
|
67
|
+
entries = @index.resolve(target.slice, context.nesting)
|
68
|
+
return unless entries
|
69
|
+
|
70
|
+
# While the spec allows for multiple entries, VSCode seems to only support one
|
71
|
+
# We'll just return the first one for now
|
72
|
+
first_entry = T.must(entries.first)
|
73
|
+
|
74
|
+
range = range_from_location(first_entry.location)
|
75
|
+
|
76
|
+
[
|
77
|
+
Interface::TypeHierarchyItem.new(
|
78
|
+
name: first_entry.name,
|
79
|
+
kind: kind_for_entry(first_entry),
|
80
|
+
uri: URI::Generic.from_path(path: first_entry.file_path).to_s,
|
81
|
+
range: range,
|
82
|
+
selection_range: range,
|
83
|
+
),
|
84
|
+
]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -34,7 +34,7 @@ module RubyLsp
|
|
34
34
|
sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
|
35
35
|
def perform
|
36
36
|
# [node, parent]
|
37
|
-
queue = [[@document.
|
37
|
+
queue = [[@document.parse_result.value, nil]]
|
38
38
|
|
39
39
|
until queue.empty?
|
40
40
|
node, parent = queue.shift
|
@@ -25,6 +25,7 @@ module RubyLsp
|
|
25
25
|
super()
|
26
26
|
@document = document
|
27
27
|
@range = range
|
28
|
+
@tree = T.let(document.parse_result.value, Prism::ProgramNode)
|
28
29
|
end
|
29
30
|
|
30
31
|
sig { override.returns(String) }
|
@@ -32,7 +33,7 @@ module RubyLsp
|
|
32
33
|
return ast_for_range if @range
|
33
34
|
|
34
35
|
output_string = +""
|
35
|
-
PP.pp(@
|
36
|
+
PP.pp(@tree, output_string)
|
36
37
|
output_string
|
37
38
|
end
|
38
39
|
|
@@ -46,7 +47,7 @@ module RubyLsp
|
|
46
47
|
start_char = scanner.find_char_position(range[:start])
|
47
48
|
end_char = scanner.find_char_position(range[:end])
|
48
49
|
|
49
|
-
queue = @
|
50
|
+
queue = @tree.statements.body.dup
|
50
51
|
found_nodes = []
|
51
52
|
|
52
53
|
until queue.empty?
|
@@ -26,7 +26,7 @@ module RubyLsp
|
|
26
26
|
)
|
27
27
|
end
|
28
28
|
|
29
|
-
sig { params(location: Prism::Location).returns(Interface::Range) }
|
29
|
+
sig { params(location: T.any(Prism::Location, RubyIndexer::Location)).returns(Interface::Range) }
|
30
30
|
def range_from_location(location)
|
31
31
|
Interface::Range.new(
|
32
32
|
start: Interface::Position.new(
|
@@ -186,6 +186,24 @@ module RubyLsp
|
|
186
186
|
current = current.parent
|
187
187
|
end
|
188
188
|
end
|
189
|
+
|
190
|
+
sig { params(entry: RubyIndexer::Entry).returns(T.nilable(Integer)) }
|
191
|
+
def kind_for_entry(entry)
|
192
|
+
case entry
|
193
|
+
when RubyIndexer::Entry::Class
|
194
|
+
Constant::SymbolKind::CLASS
|
195
|
+
when RubyIndexer::Entry::Module
|
196
|
+
Constant::SymbolKind::NAMESPACE
|
197
|
+
when RubyIndexer::Entry::Constant
|
198
|
+
Constant::SymbolKind::CONSTANT
|
199
|
+
when RubyIndexer::Entry::Method
|
200
|
+
entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
|
201
|
+
when RubyIndexer::Entry::Accessor
|
202
|
+
Constant::SymbolKind::PROPERTY
|
203
|
+
when RubyIndexer::Entry::InstanceVariable
|
204
|
+
Constant::SymbolKind::FIELD
|
205
|
+
end
|
206
|
+
end
|
189
207
|
end
|
190
208
|
end
|
191
209
|
end
|
@@ -42,7 +42,7 @@ module RubyLsp
|
|
42
42
|
def to_lsp_code_actions
|
43
43
|
code_actions = []
|
44
44
|
|
45
|
-
code_actions << autocorrect_action if
|
45
|
+
code_actions << autocorrect_action if correctable?
|
46
46
|
code_actions << disable_line_action
|
47
47
|
|
48
48
|
code_actions
|
@@ -70,7 +70,7 @@ module RubyLsp
|
|
70
70
|
),
|
71
71
|
),
|
72
72
|
data: {
|
73
|
-
correctable:
|
73
|
+
correctable: correctable?,
|
74
74
|
code_actions: to_lsp_code_actions,
|
75
75
|
},
|
76
76
|
)
|
@@ -81,7 +81,7 @@ module RubyLsp
|
|
81
81
|
sig { returns(String) }
|
82
82
|
def message
|
83
83
|
message = @offense.message
|
84
|
-
message += "\n\nThis offense is not auto-correctable.\n" unless
|
84
|
+
message += "\n\nThis offense is not auto-correctable.\n" unless correctable?
|
85
85
|
message
|
86
86
|
end
|
87
87
|
|
@@ -115,7 +115,7 @@ module RubyLsp
|
|
115
115
|
uri: @uri.to_s,
|
116
116
|
version: nil,
|
117
117
|
),
|
118
|
-
edits:
|
118
|
+
edits: correctable? ? offense_replacements : [],
|
119
119
|
),
|
120
120
|
],
|
121
121
|
),
|
@@ -193,6 +193,14 @@ module RubyLsp
|
|
193
193
|
line.length
|
194
194
|
end
|
195
195
|
end
|
196
|
+
|
197
|
+
# When `RuboCop::LSP.enable` is called, contextual autocorrect will not offer itself
|
198
|
+
# as `correctable?` to prevent annoying changes while typing. Instead check if
|
199
|
+
# a corrector is present. If it is, then that means some code transformation can be applied.
|
200
|
+
sig { returns(T::Boolean) }
|
201
|
+
def correctable?
|
202
|
+
!@offense.corrector.nil?
|
203
|
+
end
|
196
204
|
end
|
197
205
|
end
|
198
206
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# 
|
7
|
+
#
|
8
|
+
# The [type hierarchy supertypes
|
9
|
+
# request](https://microsoft.github.io/language-server-protocol/specification#typeHierarchy_supertypes)
|
10
|
+
# displays the list of ancestors (supertypes) for the selected type.
|
11
|
+
#
|
12
|
+
# # Example
|
13
|
+
#
|
14
|
+
# ```ruby
|
15
|
+
# class Foo; end
|
16
|
+
# class Bar < Foo; end
|
17
|
+
#
|
18
|
+
# puts Bar # <-- right click on `Bar` and select "Show Type Hierarchy"
|
19
|
+
# ```
|
20
|
+
class TypeHierarchySupertypes < Request
|
21
|
+
extend T::Sig
|
22
|
+
|
23
|
+
include Support::Common
|
24
|
+
|
25
|
+
sig { params(index: RubyIndexer::Index, item: T::Hash[Symbol, T.untyped]).void }
|
26
|
+
def initialize(index, item)
|
27
|
+
super()
|
28
|
+
|
29
|
+
@index = index
|
30
|
+
@item = item
|
31
|
+
end
|
32
|
+
|
33
|
+
sig { override.returns(T.nilable(T::Array[Interface::TypeHierarchyItem])) }
|
34
|
+
def perform
|
35
|
+
name = @item[:name]
|
36
|
+
entries = @index[name]
|
37
|
+
|
38
|
+
parents = T.let(Set.new, T::Set[RubyIndexer::Entry::Namespace])
|
39
|
+
return unless entries&.any?
|
40
|
+
|
41
|
+
entries.each do |entry|
|
42
|
+
next unless entry.is_a?(RubyIndexer::Entry::Namespace)
|
43
|
+
|
44
|
+
if entry.is_a?(RubyIndexer::Entry::Class)
|
45
|
+
parent_class_name = entry.parent_class
|
46
|
+
if parent_class_name
|
47
|
+
resolved_parent_entries = @index.resolve(parent_class_name, entry.nesting)
|
48
|
+
resolved_parent_entries&.each do |entry|
|
49
|
+
next unless entry.is_a?(RubyIndexer::Entry::Class)
|
50
|
+
|
51
|
+
parents << entry
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
entry.mixin_operations.each do |mixin_operation|
|
57
|
+
mixin_name = mixin_operation.module_name
|
58
|
+
resolved_mixin_entries = @index.resolve(mixin_name, entry.nesting)
|
59
|
+
next unless resolved_mixin_entries
|
60
|
+
|
61
|
+
resolved_mixin_entries.each do |mixin_entry|
|
62
|
+
next unless mixin_entry.is_a?(RubyIndexer::Entry::Module)
|
63
|
+
|
64
|
+
parents << mixin_entry
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
parents.map { |entry| hierarchy_item(entry) }
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
sig { params(entry: RubyIndexer::Entry).returns(Interface::TypeHierarchyItem) }
|
75
|
+
def hierarchy_item(entry)
|
76
|
+
Interface::TypeHierarchyItem.new(
|
77
|
+
name: entry.name,
|
78
|
+
kind: kind_for_entry(entry),
|
79
|
+
uri: URI::Generic.from_path(path: entry.file_path).to_s,
|
80
|
+
range: range_from_location(entry.location),
|
81
|
+
selection_range: range_from_location(entry.name_location),
|
82
|
+
detail: entry.file_name,
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -52,7 +52,7 @@ module RubyLsp
|
|
52
52
|
|
53
53
|
Interface::WorkspaceSymbol.new(
|
54
54
|
name: entry.name,
|
55
|
-
container_name:
|
55
|
+
container_name: container.join("::"),
|
56
56
|
kind: kind,
|
57
57
|
location: Interface::Location.new(
|
58
58
|
uri: URI::Generic.from_path(path: file_path).to_s,
|
@@ -64,26 +64,6 @@ module RubyLsp
|
|
64
64
|
)
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
sig { params(entry: RubyIndexer::Entry).returns(T.nilable(Integer)) }
|
71
|
-
def kind_for_entry(entry)
|
72
|
-
case entry
|
73
|
-
when RubyIndexer::Entry::Class
|
74
|
-
Constant::SymbolKind::CLASS
|
75
|
-
when RubyIndexer::Entry::Module
|
76
|
-
Constant::SymbolKind::NAMESPACE
|
77
|
-
when RubyIndexer::Entry::Constant
|
78
|
-
Constant::SymbolKind::CONSTANT
|
79
|
-
when RubyIndexer::Entry::Method
|
80
|
-
entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
|
81
|
-
when RubyIndexer::Entry::Accessor
|
82
|
-
Constant::SymbolKind::PROPERTY
|
83
|
-
when RubyIndexer::Entry::InstanceVariable
|
84
|
-
Constant::SymbolKind::FIELD
|
85
|
-
end
|
86
|
-
end
|
87
67
|
end
|
88
68
|
end
|
89
69
|
end
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -47,6 +47,8 @@ module RubyLsp
|
|
47
47
|
autoload :ShowSyntaxTree, "ruby_lsp/requests/show_syntax_tree"
|
48
48
|
autoload :WorkspaceSymbol, "ruby_lsp/requests/workspace_symbol"
|
49
49
|
autoload :SignatureHelp, "ruby_lsp/requests/signature_help"
|
50
|
+
autoload :PrepareTypeHierarchy, "ruby_lsp/requests/prepare_type_hierarchy"
|
51
|
+
autoload :TypeHierarchySupertypes, "ruby_lsp/requests/type_hierarchy_supertypes"
|
50
52
|
|
51
53
|
# :nodoc:
|
52
54
|
module Support
|
@@ -10,5 +10,15 @@ module RubyLsp
|
|
10
10
|
@needs_parsing = false
|
11
11
|
@parse_result = Prism.parse(@source)
|
12
12
|
end
|
13
|
+
|
14
|
+
sig { override.returns(T::Boolean) }
|
15
|
+
def syntax_error?
|
16
|
+
@parse_result.failure?
|
17
|
+
end
|
18
|
+
|
19
|
+
sig { override.returns(LanguageId) }
|
20
|
+
def language_id
|
21
|
+
LanguageId::Ruby
|
22
|
+
end
|
13
23
|
end
|
14
24
|
end
|