ruby-lsp 0.3.8 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -1
- data/VERSION +1 -1
- data/exe/ruby-lsp +2 -1
- data/lib/ruby_lsp/executor.rb +362 -0
- data/lib/ruby_lsp/internal.rb +6 -1
- data/lib/ruby_lsp/requests/base_request.rb +10 -3
- data/lib/ruby_lsp/requests/code_actions.rb +21 -7
- data/lib/ruby_lsp/requests/diagnostics.rb +7 -11
- data/lib/ruby_lsp/requests/formatting.rb +8 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +33 -14
- data/lib/ruby_lsp/requests/path_completion.rb +88 -0
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +35 -11
- data/lib/ruby_lsp/requests/support/annotation.rb +46 -0
- data/lib/ruby_lsp/requests/support/highlight_target.rb +14 -3
- data/lib/ruby_lsp/requests/support/prefix_tree.rb +80 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +29 -44
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +27 -1
- data/lib/ruby_lsp/requests/support/sorbet.rb +120 -0
- data/lib/ruby_lsp/requests.rb +5 -1
- data/lib/ruby_lsp/server.rb +128 -221
- data/lib/ruby_lsp/utils.rb +78 -0
- metadata +12 -9
- data/lib/ruby_lsp/handler.rb +0 -118
- data/lib/ruby_lsp/queue.rb +0 -182
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +0 -32
@@ -0,0 +1,88 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# ![Path completion demo](../../misc/path_completion.gif)
|
7
|
+
#
|
8
|
+
# The [completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
9
|
+
# request looks up Ruby files in the $LOAD_PATH to suggest path completion inside `require` statements.
|
10
|
+
#
|
11
|
+
# # Example
|
12
|
+
#
|
13
|
+
# ```ruby
|
14
|
+
# require "ruby_lsp/requests" # --> completion: suggests `base_request`, `code_actions`, ...
|
15
|
+
# ```
|
16
|
+
class PathCompletion < BaseRequest
|
17
|
+
extend T::Sig
|
18
|
+
|
19
|
+
sig { params(document: Document, position: Document::PositionShape).void }
|
20
|
+
def initialize(document, position)
|
21
|
+
super(document)
|
22
|
+
|
23
|
+
@tree = T.let(Support::PrefixTree.new(collect_load_path_files), Support::PrefixTree)
|
24
|
+
|
25
|
+
char_position = document.create_scanner.find_char_position(position)
|
26
|
+
@target = T.let(find(char_position), T.nilable(SyntaxTree::TStringContent))
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::CompletionItem], Object)) }
|
30
|
+
def run
|
31
|
+
# no @target means the we are not inside a `require` call
|
32
|
+
return [] unless @target
|
33
|
+
|
34
|
+
text = @target.value
|
35
|
+
@tree.search(text).sort.map! do |path|
|
36
|
+
build_completion(path, path.delete_prefix(text))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
sig { returns(T::Array[String]) }
|
43
|
+
def collect_load_path_files
|
44
|
+
$LOAD_PATH.flat_map do |p|
|
45
|
+
Dir.glob("**/*.rb", base: p)
|
46
|
+
end.map! do |result|
|
47
|
+
result.delete_suffix!(".rb")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
sig { params(position: Integer).returns(T.nilable(SyntaxTree::TStringContent)) }
|
52
|
+
def find(position)
|
53
|
+
matched, parent = locate(
|
54
|
+
T.must(@document.tree),
|
55
|
+
position,
|
56
|
+
node_types: [SyntaxTree::Command, SyntaxTree::CommandCall, SyntaxTree::CallNode],
|
57
|
+
)
|
58
|
+
|
59
|
+
return unless matched && parent
|
60
|
+
|
61
|
+
case matched
|
62
|
+
when SyntaxTree::Command, SyntaxTree::CallNode, SyntaxTree::CommandCall
|
63
|
+
return unless matched.message.value == "require"
|
64
|
+
|
65
|
+
args = matched.arguments
|
66
|
+
args = args.arguments if args.is_a?(SyntaxTree::ArgParen)
|
67
|
+
|
68
|
+
path_node = args.parts.first.parts.first
|
69
|
+
return unless path_node
|
70
|
+
return unless (path_node.location.start_char..path_node.location.end_char).cover?(position)
|
71
|
+
|
72
|
+
path_node
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
sig do
|
77
|
+
params(label: String, insert_text: String).returns(LanguageServer::Protocol::Interface::CompletionItem)
|
78
|
+
end
|
79
|
+
def build_completion(label, insert_text)
|
80
|
+
LanguageServer::Protocol::Interface::CompletionItem.new(
|
81
|
+
label: label,
|
82
|
+
insert_text: insert_text,
|
83
|
+
kind: LanguageServer::Protocol::Constant::CompletionItemKind::REFERENCE,
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -20,7 +20,7 @@ module RubyLsp
|
|
20
20
|
# ```
|
21
21
|
class SemanticHighlighting < BaseRequest
|
22
22
|
extend T::Sig
|
23
|
-
include SyntaxTree::
|
23
|
+
include SyntaxTree::WithScope
|
24
24
|
|
25
25
|
TOKEN_TYPES = T.let(
|
26
26
|
{
|
@@ -78,11 +78,28 @@ module RubyLsp
|
|
78
78
|
T::Array[String],
|
79
79
|
)
|
80
80
|
|
81
|
-
class SemanticToken
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
81
|
+
class SemanticToken
|
82
|
+
extend T::Sig
|
83
|
+
|
84
|
+
sig { returns(SyntaxTree::Location) }
|
85
|
+
attr_reader :location
|
86
|
+
|
87
|
+
sig { returns(Integer) }
|
88
|
+
attr_reader :length
|
89
|
+
|
90
|
+
sig { returns(Integer) }
|
91
|
+
attr_reader :type
|
92
|
+
|
93
|
+
sig { returns(T::Array[Integer]) }
|
94
|
+
attr_reader :modifier
|
95
|
+
|
96
|
+
sig { params(location: SyntaxTree::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
|
97
|
+
def initialize(location:, length:, type:, modifier:)
|
98
|
+
@location = location
|
99
|
+
@length = length
|
100
|
+
@type = type
|
101
|
+
@modifier = modifier
|
102
|
+
end
|
86
103
|
end
|
87
104
|
|
88
105
|
sig do
|
@@ -126,8 +143,10 @@ module RubyLsp
|
|
126
143
|
visit(node.receiver)
|
127
144
|
|
128
145
|
message = node.message
|
129
|
-
|
130
|
-
|
146
|
+
if message != :call && !special_method?(message.value)
|
147
|
+
type = Support::Sorbet.annotation?(node) ? :type : :method
|
148
|
+
|
149
|
+
add_token(message.location, type)
|
131
150
|
end
|
132
151
|
|
133
152
|
visit(node.arguments)
|
@@ -137,7 +156,9 @@ module RubyLsp
|
|
137
156
|
def visit_command(node)
|
138
157
|
return super unless visible?(node, @range)
|
139
158
|
|
140
|
-
|
159
|
+
unless special_method?(node.message.value)
|
160
|
+
add_token(node.message.location, :method)
|
161
|
+
end
|
141
162
|
visit(node.arguments)
|
142
163
|
end
|
143
164
|
|
@@ -243,7 +264,10 @@ module RubyLsp
|
|
243
264
|
def visit_vcall(node)
|
244
265
|
return super unless visible?(node, @range)
|
245
266
|
|
246
|
-
|
267
|
+
return if special_method?(node.value.value)
|
268
|
+
|
269
|
+
type = Support::Sorbet.annotation?(node) ? :type : :method
|
270
|
+
add_token(node.value.location, type)
|
247
271
|
end
|
248
272
|
|
249
273
|
sig { override.params(node: SyntaxTree::ClassDeclaration).void }
|
@@ -305,7 +329,7 @@ module RubyLsp
|
|
305
329
|
|
306
330
|
sig { params(value: SyntaxTree::Ident).returns(Symbol) }
|
307
331
|
def type_for_local(value)
|
308
|
-
local =
|
332
|
+
local = current_scope.find_local(value.value)
|
309
333
|
|
310
334
|
if local.nil? || local.type == :variable
|
311
335
|
:variable
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
module Support
|
7
|
+
class Annotation
|
8
|
+
extend T::Sig
|
9
|
+
sig do
|
10
|
+
params(
|
11
|
+
arity: T.any(Integer, T::Range[Integer]),
|
12
|
+
receiver: T::Boolean,
|
13
|
+
).void
|
14
|
+
end
|
15
|
+
def initialize(arity:, receiver: false)
|
16
|
+
@arity = arity
|
17
|
+
@receiver = receiver
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { returns(T.any(Integer, T::Range[Integer])) }
|
21
|
+
attr_reader :arity
|
22
|
+
|
23
|
+
sig { returns(T::Boolean) }
|
24
|
+
attr_reader :receiver
|
25
|
+
|
26
|
+
sig { params(arity: T.any(T::Range[Integer], Integer)).returns(T::Boolean) }
|
27
|
+
def supports_arity?(arity)
|
28
|
+
if @arity.is_a?(Integer)
|
29
|
+
@arity == arity
|
30
|
+
elsif @arity.is_a?(Range)
|
31
|
+
@arity.cover?(arity)
|
32
|
+
else
|
33
|
+
T.absurd(@arity)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
sig { params(receiver: T.nilable(String)).returns(T::Boolean) }
|
38
|
+
def supports_receiver?(receiver)
|
39
|
+
return receiver.nil? || receiver.empty? if @receiver == false
|
40
|
+
|
41
|
+
receiver == "T"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -10,9 +10,20 @@ module RubyLsp
|
|
10
10
|
READ = LanguageServer::Protocol::Constant::DocumentHighlightKind::READ
|
11
11
|
WRITE = LanguageServer::Protocol::Constant::DocumentHighlightKind::WRITE
|
12
12
|
|
13
|
-
class HighlightMatch
|
14
|
-
|
15
|
-
|
13
|
+
class HighlightMatch
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
sig { returns(Integer) }
|
17
|
+
attr_reader :type
|
18
|
+
|
19
|
+
sig { returns(SyntaxTree::Node) }
|
20
|
+
attr_reader :node
|
21
|
+
|
22
|
+
sig { params(type: Integer, node: SyntaxTree::Node).void }
|
23
|
+
def initialize(type:, node:)
|
24
|
+
@type = type
|
25
|
+
@node = node
|
26
|
+
end
|
16
27
|
end
|
17
28
|
|
18
29
|
sig { params(node: SyntaxTree::Node).void }
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
module Support
|
7
|
+
class PrefixTree
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(items: T::Array[String]).void }
|
11
|
+
def initialize(items)
|
12
|
+
@root = T.let(Node.new(""), Node)
|
13
|
+
|
14
|
+
items.each do |item|
|
15
|
+
insert(item)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
sig { params(prefix: String).returns(T::Array[String]) }
|
20
|
+
def search(prefix)
|
21
|
+
node = T.let(@root, Node)
|
22
|
+
|
23
|
+
prefix.each_char do |char|
|
24
|
+
snode = node.children[char]
|
25
|
+
return [] unless snode
|
26
|
+
|
27
|
+
node = snode
|
28
|
+
end
|
29
|
+
|
30
|
+
node.collect
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
sig { params(item: String).void }
|
36
|
+
def insert(item)
|
37
|
+
node = T.let(@root, Node)
|
38
|
+
|
39
|
+
item.each_char do |char|
|
40
|
+
node = node.children[char] ||= Node.new(node.value + char)
|
41
|
+
end
|
42
|
+
|
43
|
+
node.leaf = true
|
44
|
+
end
|
45
|
+
|
46
|
+
class Node
|
47
|
+
extend T::Sig
|
48
|
+
|
49
|
+
sig { returns(T::Hash[String, Node]) }
|
50
|
+
attr_reader :children
|
51
|
+
|
52
|
+
sig { returns(String) }
|
53
|
+
attr_reader :value
|
54
|
+
|
55
|
+
sig { returns(T::Boolean) }
|
56
|
+
attr_accessor :leaf
|
57
|
+
|
58
|
+
sig { params(value: String).void }
|
59
|
+
def initialize(value)
|
60
|
+
@children = T.let({}, T::Hash[String, Node])
|
61
|
+
@value = T.let(value, String)
|
62
|
+
@leaf = T.let(false, T::Boolean)
|
63
|
+
end
|
64
|
+
|
65
|
+
sig { returns(T::Array[String]) }
|
66
|
+
def collect
|
67
|
+
result = T.let([], T::Array[String])
|
68
|
+
result << value if leaf
|
69
|
+
|
70
|
+
children.each_value do |node|
|
71
|
+
result.concat(node.collect)
|
72
|
+
end
|
73
|
+
|
74
|
+
result
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -9,52 +9,35 @@ module RubyLsp
|
|
9
9
|
|
10
10
|
RUBOCOP_TO_LSP_SEVERITY = T.let(
|
11
11
|
{
|
12
|
-
convention:
|
13
|
-
info:
|
14
|
-
refactor:
|
15
|
-
warning:
|
16
|
-
error:
|
17
|
-
fatal:
|
12
|
+
convention: Constant::DiagnosticSeverity::INFORMATION,
|
13
|
+
info: Constant::DiagnosticSeverity::INFORMATION,
|
14
|
+
refactor: Constant::DiagnosticSeverity::INFORMATION,
|
15
|
+
warning: Constant::DiagnosticSeverity::WARNING,
|
16
|
+
error: Constant::DiagnosticSeverity::ERROR,
|
17
|
+
fatal: Constant::DiagnosticSeverity::ERROR,
|
18
18
|
}.freeze,
|
19
19
|
T::Hash[Symbol, Integer],
|
20
20
|
)
|
21
21
|
|
22
|
-
sig { returns(T::Array[LanguageServer::Protocol::Interface::TextEdit]) }
|
23
|
-
attr_reader :replacements
|
24
|
-
|
25
22
|
sig { params(offense: RuboCop::Cop::Offense, uri: String).void }
|
26
23
|
def initialize(offense, uri)
|
27
24
|
@offense = offense
|
28
25
|
@uri = uri
|
29
|
-
@replacements = T.let(
|
30
|
-
offense.correctable? ? offense_replacements : [],
|
31
|
-
T::Array[LanguageServer::Protocol::Interface::TextEdit],
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
sig { returns(T::Boolean) }
|
36
|
-
def correctable?
|
37
|
-
@offense.correctable?
|
38
26
|
end
|
39
27
|
|
40
|
-
sig {
|
41
|
-
def in_range?(range)
|
42
|
-
range.cover?(@offense.line - 1)
|
43
|
-
end
|
44
|
-
|
45
|
-
sig { returns(LanguageServer::Protocol::Interface::CodeAction) }
|
28
|
+
sig { returns(Interface::CodeAction) }
|
46
29
|
def to_lsp_code_action
|
47
|
-
|
30
|
+
Interface::CodeAction.new(
|
48
31
|
title: "Autocorrect #{@offense.cop_name}",
|
49
|
-
kind:
|
50
|
-
edit:
|
32
|
+
kind: Constant::CodeActionKind::QUICK_FIX,
|
33
|
+
edit: Interface::WorkspaceEdit.new(
|
51
34
|
document_changes: [
|
52
|
-
|
53
|
-
text_document:
|
35
|
+
Interface::TextDocumentEdit.new(
|
36
|
+
text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
|
54
37
|
uri: @uri,
|
55
38
|
version: nil,
|
56
39
|
),
|
57
|
-
edits: @
|
40
|
+
edits: @offense.correctable? ? offense_replacements : [],
|
58
41
|
),
|
59
42
|
],
|
60
43
|
),
|
@@ -62,45 +45,47 @@ module RubyLsp
|
|
62
45
|
)
|
63
46
|
end
|
64
47
|
|
65
|
-
sig { returns(
|
48
|
+
sig { returns(Interface::Diagnostic) }
|
66
49
|
def to_lsp_diagnostic
|
67
50
|
if @offense.correctable?
|
68
51
|
severity = RUBOCOP_TO_LSP_SEVERITY[@offense.severity.name]
|
69
52
|
message = @offense.message
|
70
53
|
else
|
71
|
-
severity =
|
54
|
+
severity = Constant::DiagnosticSeverity::WARNING
|
72
55
|
message = "#{@offense.message}\n\nThis offense is not auto-correctable.\n"
|
73
56
|
end
|
74
|
-
|
57
|
+
|
58
|
+
Interface::Diagnostic.new(
|
75
59
|
message: message,
|
76
60
|
source: "RuboCop",
|
77
61
|
code: @offense.cop_name,
|
78
62
|
severity: severity,
|
79
|
-
range:
|
80
|
-
start:
|
63
|
+
range: Interface::Range.new(
|
64
|
+
start: Interface::Position.new(
|
81
65
|
line: @offense.line - 1,
|
82
66
|
character: @offense.column,
|
83
67
|
),
|
84
|
-
end:
|
68
|
+
end: Interface::Position.new(
|
85
69
|
line: @offense.last_line - 1,
|
86
70
|
character: @offense.last_column,
|
87
71
|
),
|
88
72
|
),
|
73
|
+
data: {
|
74
|
+
correctable: @offense.correctable?,
|
75
|
+
code_action: to_lsp_code_action,
|
76
|
+
},
|
89
77
|
)
|
90
78
|
end
|
91
79
|
|
92
80
|
private
|
93
81
|
|
94
|
-
sig { returns(T::Array[
|
82
|
+
sig { returns(T::Array[Interface::TextEdit]) }
|
95
83
|
def offense_replacements
|
96
84
|
@offense.corrector.as_replacements.map do |range, replacement|
|
97
|
-
|
98
|
-
range:
|
99
|
-
start:
|
100
|
-
end:
|
101
|
-
line: range.last_line - 1,
|
102
|
-
character: range.last_column,
|
103
|
-
),
|
85
|
+
Interface::TextEdit.new(
|
86
|
+
range: Interface::Range.new(
|
87
|
+
start: Interface::Position.new(line: range.line - 1, character: range.column),
|
88
|
+
end: Interface::Position.new(line: range.last_line - 1, character: range.last_column),
|
104
89
|
),
|
105
90
|
new_text: replacement,
|
106
91
|
)
|
@@ -21,7 +21,7 @@ module RubyLsp
|
|
21
21
|
@runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
|
22
22
|
end
|
23
23
|
|
24
|
-
sig { params(uri: String, document: Document).returns(
|
24
|
+
sig { params(uri: String, document: Document).returns(String) }
|
25
25
|
def run(uri, document)
|
26
26
|
filename = CGI.unescape(URI.parse(uri).path)
|
27
27
|
|
@@ -16,6 +16,22 @@ end
|
|
16
16
|
module RubyLsp
|
17
17
|
module Requests
|
18
18
|
module Support
|
19
|
+
class InternalRuboCopError < StandardError
|
20
|
+
extend T::Sig
|
21
|
+
|
22
|
+
MESSAGE = <<~EOS
|
23
|
+
An internal error occurred for the %s cop.
|
24
|
+
Updating to a newer version of RuboCop may solve this.
|
25
|
+
For more details, run RuboCop on the command line.
|
26
|
+
EOS
|
27
|
+
|
28
|
+
sig { params(rubocop_error: RuboCop::ErrorWithAnalyzedFileLocation).void }
|
29
|
+
def initialize(rubocop_error)
|
30
|
+
message = format(MESSAGE, rubocop_error.cop.name)
|
31
|
+
super(message)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
19
35
|
# :nodoc:
|
20
36
|
class RuboCopRunner < RuboCop::Runner
|
21
37
|
extend T::Sig
|
@@ -31,10 +47,18 @@ module RubyLsp
|
|
31
47
|
"--force-exclusion",
|
32
48
|
"--format",
|
33
49
|
"RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
|
34
|
-
]
|
50
|
+
],
|
35
51
|
T::Array[String],
|
36
52
|
)
|
37
53
|
|
54
|
+
begin
|
55
|
+
RuboCop::Options.new.parse(["--raise-cop-error"])
|
56
|
+
DEFAULT_ARGS << "--raise-cop-error"
|
57
|
+
rescue OptionParser::InvalidOption
|
58
|
+
# older versions of RuboCop don't support this flag
|
59
|
+
end
|
60
|
+
DEFAULT_ARGS.freeze
|
61
|
+
|
38
62
|
sig { params(args: String).void }
|
39
63
|
def initialize(*args)
|
40
64
|
@options = T.let({}, T::Hash[Symbol, T.untyped])
|
@@ -63,6 +87,8 @@ module RubyLsp
|
|
63
87
|
raise Formatting::Error, error.message
|
64
88
|
rescue RuboCop::ValidationError => error
|
65
89
|
raise ConfigurationError, error.message
|
90
|
+
rescue RuboCop::ErrorWithAnalyzedFileLocation => error
|
91
|
+
raise InternalRuboCopError, error
|
66
92
|
end
|
67
93
|
|
68
94
|
sig { returns(String) }
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
module Support
|
7
|
+
class Sorbet
|
8
|
+
class << self
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
ANNOTATIONS = T.let(
|
12
|
+
{
|
13
|
+
"abstract!" => Annotation.new(arity: 0),
|
14
|
+
"absurd" => Annotation.new(arity: 1, receiver: true),
|
15
|
+
"all" => Annotation.new(arity: (2..), receiver: true),
|
16
|
+
"any" => Annotation.new(arity: (2..), receiver: true),
|
17
|
+
"assert_type!" => Annotation.new(arity: 2, receiver: true),
|
18
|
+
"attached_class" => Annotation.new(arity: 0, receiver: true),
|
19
|
+
"bind" => Annotation.new(arity: 2, receiver: true),
|
20
|
+
"cast" => Annotation.new(arity: 2, receiver: true),
|
21
|
+
"class_of" => Annotation.new(arity: 1, receiver: true),
|
22
|
+
"enums" => Annotation.new(arity: 0),
|
23
|
+
"interface!" => Annotation.new(arity: 0),
|
24
|
+
"let" => Annotation.new(arity: 2, receiver: true),
|
25
|
+
"mixes_in_class_methods" => Annotation.new(arity: 1),
|
26
|
+
"must" => Annotation.new(arity: 1, receiver: true),
|
27
|
+
"must_because" => Annotation.new(arity: 1, receiver: true),
|
28
|
+
"nilable" => Annotation.new(arity: 1, receiver: true),
|
29
|
+
"noreturn" => Annotation.new(arity: 0, receiver: true),
|
30
|
+
"requires_ancestor" => Annotation.new(arity: 0),
|
31
|
+
"reveal_type" => Annotation.new(arity: 1, receiver: true),
|
32
|
+
"sealed!" => Annotation.new(arity: 0),
|
33
|
+
"self_type" => Annotation.new(arity: 0, receiver: true),
|
34
|
+
"sig" => Annotation.new(arity: 0),
|
35
|
+
"type_member" => Annotation.new(arity: (0..1)),
|
36
|
+
"type_template" => Annotation.new(arity: 0),
|
37
|
+
"unsafe" => Annotation.new(arity: 1),
|
38
|
+
"untyped" => Annotation.new(arity: 0, receiver: true),
|
39
|
+
},
|
40
|
+
T::Hash[String, Annotation],
|
41
|
+
)
|
42
|
+
|
43
|
+
sig do
|
44
|
+
params(
|
45
|
+
node: T.any(SyntaxTree::CallNode, SyntaxTree::VCall),
|
46
|
+
).returns(T::Boolean)
|
47
|
+
end
|
48
|
+
def annotation?(node)
|
49
|
+
annotation = annotation(node)
|
50
|
+
|
51
|
+
return false if annotation.nil?
|
52
|
+
|
53
|
+
return false unless annotation.supports_receiver?(receiver_name(node))
|
54
|
+
|
55
|
+
annotation.supports_arity?(node.arity)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
sig { params(node: T.any(SyntaxTree::CallNode, SyntaxTree::VCall)).returns(T.nilable(Annotation)) }
|
61
|
+
def annotation(node)
|
62
|
+
case node
|
63
|
+
when SyntaxTree::VCall
|
64
|
+
ANNOTATIONS[node.value.value]
|
65
|
+
when SyntaxTree::CallNode
|
66
|
+
ANNOTATIONS[node.message.value]
|
67
|
+
else
|
68
|
+
T.absurd(node)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
sig do
|
73
|
+
params(receiver: T.any(SyntaxTree::CallNode, SyntaxTree::VCall)).returns(T.nilable(String))
|
74
|
+
end
|
75
|
+
def receiver_name(receiver)
|
76
|
+
case receiver
|
77
|
+
when SyntaxTree::CallNode
|
78
|
+
node_name(receiver.receiver)
|
79
|
+
when SyntaxTree::VCall
|
80
|
+
nil
|
81
|
+
else
|
82
|
+
T.absurd(receiver)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
sig do
|
87
|
+
params(node: T.nilable(T.any(
|
88
|
+
SyntaxTree::VarRef,
|
89
|
+
SyntaxTree::CallNode,
|
90
|
+
SyntaxTree::VCall,
|
91
|
+
SyntaxTree::Ident,
|
92
|
+
SyntaxTree::Backtick,
|
93
|
+
SyntaxTree::Const,
|
94
|
+
SyntaxTree::Op,
|
95
|
+
Symbol,
|
96
|
+
))).returns(T.nilable(String))
|
97
|
+
end
|
98
|
+
def node_name(node)
|
99
|
+
case node
|
100
|
+
when NilClass
|
101
|
+
nil
|
102
|
+
when SyntaxTree::VarRef
|
103
|
+
node.value.value
|
104
|
+
when SyntaxTree::CallNode
|
105
|
+
node_name(node.receiver)
|
106
|
+
when SyntaxTree::VCall
|
107
|
+
node_name(node.value)
|
108
|
+
when SyntaxTree::Ident, SyntaxTree::Backtick, SyntaxTree::Const, SyntaxTree::Op
|
109
|
+
node.value
|
110
|
+
when Symbol
|
111
|
+
node.to_s
|
112
|
+
else
|
113
|
+
T.absurd(node)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -16,6 +16,7 @@ module RubyLsp
|
|
16
16
|
# - {RubyLsp::Requests::CodeActions}
|
17
17
|
# - {RubyLsp::Requests::DocumentHighlight}
|
18
18
|
# - {RubyLsp::Requests::InlayHints}
|
19
|
+
# - {RubyLsp::Requests::PathCompletion}
|
19
20
|
|
20
21
|
module Requests
|
21
22
|
autoload :BaseRequest, "ruby_lsp/requests/base_request"
|
@@ -31,15 +32,18 @@ module RubyLsp
|
|
31
32
|
autoload :CodeActions, "ruby_lsp/requests/code_actions"
|
32
33
|
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
33
34
|
autoload :InlayHints, "ruby_lsp/requests/inlay_hints"
|
35
|
+
autoload :PathCompletion, "ruby_lsp/requests/path_completion"
|
34
36
|
|
35
37
|
# :nodoc:
|
36
38
|
module Support
|
37
39
|
autoload :RuboCopDiagnostic, "ruby_lsp/requests/support/rubocop_diagnostic"
|
38
40
|
autoload :SelectionRange, "ruby_lsp/requests/support/selection_range"
|
39
41
|
autoload :SemanticTokenEncoder, "ruby_lsp/requests/support/semantic_token_encoder"
|
40
|
-
autoload :
|
42
|
+
autoload :Annotation, "ruby_lsp/requests/support/annotation"
|
43
|
+
autoload :Sorbet, "ruby_lsp/requests/support/sorbet"
|
41
44
|
autoload :HighlightTarget, "ruby_lsp/requests/support/highlight_target"
|
42
45
|
autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
|
46
|
+
autoload :PrefixTree, "ruby_lsp/requests/support/prefix_tree"
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|