steep 1.4.0 → 1.5.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.vscode/steep-shared.code-snippets +41 -0
- data/CHANGELOG.md +37 -0
- data/Gemfile +2 -5
- data/Gemfile.lock +20 -17
- data/Gemfile.steep +1 -1
- data/Gemfile.steep.lock +6 -6
- data/Rakefile +198 -0
- data/Steepfile +3 -1
- data/lib/steep/ast/builtin.rb +9 -7
- data/lib/steep/ast/node/type_application.rb +13 -5
- data/lib/steep/ast/node/type_assertion.rb +28 -9
- data/lib/steep/ast/types/factory.rb +39 -7
- data/lib/steep/cli.rb +2 -1
- data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
- data/lib/steep/diagnostic/lsp_formatter.rb +3 -3
- data/lib/steep/diagnostic/ruby.rb +73 -12
- data/lib/steep/drivers/annotations.rb +1 -0
- data/lib/steep/drivers/check.rb +18 -13
- data/lib/steep/drivers/checkfile.rb +1 -1
- data/lib/steep/drivers/diagnostic_printer.rb +6 -4
- data/lib/steep/drivers/init.rb +2 -1
- data/lib/steep/drivers/print_project.rb +3 -1
- data/lib/steep/drivers/stats.rb +1 -1
- data/lib/steep/drivers/utils/driver_helper.rb +10 -8
- data/lib/steep/drivers/utils/jobs_option.rb +6 -1
- data/lib/steep/drivers/validate.rb +9 -5
- data/lib/steep/drivers/watch.rb +8 -3
- data/lib/steep/expectations.rb +144 -75
- data/lib/steep/index/signature_symbol_provider.rb +22 -13
- data/lib/steep/node_helper.rb +172 -0
- data/lib/steep/server/base_worker.rb +2 -1
- data/lib/steep/server/change_buffer.rb +17 -15
- data/lib/steep/server/interaction_worker.rb +20 -0
- data/lib/steep/server/lsp_formatter.rb +20 -1
- data/lib/steep/server/master.rb +51 -36
- data/lib/steep/server/type_check_worker.rb +18 -2
- data/lib/steep/server/worker_process.rb +19 -2
- data/lib/steep/services/completion_provider.rb +189 -3
- data/lib/steep/services/file_loader.rb +1 -1
- data/lib/steep/services/goto_service.rb +123 -27
- data/lib/steep/services/signature_help_provider.rb +1 -6
- data/lib/steep/signature/validator.rb +6 -1
- data/lib/steep/source.rb +165 -108
- data/lib/steep/subtyping/check.rb +5 -3
- data/lib/steep/subtyping/variable_variance.rb +11 -0
- data/lib/steep/thread_waiter.rb +35 -0
- data/lib/steep/type_construction.rb +416 -171
- data/lib/steep/type_inference/block_params.rb +50 -9
- data/lib/steep/type_inference/context.rb +4 -0
- data/lib/steep/type_inference/context_array.rb +6 -6
- data/lib/steep/type_inference/logic_type_interpreter.rb +202 -68
- data/lib/steep/typing.rb +5 -4
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +21 -14
- data/sample/Steepfile +1 -0
- data/sig/shims/bundler.rbs +3 -0
- data/sig/shims/language-server_protocol.rbs +151 -10
- data/sig/shims/parser/nodes.rbs +210 -0
- data/sig/shims/parser.rbs +10 -0
- data/sig/steep/ast/builtin.rbs +2 -2
- data/sig/steep/ast/node/type_application.rbs +2 -2
- data/sig/steep/ast/node/type_assertion.rbs +8 -2
- data/sig/steep/ast/types/factory.rbs +28 -1
- data/sig/steep/diagnostic/deprecated/else_on_exhaustive_case.rbs +13 -0
- data/sig/steep/diagnostic/lsp_formatter.rbs +5 -2
- data/sig/steep/diagnostic/ruby.rbs +76 -6
- data/sig/steep/drivers/annotations.rbs +5 -5
- data/sig/steep/drivers/check.rbs +11 -11
- data/sig/steep/drivers/diagnostic_printer.rbs +9 -9
- data/sig/steep/drivers/init.rbs +6 -6
- data/sig/steep/drivers/print_project.rbs +4 -4
- data/sig/steep/drivers/utils/driver_helper.rbs +8 -6
- data/sig/steep/drivers/validate.rbs +4 -4
- data/sig/steep/drivers/watch.rbs +1 -1
- data/sig/steep/expectations.rbs +72 -0
- data/sig/steep/index/signature_symbol_provider.rbs +22 -10
- data/sig/steep/interface/block.rbs +2 -0
- data/sig/steep/interface/function.rbs +2 -2
- data/sig/steep/node_helper.rbs +56 -0
- data/sig/steep/path_helper.rbs +1 -1
- data/sig/steep/project/options.rbs +1 -1
- data/sig/steep/range_extension.rbs +2 -2
- data/sig/steep/server/master.rbs +16 -2
- data/sig/steep/server/type_check_worker.rbs +5 -1
- data/sig/steep/server/worker_process.rbs +5 -1
- data/sig/steep/services/completion_provider.rbs +31 -1
- data/sig/steep/services/goto_service.rbs +80 -19
- data/sig/steep/source.rbs +27 -4
- data/sig/steep/subtyping/variable_variance.rbs +9 -9
- data/sig/steep/thread_waiter.rbs +13 -0
- data/sig/steep/type_construction.rbs +26 -9
- data/sig/steep/type_inference/block_params.rbs +13 -1
- data/sig/steep/type_inference/context.rbs +5 -1
- data/sig/steep/type_inference/context_array.rbs +16 -15
- data/sig/steep/type_inference/logic_type_interpreter.rbs +36 -6
- data/sig/steep/type_inference/type_env_builder.rbs +4 -0
- data/sig/steep/typing.rbs +22 -20
- data/sig/steep.rbs +14 -13
- data/smoke/and/a.rb +1 -1
- data/smoke/and/test_expectations.yml +5 -7
- data/smoke/diagnostics/incompatible_annotation.rb +1 -1
- data/smoke/diagnostics/test_expectations.yml +2 -2
- data/smoke/enumerator/a.rb +0 -7
- data/smoke/enumerator/b.rb +0 -2
- data/smoke/enumerator/test_expectations.yml +17 -105
- data/smoke/lambda/a.rb +0 -5
- data/smoke/lambda/test_expectations.yml +0 -22
- data/smoke/type_case/test_expectations.yml +10 -0
- data/steep.gemspec +2 -2
- metadata +16 -9
data/lib/steep/expectations.rb
CHANGED
@@ -1,5 +1,136 @@
|
|
1
1
|
module Steep
|
2
2
|
class Expectations
|
3
|
+
class Diagnostic < Struct.new(:start_position, :end_position, :severity, :message, :code, keyword_init: true)
|
4
|
+
DiagnosticSeverity = LanguageServer::Protocol::Constant::DiagnosticSeverity
|
5
|
+
|
6
|
+
def self.from_hash(hash)
|
7
|
+
start_position = {
|
8
|
+
line: hash.dig("range", "start", "line") - 1,
|
9
|
+
character: hash.dig("range", "start", "character")
|
10
|
+
} #: position
|
11
|
+
end_position = {
|
12
|
+
line: hash.dig("range", "end", "line") - 1,
|
13
|
+
character: hash.dig("range", "end", "character")
|
14
|
+
} #: position
|
15
|
+
|
16
|
+
severity =
|
17
|
+
case hash["severity"] || "ERROR"
|
18
|
+
when "ERROR"
|
19
|
+
:error
|
20
|
+
when "WARNING"
|
21
|
+
:warning
|
22
|
+
when "INFORMATION"
|
23
|
+
:information
|
24
|
+
when "HINT"
|
25
|
+
:hint
|
26
|
+
end #: Diagnostic::LSPFormatter::severity
|
27
|
+
|
28
|
+
Diagnostic.new(
|
29
|
+
start_position: start_position,
|
30
|
+
end_position: end_position,
|
31
|
+
severity: severity,
|
32
|
+
message: hash["message"],
|
33
|
+
code: hash["code"]
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.from_lsp(diagnostic)
|
38
|
+
start_position = {
|
39
|
+
line: diagnostic.dig(:range, :start, :line),
|
40
|
+
character: diagnostic.dig(:range, :start, :character)
|
41
|
+
} #: position
|
42
|
+
end_position = {
|
43
|
+
line: diagnostic.dig(:range, :end, :line),
|
44
|
+
character: diagnostic.dig(:range, :end, :character)
|
45
|
+
} #: position
|
46
|
+
|
47
|
+
severity =
|
48
|
+
case diagnostic[:severity]
|
49
|
+
when DiagnosticSeverity::ERROR
|
50
|
+
:error
|
51
|
+
when DiagnosticSeverity::WARNING
|
52
|
+
:warning
|
53
|
+
when DiagnosticSeverity::INFORMATION
|
54
|
+
:information
|
55
|
+
when DiagnosticSeverity::HINT
|
56
|
+
:hint
|
57
|
+
else
|
58
|
+
:error
|
59
|
+
end #: Diagnostic::LSPFormatter::severity
|
60
|
+
|
61
|
+
Diagnostic.new(
|
62
|
+
start_position: start_position,
|
63
|
+
end_position: end_position,
|
64
|
+
severity: severity,
|
65
|
+
message: diagnostic[:message],
|
66
|
+
code: diagnostic[:code]
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_hash
|
71
|
+
{
|
72
|
+
"range" => {
|
73
|
+
"start" => {
|
74
|
+
"line" => start_position[:line] + 1,
|
75
|
+
"character" => start_position[:character]
|
76
|
+
},
|
77
|
+
"end" => {
|
78
|
+
"line" => end_position[:line] + 1,
|
79
|
+
"character" => end_position[:character]
|
80
|
+
}
|
81
|
+
},
|
82
|
+
"severity" => severity.to_s.upcase,
|
83
|
+
"message" => message,
|
84
|
+
"code" => code
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def lsp_severity
|
89
|
+
case severity
|
90
|
+
when :error
|
91
|
+
DiagnosticSeverity::ERROR
|
92
|
+
when :warning
|
93
|
+
DiagnosticSeverity::WARNING
|
94
|
+
when :information
|
95
|
+
DiagnosticSeverity::INFORMATION
|
96
|
+
when :hint
|
97
|
+
DiagnosticSeverity::HINT
|
98
|
+
else
|
99
|
+
raise
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_lsp
|
104
|
+
{
|
105
|
+
range: {
|
106
|
+
start: {
|
107
|
+
line: start_position[:line],
|
108
|
+
character: start_position[:character]
|
109
|
+
},
|
110
|
+
end: {
|
111
|
+
line: end_position[:line],
|
112
|
+
character: end_position[:character]
|
113
|
+
}
|
114
|
+
},
|
115
|
+
severity: lsp_severity,
|
116
|
+
message: message,
|
117
|
+
code: code
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def sort_key
|
122
|
+
[
|
123
|
+
start_position[:line],
|
124
|
+
start_position[:character],
|
125
|
+
end_position[:line],
|
126
|
+
end_position[:character],
|
127
|
+
code,
|
128
|
+
severity,
|
129
|
+
message
|
130
|
+
]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
3
134
|
class TestResult
|
4
135
|
attr_reader :path
|
5
136
|
attr_reader :expectation
|
@@ -21,17 +152,17 @@ module Steep
|
|
21
152
|
|
22
153
|
def each_diagnostics
|
23
154
|
if block_given?
|
24
|
-
expected_set = Set.new(expectation)
|
25
|
-
actual_set = Set.new(actual)
|
155
|
+
expected_set = Set.new(expectation) #: Set[Diagnostic]
|
156
|
+
actual_set = Set.new(actual) #: Set[Diagnostic]
|
26
157
|
|
27
|
-
(expected_set + actual_set).sort_by
|
158
|
+
(expected_set + actual_set).sort_by(&:sort_key).each do |diagnostic|
|
28
159
|
case
|
29
|
-
when expected_set.include?(
|
30
|
-
yield :expected,
|
31
|
-
when expected_set.include?(
|
32
|
-
yield :missing,
|
33
|
-
when actual_set.include?(
|
34
|
-
yield :unexpected,
|
160
|
+
when expected_set.include?(diagnostic) && actual_set.include?(diagnostic)
|
161
|
+
yield [:expected, diagnostic]
|
162
|
+
when expected_set.include?(diagnostic)
|
163
|
+
yield [:missing, diagnostic]
|
164
|
+
when actual_set.include?(diagnostic)
|
165
|
+
yield [:unexpected, diagnostic]
|
35
166
|
end
|
36
167
|
end
|
37
168
|
else
|
@@ -56,18 +187,6 @@ module Steep
|
|
56
187
|
|
57
188
|
attr_reader :diagnostics
|
58
189
|
|
59
|
-
def self.sort_key(hash)
|
60
|
-
[
|
61
|
-
hash.dig(:range, :start, :line),
|
62
|
-
hash.dig(:range, :start, :character),
|
63
|
-
hash.dig(:range, :end, :line),
|
64
|
-
hash.dig(:range, :end, :character),
|
65
|
-
hash[:code],
|
66
|
-
hash[:severity],
|
67
|
-
hash[:message]
|
68
|
-
]
|
69
|
-
end
|
70
|
-
|
71
190
|
def initialize()
|
72
191
|
@diagnostics = {}
|
73
192
|
end
|
@@ -81,14 +200,13 @@ module Steep
|
|
81
200
|
end
|
82
201
|
|
83
202
|
def to_yaml
|
84
|
-
array = []
|
203
|
+
array = [] #: Array[{ "file" => String, "diagnostics" => Array[untyped] }]
|
85
204
|
|
86
205
|
diagnostics.each_key.sort.each do |key|
|
87
206
|
ds = diagnostics[key]
|
88
207
|
array << {
|
89
208
|
"file" => key.to_s,
|
90
|
-
'diagnostics' => ds.sort_by
|
91
|
-
.map { |d| Expectations.lsp_to_hash(d) }
|
209
|
+
'diagnostics' => ds.sort_by(&:sort_key).map(&:to_hash)
|
92
210
|
}
|
93
211
|
end
|
94
212
|
|
@@ -100,60 +218,11 @@ module Steep
|
|
100
218
|
|
101
219
|
YAML.load(content, filename: path.to_s).each do |entry|
|
102
220
|
file = Pathname(entry["file"])
|
103
|
-
expectations.diagnostics[file] =
|
104
|
-
|
105
|
-
.sort_by! {|h| sort_key(h) }
|
221
|
+
expectations.diagnostics[file] =
|
222
|
+
entry["diagnostics"].map {|hash| Diagnostic.from_hash(hash) }.sort_by!(&:sort_key)
|
106
223
|
end
|
107
224
|
|
108
225
|
expectations
|
109
226
|
end
|
110
|
-
|
111
|
-
# Translate hash to LSP Diagnostic message
|
112
|
-
def self.hash_to_lsp(hash)
|
113
|
-
{
|
114
|
-
range: {
|
115
|
-
start: {
|
116
|
-
line: hash.dig("range", "start", "line") - 1,
|
117
|
-
character: hash.dig("range", "start", "character")
|
118
|
-
},
|
119
|
-
end: {
|
120
|
-
line: hash.dig("range", "end", "line") - 1,
|
121
|
-
character: hash.dig("range", "end", "character")
|
122
|
-
}
|
123
|
-
},
|
124
|
-
severity: {
|
125
|
-
"ERROR" => LSP::Constant::DiagnosticSeverity::ERROR,
|
126
|
-
"WARNING" => LSP::Constant::DiagnosticSeverity::WARNING,
|
127
|
-
"INFORMATION" => LSP::Constant::DiagnosticSeverity::INFORMATION,
|
128
|
-
"HINT" => LSP::Constant::DiagnosticSeverity::HINT
|
129
|
-
}[hash["severity"] || "ERROR"],
|
130
|
-
message: hash["message"],
|
131
|
-
code: hash["code"]
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
|
-
# Translate LSP diagnostic message to hash
|
136
|
-
def self.lsp_to_hash(lsp)
|
137
|
-
{
|
138
|
-
"range" => {
|
139
|
-
"start" => {
|
140
|
-
"line" => lsp.dig(:range, :start, :line) + 1,
|
141
|
-
"character" => lsp.dig(:range, :start, :character)
|
142
|
-
},
|
143
|
-
"end" => {
|
144
|
-
"line" => lsp.dig(:range, :end, :line) + 1,
|
145
|
-
"character" => lsp.dig(:range, :end, :character)
|
146
|
-
}
|
147
|
-
},
|
148
|
-
"severity" => {
|
149
|
-
LSP::Constant::DiagnosticSeverity::ERROR => "ERROR",
|
150
|
-
LSP::Constant::DiagnosticSeverity::WARNING => "WARNING",
|
151
|
-
LSP::Constant::DiagnosticSeverity::INFORMATION => "INFORMATION",
|
152
|
-
LSP::Constant::DiagnosticSeverity::HINT => "HINT"
|
153
|
-
}[lsp[:severity] || LSP::Constant::DiagnosticSeverity::ERROR],
|
154
|
-
"message" => lsp[:message],
|
155
|
-
"code" => lsp[:code]
|
156
|
-
}
|
157
|
-
end
|
158
227
|
end
|
159
228
|
end
|
@@ -2,7 +2,9 @@ module Steep
|
|
2
2
|
module Index
|
3
3
|
class SignatureSymbolProvider
|
4
4
|
LSP = LanguageServer::Protocol
|
5
|
-
|
5
|
+
|
6
|
+
class SymbolInformation < Struct.new(:name, :kind, :container_name, :location, keyword_init: true)
|
7
|
+
end
|
6
8
|
|
7
9
|
attr_reader :project
|
8
10
|
attr_reader :indexes
|
@@ -48,7 +50,7 @@ module Steep
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def query_symbol(query)
|
51
|
-
symbols = []
|
53
|
+
symbols = [] #: Array[SymbolInformation]
|
52
54
|
|
53
55
|
indexes.each do |index|
|
54
56
|
index.each_entry do |entry|
|
@@ -60,34 +62,35 @@ module Steep
|
|
60
62
|
name = entry.type_name.name.to_s
|
61
63
|
|
62
64
|
entry.declarations.each do |decl|
|
63
|
-
|
65
|
+
location = decl.location or next
|
66
|
+
next unless assigned?(Pathname(location.buffer.name))
|
64
67
|
|
65
68
|
case decl
|
66
69
|
when RBS::AST::Declarations::Class
|
67
70
|
symbols << SymbolInformation.new(
|
68
71
|
name: name,
|
69
|
-
location:
|
72
|
+
location: location,
|
70
73
|
kind: LSP::Constant::SymbolKind::CLASS,
|
71
74
|
container_name: container_name
|
72
75
|
)
|
73
76
|
when RBS::AST::Declarations::Module
|
74
77
|
symbols << SymbolInformation.new(
|
75
78
|
name: name,
|
76
|
-
location:
|
79
|
+
location: location,
|
77
80
|
kind: LSP::Constant::SymbolKind::MODULE,
|
78
81
|
container_name: container_name
|
79
82
|
)
|
80
83
|
when RBS::AST::Declarations::Interface
|
81
84
|
symbols << SymbolInformation.new(
|
82
85
|
name: name,
|
83
|
-
location:
|
86
|
+
location: location,
|
84
87
|
kind: LSP::Constant::SymbolKind::INTERFACE,
|
85
88
|
container_name: container_name
|
86
89
|
)
|
87
90
|
when RBS::AST::Declarations::TypeAlias
|
88
91
|
symbols << SymbolInformation.new(
|
89
92
|
name: name,
|
90
|
-
location:
|
93
|
+
location: location,
|
91
94
|
kind: LSP::Constant::SymbolKind::ENUM,
|
92
95
|
container_name: container_name
|
93
96
|
)
|
@@ -101,31 +104,34 @@ module Steep
|
|
101
104
|
"##{entry.method_name.method_name}"
|
102
105
|
when SingletonMethodName
|
103
106
|
".#{entry.method_name.method_name}"
|
107
|
+
else
|
108
|
+
raise
|
104
109
|
end
|
105
110
|
container_name = entry.method_name.type_name.relative!.to_s
|
106
111
|
|
107
112
|
entry.declarations.each do |decl|
|
108
|
-
|
113
|
+
location = decl.location or next
|
114
|
+
next unless assigned?(Pathname(location.buffer.name))
|
109
115
|
|
110
116
|
case decl
|
111
117
|
when RBS::AST::Members::MethodDefinition
|
112
118
|
symbols << SymbolInformation.new(
|
113
119
|
name: name,
|
114
|
-
location:
|
120
|
+
location: location,
|
115
121
|
kind: LSP::Constant::SymbolKind::METHOD,
|
116
122
|
container_name: container_name
|
117
123
|
)
|
118
124
|
when RBS::AST::Members::Alias
|
119
125
|
symbols << SymbolInformation.new(
|
120
126
|
name: name,
|
121
|
-
location:
|
127
|
+
location: location,
|
122
128
|
kind: LSP::Constant::SymbolKind::METHOD,
|
123
129
|
container_name: container_name
|
124
130
|
)
|
125
131
|
when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
|
126
132
|
symbols << SymbolInformation.new(
|
127
133
|
name: name,
|
128
|
-
location:
|
134
|
+
location: location,
|
129
135
|
kind: LSP::Constant::SymbolKind::PROPERTY,
|
130
136
|
container_name: container_name
|
131
137
|
)
|
@@ -133,7 +139,7 @@ module Steep
|
|
133
139
|
if decl.ivar_name
|
134
140
|
symbols << SymbolInformation.new(
|
135
141
|
name: decl.ivar_name.to_s,
|
136
|
-
location:
|
142
|
+
location: location,
|
137
143
|
kind: LSP::Constant::SymbolKind::FIELD,
|
138
144
|
container_name: container_name
|
139
145
|
)
|
@@ -144,6 +150,7 @@ module Steep
|
|
144
150
|
next unless SignatureSymbolProvider.test_const_name(query, entry.const_name)
|
145
151
|
|
146
152
|
entry.declarations.each do |decl|
|
153
|
+
next unless decl.location
|
147
154
|
next unless assigned?(Pathname(decl.location.buffer.name))
|
148
155
|
|
149
156
|
symbols << SymbolInformation.new(
|
@@ -157,12 +164,14 @@ module Steep
|
|
157
164
|
next unless SignatureSymbolProvider.test_global_name(query, entry.global_name)
|
158
165
|
|
159
166
|
entry.declarations.each do |decl|
|
167
|
+
next unless decl.location
|
160
168
|
next unless assigned?(Pathname(decl.location.buffer.name))
|
161
169
|
|
162
170
|
symbols << SymbolInformation.new(
|
163
171
|
name: decl.name.to_s,
|
164
172
|
location: decl.location,
|
165
|
-
kind: LSP::Constant::SymbolKind::VARIABLE
|
173
|
+
kind: LSP::Constant::SymbolKind::VARIABLE,
|
174
|
+
container_name: nil
|
166
175
|
)
|
167
176
|
end
|
168
177
|
end
|
data/lib/steep/node_helper.rb
CHANGED
@@ -25,6 +25,8 @@ module Steep
|
|
25
25
|
|
26
26
|
def value_node?(node)
|
27
27
|
case node.type
|
28
|
+
when :self
|
29
|
+
true
|
28
30
|
when :true, :false, :str, :sym, :int, :float, :nil
|
29
31
|
true
|
30
32
|
when :lvar
|
@@ -45,5 +47,175 @@ module Steep
|
|
45
47
|
false
|
46
48
|
end
|
47
49
|
end
|
50
|
+
|
51
|
+
def deconstruct_if_node(node)
|
52
|
+
if node.type == :if
|
53
|
+
[
|
54
|
+
node.children[0],
|
55
|
+
node.children[1],
|
56
|
+
node.children[2],
|
57
|
+
_ = node.location
|
58
|
+
]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def deconstruct_if_node!(node)
|
63
|
+
deconstruct_if_node(node) or raise
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_if_node(node)
|
67
|
+
if (a, b, c, d = deconstruct_if_node(node))
|
68
|
+
yield(a, b, c, d)
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def deconstruct_whileish_node(node)
|
75
|
+
case node.type
|
76
|
+
when :while, :until, :while_post, :until_post
|
77
|
+
[
|
78
|
+
node.children[0],
|
79
|
+
node.children[1],
|
80
|
+
_ = node.location
|
81
|
+
]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def deconstruct_whileish_node!(node)
|
86
|
+
deconstruct_whileish_node(node) or raise
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_whileish_node(node)
|
90
|
+
if (a, b, c = deconstruct_whileish_node(node))
|
91
|
+
yield(a, b, c)
|
92
|
+
else
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def deconstruct_case_node(node)
|
98
|
+
case node.type
|
99
|
+
when :case
|
100
|
+
cond, *whens, else_ = node.children
|
101
|
+
[
|
102
|
+
cond,
|
103
|
+
whens,
|
104
|
+
else_,
|
105
|
+
_ = node.loc
|
106
|
+
]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def deconstruct_case_node!(node)
|
111
|
+
deconstruct_case_node(node) or raise
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_case_node(node)
|
115
|
+
if (a, b, c, d = deconstruct_case_node(node))
|
116
|
+
yield a, b, c, d
|
117
|
+
else
|
118
|
+
false
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def deconstruct_when_node(node)
|
123
|
+
case node.type
|
124
|
+
when :when
|
125
|
+
*conds, body = node.children
|
126
|
+
[
|
127
|
+
conds,
|
128
|
+
body,
|
129
|
+
_ = node.loc
|
130
|
+
]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def deconstruct_when_node!(node)
|
135
|
+
deconstruct_when_node(node) or raise
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_when_node(node)
|
139
|
+
if (a, b, c = deconstruct_when_node(node))
|
140
|
+
yield a, b, c
|
141
|
+
else
|
142
|
+
false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def deconstruct_rescue_node(node)
|
147
|
+
case node.type
|
148
|
+
when :rescue
|
149
|
+
body, *resbodies, else_ = node.children
|
150
|
+
|
151
|
+
[
|
152
|
+
body,
|
153
|
+
resbodies,
|
154
|
+
else_,
|
155
|
+
_ = node.loc
|
156
|
+
]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def deconstruct_rescue_node!(node)
|
161
|
+
deconstruct_rescue_node(node) or raise
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_rescue_node(node)
|
165
|
+
if (a, b, c, d = deconstruct_rescue_node(node))
|
166
|
+
yield a, b, c, d
|
167
|
+
else
|
168
|
+
false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def deconstruct_resbody_node(node)
|
173
|
+
case node.type
|
174
|
+
when :resbody
|
175
|
+
[
|
176
|
+
node.children[0],
|
177
|
+
node.children[1],
|
178
|
+
node.children[2],
|
179
|
+
_ = node.loc
|
180
|
+
]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def deconstruct_resbody_node!(node)
|
185
|
+
deconstruct_resbody_node(node) or raise
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_resbody_node(node)
|
189
|
+
if (a, b, c, d = deconstruct_resbody_node(node))
|
190
|
+
yield a, b, c, d
|
191
|
+
else
|
192
|
+
false
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def deconstruct_send_node(node)
|
197
|
+
case node.type
|
198
|
+
when :send, :csend
|
199
|
+
receiver, selector, *args = node.children
|
200
|
+
[
|
201
|
+
receiver,
|
202
|
+
selector,
|
203
|
+
args,
|
204
|
+
_ = node.loc
|
205
|
+
]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def deconstruct_send_node!(node)
|
210
|
+
deconstruct_send_node(node) or raise
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_send_node(node)
|
214
|
+
if (a, b, c, d = deconstruct_send_node(node))
|
215
|
+
yield a, b, c, d
|
216
|
+
else
|
217
|
+
false
|
218
|
+
end
|
219
|
+
end
|
48
220
|
end
|
49
221
|
end
|
@@ -40,6 +40,8 @@ module Steep
|
|
40
40
|
def run
|
41
41
|
tags = Steep.logger.formatter.current_tags.dup
|
42
42
|
thread = Thread.new do
|
43
|
+
Thread.current.abort_on_exception = true
|
44
|
+
|
43
45
|
Steep.logger.formatter.push_tags(*tags)
|
44
46
|
Steep.logger.tagged "background" do
|
45
47
|
while job = queue.pop
|
@@ -69,7 +71,6 @@ module Steep
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
72
|
-
thread.abort_on_exception = true
|
73
74
|
|
74
75
|
Steep.logger.tagged "frontend" do
|
75
76
|
begin
|
@@ -16,7 +16,7 @@ module Steep
|
|
16
16
|
buffered_changes.clear
|
17
17
|
copy
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
if block_given?
|
21
21
|
yield changes
|
22
22
|
else
|
@@ -41,21 +41,23 @@ module Steep
|
|
41
41
|
|
42
42
|
def collect_changes(request)
|
43
43
|
push_buffer do |changes|
|
44
|
-
path =
|
45
|
-
|
46
|
-
|
44
|
+
if path = Steep::PathHelper.to_pathname(request[:params][:textDocument][:uri])
|
45
|
+
path = project.relative_path(path)
|
46
|
+
version = request[:params][:textDocument][:version]
|
47
|
+
Steep.logger.info { "Updating source: path=#{path}, version=#{version}..." }
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
49
|
+
changes[path] ||= []
|
50
|
+
request[:params][:contentChanges].each do |change|
|
51
|
+
changes[path] << Services::ContentChange.new(
|
52
|
+
range: change[:range]&.yield_self {|range|
|
53
|
+
[
|
54
|
+
range[:start].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) },
|
55
|
+
range[:end].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) }
|
56
|
+
]
|
57
|
+
},
|
58
|
+
text: change[:text]
|
59
|
+
)
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
@@ -361,6 +361,26 @@ module Steep
|
|
361
361
|
new_text: item.identifier.to_s
|
362
362
|
)
|
363
363
|
)
|
364
|
+
when Services::CompletionProvider::TypeNameItem
|
365
|
+
kind =
|
366
|
+
case
|
367
|
+
when item.absolute_type_name.class?
|
368
|
+
LSP::Constant::CompletionItemKind::CLASS
|
369
|
+
when item.absolute_type_name.interface?
|
370
|
+
LSP::Constant::CompletionItemKind::INTERFACE
|
371
|
+
when item.absolute_type_name.alias?
|
372
|
+
LSP::Constant::CompletionItemKind::FIELD
|
373
|
+
end
|
374
|
+
LSP::Interface::CompletionItem.new(
|
375
|
+
label: item.relative_type_name.to_s,
|
376
|
+
kind: kind,
|
377
|
+
label_details: nil,
|
378
|
+
documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
|
379
|
+
text_edit: LSP::Interface::TextEdit.new(
|
380
|
+
range: range,
|
381
|
+
new_text: item.relative_type_name.to_s
|
382
|
+
)
|
383
|
+
)
|
364
384
|
end
|
365
385
|
end
|
366
386
|
|
@@ -231,6 +231,25 @@ module Steep
|
|
231
231
|
format_method_item_doc(item.method_types, method_names, comments)
|
232
232
|
when Services::CompletionProvider::GeneratedMethodNameItem
|
233
233
|
format_method_item_doc(item.method_types, [], {}, "🤖 Generated method for receiver type")
|
234
|
+
when Services::CompletionProvider::TypeNameItem
|
235
|
+
io = StringIO.new
|
236
|
+
|
237
|
+
io.puts <<~MD
|
238
|
+
```rbs
|
239
|
+
#{declaration_summary(item.decl)}
|
240
|
+
```
|
241
|
+
MD
|
242
|
+
|
243
|
+
unless item.comments.empty?
|
244
|
+
io.puts "----"
|
245
|
+
io.puts format_comments(
|
246
|
+
item.comments.map {|comment|
|
247
|
+
[item.absolute_type_name.relative!.to_s, comment] #: [String, RBS::AST::Comment?]
|
248
|
+
}
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
io.string
|
234
253
|
end
|
235
254
|
end
|
236
255
|
|
@@ -296,7 +315,7 @@ module Steep
|
|
296
315
|
|
297
316
|
io = StringIO.new
|
298
317
|
if header
|
299
|
-
io.puts "### 📚 #{header}"
|
318
|
+
io.puts "### 📚 #{header.gsub("_", "\\_")}"
|
300
319
|
io.puts
|
301
320
|
end
|
302
321
|
io.puts comment.string.rstrip.gsub(/^[ \t]*<!--(?~-->)-->\n/, "").gsub(/\A([ \t]*\n)+/, "")
|