steep 1.8.3 → 1.9.0.dev.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +0 -22
- data/Steepfile +35 -26
- data/bin/rbs-inline +19 -0
- data/lib/steep/cli.rb +38 -5
- data/lib/steep/diagnostic/ruby.rb +11 -58
- data/lib/steep/drivers/annotations.rb +1 -1
- data/lib/steep/drivers/check.rb +103 -1
- data/lib/steep/drivers/checkfile.rb +10 -8
- data/lib/steep/drivers/print_project.rb +83 -40
- data/lib/steep/drivers/utils/driver_helper.rb +39 -6
- data/lib/steep/drivers/watch.rb +24 -2
- data/lib/steep/index/signature_symbol_provider.rb +8 -8
- data/lib/steep/interface/builder.rb +14 -1
- data/lib/steep/interface/function.rb +2 -2
- data/lib/steep/path_helper.rb +4 -2
- data/lib/steep/project/dsl.rb +176 -151
- data/lib/steep/project/group.rb +31 -0
- data/lib/steep/project/pattern.rb +4 -0
- data/lib/steep/project/target.rb +32 -6
- data/lib/steep/project.rb +38 -10
- data/lib/steep/server/custom_methods.rb +16 -0
- data/lib/steep/server/delay_queue.rb +0 -3
- data/lib/steep/server/interaction_worker.rb +2 -11
- data/lib/steep/server/master.rb +129 -279
- 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 +60 -86
- data/lib/steep/services/file_loader.rb +23 -0
- data/lib/steep/services/goto_service.rb +40 -31
- data/lib/steep/services/hover_provider/singleton_methods.rb +4 -4
- data/lib/steep/services/path_assignment.rb +23 -4
- data/lib/steep/services/type_check_service.rb +76 -159
- data/lib/steep/signature/validator.rb +4 -4
- data/lib/steep/subtyping/check.rb +2 -2
- data/lib/steep/thread_waiter.rb +24 -16
- data/lib/steep/type_construction.rb +12 -3
- data/lib/steep/type_inference/block_params.rb +1 -2
- data/lib/steep/type_inference/context.rb +1 -1
- data/lib/steep/type_inference/type_env.rb +4 -4
- data/lib/steep/type_inference/type_env_builder.rb +1 -1
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +6 -4
- data/sample/Steepfile +6 -0
- data/sample/lib/conference.rb +1 -5
- data/steep.gemspec +7 -1
- metadata +9 -6
- data/lib/steep/drivers/validate.rb +0 -65
data/lib/steep/server/master.rb
CHANGED
@@ -3,252 +3,6 @@ module Steep
|
|
3
3
|
class Master
|
4
4
|
LSP = LanguageServer::Protocol
|
5
5
|
|
6
|
-
class TypeCheckRequest
|
7
|
-
attr_reader :guid
|
8
|
-
attr_reader :library_paths
|
9
|
-
attr_reader :signature_paths
|
10
|
-
attr_reader :code_paths
|
11
|
-
attr_reader :priority_paths
|
12
|
-
attr_reader :checked_paths
|
13
|
-
attr_reader :work_done_progress
|
14
|
-
attr_reader :started_at
|
15
|
-
attr_accessor :needs_response
|
16
|
-
|
17
|
-
def initialize(guid:, progress:)
|
18
|
-
@guid = guid
|
19
|
-
@library_paths = Set[]
|
20
|
-
@signature_paths = Set[]
|
21
|
-
@code_paths = Set[]
|
22
|
-
@priority_paths = Set[]
|
23
|
-
@checked_paths = Set[]
|
24
|
-
@work_done_progress = progress
|
25
|
-
@started_at = Time.now
|
26
|
-
@needs_response = false
|
27
|
-
end
|
28
|
-
|
29
|
-
def uri(path)
|
30
|
-
Steep::PathHelper.to_uri(path)
|
31
|
-
end
|
32
|
-
|
33
|
-
def as_json(assignment:)
|
34
|
-
{
|
35
|
-
guid: guid,
|
36
|
-
library_uris: library_paths.grep(assignment).map {|path| uri(path).to_s },
|
37
|
-
signature_uris: signature_paths.grep(assignment).map {|path| uri(path).to_s },
|
38
|
-
code_uris: code_paths.grep(assignment).map {|path| uri(path).to_s },
|
39
|
-
priority_uris: priority_paths.map {|path| uri(path).to_s }
|
40
|
-
}
|
41
|
-
end
|
42
|
-
|
43
|
-
def total
|
44
|
-
library_paths.size + signature_paths.size + code_paths.size
|
45
|
-
end
|
46
|
-
|
47
|
-
def percentage
|
48
|
-
checked_paths.size * 100 / total
|
49
|
-
end
|
50
|
-
|
51
|
-
def all_paths
|
52
|
-
library_paths + signature_paths + code_paths
|
53
|
-
end
|
54
|
-
|
55
|
-
def checking_path?(path)
|
56
|
-
[library_paths, signature_paths, code_paths].any? do |paths|
|
57
|
-
paths.include?(path)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def checked(path)
|
62
|
-
raise unless checking_path?(path)
|
63
|
-
checked_paths << path
|
64
|
-
end
|
65
|
-
|
66
|
-
def finished?
|
67
|
-
total <= checked_paths.size
|
68
|
-
end
|
69
|
-
|
70
|
-
def unchecked_paths
|
71
|
-
all_paths - checked_paths
|
72
|
-
end
|
73
|
-
|
74
|
-
def unchecked_code_paths
|
75
|
-
code_paths - checked_paths
|
76
|
-
end
|
77
|
-
|
78
|
-
def unchecked_library_paths
|
79
|
-
library_paths - checked_paths
|
80
|
-
end
|
81
|
-
|
82
|
-
def unchecked_signature_paths
|
83
|
-
signature_paths - checked_paths
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class TypeCheckController
|
88
|
-
attr_reader :project
|
89
|
-
attr_reader :priority_paths
|
90
|
-
attr_reader :changed_paths
|
91
|
-
attr_reader :target_paths
|
92
|
-
|
93
|
-
class TargetPaths
|
94
|
-
attr_reader :project
|
95
|
-
attr_reader :target
|
96
|
-
attr_reader :code_paths
|
97
|
-
attr_reader :signature_paths
|
98
|
-
attr_reader :library_paths
|
99
|
-
|
100
|
-
def initialize(project:, target:)
|
101
|
-
@project = project
|
102
|
-
@target = target
|
103
|
-
@code_paths = Set[]
|
104
|
-
@signature_paths = Set[]
|
105
|
-
@library_paths = Set[]
|
106
|
-
end
|
107
|
-
|
108
|
-
def all_paths
|
109
|
-
code_paths + signature_paths + library_paths
|
110
|
-
end
|
111
|
-
|
112
|
-
def library_path?(path)
|
113
|
-
library_paths.include?(path)
|
114
|
-
end
|
115
|
-
|
116
|
-
def signature_path?(path)
|
117
|
-
signature_paths.include?(path)
|
118
|
-
end
|
119
|
-
|
120
|
-
def code_path?(path)
|
121
|
-
code_paths.include?(path)
|
122
|
-
end
|
123
|
-
|
124
|
-
def add(path, library: false)
|
125
|
-
return true if signature_path?(path) || code_path?(path) || library_path?(path)
|
126
|
-
|
127
|
-
if library
|
128
|
-
library_paths << path
|
129
|
-
true
|
130
|
-
else
|
131
|
-
relative_path = project.relative_path(path)
|
132
|
-
|
133
|
-
case
|
134
|
-
when target.source_pattern =~ relative_path
|
135
|
-
code_paths << path
|
136
|
-
true
|
137
|
-
when target.signature_pattern =~ relative_path
|
138
|
-
signature_paths << path
|
139
|
-
true
|
140
|
-
else
|
141
|
-
false
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
alias << add
|
147
|
-
end
|
148
|
-
|
149
|
-
def initialize(project:)
|
150
|
-
@project = project
|
151
|
-
@priority_paths = Set[]
|
152
|
-
@changed_paths = Set[]
|
153
|
-
@target_paths = project.targets.each.map {|target| TargetPaths.new(project: project, target: target) }
|
154
|
-
end
|
155
|
-
|
156
|
-
def load(command_line_args:)
|
157
|
-
loader = Services::FileLoader.new(base_dir: project.base_dir)
|
158
|
-
|
159
|
-
files = {} #: Hash[String, String]
|
160
|
-
|
161
|
-
target_paths.each do |paths|
|
162
|
-
target = paths.target
|
163
|
-
|
164
|
-
signature_service = Services::SignatureService.load_from(target.new_env_loader(project: project))
|
165
|
-
paths.library_paths.merge(signature_service.env_rbs_paths)
|
166
|
-
|
167
|
-
loader.each_path_in_patterns(target.source_pattern, command_line_args) do |path|
|
168
|
-
paths.code_paths << project.absolute_path(path)
|
169
|
-
files[path.to_s] = project.absolute_path(path).read
|
170
|
-
if files.size > 1000
|
171
|
-
yield files.dup
|
172
|
-
files.clear
|
173
|
-
end
|
174
|
-
end
|
175
|
-
loader.each_path_in_patterns(target.signature_pattern) do |path|
|
176
|
-
paths.signature_paths << project.absolute_path(path)
|
177
|
-
files[path.to_s] = project.absolute_path(path).read
|
178
|
-
if files.size > 1000
|
179
|
-
yield files.dup
|
180
|
-
files.clear
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
changed_paths.merge(paths.all_paths)
|
185
|
-
end
|
186
|
-
|
187
|
-
yield files.dup unless files.empty?
|
188
|
-
end
|
189
|
-
|
190
|
-
def push_changes(path)
|
191
|
-
return if target_paths.any? {|paths| paths.library_path?(path) }
|
192
|
-
|
193
|
-
target_paths.each {|paths| paths << path }
|
194
|
-
|
195
|
-
if target_paths.any? {|paths| paths.code_path?(path) || paths.signature_path?(path) }
|
196
|
-
changed_paths << path
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def update_priority(open: nil, close: nil)
|
201
|
-
path = open || close
|
202
|
-
path or raise
|
203
|
-
|
204
|
-
target_paths.each {|paths| paths << path }
|
205
|
-
|
206
|
-
case
|
207
|
-
when open
|
208
|
-
priority_paths << path
|
209
|
-
when close
|
210
|
-
priority_paths.delete path
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
def make_request(guid: SecureRandom.uuid, last_request: nil, include_unchanged: false, progress:)
|
215
|
-
return if changed_paths.empty? && !include_unchanged
|
216
|
-
|
217
|
-
TypeCheckRequest.new(guid: guid, progress: progress).tap do |request|
|
218
|
-
if last_request
|
219
|
-
request.library_paths.merge(last_request.unchecked_library_paths)
|
220
|
-
request.signature_paths.merge(last_request.unchecked_signature_paths)
|
221
|
-
request.code_paths.merge(last_request.unchecked_code_paths)
|
222
|
-
end
|
223
|
-
|
224
|
-
if include_unchanged
|
225
|
-
target_paths.each do |paths|
|
226
|
-
request.signature_paths.merge(paths.signature_paths)
|
227
|
-
request.library_paths.merge(paths.library_paths)
|
228
|
-
request.code_paths.merge(paths.code_paths)
|
229
|
-
end
|
230
|
-
else
|
231
|
-
updated_paths = target_paths.select {|paths| changed_paths.intersect?(paths.all_paths) }
|
232
|
-
|
233
|
-
updated_paths.each do |paths|
|
234
|
-
case
|
235
|
-
when paths.signature_paths.intersect?(changed_paths)
|
236
|
-
request.signature_paths.merge(paths.signature_paths)
|
237
|
-
request.library_paths.merge(paths.library_paths)
|
238
|
-
request.code_paths.merge(paths.code_paths)
|
239
|
-
when paths.code_paths.intersect?(changed_paths)
|
240
|
-
request.code_paths.merge(paths.code_paths & changed_paths)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
request.priority_paths.merge(priority_paths)
|
246
|
-
|
247
|
-
changed_paths.clear()
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
6
|
class ResultHandler
|
253
7
|
attr_reader :request
|
254
8
|
attr_reader :completion_handler
|
@@ -424,6 +178,7 @@ module Steep
|
|
424
178
|
attr_reader :job_queue, :write_queue
|
425
179
|
|
426
180
|
attr_reader :current_type_check_request
|
181
|
+
attr_reader :current_diagnostics
|
427
182
|
attr_reader :controller
|
428
183
|
attr_reader :result_controller
|
429
184
|
|
@@ -442,6 +197,7 @@ module Steep
|
|
442
197
|
@commandline_args = []
|
443
198
|
@job_queue = queue
|
444
199
|
@write_queue = SizedQueue.new(100)
|
200
|
+
@current_diagnostics = {}
|
445
201
|
|
446
202
|
@controller = TypeCheckController.new(project: project)
|
447
203
|
@result_controller = ResultController.new()
|
@@ -533,7 +289,10 @@ module Steep
|
|
533
289
|
end
|
534
290
|
end
|
535
291
|
|
536
|
-
waiter = ThreadWaiter.new
|
292
|
+
waiter = ThreadWaiter.new
|
293
|
+
each_worker do |worker|
|
294
|
+
waiter << worker.wait_thread
|
295
|
+
end
|
537
296
|
waiter.wait_one()
|
538
297
|
|
539
298
|
unless job_queue.closed?
|
@@ -623,7 +382,11 @@ module Steep
|
|
623
382
|
declaration_provider: false,
|
624
383
|
implementation_provider: true,
|
625
384
|
type_definition_provider: true
|
626
|
-
)
|
385
|
+
),
|
386
|
+
server_info: {
|
387
|
+
name: "steep",
|
388
|
+
version: VERSION
|
389
|
+
}
|
627
390
|
)
|
628
391
|
}
|
629
392
|
)
|
@@ -647,6 +410,10 @@ module Steep
|
|
647
410
|
end
|
648
411
|
end
|
649
412
|
|
413
|
+
if typecheck_automatically
|
414
|
+
progress.end()
|
415
|
+
end
|
416
|
+
|
650
417
|
if file_system_watcher_supported?
|
651
418
|
patterns = [] #: Array[String]
|
652
419
|
project.targets.each do |target|
|
@@ -693,11 +460,13 @@ module Steep
|
|
693
460
|
)
|
694
461
|
end
|
695
462
|
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
463
|
+
controller.changed_paths.clear()
|
464
|
+
|
465
|
+
# if typecheck_automatically
|
466
|
+
# if request = controller.make_request(guid: progress.guid, include_unchanged: true, progress: progress)
|
467
|
+
# start_type_check(request: request, last_request: nil)
|
468
|
+
# end
|
469
|
+
# end
|
701
470
|
end
|
702
471
|
end
|
703
472
|
|
@@ -742,7 +511,6 @@ module Steep
|
|
742
511
|
|
743
512
|
start_type_check(
|
744
513
|
last_request: last_request,
|
745
|
-
include_unchanged: true,
|
746
514
|
progress: work_done_progress(guid),
|
747
515
|
needs_response: false
|
748
516
|
)
|
@@ -781,8 +549,15 @@ module Steep
|
|
781
549
|
text = message[:params][:textDocument][:text]
|
782
550
|
|
783
551
|
if path = pathname(uri)
|
784
|
-
|
785
|
-
|
552
|
+
if target = project.group_for_path(path)
|
553
|
+
controller.update_priority(open: path)
|
554
|
+
# broadcast_notification(CustomMethods::FileReset.notification({ uri: uri, content: text }))
|
555
|
+
|
556
|
+
start_type_checking_queue.execute do
|
557
|
+
guid = SecureRandom.uuid
|
558
|
+
start_type_check(last_request: current_type_check_request, progress: work_done_progress(guid), needs_response: true)
|
559
|
+
end
|
560
|
+
end
|
786
561
|
end
|
787
562
|
|
788
563
|
when "textDocument/didClose"
|
@@ -821,6 +596,7 @@ module Steep
|
|
821
596
|
|
822
597
|
group.on_completion do |handlers|
|
823
598
|
result = handlers.flat_map(&:result)
|
599
|
+
result.uniq!
|
824
600
|
enqueue_write_job SendMessageJob.to_client(message: { id: message[:id], result: result })
|
825
601
|
end
|
826
602
|
end
|
@@ -848,6 +624,7 @@ module Steep
|
|
848
624
|
|
849
625
|
group.on_completion do |handlers|
|
850
626
|
links = handlers.flat_map(&:result)
|
627
|
+
links.uniq!
|
851
628
|
enqueue_write_job SendMessageJob.to_client(
|
852
629
|
message: {
|
853
630
|
id: message[:id],
|
@@ -866,15 +643,35 @@ module Steep
|
|
866
643
|
end
|
867
644
|
|
868
645
|
when CustomMethods::TypeCheck::METHOD
|
646
|
+
id = message[:id]
|
869
647
|
params = message[:params] #: CustomMethods::TypeCheck::params
|
870
|
-
guid = params[:guid]
|
871
648
|
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
649
|
+
request = TypeCheckController::Request.new(guid: id, progress: work_done_progress(id))
|
650
|
+
request.needs_response = true
|
651
|
+
|
652
|
+
params[:code_paths].each do |target_name, path|
|
653
|
+
request.code_paths << [target_name.to_sym, Pathname(path)]
|
654
|
+
end
|
655
|
+
params[:signature_paths].each do |target_name, path|
|
656
|
+
request.signature_paths << [target_name.to_sym, Pathname(path)]
|
657
|
+
end
|
658
|
+
params[:library_paths].each do |target_name, path|
|
659
|
+
request.library_paths << [target_name.to_sym, Pathname(path)]
|
660
|
+
end
|
661
|
+
|
662
|
+
start_type_check(request: request, last_request: nil)
|
663
|
+
|
664
|
+
when CustomMethods::TypeCheckGroups::METHOD
|
665
|
+
params = message[:params] #: CustomMethods::TypeCheckGroups::params
|
666
|
+
|
667
|
+
groups = params.fetch(:groups)
|
668
|
+
|
669
|
+
progress = work_done_progress(SecureRandom.uuid)
|
670
|
+
progress.begin("Type checking #{groups.empty? ? "project" : groups.join(", ")}", request_id: fresh_request_id)
|
671
|
+
|
672
|
+
request = controller.make_group_request(groups, progress: progress)
|
673
|
+
request.needs_response = false
|
674
|
+
start_type_check(request: request, last_request: current_type_check_request, report_progress_threshold: 0)
|
878
675
|
|
879
676
|
when "$/ping"
|
880
677
|
enqueue_write_job SendMessageJob.to_client(
|
@@ -884,6 +681,25 @@ module Steep
|
|
884
681
|
}
|
885
682
|
)
|
886
683
|
|
684
|
+
when CustomMethods::Groups::METHOD
|
685
|
+
groups = [] #: Array[String]
|
686
|
+
|
687
|
+
project.targets.each do |target|
|
688
|
+
unless target.source_pattern.empty? && target.signature_pattern.empty?
|
689
|
+
groups << target.name.to_s
|
690
|
+
end
|
691
|
+
|
692
|
+
target.groups.each do |group|
|
693
|
+
unless group.source_pattern.empty? && group.signature_pattern.empty?
|
694
|
+
groups << "#{target.name}.#{group.name}"
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
enqueue_write_job(SendMessageJob.to_client(
|
700
|
+
message: CustomMethods::Groups.response(message[:id], groups)
|
701
|
+
))
|
702
|
+
|
887
703
|
when "shutdown"
|
888
704
|
start_type_checking_queue.cancel
|
889
705
|
|
@@ -916,9 +732,12 @@ module Steep
|
|
916
732
|
case message[:method]
|
917
733
|
when CustomMethods::TypeCheck__Progress::METHOD
|
918
734
|
params = message[:params] #: CustomMethods::TypeCheck__Progress::params
|
735
|
+
target = project.targets.find {|target| target.name.to_s == params[:target] } or raise
|
919
736
|
on_type_check_update(
|
920
737
|
guid: params[:guid],
|
921
|
-
path: Pathname(params[:path])
|
738
|
+
path: Pathname(params[:path]),
|
739
|
+
target: target,
|
740
|
+
diagnostics: params[:diagnostics]
|
922
741
|
)
|
923
742
|
else
|
924
743
|
# Forward other notifications
|
@@ -966,23 +785,35 @@ module Steep
|
|
966
785
|
request.needs_response = needs_response ? true : false
|
967
786
|
end
|
968
787
|
|
788
|
+
if last_request
|
789
|
+
request.merge!(last_request)
|
790
|
+
end
|
791
|
+
|
969
792
|
if request.total > report_progress_threshold
|
970
|
-
|
793
|
+
request.report_progress!
|
794
|
+
end
|
971
795
|
|
972
|
-
|
796
|
+
if request.each_unchecked_target_path.to_a.empty?
|
797
|
+
finish_type_check(request)
|
798
|
+
@current_type_check_request = nil
|
799
|
+
return
|
800
|
+
end
|
973
801
|
|
974
|
-
|
975
|
-
# If `request:` keyword arg is not given
|
976
|
-
request.work_done_progress.begin("Type checking", request_id: fresh_request_id)
|
977
|
-
end
|
802
|
+
Steep.logger.info "Starting new progress..."
|
978
803
|
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
804
|
+
@current_type_check_request = request
|
805
|
+
if last_request
|
806
|
+
checking_paths = request.each_path.to_set
|
807
|
+
current_diagnostics.keep_if do |path, _|
|
808
|
+
checking_paths.include?(path)
|
983
809
|
end
|
984
810
|
else
|
985
|
-
|
811
|
+
current_diagnostics.clear
|
812
|
+
end
|
813
|
+
|
814
|
+
if progress
|
815
|
+
# If `request:` keyword arg is not given
|
816
|
+
request.work_done_progress.begin("Type checking", request_id: fresh_request_id)
|
986
817
|
end
|
987
818
|
|
988
819
|
Steep.logger.info "Sending $/typecheck/start notifications"
|
@@ -1000,14 +831,17 @@ module Steep
|
|
1000
831
|
end
|
1001
832
|
end
|
1002
833
|
|
1003
|
-
def on_type_check_update(guid:, path:)
|
834
|
+
def on_type_check_update(guid:, path:, target:, diagnostics:)
|
1004
835
|
if current = current_type_check_request()
|
1005
836
|
if current.guid == guid
|
1006
|
-
current.checked(path)
|
1007
|
-
|
837
|
+
current.checked(path, target)
|
838
|
+
|
839
|
+
Steep.logger.info { "Request updated: checked=#{path}, unchecked=#{current.each_unchecked_code_target_path.size}, diagnostics=#{diagnostics&.size}" }
|
1008
840
|
|
1009
841
|
percentage = current.percentage
|
1010
|
-
current.work_done_progress.report(percentage, "#{
|
842
|
+
current.work_done_progress.report(percentage, "#{current.checked_paths.size}/#{current.total}") if current.report_progress
|
843
|
+
|
844
|
+
push_diagnostics(path, diagnostics)
|
1011
845
|
|
1012
846
|
if current.finished?
|
1013
847
|
finish_type_check(current)
|
@@ -1072,6 +906,22 @@ module Steep
|
|
1072
906
|
end
|
1073
907
|
end
|
1074
908
|
end
|
909
|
+
|
910
|
+
def push_diagnostics(path, diagnostics)
|
911
|
+
if diagnostics
|
912
|
+
ds = (current_diagnostics[path] ||= [])
|
913
|
+
|
914
|
+
ds.concat(diagnostics)
|
915
|
+
ds.uniq!
|
916
|
+
|
917
|
+
write_queue.push SendMessageJob.to_client(
|
918
|
+
message: {
|
919
|
+
method: :"textDocument/publishDiagnostics",
|
920
|
+
params: { uri: Steep::PathHelper.to_uri(path).to_s, diagnostics: ds }
|
921
|
+
}
|
922
|
+
)
|
923
|
+
end
|
924
|
+
end
|
1075
925
|
end
|
1076
926
|
end
|
1077
927
|
end
|