steep-activesupport-4 1.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.gitmodules +0 -0
- data/CHANGELOG.md +1032 -0
- data/LICENSE +21 -0
- data/README.md +260 -0
- data/Rakefile +227 -0
- data/Steepfile +68 -0
- data/bin/console +14 -0
- data/bin/generate-diagnostics-docs.rb +112 -0
- data/bin/mem_graph.rb +67 -0
- data/bin/mem_prof.rb +102 -0
- data/bin/output_rebaseline.rb +34 -0
- data/bin/output_test.rb +60 -0
- data/bin/rbs +20 -0
- data/bin/rbs-inline +19 -0
- data/bin/setup +9 -0
- data/bin/stackprof_test.rb +19 -0
- data/bin/steep +19 -0
- data/bin/steep-check.rb +251 -0
- data/bin/steep-prof +16 -0
- data/doc/narrowing.md +195 -0
- data/doc/shape.md +194 -0
- data/exe/steep +18 -0
- data/guides/README.md +5 -0
- data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
- data/guides/src/getting-started/getting-started.md +163 -0
- data/guides/src/nil-optional/nil-optional.md +195 -0
- data/lib/steep/annotation_parser.rb +199 -0
- data/lib/steep/ast/annotation/collection.rb +172 -0
- data/lib/steep/ast/annotation.rb +137 -0
- data/lib/steep/ast/builtin.rb +104 -0
- data/lib/steep/ast/ignore.rb +148 -0
- data/lib/steep/ast/node/type_application.rb +88 -0
- data/lib/steep/ast/node/type_assertion.rb +81 -0
- data/lib/steep/ast/types/any.rb +35 -0
- data/lib/steep/ast/types/boolean.rb +45 -0
- data/lib/steep/ast/types/bot.rb +35 -0
- data/lib/steep/ast/types/class.rb +43 -0
- data/lib/steep/ast/types/factory.rb +557 -0
- data/lib/steep/ast/types/helper.rb +40 -0
- data/lib/steep/ast/types/instance.rb +42 -0
- data/lib/steep/ast/types/intersection.rb +93 -0
- data/lib/steep/ast/types/literal.rb +59 -0
- data/lib/steep/ast/types/logic.rb +84 -0
- data/lib/steep/ast/types/name.rb +128 -0
- data/lib/steep/ast/types/nil.rb +41 -0
- data/lib/steep/ast/types/proc.rb +117 -0
- data/lib/steep/ast/types/record.rb +79 -0
- data/lib/steep/ast/types/self.rb +43 -0
- data/lib/steep/ast/types/shared_instance.rb +11 -0
- data/lib/steep/ast/types/top.rb +35 -0
- data/lib/steep/ast/types/tuple.rb +60 -0
- data/lib/steep/ast/types/union.rb +97 -0
- data/lib/steep/ast/types/var.rb +65 -0
- data/lib/steep/ast/types/void.rb +35 -0
- data/lib/steep/cli.rb +401 -0
- data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
- data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
- data/lib/steep/diagnostic/helper.rb +18 -0
- data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
- data/lib/steep/diagnostic/result_printer2.rb +48 -0
- data/lib/steep/diagnostic/ruby.rb +1221 -0
- data/lib/steep/diagnostic/signature.rb +570 -0
- data/lib/steep/drivers/annotations.rb +52 -0
- data/lib/steep/drivers/check.rb +339 -0
- data/lib/steep/drivers/checkfile.rb +210 -0
- data/lib/steep/drivers/diagnostic_printer.rb +105 -0
- data/lib/steep/drivers/init.rb +66 -0
- data/lib/steep/drivers/langserver.rb +56 -0
- data/lib/steep/drivers/print_project.rb +113 -0
- data/lib/steep/drivers/stats.rb +203 -0
- data/lib/steep/drivers/utils/driver_helper.rb +143 -0
- data/lib/steep/drivers/utils/jobs_option.rb +26 -0
- data/lib/steep/drivers/vendor.rb +27 -0
- data/lib/steep/drivers/watch.rb +194 -0
- data/lib/steep/drivers/worker.rb +58 -0
- data/lib/steep/equatable.rb +23 -0
- data/lib/steep/expectations.rb +228 -0
- data/lib/steep/index/rbs_index.rb +350 -0
- data/lib/steep/index/signature_symbol_provider.rb +185 -0
- data/lib/steep/index/source_index.rb +167 -0
- data/lib/steep/interface/block.rb +103 -0
- data/lib/steep/interface/builder.rb +843 -0
- data/lib/steep/interface/function.rb +1090 -0
- data/lib/steep/interface/method_type.rb +330 -0
- data/lib/steep/interface/shape.rb +239 -0
- data/lib/steep/interface/substitution.rb +159 -0
- data/lib/steep/interface/type_param.rb +115 -0
- data/lib/steep/located_value.rb +20 -0
- data/lib/steep/method_name.rb +42 -0
- data/lib/steep/module_helper.rb +24 -0
- data/lib/steep/node_helper.rb +273 -0
- data/lib/steep/path_helper.rb +30 -0
- data/lib/steep/project/dsl.rb +268 -0
- data/lib/steep/project/group.rb +31 -0
- data/lib/steep/project/options.rb +63 -0
- data/lib/steep/project/pattern.rb +59 -0
- data/lib/steep/project/target.rb +92 -0
- data/lib/steep/project.rb +78 -0
- data/lib/steep/rake_task.rb +132 -0
- data/lib/steep/range_extension.rb +29 -0
- data/lib/steep/server/base_worker.rb +97 -0
- data/lib/steep/server/change_buffer.rb +73 -0
- data/lib/steep/server/custom_methods.rb +77 -0
- data/lib/steep/server/delay_queue.rb +45 -0
- data/lib/steep/server/interaction_worker.rb +492 -0
- data/lib/steep/server/lsp_formatter.rb +455 -0
- data/lib/steep/server/master.rb +912 -0
- data/lib/steep/server/target_group_files.rb +205 -0
- data/lib/steep/server/type_check_controller.rb +366 -0
- data/lib/steep/server/type_check_worker.rb +303 -0
- data/lib/steep/server/work_done_progress.rb +64 -0
- data/lib/steep/server/worker_process.rb +176 -0
- data/lib/steep/services/completion_provider.rb +802 -0
- data/lib/steep/services/content_change.rb +61 -0
- data/lib/steep/services/file_loader.rb +74 -0
- data/lib/steep/services/goto_service.rb +441 -0
- data/lib/steep/services/hover_provider/rbs.rb +88 -0
- data/lib/steep/services/hover_provider/ruby.rb +221 -0
- data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
- data/lib/steep/services/path_assignment.rb +46 -0
- data/lib/steep/services/signature_help_provider.rb +202 -0
- data/lib/steep/services/signature_service.rb +428 -0
- data/lib/steep/services/stats_calculator.rb +68 -0
- data/lib/steep/services/type_check_service.rb +394 -0
- data/lib/steep/services/type_name_completion.rb +236 -0
- data/lib/steep/signature/validator.rb +651 -0
- data/lib/steep/source/ignore_ranges.rb +69 -0
- data/lib/steep/source.rb +691 -0
- data/lib/steep/subtyping/cache.rb +30 -0
- data/lib/steep/subtyping/check.rb +1113 -0
- data/lib/steep/subtyping/constraints.rb +341 -0
- data/lib/steep/subtyping/relation.rb +101 -0
- data/lib/steep/subtyping/result.rb +324 -0
- data/lib/steep/subtyping/variable_variance.rb +89 -0
- data/lib/steep/test.rb +9 -0
- data/lib/steep/thread_waiter.rb +43 -0
- data/lib/steep/type_construction.rb +5183 -0
- data/lib/steep/type_inference/block_params.rb +416 -0
- data/lib/steep/type_inference/case_when.rb +303 -0
- data/lib/steep/type_inference/constant_env.rb +56 -0
- data/lib/steep/type_inference/context.rb +195 -0
- data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
- data/lib/steep/type_inference/method_call.rb +193 -0
- data/lib/steep/type_inference/method_params.rb +531 -0
- data/lib/steep/type_inference/multiple_assignment.rb +194 -0
- data/lib/steep/type_inference/send_args.rb +712 -0
- data/lib/steep/type_inference/type_env.rb +341 -0
- data/lib/steep/type_inference/type_env_builder.rb +138 -0
- data/lib/steep/typing.rb +321 -0
- data/lib/steep/version.rb +3 -0
- data/lib/steep.rb +369 -0
- data/manual/annotations.md +181 -0
- data/manual/ignore.md +20 -0
- data/manual/ruby-diagnostics.md +1879 -0
- data/sample/Steepfile +22 -0
- data/sample/lib/conference.rb +49 -0
- data/sample/lib/length.rb +35 -0
- data/sample/sig/conference.rbs +42 -0
- data/sample/sig/generics.rbs +15 -0
- data/sample/sig/length.rbs +34 -0
- data/steep-activesupport-4.gemspec +55 -0
- metadata +437 -0
@@ -0,0 +1,303 @@
|
|
1
|
+
module Steep
|
2
|
+
module Server
|
3
|
+
class TypeCheckWorker < BaseWorker
|
4
|
+
attr_reader :project, :assignment, :service
|
5
|
+
attr_reader :commandline_args
|
6
|
+
attr_reader :current_type_check_guid
|
7
|
+
|
8
|
+
WorkspaceSymbolJob = _ = Struct.new(:query, :id, keyword_init: true)
|
9
|
+
StatsJob = _ = Struct.new(:id, keyword_init: true)
|
10
|
+
StartTypeCheckJob = _ = Struct.new(:guid, :changes, keyword_init: true)
|
11
|
+
TypeCheckCodeJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
|
12
|
+
ValidateAppSignatureJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
|
13
|
+
ValidateLibrarySignatureJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
|
14
|
+
class GotoJob < Struct.new(:id, :kind, :params, keyword_init: true)
|
15
|
+
def self.implementation(id:, params:)
|
16
|
+
new(
|
17
|
+
kind: :implementation,
|
18
|
+
id: id,
|
19
|
+
params: params
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.definition(id:, params:)
|
24
|
+
new(
|
25
|
+
kind: :definition,
|
26
|
+
id: id,
|
27
|
+
params: params
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.type_definition(id:, params:)
|
32
|
+
new(
|
33
|
+
kind: :type_definition,
|
34
|
+
id: id,
|
35
|
+
params: params
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def implementation?
|
40
|
+
kind == :implementation
|
41
|
+
end
|
42
|
+
|
43
|
+
def definition?
|
44
|
+
kind == :definition
|
45
|
+
end
|
46
|
+
|
47
|
+
def type_definition?
|
48
|
+
kind == :type_definition
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
include ChangeBuffer
|
53
|
+
|
54
|
+
def initialize(project:, reader:, writer:, assignment:, commandline_args:)
|
55
|
+
super(project: project, reader: reader, writer: writer)
|
56
|
+
|
57
|
+
@assignment = assignment
|
58
|
+
@buffered_changes = {}
|
59
|
+
@mutex = Mutex.new()
|
60
|
+
@queue = Queue.new
|
61
|
+
@commandline_args = commandline_args
|
62
|
+
@current_type_check_guid = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def service
|
66
|
+
@service ||= Services::TypeCheckService.new(project: project)
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_request(request)
|
70
|
+
case request[:method]
|
71
|
+
when "initialize"
|
72
|
+
writer.write({ id: request[:id], result: nil})
|
73
|
+
|
74
|
+
when "textDocument/didChange"
|
75
|
+
collect_changes(request)
|
76
|
+
|
77
|
+
when CustomMethods::FileLoad::METHOD
|
78
|
+
input = request[:params][:content]
|
79
|
+
load_files(input)
|
80
|
+
|
81
|
+
when CustomMethods::FileReset::METHOD
|
82
|
+
params = request[:params] #: CustomMethods::FileReset::params
|
83
|
+
uri = params[:uri]
|
84
|
+
text = params[:content]
|
85
|
+
reset_change(uri: uri, text: text)
|
86
|
+
|
87
|
+
when "workspace/symbol"
|
88
|
+
query = request[:params][:query]
|
89
|
+
queue << WorkspaceSymbolJob.new(id: request[:id], query: query)
|
90
|
+
when CustomMethods::Stats::METHOD
|
91
|
+
queue << StatsJob.new(id: request[:id])
|
92
|
+
when CustomMethods::TypeCheck__Start::METHOD
|
93
|
+
params = request[:params] #: CustomMethods::TypeCheck__Start::params
|
94
|
+
enqueue_typecheck_jobs(params)
|
95
|
+
when "textDocument/definition"
|
96
|
+
queue << GotoJob.definition(id: request[:id], params: request[:params])
|
97
|
+
when "textDocument/implementation"
|
98
|
+
queue << GotoJob.implementation(id: request[:id], params: request[:params])
|
99
|
+
when "textDocument/typeDefinition"
|
100
|
+
queue << GotoJob.type_definition(id: request[:id], params: request[:params])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def enqueue_typecheck_jobs(params)
|
105
|
+
guid = params[:guid]
|
106
|
+
|
107
|
+
@current_type_check_guid = guid
|
108
|
+
|
109
|
+
pop_buffer() do |changes|
|
110
|
+
Steep.logger.info { "Enqueueing StartTypeCheckJob for guid=#{guid}" }
|
111
|
+
queue << StartTypeCheckJob.new(guid: guid, changes: changes)
|
112
|
+
end
|
113
|
+
|
114
|
+
targets = project.targets.each.with_object({}) do |target, hash| #$ Hash[String, Project::Target]
|
115
|
+
hash[target.name.to_s] = target
|
116
|
+
end
|
117
|
+
|
118
|
+
priority_paths = Set.new(params[:priority_uris].map {|uri| Steep::PathHelper.to_pathname!(uri) })
|
119
|
+
libraries = params[:library_uris].map {|target_name, uri| [targets.fetch(target_name), Steep::PathHelper.to_pathname!(uri)] } #: Array[[Project::Target, Pathname]]
|
120
|
+
signatures = params[:signature_uris].map {|target_name, uri| [targets.fetch(target_name), Steep::PathHelper.to_pathname!(uri)] } #: Array[[Project::Target, Pathname]]
|
121
|
+
codes = params[:code_uris].map {|target_name, uri| [targets.fetch(target_name), Steep::PathHelper.to_pathname!(uri)] } #: Array[[Project::Target, Pathname]]
|
122
|
+
|
123
|
+
priority_libs, non_priority_libs = libraries.partition {|_, path| priority_paths.include?(path) }
|
124
|
+
priority_sigs, non_priority_sigs = signatures.partition {|_, path| priority_paths.include?(path) }
|
125
|
+
priority_codes, non_priority_codes = codes.partition {|_, path| priority_paths.include?(path) }
|
126
|
+
|
127
|
+
priority_codes.each do |target, path|
|
128
|
+
Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
|
129
|
+
queue << TypeCheckCodeJob.new(guid: guid, path: path, target: target)
|
130
|
+
end
|
131
|
+
|
132
|
+
priority_sigs.each do |target, path|
|
133
|
+
Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
|
134
|
+
queue << ValidateAppSignatureJob.new(guid: guid, path: path, target: target)
|
135
|
+
end
|
136
|
+
|
137
|
+
priority_libs.each do |target, path|
|
138
|
+
Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
|
139
|
+
queue << ValidateLibrarySignatureJob.new(guid: guid, path: path, target: target)
|
140
|
+
end
|
141
|
+
|
142
|
+
non_priority_codes.each do |target, path|
|
143
|
+
Steep.logger.info { "Enqueueing TypeCheckCodeJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
|
144
|
+
queue << TypeCheckCodeJob.new(guid: guid, path: path, target: target)
|
145
|
+
end
|
146
|
+
|
147
|
+
non_priority_sigs.each do |target, path|
|
148
|
+
Steep.logger.info { "Enqueueing ValidateAppSignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
|
149
|
+
queue << ValidateAppSignatureJob.new(guid: guid, path: path, target: target)
|
150
|
+
end
|
151
|
+
|
152
|
+
non_priority_libs.each do |target, path|
|
153
|
+
Steep.logger.info { "Enqueueing ValidateLibrarySignatureJob for guid=#{guid}, path=#{path}, target=#{target.name}" }
|
154
|
+
queue << ValidateLibrarySignatureJob.new(guid: guid, path: path, target: target)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def handle_job(job)
|
159
|
+
case job
|
160
|
+
when StartTypeCheckJob
|
161
|
+
Steep.logger.info { "Processing StartTypeCheckJob for guid=#{job.guid}" }
|
162
|
+
service.update(changes: job.changes)
|
163
|
+
|
164
|
+
when ValidateAppSignatureJob
|
165
|
+
if job.guid == current_type_check_guid
|
166
|
+
Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }
|
167
|
+
|
168
|
+
formatter = Diagnostic::LSPFormatter.new({}, **{})
|
169
|
+
|
170
|
+
diagnostics = service.validate_signature(path: project.relative_path(job.path), target: job.target)
|
171
|
+
|
172
|
+
typecheck_progress(
|
173
|
+
path: job.path,
|
174
|
+
guid: job.guid,
|
175
|
+
target: job.target,
|
176
|
+
diagnostics: diagnostics.filter_map { formatter.format(_1) }
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
when ValidateLibrarySignatureJob
|
181
|
+
if job.guid == current_type_check_guid
|
182
|
+
Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }
|
183
|
+
|
184
|
+
formatter = Diagnostic::LSPFormatter.new({}, **{})
|
185
|
+
diagnostics = service.validate_signature(path: job.path, target: job.target)
|
186
|
+
|
187
|
+
typecheck_progress(path: job.path, guid: job.guid, target: job.target, diagnostics: diagnostics.filter_map { formatter.format(_1) })
|
188
|
+
end
|
189
|
+
|
190
|
+
when TypeCheckCodeJob
|
191
|
+
if job.guid == current_type_check_guid
|
192
|
+
Steep.logger.info { "Processing TypeCheckCodeJob for guid=#{job.guid}, path=#{job.path}, target=#{job.target.name}" }
|
193
|
+
group_target = project.group_for_source_path(job.path) || job.target
|
194
|
+
formatter = Diagnostic::LSPFormatter.new(group_target.code_diagnostics_config)
|
195
|
+
relative_path = project.relative_path(job.path)
|
196
|
+
diagnostics = service.typecheck_source(path: relative_path, target: job.target)
|
197
|
+
typecheck_progress(path: job.path, guid: job.guid, target: job.target, diagnostics: diagnostics&.filter_map { formatter.format(_1) })
|
198
|
+
end
|
199
|
+
|
200
|
+
when WorkspaceSymbolJob
|
201
|
+
writer.write(
|
202
|
+
id: job.id,
|
203
|
+
result: workspace_symbol_result(job.query)
|
204
|
+
)
|
205
|
+
when StatsJob
|
206
|
+
writer.write(
|
207
|
+
id: job.id,
|
208
|
+
result: stats_result().map(&:as_json)
|
209
|
+
)
|
210
|
+
when GotoJob
|
211
|
+
writer.write(
|
212
|
+
id: job.id,
|
213
|
+
result: goto(job)
|
214
|
+
)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def typecheck_progress(guid:, path:, target:, diagnostics:)
|
219
|
+
writer.write(CustomMethods::TypeCheck__Progress.notification({ guid: guid, path: path.to_s, target: target.name.to_s, diagnostics: diagnostics }))
|
220
|
+
end
|
221
|
+
|
222
|
+
def workspace_symbol_result(query)
|
223
|
+
Steep.measure "Generating workspace symbol list for query=`#{query}`" do
|
224
|
+
provider = Index::SignatureSymbolProvider.new(project: project, assignment: assignment)
|
225
|
+
project.targets.each do |target|
|
226
|
+
index = service.signature_services.fetch(target.name).latest_rbs_index
|
227
|
+
provider.indexes[target] = index
|
228
|
+
end
|
229
|
+
|
230
|
+
symbols = provider.query_symbol(query)
|
231
|
+
|
232
|
+
symbols.map do |symbol|
|
233
|
+
LSP::Interface::SymbolInformation.new(
|
234
|
+
name: symbol.name,
|
235
|
+
kind: symbol.kind,
|
236
|
+
location: symbol.location.yield_self do |location|
|
237
|
+
path = Pathname(location.buffer.name)
|
238
|
+
{
|
239
|
+
uri: Steep::PathHelper.to_uri(project.absolute_path(path)),
|
240
|
+
range: {
|
241
|
+
start: { line: location.start_line - 1, character: location.start_column },
|
242
|
+
end: { line: location.end_line - 1, character: location.end_column }
|
243
|
+
}
|
244
|
+
}
|
245
|
+
end,
|
246
|
+
container_name: symbol.container_name
|
247
|
+
)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def stats_result
|
253
|
+
calculator = Services::StatsCalculator.new(service: service)
|
254
|
+
|
255
|
+
project.targets.each.with_object([]) do |target, stats|
|
256
|
+
service.source_files.each_value do |file|
|
257
|
+
next unless target.possible_source_file?(file.path)
|
258
|
+
absolute_path = project.absolute_path(file.path)
|
259
|
+
next unless assignment =~ [target, absolute_path]
|
260
|
+
|
261
|
+
stats << calculator.calc_stats(target, file: file)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def goto(job)
|
267
|
+
path = Steep::PathHelper.to_pathname(job.params[:textDocument][:uri]) or return []
|
268
|
+
line = job.params[:position][:line] + 1
|
269
|
+
column = job.params[:position][:character]
|
270
|
+
|
271
|
+
goto_service = Services::GotoService.new(type_check: service, assignment: assignment)
|
272
|
+
locations =
|
273
|
+
case
|
274
|
+
when job.definition?
|
275
|
+
goto_service.definition(path: path, line: line, column: column)
|
276
|
+
when job.implementation?
|
277
|
+
goto_service.implementation(path: path, line: line, column: column)
|
278
|
+
when job.type_definition?
|
279
|
+
goto_service.type_definition(path: path, line: line, column: column)
|
280
|
+
else
|
281
|
+
raise
|
282
|
+
end
|
283
|
+
|
284
|
+
locations.map do |loc|
|
285
|
+
path =
|
286
|
+
case loc
|
287
|
+
when RBS::Location
|
288
|
+
Pathname(loc.buffer.name)
|
289
|
+
else
|
290
|
+
Pathname(loc.source_buffer.name)
|
291
|
+
end
|
292
|
+
|
293
|
+
path = project.absolute_path(path)
|
294
|
+
|
295
|
+
{
|
296
|
+
uri: Steep::PathHelper.to_uri(path).to_s,
|
297
|
+
range: loc.as_lsp_range
|
298
|
+
}
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Steep
|
2
|
+
module Server
|
3
|
+
class WorkDoneProgress
|
4
|
+
attr_reader :sender, :guid, :percentage
|
5
|
+
|
6
|
+
def initialize(guid, &block)
|
7
|
+
@sender = block
|
8
|
+
@guid = guid
|
9
|
+
@percentage = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def begin(title, message = nil, request_id:)
|
13
|
+
sender.call(
|
14
|
+
{
|
15
|
+
id: request_id,
|
16
|
+
method: "window/workDoneProgress/create",
|
17
|
+
params: { token: guid }
|
18
|
+
}
|
19
|
+
)
|
20
|
+
|
21
|
+
value = { kind: "begin", cancellable: false, title: title, percentage: percentage }
|
22
|
+
value[:message] = message if message
|
23
|
+
|
24
|
+
sender.call(
|
25
|
+
{
|
26
|
+
method: "$/progress",
|
27
|
+
params: { token: guid, value: value }
|
28
|
+
}
|
29
|
+
)
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def report(percentage, message = nil)
|
35
|
+
@percentage = percentage
|
36
|
+
value = { kind: "report", percentage: percentage }
|
37
|
+
value[:message] = message if message
|
38
|
+
|
39
|
+
sender.call(
|
40
|
+
{
|
41
|
+
method: "$/progress",
|
42
|
+
params: { token: guid, value: value }
|
43
|
+
}
|
44
|
+
)
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def end(message = nil)
|
50
|
+
value = { kind: "end" }
|
51
|
+
value[:message] = message if message
|
52
|
+
|
53
|
+
sender.call(
|
54
|
+
{
|
55
|
+
method: "$/progress",
|
56
|
+
params: { token: guid, value: value }
|
57
|
+
}
|
58
|
+
)
|
59
|
+
|
60
|
+
self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module Steep
|
2
|
+
module Server
|
3
|
+
class WorkerProcess
|
4
|
+
attr_reader :reader
|
5
|
+
attr_reader :writer
|
6
|
+
attr_reader :stderr
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :wait_thread
|
10
|
+
attr_reader :index
|
11
|
+
|
12
|
+
def initialize(reader:, writer:, stderr:, wait_thread:, name:, index: nil)
|
13
|
+
@reader = reader
|
14
|
+
@writer = writer
|
15
|
+
@stderr = stderr
|
16
|
+
@wait_thread = wait_thread
|
17
|
+
@name = name
|
18
|
+
@index = index
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.start_worker(type, name:, steepfile:, steep_command:, index: nil, delay_shutdown: false, patterns: [])
|
22
|
+
begin
|
23
|
+
unless steep_command
|
24
|
+
fork_worker(
|
25
|
+
type,
|
26
|
+
name: name,
|
27
|
+
steepfile: steepfile,
|
28
|
+
index: index,
|
29
|
+
delay_shutdown: delay_shutdown,
|
30
|
+
patterns: patterns
|
31
|
+
)
|
32
|
+
else
|
33
|
+
# Use `#spawn_worker`
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
rescue NotImplementedError
|
37
|
+
spawn_worker(
|
38
|
+
type,
|
39
|
+
name: name,
|
40
|
+
steepfile: steepfile,
|
41
|
+
steep_command: steep_command || "steep",
|
42
|
+
index: index,
|
43
|
+
delay_shutdown: delay_shutdown,
|
44
|
+
patterns: patterns
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.fork_worker(type, name:, steepfile:, index:, delay_shutdown:, patterns:)
|
50
|
+
stdin_in, stdin_out = IO.pipe
|
51
|
+
stdout_in, stdout_out = IO.pipe
|
52
|
+
|
53
|
+
worker = Drivers::Worker.new(stdout: stdout_out, stdin: stdin_in, stderr: STDERR)
|
54
|
+
|
55
|
+
worker.steepfile = steepfile
|
56
|
+
worker.worker_type = type
|
57
|
+
worker.worker_name = name
|
58
|
+
worker.delay_shutdown = delay_shutdown
|
59
|
+
if (max, this = index)
|
60
|
+
worker.max_index = max
|
61
|
+
worker.index = this
|
62
|
+
end
|
63
|
+
worker.commandline_args = patterns
|
64
|
+
|
65
|
+
pid = fork do
|
66
|
+
Process.setpgid(0, 0)
|
67
|
+
Steep.ui_logger.level = :fatal
|
68
|
+
stdin_out.close
|
69
|
+
stdout_in.close
|
70
|
+
worker.run()
|
71
|
+
end
|
72
|
+
|
73
|
+
pid or raise
|
74
|
+
|
75
|
+
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin_out)
|
76
|
+
reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout_in)
|
77
|
+
|
78
|
+
# @type var wait_thread: Thread & _ProcessWaitThread
|
79
|
+
wait_thread = _ = Thread.new { Process.waitpid(pid) }
|
80
|
+
wait_thread.define_singleton_method(:pid) { pid }
|
81
|
+
|
82
|
+
stdin_in.close
|
83
|
+
stdout_out.close
|
84
|
+
|
85
|
+
new(
|
86
|
+
reader: reader,
|
87
|
+
writer: writer,
|
88
|
+
stderr: STDERR,
|
89
|
+
wait_thread: wait_thread,
|
90
|
+
name: name,
|
91
|
+
index: index&.[](1)
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.spawn_worker(type, name:, steepfile:, steep_command:, index:, delay_shutdown:, patterns:)
|
96
|
+
args = ["--name=#{name}"]
|
97
|
+
args << "--steepfile=#{steepfile}" if steepfile
|
98
|
+
args << (%w(debug info warn error fatal unknown)[Steep.logger.level].yield_self {|log_level| "--log-level=#{log_level}" })
|
99
|
+
|
100
|
+
if Steep.log_output.is_a?(String)
|
101
|
+
args << "--log-output=#{Steep.log_output}"
|
102
|
+
end
|
103
|
+
|
104
|
+
if (max, this = index)
|
105
|
+
args << "--max-index=#{max}"
|
106
|
+
args << "--index=#{this}"
|
107
|
+
end
|
108
|
+
|
109
|
+
if delay_shutdown
|
110
|
+
args << "--delay-shutdown"
|
111
|
+
end
|
112
|
+
|
113
|
+
command = case type
|
114
|
+
when :interaction
|
115
|
+
[steep_command, "worker", "--interaction", *args, *patterns]
|
116
|
+
when :typecheck
|
117
|
+
[steep_command, "worker", "--typecheck", *args, *patterns]
|
118
|
+
else
|
119
|
+
raise "Unknown type: #{type}"
|
120
|
+
end
|
121
|
+
|
122
|
+
stdin, stdout, thread = if Gem.win_platform?
|
123
|
+
__skip__ = Open3.popen2(*command, new_pgroup: true)
|
124
|
+
else
|
125
|
+
__skip__ = Open3.popen2(*command, pgroup: true)
|
126
|
+
end
|
127
|
+
stderr = nil
|
128
|
+
|
129
|
+
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin)
|
130
|
+
reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout)
|
131
|
+
|
132
|
+
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index&.[](1))
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.start_typecheck_workers(steepfile:, args:, steep_command:, count: [Etc.nprocessors - 1, 1].max || raise, delay_shutdown: false)
|
136
|
+
count.times.map do |i|
|
137
|
+
start_worker(
|
138
|
+
:typecheck,
|
139
|
+
name: "typecheck@#{i}",
|
140
|
+
steepfile: steepfile,
|
141
|
+
steep_command: steep_command,
|
142
|
+
index: [count, i],
|
143
|
+
patterns: args,
|
144
|
+
delay_shutdown: delay_shutdown,
|
145
|
+
)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def <<(message)
|
150
|
+
writer.write(message)
|
151
|
+
end
|
152
|
+
|
153
|
+
def read(&block)
|
154
|
+
reader.read(&block)
|
155
|
+
end
|
156
|
+
|
157
|
+
def kill(force: false)
|
158
|
+
Steep.logger.tagged("WorkerProcess#kill@#{name}(#{wait_thread.pid})") do
|
159
|
+
begin
|
160
|
+
signal = force ? :KILL : :TERM
|
161
|
+
Steep.logger.debug("Sending signal SIG#{signal}...")
|
162
|
+
Process.kill(signal, wait_thread.pid)
|
163
|
+
Steep.logger.debug("Successfully sent the signal.")
|
164
|
+
rescue Errno::ESRCH => error
|
165
|
+
Steep.logger.debug("Failed #{error.inspect}")
|
166
|
+
end
|
167
|
+
unless force
|
168
|
+
Steep.logger.debug("Waiting for process exit...")
|
169
|
+
wait_thread.join()
|
170
|
+
Steep.logger.debug("Confirmed process exit.")
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|