solargraph 0.53.4 → 0.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/lib/solargraph/api_map/cache.rb +2 -12
- data/lib/solargraph/api_map/store.rb +14 -5
- data/lib/solargraph/api_map.rb +67 -24
- data/lib/solargraph/complex_type/type_methods.rb +70 -39
- data/lib/solargraph/complex_type/unique_type.rb +187 -73
- data/lib/solargraph/complex_type.rb +105 -40
- data/lib/solargraph/doc_map.rb +19 -3
- data/lib/solargraph/gem_pins.rb +9 -1
- data/lib/solargraph/language_server/host/dispatch.rb +8 -1
- data/lib/solargraph/language_server/host/message_worker.rb +29 -3
- data/lib/solargraph/language_server/host/sources.rb +1 -61
- data/lib/solargraph/language_server/host.rb +21 -68
- data/lib/solargraph/language_server/message/base.rb +1 -1
- data/lib/solargraph/language_server/message/initialize.rb +14 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +135 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +144 -113
- data/lib/solargraph/location.rb +14 -1
- data/lib/solargraph/parser/node_processor/base.rb +3 -2
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -7
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -5
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +6 -4
- data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
- data/lib/solargraph/parser.rb +2 -5
- data/lib/solargraph/pin/base.rb +15 -1
- data/lib/solargraph/pin/base_variable.rb +35 -6
- data/lib/solargraph/pin/block.rb +48 -11
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +8 -3
- data/lib/solargraph/pin/common.rb +2 -6
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/delegated_method.rb +5 -1
- data/lib/solargraph/pin/documenting.rb +2 -0
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/method.rb +54 -32
- data/lib/solargraph/pin/namespace.rb +4 -4
- data/lib/solargraph/pin/parameter.rb +14 -39
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin/signature.rb +3 -129
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/range.rb +2 -4
- data/lib/solargraph/rbs_map/conversions.rb +79 -42
- data/lib/solargraph/rbs_map/core_fills.rb +6 -6
- data/lib/solargraph/rbs_map.rb +11 -3
- data/lib/solargraph/shell.rb +35 -15
- data/lib/solargraph/source/chain/array.rb +6 -5
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +78 -50
- data/lib/solargraph/source/chain/link.rb +9 -0
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +60 -16
- data/lib/solargraph/source/cursor.rb +13 -2
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +102 -129
- data/lib/solargraph/source_map/clip.rb +4 -4
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map/mapper.rb +3 -2
- data/lib/solargraph/source_map.rb +37 -15
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +50 -25
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +2 -1
- data/lib/solargraph/workspace.rb +13 -0
- metadata +6 -3
- data/lib/solargraph/language_server/host/cataloger.rb +0 -57
data/lib/solargraph/library.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
+
require 'observer'
|
4
5
|
|
5
6
|
module Solargraph
|
6
7
|
# A Library handles coordination between a Workspace and an ApiMap.
|
7
8
|
#
|
8
9
|
class Library
|
9
10
|
include Logging
|
11
|
+
include Observable
|
10
12
|
|
11
13
|
# @return [Solargraph::Workspace]
|
12
14
|
attr_reader :workspace
|
@@ -17,12 +19,19 @@ module Solargraph
|
|
17
19
|
# @return [Source, nil]
|
18
20
|
attr_reader :current
|
19
21
|
|
22
|
+
# @return [LanguageServer::Progress, nil]
|
23
|
+
attr_reader :cache_progress
|
24
|
+
|
20
25
|
# @param workspace [Solargraph::Workspace]
|
21
26
|
# @param name [String, nil]
|
22
27
|
def initialize workspace = Solargraph::Workspace.new, name = nil
|
23
28
|
@workspace = workspace
|
24
29
|
@name = name
|
25
|
-
@
|
30
|
+
# @type [Integer, nil]
|
31
|
+
@total = nil
|
32
|
+
# @type [Source, nil]
|
33
|
+
@current = nil
|
34
|
+
@sync_count = 0
|
26
35
|
end
|
27
36
|
|
28
37
|
def inspect
|
@@ -35,7 +44,7 @@ module Solargraph
|
|
35
44
|
#
|
36
45
|
# @return [Boolean]
|
37
46
|
def synchronized?
|
38
|
-
@
|
47
|
+
@sync_count < 2
|
39
48
|
end
|
40
49
|
|
41
50
|
# Attach a source to the library.
|
@@ -47,17 +56,15 @@ module Solargraph
|
|
47
56
|
# @param source [Source, nil]
|
48
57
|
# @return [void]
|
49
58
|
def attach source
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@external_requires = nil
|
55
|
-
@synchronized = false
|
56
|
-
end
|
57
|
-
@current = source
|
58
|
-
maybe_map @current
|
59
|
-
catalog_inlock
|
59
|
+
if @current && (!source || @current.filename != source.filename) && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
|
60
|
+
source_map_hash.delete @current.filename
|
61
|
+
source_map_external_require_hash.delete @current.filename
|
62
|
+
@external_requires = nil
|
60
63
|
end
|
64
|
+
changed = source && @current != source
|
65
|
+
@current = source
|
66
|
+
maybe_map @current
|
67
|
+
catalog if changed
|
61
68
|
end
|
62
69
|
|
63
70
|
# True if the specified file is currently attached.
|
@@ -95,15 +102,10 @@ module Solargraph
|
|
95
102
|
# @param text [String] The contents of the file
|
96
103
|
# @return [Boolean] True if the file was added to the workspace.
|
97
104
|
def create filename, text
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
source = Solargraph::Source.load_string(text, filename)
|
103
|
-
workspace.merge(source)
|
104
|
-
result = true
|
105
|
-
end
|
106
|
-
result
|
105
|
+
return false unless contain?(filename) || open?(filename)
|
106
|
+
source = Solargraph::Source.load_string(text, filename)
|
107
|
+
workspace.merge(source)
|
108
|
+
true
|
107
109
|
end
|
108
110
|
|
109
111
|
# Create file sources from files on disk. A file is ignored if it is
|
@@ -112,14 +114,11 @@ module Solargraph
|
|
112
114
|
# @param filenames [Array<String>]
|
113
115
|
# @return [Boolean] True if at least one file was added to the workspace.
|
114
116
|
def create_from_disk *filenames
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
result = workspace.merge(*sources)
|
121
|
-
sources.each { |source| maybe_map source }
|
122
|
-
end
|
117
|
+
sources = filenames
|
118
|
+
.reject { |filename| File.directory?(filename) || !File.exist?(filename) }
|
119
|
+
.map { |filename| Solargraph::Source.load_string(File.read(filename), filename) }
|
120
|
+
result = workspace.merge(*sources)
|
121
|
+
sources.each { |source| maybe_map source }
|
123
122
|
result
|
124
123
|
end
|
125
124
|
|
@@ -133,10 +132,7 @@ module Solargraph
|
|
133
132
|
result = false
|
134
133
|
filenames.each do |filename|
|
135
134
|
detach filename
|
136
|
-
|
137
|
-
result ||= workspace.remove(filename)
|
138
|
-
@synchronized = !result if synchronized?
|
139
|
-
end
|
135
|
+
result ||= workspace.remove(filename)
|
140
136
|
end
|
141
137
|
result
|
142
138
|
end
|
@@ -147,11 +143,10 @@ module Solargraph
|
|
147
143
|
# @param filename [String]
|
148
144
|
# @return [void]
|
149
145
|
def close filename
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
end
|
146
|
+
return unless @current&.filename == filename
|
147
|
+
|
148
|
+
@current = nil
|
149
|
+
catalog unless workspace.has_file?(filename)
|
155
150
|
end
|
156
151
|
|
157
152
|
# Get completion suggestions at the specified file and location.
|
@@ -162,9 +157,10 @@ module Solargraph
|
|
162
157
|
# @return [SourceMap::Completion, nil]
|
163
158
|
# @todo Take a Location instead of filename/line/column
|
164
159
|
def completions_at filename, line, column
|
160
|
+
sync_catalog
|
165
161
|
position = Position.new(line, column)
|
166
162
|
cursor = Source::Cursor.new(read(filename), position)
|
167
|
-
api_map.clip(cursor).complete
|
163
|
+
mutex.synchronize { api_map.clip(cursor).complete }
|
168
164
|
rescue FileNotFoundError => e
|
169
165
|
handle_file_not_found filename, e
|
170
166
|
end
|
@@ -178,6 +174,7 @@ module Solargraph
|
|
178
174
|
# @return [Array<Solargraph::Pin::Base>, nil]
|
179
175
|
# @todo Take filename/position instead of filename/line/column
|
180
176
|
def definitions_at filename, line, column
|
177
|
+
sync_catalog
|
181
178
|
position = Position.new(line, column)
|
182
179
|
cursor = Source::Cursor.new(read(filename), position)
|
183
180
|
if cursor.comment?
|
@@ -187,13 +184,20 @@ module Solargraph
|
|
187
184
|
rgt = source.code[offset..-1].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
|
188
185
|
if lft && rgt
|
189
186
|
tag = (lft[1] + rgt[1]).sub(/:+$/, '')
|
190
|
-
clip = api_map.clip(cursor)
|
187
|
+
clip = mutex.synchronize { api_map.clip(cursor) }
|
191
188
|
clip.translate tag
|
192
189
|
else
|
193
190
|
[]
|
194
191
|
end
|
195
192
|
else
|
196
|
-
|
193
|
+
mutex.synchronize do
|
194
|
+
clip = api_map.clip(cursor)
|
195
|
+
if cursor.assign?
|
196
|
+
[Pin::ProxyType.new(name: cursor.word, return_type: clip.infer)]
|
197
|
+
else
|
198
|
+
clip.define.map { |pin| pin.realize(api_map) }
|
199
|
+
end
|
200
|
+
end
|
197
201
|
end
|
198
202
|
rescue FileNotFoundError => e
|
199
203
|
handle_file_not_found(filename, e)
|
@@ -208,9 +212,10 @@ module Solargraph
|
|
208
212
|
# @return [Array<Solargraph::Pin::Base>, nil]
|
209
213
|
# @todo Take filename/position instead of filename/line/column
|
210
214
|
def type_definitions_at filename, line, column
|
215
|
+
sync_catalog
|
211
216
|
position = Position.new(line, column)
|
212
217
|
cursor = Source::Cursor.new(read(filename), position)
|
213
|
-
api_map.clip(cursor).types
|
218
|
+
mutex.synchronize { api_map.clip(cursor).types }
|
214
219
|
rescue FileNotFoundError => e
|
215
220
|
handle_file_not_found filename, e
|
216
221
|
end
|
@@ -224,9 +229,10 @@ module Solargraph
|
|
224
229
|
# @return [Array<Solargraph::Pin::Base>]
|
225
230
|
# @todo Take filename/position instead of filename/line/column
|
226
231
|
def signatures_at filename, line, column
|
232
|
+
sync_catalog
|
227
233
|
position = Position.new(line, column)
|
228
234
|
cursor = Source::Cursor.new(read(filename), position)
|
229
|
-
api_map.clip(cursor).signify
|
235
|
+
mutex.synchronize { api_map.clip(cursor).signify }
|
230
236
|
end
|
231
237
|
|
232
238
|
# @param filename [String]
|
@@ -237,8 +243,9 @@ module Solargraph
|
|
237
243
|
# @return [Array<Solargraph::Range>]
|
238
244
|
# @todo Take a Location instead of filename/line/column
|
239
245
|
def references_from filename, line, column, strip: false, only: false
|
240
|
-
|
241
|
-
|
246
|
+
sync_catalog
|
247
|
+
cursor = Source::Cursor.new(read(filename), [line, column])
|
248
|
+
clip = mutex.synchronize { api_map.clip(cursor) }
|
242
249
|
pin = clip.define.first
|
243
250
|
return [] unless pin
|
244
251
|
result = []
|
@@ -283,7 +290,8 @@ module Solargraph
|
|
283
290
|
# @param location [Location]
|
284
291
|
# @return [Array<Solargraph::Pin::Base>]
|
285
292
|
def locate_pins location
|
286
|
-
|
293
|
+
sync_catalog
|
294
|
+
mutex.synchronize { api_map.locate_pins(location).map { |pin| pin.realize(api_map) } }
|
287
295
|
end
|
288
296
|
|
289
297
|
# Match a require reference to a file.
|
@@ -316,19 +324,22 @@ module Solargraph
|
|
316
324
|
# @param path [String]
|
317
325
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
318
326
|
def get_path_pins path
|
319
|
-
|
327
|
+
sync_catalog
|
328
|
+
mutex.synchronize { api_map.get_path_suggestions(path) }
|
320
329
|
end
|
321
330
|
|
322
331
|
# @param query [String]
|
323
332
|
# @return [Enumerable<YARD::CodeObjects::Base>]
|
324
333
|
def document query
|
325
|
-
|
334
|
+
sync_catalog
|
335
|
+
mutex.synchronize { api_map.document query }
|
326
336
|
end
|
327
337
|
|
328
338
|
# @param query [String]
|
329
339
|
# @return [Array<String>]
|
330
340
|
def search query
|
331
|
-
|
341
|
+
sync_catalog
|
342
|
+
mutex.synchronize { api_map.search query }
|
332
343
|
end
|
333
344
|
|
334
345
|
# Get an array of all symbols in the workspace that match the query.
|
@@ -336,7 +347,8 @@ module Solargraph
|
|
336
347
|
# @param query [String]
|
337
348
|
# @return [Array<Pin::Base>]
|
338
349
|
def query_symbols query
|
339
|
-
|
350
|
+
sync_catalog
|
351
|
+
mutex.synchronize { api_map.query_symbols query }
|
340
352
|
end
|
341
353
|
|
342
354
|
# Get an array of document symbols.
|
@@ -348,13 +360,15 @@ module Solargraph
|
|
348
360
|
# @param filename [String]
|
349
361
|
# @return [Array<Solargraph::Pin::Base>]
|
350
362
|
def document_symbols filename
|
351
|
-
|
363
|
+
sync_catalog
|
364
|
+
mutex.synchronize { api_map.document_symbols(filename) }
|
352
365
|
end
|
353
366
|
|
354
367
|
# @param path [String]
|
355
368
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
356
369
|
def path_pins path
|
357
|
-
|
370
|
+
sync_catalog
|
371
|
+
mutex.synchronize { api_map.get_path_suggestions(path) }
|
358
372
|
end
|
359
373
|
|
360
374
|
# @return [Array<SourceMap>]
|
@@ -380,10 +394,10 @@ module Solargraph
|
|
380
394
|
# everything in the workspace should get diagnosed, or if there should
|
381
395
|
# be an option to do so.
|
382
396
|
#
|
397
|
+
sync_catalog
|
383
398
|
return [] unless open?(filename)
|
384
399
|
result = []
|
385
400
|
source = read(filename)
|
386
|
-
catalog
|
387
401
|
repargs = {}
|
388
402
|
workspace.config.reporters.each do |line|
|
389
403
|
if line == 'all!'
|
@@ -409,21 +423,7 @@ module Solargraph
|
|
409
423
|
#
|
410
424
|
# @return [void]
|
411
425
|
def catalog
|
412
|
-
|
413
|
-
catalog_inlock
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
# @return [void]
|
418
|
-
private def catalog_inlock
|
419
|
-
return if synchronized?
|
420
|
-
|
421
|
-
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
422
|
-
api_map.catalog bench
|
423
|
-
@synchronized = true
|
424
|
-
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
425
|
-
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
426
|
-
cache_next_gemspec
|
426
|
+
@sync_count += 1
|
427
427
|
end
|
428
428
|
|
429
429
|
# @return [Bench]
|
@@ -461,13 +461,8 @@ module Solargraph
|
|
461
461
|
# @param source [Source]
|
462
462
|
# @return [Boolean] True if the source was merged into the workspace.
|
463
463
|
def merge source
|
464
|
-
|
465
|
-
|
466
|
-
mutex.synchronize do
|
467
|
-
result = workspace.merge(source)
|
468
|
-
maybe_map source
|
469
|
-
end
|
470
|
-
# catalog
|
464
|
+
result = workspace.merge(source)
|
465
|
+
maybe_map source
|
471
466
|
result
|
472
467
|
end
|
473
468
|
|
@@ -483,17 +478,13 @@ module Solargraph
|
|
483
478
|
# @return [SourceMap, Boolean]
|
484
479
|
def next_map
|
485
480
|
return false if mapped?
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
source_map_hash[src.filename]
|
494
|
-
else
|
495
|
-
false
|
496
|
-
end
|
481
|
+
src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
|
482
|
+
if src
|
483
|
+
Logging.logger.debug "Mapping #{src.filename}"
|
484
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
485
|
+
source_map_hash[src.filename]
|
486
|
+
else
|
487
|
+
false
|
497
488
|
end
|
498
489
|
end
|
499
490
|
|
@@ -501,7 +492,7 @@ module Solargraph
|
|
501
492
|
def map!
|
502
493
|
workspace.sources.each do |src|
|
503
494
|
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
504
|
-
find_external_requires
|
495
|
+
find_external_requires source_map_hash[src.filename]
|
505
496
|
end
|
506
497
|
self
|
507
498
|
end
|
@@ -575,30 +566,16 @@ module Solargraph
|
|
575
566
|
end
|
576
567
|
end
|
577
568
|
|
578
|
-
# @param source [Source]
|
569
|
+
# @param source [Source, nil]
|
579
570
|
# @return [void]
|
580
571
|
def maybe_map source
|
581
572
|
return unless source
|
582
573
|
return unless @current == source || workspace.has_file?(source.filename)
|
583
574
|
if source_map_hash.key?(source.filename)
|
584
|
-
|
585
|
-
|
586
|
-
source.synchronized?
|
587
|
-
if source.synchronized?
|
588
|
-
new_map = Solargraph::SourceMap.map(source)
|
589
|
-
unless source_map_hash[source.filename].try_merge!(new_map)
|
590
|
-
source_map_hash[source.filename] = new_map
|
591
|
-
find_external_requires(source_map_hash[source.filename])
|
592
|
-
@synchronized = false
|
593
|
-
end
|
594
|
-
else
|
595
|
-
# @todo Smelly instance variable access
|
596
|
-
source_map_hash[source.filename].instance_variable_set(:@source, source)
|
597
|
-
end
|
575
|
+
new_map = Solargraph::SourceMap.map(source)
|
576
|
+
source_map_hash[source.filename] = new_map
|
598
577
|
else
|
599
578
|
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
600
|
-
find_external_requires(source_map_hash[source.filename])
|
601
|
-
@synchronized = false
|
602
579
|
end
|
603
580
|
end
|
604
581
|
|
@@ -609,24 +586,78 @@ module Solargraph
|
|
609
586
|
|
610
587
|
# @return [void]
|
611
588
|
def cache_next_gemspec
|
612
|
-
return if @
|
613
|
-
spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec)}
|
614
|
-
return unless spec
|
589
|
+
return if @cache_progress
|
590
|
+
spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec) }
|
591
|
+
return end_cache_progress unless spec
|
615
592
|
|
593
|
+
pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
|
616
594
|
logger.info "Caching #{spec.name} #{spec.version}"
|
617
595
|
Thread.new do
|
618
|
-
|
619
|
-
|
596
|
+
cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
|
597
|
+
report_cache_progress spec.name, pending
|
598
|
+
Process.wait(cache_pid)
|
620
599
|
logger.info "Cached #{spec.name} #{spec.version}"
|
621
|
-
|
622
|
-
rescue Errno::EINVAL => e
|
600
|
+
rescue Errno::EINVAL => _e
|
623
601
|
logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
|
624
|
-
@synchronized = false
|
625
602
|
rescue StandardError => e
|
626
603
|
cache_errors.add spec
|
627
604
|
Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
|
628
605
|
ensure
|
629
|
-
|
606
|
+
end_cache_progress
|
607
|
+
catalog
|
608
|
+
sync_catalog
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
# @param gem_name [String]
|
613
|
+
# @param pending [Integer]
|
614
|
+
# @return [void]
|
615
|
+
def report_cache_progress gem_name, pending
|
616
|
+
@total ||= pending
|
617
|
+
@total = pending if pending > @total
|
618
|
+
finished = @total - pending
|
619
|
+
pct = if @total.zero?
|
620
|
+
0
|
621
|
+
else
|
622
|
+
((finished.to_f / @total.to_f) * 100).to_i
|
623
|
+
end
|
624
|
+
message = "#{gem_name}#{pending > 0 ? " (+#{pending})" : ''}"
|
625
|
+
# "
|
626
|
+
if @cache_progress
|
627
|
+
@cache_progress.report(message, pct)
|
628
|
+
else
|
629
|
+
@cache_progress = LanguageServer::Progress.new('Caching gem')
|
630
|
+
# If we don't send both a begin and a report, the progress notification
|
631
|
+
# might get stuck in the status bar forever
|
632
|
+
@cache_progress.begin(message, pct)
|
633
|
+
changed
|
634
|
+
notify_observers @cache_progress
|
635
|
+
@cache_progress.report(message, pct)
|
636
|
+
end
|
637
|
+
changed
|
638
|
+
notify_observers @cache_progress
|
639
|
+
end
|
640
|
+
|
641
|
+
# @return [void]
|
642
|
+
def end_cache_progress
|
643
|
+
changed if @cache_progress&.finish('done')
|
644
|
+
notify_observers @cache_progress
|
645
|
+
@cache_progress = nil
|
646
|
+
@total = nil
|
647
|
+
end
|
648
|
+
|
649
|
+
def sync_catalog
|
650
|
+
return if @sync_count == 0
|
651
|
+
|
652
|
+
mutex.synchronize do
|
653
|
+
logger.warn "CATALOG"
|
654
|
+
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
655
|
+
api_map.catalog bench
|
656
|
+
source_map_hash.values.each { |map| find_external_requires(map) }
|
657
|
+
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
658
|
+
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
659
|
+
cache_next_gemspec
|
660
|
+
@sync_count = 0
|
630
661
|
end
|
631
662
|
end
|
632
663
|
end
|
data/lib/solargraph/location.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Solargraph
|
4
|
-
# A section of text identified by its filename
|
4
|
+
# A pointer to a section of source text identified by its filename
|
5
|
+
# and Range.
|
5
6
|
#
|
6
7
|
class Location
|
7
8
|
# @return [String]
|
@@ -17,6 +18,11 @@ module Solargraph
|
|
17
18
|
@range = range
|
18
19
|
end
|
19
20
|
|
21
|
+
# @param location [self]
|
22
|
+
def contain? location
|
23
|
+
range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
|
24
|
+
end
|
25
|
+
|
20
26
|
# @return [Hash]
|
21
27
|
def to_hash
|
22
28
|
{
|
@@ -25,6 +31,13 @@ module Solargraph
|
|
25
31
|
}
|
26
32
|
end
|
27
33
|
|
34
|
+
# @param node [Parser::AST::Node, nil]
|
35
|
+
def self.from_node(node)
|
36
|
+
return nil if node.nil? || node.loc.nil?
|
37
|
+
range = Range.from_node(node)
|
38
|
+
self.new(node.loc.expression.source_buffer.name, range)
|
39
|
+
end
|
40
|
+
|
28
41
|
# @param other [BasicObject]
|
29
42
|
def == other
|
30
43
|
return false unless other.is_a?(Location)
|
@@ -13,7 +13,7 @@ module Solargraph
|
|
13
13
|
# @return [Array<Pin::Base>]
|
14
14
|
attr_reader :pins
|
15
15
|
|
16
|
-
# @return [Array<Pin::
|
16
|
+
# @return [Array<Pin::BaseVariable>]
|
17
17
|
attr_reader :locals
|
18
18
|
|
19
19
|
# @param node [Parser::AST::Node]
|
@@ -62,7 +62,7 @@ module Solargraph
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# @param position [Solargraph::Position]
|
65
|
-
# @return [Pin::
|
65
|
+
# @return [Pin::Closure, nil]
|
66
66
|
def named_path_pin position
|
67
67
|
pins.select{|pin| pin.is_a?(Pin::Closure) && pin.path && !pin.path.empty? && pin.location.range.contain?(position)}.last
|
68
68
|
end
|
@@ -71,6 +71,7 @@ module Solargraph
|
|
71
71
|
# @param position [Solargraph::Position]
|
72
72
|
# @return [Pin::Closure, nil]
|
73
73
|
def block_pin position
|
74
|
+
# @todo determine if this can return a Pin::Block
|
74
75
|
pins.select{|pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position)}.last
|
75
76
|
end
|
76
77
|
|
@@ -24,6 +24,7 @@ module Solargraph
|
|
24
24
|
# @param node [Parser::AST::Node]
|
25
25
|
# @param region [Region]
|
26
26
|
# @param pins [Array<Pin::Base>]
|
27
|
+
# @param locals [Array<Pin::BaseVariable>]
|
27
28
|
# @return [Array(Array<Pin::Base>, Array<Pin::Base>)]
|
28
29
|
def self.process node, region = Region.new, pins = [], locals = []
|
29
30
|
if pins.empty?
|
@@ -48,12 +48,6 @@ module Solargraph
|
|
48
48
|
NodeProcessor.process(source.node, Region.new(source: source))
|
49
49
|
end
|
50
50
|
|
51
|
-
# @param node [Parser::AST::Node]
|
52
|
-
# @return [Array<Parser::AST::Node>]
|
53
|
-
def returns_from node
|
54
|
-
NodeMethods.returns_from(node)
|
55
|
-
end
|
56
|
-
|
57
51
|
# @param source [Source]
|
58
52
|
# @param name [String]
|
59
53
|
# @return [Array<Location>]
|
@@ -62,10 +56,12 @@ module Solargraph
|
|
62
56
|
reg = /#{Regexp.escape name[0..-2]}\s*=/
|
63
57
|
# @param code [String]
|
64
58
|
# @param offset [Integer]
|
59
|
+
# @return [Array(Integer, Integer), Array(nil, nil)]
|
65
60
|
extract_offset = ->(code, offset) { reg.match(code, offset).offset(0) }
|
66
61
|
else
|
67
62
|
# @param code [String]
|
68
63
|
# @param offset [Integer]
|
64
|
+
# @return [Array(Integer, Integer), Array(nil, nil)]
|
69
65
|
extract_offset = ->(code, offset) { [soff = code.index(name, offset), soff + name.length] }
|
70
66
|
end
|
71
67
|
inner_node_references(name, source.node).map do |n|
|
@@ -115,7 +111,7 @@ module Solargraph
|
|
115
111
|
NodeMethods.infer_literal_node_type node
|
116
112
|
end
|
117
113
|
|
118
|
-
# @return [
|
114
|
+
# @return [Integer]
|
119
115
|
def version
|
120
116
|
parser.version
|
121
117
|
end
|
@@ -89,15 +89,21 @@ module Solargraph
|
|
89
89
|
elsif n.type == :const
|
90
90
|
const = unpack_name(n)
|
91
91
|
result.push Chain::Constant.new(const)
|
92
|
-
elsif [:
|
92
|
+
elsif [:lvasgn, :ivasgn, :gvasgn, :cvasgn].include?(n.type)
|
93
|
+
result.concat generate_links(n.children[1])
|
94
|
+
elsif n.type == :lvar
|
93
95
|
result.push Chain::Call.new(n.children[0].to_s)
|
94
|
-
elsif
|
95
|
-
|
96
|
-
elsif
|
97
|
-
|
98
|
-
elsif
|
99
|
-
|
96
|
+
elsif n.type == :ivar
|
97
|
+
result.push Chain::InstanceVariable.new(n.children[0].to_s)
|
98
|
+
elsif n.type == :cvar
|
99
|
+
result.push Chain::ClassVariable.new(n.children[0].to_s)
|
100
|
+
elsif n.type == :gvar
|
101
|
+
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
100
102
|
elsif n.type == :or_asgn
|
103
|
+
# @todo: Need a new Link class here that evaluates the
|
104
|
+
# existing variable type with the RHS, and generates a
|
105
|
+
# union type of the LHS alone if never nil, or minus nil +
|
106
|
+
# RHS if it is nilable.
|
101
107
|
result.concat generate_links n.children[1]
|
102
108
|
elsif [:class, :module, :def, :defs].include?(n.type)
|
103
109
|
# @todo Undefined or what?
|
@@ -181,10 +181,6 @@ module Solargraph
|
|
181
181
|
elsif [:super, :zsuper].include?(node.type)
|
182
182
|
result.push node
|
183
183
|
node.children.each { |child| result.concat call_nodes_from(child) }
|
184
|
-
elsif node.type == :masgn
|
185
|
-
# @todo We're treating a mass assignment as a call node, but the
|
186
|
-
# type checker still needs the logic to handle it.
|
187
|
-
result.push node
|
188
184
|
else
|
189
185
|
node.children.each { |child| result.concat call_nodes_from(child) }
|
190
186
|
end
|
@@ -315,7 +311,7 @@ module Solargraph
|
|
315
311
|
# statements in value positions.
|
316
312
|
module DeepInference
|
317
313
|
class << self
|
318
|
-
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless
|
314
|
+
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless]
|
319
315
|
CONDITIONAL_ALL = [:or]
|
320
316
|
ONLY_ONE_CHILD = [:return]
|
321
317
|
FIRST_TWO_CHILDREN = [:rescue]
|