solargraph 0.53.4 → 0.54.0
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 +22 -0
- data/lib/solargraph/api_map/cache.rb +2 -12
- data/lib/solargraph/api_map/store.rb +11 -6
- data/lib/solargraph/api_map.rb +53 -17
- data/lib/solargraph/complex_type/type_methods.rb +62 -30
- data/lib/solargraph/complex_type/unique_type.rb +117 -66
- data/lib/solargraph/complex_type.rb +41 -25
- 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/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/formatting.rb +1 -0
- data/lib/solargraph/language_server/progress.rb +118 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +136 -96
- 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_methods.rb +0 -4
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +5 -3
- data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
- data/lib/solargraph/pin/base_variable.rb +34 -5
- data/lib/solargraph/pin/block.rb +55 -0
- data/lib/solargraph/pin/delegated_method.rb +5 -1
- data/lib/solargraph/pin/documenting.rb +2 -0
- data/lib/solargraph/pin/method.rb +3 -1
- data/lib/solargraph/pin/parameter.rb +5 -28
- data/lib/solargraph/rbs_map/conversions.rb +10 -6
- data/lib/solargraph/rbs_map.rb +11 -3
- data/lib/solargraph/shell.rb +18 -13
- data/lib/solargraph/source/chain.rb +20 -0
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +0 -44
- data/lib/solargraph/source_map/mapper.rb +3 -2
- data/lib/solargraph/source_map.rb +10 -0
- data/lib/solargraph/type_checker.rb +43 -18
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +2 -1
- data/lib/solargraph/workspace.rb +13 -0
- metadata +4 -3
- data/lib/solargraph/language_server/host/cataloger.rb +0 -57
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Solargraph
|
6
|
+
module LanguageServer
|
7
|
+
# Progress notification handling for language server hosts.
|
8
|
+
#
|
9
|
+
class Progress
|
10
|
+
WAITING = :waiting
|
11
|
+
CREATED = :created
|
12
|
+
FINISHED = :finished
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
attr_reader :uuid
|
16
|
+
|
17
|
+
# @return [String]
|
18
|
+
attr_reader :title
|
19
|
+
|
20
|
+
# @return [String, nil]
|
21
|
+
attr_reader :kind
|
22
|
+
|
23
|
+
# @return [String, nil]
|
24
|
+
attr_reader :message
|
25
|
+
|
26
|
+
# @return [Integer]
|
27
|
+
attr_reader :percentage
|
28
|
+
|
29
|
+
# @return [Symbol]
|
30
|
+
attr_reader :status
|
31
|
+
|
32
|
+
# @param title [String]
|
33
|
+
def initialize title
|
34
|
+
@title = title
|
35
|
+
@uuid = SecureRandom.uuid
|
36
|
+
@percentage = 0
|
37
|
+
@status = WAITING
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param message [String]
|
41
|
+
# @param percentage [Integer]
|
42
|
+
def begin message, percentage
|
43
|
+
@kind = 'begin'
|
44
|
+
@message = message
|
45
|
+
@percentage = percentage
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param message [String]
|
49
|
+
# @param percentage [Integer]
|
50
|
+
def report message, percentage
|
51
|
+
@kind = 'report'
|
52
|
+
@message = message
|
53
|
+
@percentage = percentage
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param message [String]
|
57
|
+
def finish message
|
58
|
+
@kind = 'end'
|
59
|
+
@message = message
|
60
|
+
@percentage = 100
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
# @param host [Solargraph::LanguageServer::Host]
|
65
|
+
def send host
|
66
|
+
return unless host.client_supports_progress? && !finished?
|
67
|
+
|
68
|
+
message = build
|
69
|
+
|
70
|
+
create(host) unless created?
|
71
|
+
host.send_notification '$/progress', message
|
72
|
+
@status = FINISHED if kind == 'end'
|
73
|
+
end
|
74
|
+
|
75
|
+
def created?
|
76
|
+
[CREATED, FINISHED].include?(status)
|
77
|
+
end
|
78
|
+
|
79
|
+
def finished?
|
80
|
+
status == FINISHED
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# @param host [Solargraph::LanguageServer::Host]
|
86
|
+
# @return [void]
|
87
|
+
def create host
|
88
|
+
return if created?
|
89
|
+
|
90
|
+
host.send_request 'window/workDoneProgress/create', { token: uuid }
|
91
|
+
@status = CREATED
|
92
|
+
end
|
93
|
+
|
94
|
+
def build
|
95
|
+
{
|
96
|
+
token: uuid,
|
97
|
+
value: {
|
98
|
+
kind: kind,
|
99
|
+
cancellable: false
|
100
|
+
}.merge(build_value)
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_value
|
105
|
+
case kind
|
106
|
+
when 'begin'
|
107
|
+
{ title: title, message: message, percentage: percentage }
|
108
|
+
when 'report'
|
109
|
+
{ message: message, percentage: percentage }
|
110
|
+
when 'end'
|
111
|
+
{ message: message }
|
112
|
+
else
|
113
|
+
raise "Invalid progress kind #{kind}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -15,5 +15,6 @@ module Solargraph
|
|
15
15
|
autoload :MessageTypes, 'solargraph/language_server/message_types'
|
16
16
|
autoload :Request, 'solargraph/language_server/request'
|
17
17
|
autoload :Transport, 'solargraph/language_server/transport'
|
18
|
+
autoload :Progress, 'solargraph/language_server/progress'
|
18
19
|
end
|
19
20
|
end
|
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
|
+
@threads = []
|
31
|
+
# @type [Integer, nil]
|
32
|
+
@total = nil
|
33
|
+
# @type [Source, nil]
|
34
|
+
@current = nil
|
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
|
+
!mutex.locked?
|
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
|
@@ -180,6 +176,7 @@ module Solargraph
|
|
180
176
|
def definitions_at filename, line, column
|
181
177
|
position = Position.new(line, column)
|
182
178
|
cursor = Source::Cursor.new(read(filename), position)
|
179
|
+
sync_catalog
|
183
180
|
if cursor.comment?
|
184
181
|
source = read(filename)
|
185
182
|
offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
|
@@ -187,13 +184,13 @@ 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
|
-
api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
|
193
|
+
mutex.synchronize { api_map.clip(cursor).define.map { |pin| pin.realize(api_map) } }
|
197
194
|
end
|
198
195
|
rescue FileNotFoundError => e
|
199
196
|
handle_file_not_found(filename, e)
|
@@ -210,7 +207,8 @@ module Solargraph
|
|
210
207
|
def type_definitions_at filename, line, column
|
211
208
|
position = Position.new(line, column)
|
212
209
|
cursor = Source::Cursor.new(read(filename), position)
|
213
|
-
|
210
|
+
sync_catalog
|
211
|
+
mutex.synchronize { api_map.clip(cursor).types }
|
214
212
|
rescue FileNotFoundError => e
|
215
213
|
handle_file_not_found filename, e
|
216
214
|
end
|
@@ -226,7 +224,8 @@ module Solargraph
|
|
226
224
|
def signatures_at filename, line, column
|
227
225
|
position = Position.new(line, column)
|
228
226
|
cursor = Source::Cursor.new(read(filename), position)
|
229
|
-
|
227
|
+
sync_catalog
|
228
|
+
mutex.synchronize { api_map.clip(cursor).signify }
|
230
229
|
end
|
231
230
|
|
232
231
|
# @param filename [String]
|
@@ -237,8 +236,9 @@ module Solargraph
|
|
237
236
|
# @return [Array<Solargraph::Range>]
|
238
237
|
# @todo Take a Location instead of filename/line/column
|
239
238
|
def references_from filename, line, column, strip: false, only: false
|
240
|
-
|
241
|
-
|
239
|
+
sync_catalog
|
240
|
+
cursor = Source::Cursor.new(read(filename), [line, column])
|
241
|
+
clip = mutex.synchronize { api_map.clip(cursor) }
|
242
242
|
pin = clip.define.first
|
243
243
|
return [] unless pin
|
244
244
|
result = []
|
@@ -283,7 +283,8 @@ module Solargraph
|
|
283
283
|
# @param location [Location]
|
284
284
|
# @return [Array<Solargraph::Pin::Base>]
|
285
285
|
def locate_pins location
|
286
|
-
|
286
|
+
sync_catalog
|
287
|
+
mutex.synchronize { api_map.locate_pins(location).map { |pin| pin.realize(api_map) } }
|
287
288
|
end
|
288
289
|
|
289
290
|
# Match a require reference to a file.
|
@@ -316,19 +317,22 @@ module Solargraph
|
|
316
317
|
# @param path [String]
|
317
318
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
318
319
|
def get_path_pins path
|
319
|
-
|
320
|
+
sync_catalog
|
321
|
+
mutex.synchronize { api_map.get_path_suggestions(path) }
|
320
322
|
end
|
321
323
|
|
322
324
|
# @param query [String]
|
323
325
|
# @return [Enumerable<YARD::CodeObjects::Base>]
|
324
326
|
def document query
|
325
|
-
|
327
|
+
sync_catalog
|
328
|
+
mutex.synchronize { api_map.document query }
|
326
329
|
end
|
327
330
|
|
328
331
|
# @param query [String]
|
329
332
|
# @return [Array<String>]
|
330
333
|
def search query
|
331
|
-
|
334
|
+
sync_catalog
|
335
|
+
mutex.synchronize { api_map.search query }
|
332
336
|
end
|
333
337
|
|
334
338
|
# Get an array of all symbols in the workspace that match the query.
|
@@ -336,7 +340,8 @@ module Solargraph
|
|
336
340
|
# @param query [String]
|
337
341
|
# @return [Array<Pin::Base>]
|
338
342
|
def query_symbols query
|
339
|
-
|
343
|
+
sync_catalog
|
344
|
+
mutex.synchronize { api_map.query_symbols query }
|
340
345
|
end
|
341
346
|
|
342
347
|
# Get an array of document symbols.
|
@@ -348,13 +353,15 @@ module Solargraph
|
|
348
353
|
# @param filename [String]
|
349
354
|
# @return [Array<Solargraph::Pin::Base>]
|
350
355
|
def document_symbols filename
|
351
|
-
|
356
|
+
sync_catalog
|
357
|
+
mutex.synchronize { api_map.document_symbols(filename) }
|
352
358
|
end
|
353
359
|
|
354
360
|
# @param path [String]
|
355
361
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
356
362
|
def path_pins path
|
357
|
-
|
363
|
+
sync_catalog
|
364
|
+
mutex.synchronize { api_map.get_path_suggestions(path) }
|
358
365
|
end
|
359
366
|
|
360
367
|
# @return [Array<SourceMap>]
|
@@ -380,10 +387,10 @@ module Solargraph
|
|
380
387
|
# everything in the workspace should get diagnosed, or if there should
|
381
388
|
# be an option to do so.
|
382
389
|
#
|
390
|
+
sync_catalog
|
383
391
|
return [] unless open?(filename)
|
384
392
|
result = []
|
385
393
|
source = read(filename)
|
386
|
-
catalog
|
387
394
|
repargs = {}
|
388
395
|
workspace.config.reporters.each do |line|
|
389
396
|
if line == 'all!'
|
@@ -409,21 +416,20 @@ module Solargraph
|
|
409
416
|
#
|
410
417
|
# @return [void]
|
411
418
|
def catalog
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
# @return [void]
|
418
|
-
private def catalog_inlock
|
419
|
-
return if synchronized?
|
419
|
+
@threads.delete_if(&:stop?)
|
420
|
+
@threads.push(Thread.new do
|
421
|
+
sleep 0.05 if RUBY_PLATFORM =~ /mingw/
|
422
|
+
next unless @threads.last == Thread.current
|
420
423
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
424
|
+
mutex.synchronize do
|
425
|
+
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
426
|
+
api_map.catalog bench
|
427
|
+
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
428
|
+
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
429
|
+
cache_next_gemspec
|
430
|
+
end
|
431
|
+
end)
|
432
|
+
@threads.last.run if RUBY_PLATFORM =~ /mingw/
|
427
433
|
end
|
428
434
|
|
429
435
|
# @return [Bench]
|
@@ -462,12 +468,8 @@ module Solargraph
|
|
462
468
|
# @return [Boolean] True if the source was merged into the workspace.
|
463
469
|
def merge source
|
464
470
|
Logging.logger.debug "Merging source: #{source.filename}"
|
465
|
-
result =
|
466
|
-
|
467
|
-
result = workspace.merge(source)
|
468
|
-
maybe_map source
|
469
|
-
end
|
470
|
-
# catalog
|
471
|
+
result = workspace.merge(source)
|
472
|
+
maybe_map source
|
471
473
|
result
|
472
474
|
end
|
473
475
|
|
@@ -483,17 +485,14 @@ module Solargraph
|
|
483
485
|
# @return [SourceMap, Boolean]
|
484
486
|
def next_map
|
485
487
|
return false if mapped?
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
else
|
495
|
-
false
|
496
|
-
end
|
488
|
+
src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
|
489
|
+
if src
|
490
|
+
Logging.logger.debug "Mapping #{src.filename}"
|
491
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
492
|
+
find_external_requires(source_map_hash[src.filename])
|
493
|
+
source_map_hash[src.filename]
|
494
|
+
else
|
495
|
+
false
|
497
496
|
end
|
498
497
|
end
|
499
498
|
|
@@ -575,7 +574,7 @@ module Solargraph
|
|
575
574
|
end
|
576
575
|
end
|
577
576
|
|
578
|
-
# @param source [Source]
|
577
|
+
# @param source [Source, nil]
|
579
578
|
# @return [void]
|
580
579
|
def maybe_map source
|
581
580
|
return unless source
|
@@ -589,7 +588,6 @@ module Solargraph
|
|
589
588
|
unless source_map_hash[source.filename].try_merge!(new_map)
|
590
589
|
source_map_hash[source.filename] = new_map
|
591
590
|
find_external_requires(source_map_hash[source.filename])
|
592
|
-
@synchronized = false
|
593
591
|
end
|
594
592
|
else
|
595
593
|
# @todo Smelly instance variable access
|
@@ -598,7 +596,6 @@ module Solargraph
|
|
598
596
|
else
|
599
597
|
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
600
598
|
find_external_requires(source_map_hash[source.filename])
|
601
|
-
@synchronized = false
|
602
599
|
end
|
603
600
|
end
|
604
601
|
|
@@ -609,25 +606,68 @@ module Solargraph
|
|
609
606
|
|
610
607
|
# @return [void]
|
611
608
|
def cache_next_gemspec
|
612
|
-
return if @
|
613
|
-
spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec)}
|
614
|
-
return unless spec
|
609
|
+
return if @cache_progress
|
610
|
+
spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec) }
|
611
|
+
return end_cache_progress unless spec
|
615
612
|
|
613
|
+
pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
|
616
614
|
logger.info "Caching #{spec.name} #{spec.version}"
|
617
615
|
Thread.new do
|
618
|
-
|
619
|
-
|
616
|
+
cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
|
617
|
+
report_cache_progress spec.name, pending
|
618
|
+
Process.wait(cache_pid)
|
620
619
|
logger.info "Cached #{spec.name} #{spec.version}"
|
621
|
-
|
622
|
-
rescue Errno::EINVAL => e
|
620
|
+
rescue Errno::EINVAL => _e
|
623
621
|
logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
|
624
|
-
@synchronized = false
|
625
622
|
rescue StandardError => e
|
626
623
|
cache_errors.add spec
|
627
624
|
Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
|
628
625
|
ensure
|
629
|
-
|
626
|
+
end_cache_progress
|
627
|
+
catalog
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
# @param gem_name [String]
|
632
|
+
# @param pending [Integer]
|
633
|
+
# @return [void]
|
634
|
+
def report_cache_progress gem_name, pending
|
635
|
+
@total ||= pending
|
636
|
+
@total = pending if pending > @total
|
637
|
+
finished = @total - pending
|
638
|
+
pct = if @total.zero?
|
639
|
+
0
|
640
|
+
else
|
641
|
+
((finished.to_f / @total.to_f) * 100).to_i
|
642
|
+
end
|
643
|
+
message = "#{gem_name}#{pending > 0 ? " (+#{pending})" : ''}"
|
644
|
+
# "
|
645
|
+
if @cache_progress
|
646
|
+
@cache_progress.report(message, pct)
|
647
|
+
else
|
648
|
+
@cache_progress = LanguageServer::Progress.new('Caching gem')
|
649
|
+
# If we don't send both a begin and a report, the progress notification
|
650
|
+
# might get stuck in the status bar forever
|
651
|
+
@cache_progress.begin(message, pct)
|
652
|
+
changed
|
653
|
+
notify_observers @cache_progress
|
654
|
+
@cache_progress.report(message, pct)
|
630
655
|
end
|
656
|
+
changed
|
657
|
+
notify_observers @cache_progress
|
658
|
+
end
|
659
|
+
|
660
|
+
# @return [void]
|
661
|
+
def end_cache_progress
|
662
|
+
changed if @cache_progress&.finish('done')
|
663
|
+
notify_observers @cache_progress
|
664
|
+
@cache_progress = nil
|
665
|
+
@total = nil
|
666
|
+
end
|
667
|
+
|
668
|
+
def sync_catalog
|
669
|
+
@threads.delete_if(&:stop?)
|
670
|
+
.last&.join
|
631
671
|
end
|
632
672
|
end
|
633
673
|
end
|
@@ -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
|
@@ -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
|