solargraph 0.53.3 → 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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/lib/solargraph/api_map/cache.rb +2 -12
  4. data/lib/solargraph/api_map/store.rb +11 -6
  5. data/lib/solargraph/api_map.rb +80 -26
  6. data/lib/solargraph/complex_type/type_methods.rb +62 -30
  7. data/lib/solargraph/complex_type/unique_type.rb +117 -66
  8. data/lib/solargraph/complex_type.rb +41 -25
  9. data/lib/solargraph/doc_map.rb +19 -3
  10. data/lib/solargraph/gem_pins.rb +9 -1
  11. data/lib/solargraph/language_server/host/dispatch.rb +8 -1
  12. data/lib/solargraph/language_server/host/sources.rb +1 -61
  13. data/lib/solargraph/language_server/host.rb +39 -68
  14. data/lib/solargraph/language_server/message/base.rb +1 -1
  15. data/lib/solargraph/language_server/message/initialize.rb +14 -0
  16. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  17. data/lib/solargraph/language_server/progress.rb +118 -0
  18. data/lib/solargraph/language_server.rb +1 -0
  19. data/lib/solargraph/library.rb +136 -96
  20. data/lib/solargraph/parser/node_processor/base.rb +3 -2
  21. data/lib/solargraph/parser/node_processor.rb +1 -0
  22. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
  23. data/lib/solargraph/parser/parser_gem/node_methods.rb +0 -4
  24. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
  25. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +5 -3
  26. data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
  27. data/lib/solargraph/pin/base_variable.rb +34 -5
  28. data/lib/solargraph/pin/block.rb +62 -7
  29. data/lib/solargraph/pin/delegated_method.rb +5 -1
  30. data/lib/solargraph/pin/documenting.rb +2 -0
  31. data/lib/solargraph/pin/method.rb +4 -2
  32. data/lib/solargraph/pin/parameter.rb +5 -28
  33. data/lib/solargraph/rbs_map/conversions.rb +12 -6
  34. data/lib/solargraph/rbs_map/core_fills.rb +4 -1
  35. data/lib/solargraph/rbs_map.rb +11 -3
  36. data/lib/solargraph/shell.rb +18 -13
  37. data/lib/solargraph/source/chain.rb +20 -0
  38. data/lib/solargraph/source/updater.rb +1 -0
  39. data/lib/solargraph/source.rb +0 -44
  40. data/lib/solargraph/source_map/clip.rb +1 -0
  41. data/lib/solargraph/source_map/mapper.rb +3 -2
  42. data/lib/solargraph/source_map.rb +10 -0
  43. data/lib/solargraph/type_checker.rb +44 -18
  44. data/lib/solargraph/version.rb +1 -1
  45. data/lib/solargraph/workspace/config.rb +2 -1
  46. data/lib/solargraph/workspace.rb +13 -0
  47. data/lib/solargraph/yard_map/mapper/to_method.rb +5 -2
  48. metadata +4 -3
  49. data/lib/solargraph/language_server/host/cataloger.rb +0 -57
@@ -17,43 +17,61 @@ module Solargraph
17
17
  #
18
18
  # @param name [String] The name of the type
19
19
  # @param substring [String] The substring of the type
20
- def initialize name, substring = ''
20
+ # @param make_rooted [Boolean, nil]
21
+ # @return [UniqueType]
22
+ def self.parse name, substring = '', make_rooted: nil
23
+ if name.start_with?(':::')
24
+ raise "Illegal prefix: #{name}"
25
+ end
21
26
  if name.start_with?('::')
22
- @name = name[2..-1]
23
- @rooted = true
27
+ name = name[2..-1]
28
+ rooted = true
24
29
  else
25
- @name = name
26
- @rooted = false
30
+ rooted = false
27
31
  end
28
- @substring = substring
29
- @tag = @name + substring
30
- # @type [Array<ComplexType>]
31
- @key_types = []
32
+ rooted = make_rooted unless make_rooted.nil?
33
+
32
34
  # @type [Array<ComplexType>]
33
- @subtypes = []
35
+ key_types = []
34
36
  # @type [Array<ComplexType>]
35
- @all_params = []
36
- return unless parameters?
37
- # @todo we should be able to probe the type of 'subs' without
38
- # hoisting the definition outside of the if statement
39
- subs = if @substring.start_with?('<(') && @substring.end_with?(')>')
40
- ComplexType.parse(substring[2..-3], partial: true)
41
- else
42
- ComplexType.parse(substring[1..-2], partial: true)
43
- end
44
- if hash_parameters?
45
- raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
46
- # @todo should be able to resolve map; both types have it
47
- # with same return type
48
- # @sg-ignore
49
- @key_types.concat subs[0].map { |u| ComplexType.new([u]) }
50
- # @sg-ignore
51
- @subtypes.concat subs[1].map { |u| ComplexType.new([u]) }
52
- else
53
- @subtypes.concat subs
37
+ subtypes = []
38
+ parameters_type = nil
39
+ unless substring.empty?
40
+ subs = ComplexType.parse(substring[1..-2], partial: true)
41
+ parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
42
+ if parameters_type == :hash
43
+ raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
44
+ # @todo should be able to resolve map; both types have it
45
+ # with same return type
46
+ # @sg-ignore
47
+ key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
48
+ # @sg-ignore
49
+ subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
50
+ else
51
+ subtypes.concat subs
52
+ end
54
53
  end
55
- @all_params.concat @key_types
56
- @all_params.concat @subtypes
54
+ new(name, key_types, subtypes, rooted: rooted, parameters_type: parameters_type)
55
+ end
56
+
57
+ # @param name [String]
58
+ # @param key_types [Array<ComplexType>]
59
+ # @param subtypes [Array<ComplexType>]
60
+ # @param rooted [Boolean]
61
+ # @param parameters_type [Symbol, nil]
62
+ def initialize(name, key_types = [], subtypes = [], rooted:, parameters_type: nil)
63
+ if parameters_type.nil?
64
+ raise "You must supply parameters_type if you provide parameters" unless key_types.empty? && subtypes.empty?
65
+ end
66
+ raise "Please remove leading :: and set rooted instead - #{name}" if name.start_with?('::')
67
+ @name = name
68
+ @key_types = key_types
69
+ @subtypes = subtypes
70
+ @rooted = rooted
71
+ @all_params = []
72
+ @all_params.concat key_types
73
+ @all_params.concat subtypes
74
+ @parameters_type = parameters_type
57
75
  end
58
76
 
59
77
  def to_s
@@ -76,7 +94,17 @@ module Solargraph
76
94
 
77
95
  # @return [String]
78
96
  def to_rbs
79
- if ['Tuple', 'Array'].include?(name) && fixed_parameters?
97
+ if duck_type?
98
+ 'untyped'
99
+ elsif name == 'Boolean'
100
+ 'bool'
101
+ elsif name.downcase == 'nil'
102
+ 'nil'
103
+ elsif name == GENERIC_TAG_NAME
104
+ all_params.first.name
105
+ elsif ['Class', 'Module'].include?(name)
106
+ rbs_name
107
+ elsif ['Tuple', 'Array'].include?(name) && fixed_parameters?
80
108
  # tuples don't have a name; they're just [foo, bar, baz].
81
109
  if substring == '()'
82
110
  # but there are no zero element tuples, so we go with an array
@@ -90,16 +118,37 @@ module Solargraph
90
118
  end
91
119
  end
92
120
 
121
+ # @return [Boolean]
122
+ def parameters?
123
+ !all_params.empty?
124
+ end
125
+
126
+ # @param types [Array<UniqueType, ComplexType>]
127
+ # @return [String]
128
+ def rbs_union(types)
129
+ if types.length == 1
130
+ types.first.to_rbs
131
+ else
132
+ "(#{types.map(&:to_rbs).join(' | ')})"
133
+ end
134
+ end
135
+
93
136
  # @return [String]
94
137
  def parameters_as_rbs
95
- parameters? ? "[#{all_params.map { |s| s.to_rbs }.join(', ')}]" : ''
138
+ return '' unless parameters?
139
+
140
+ return "[#{all_params.map(&:to_rbs).join(', ')}]" if key_types.empty?
141
+
142
+ # handle, e.g., Hash[K, V] case
143
+ key_types_str = rbs_union(key_types)
144
+ subtypes_str = rbs_union(subtypes)
145
+ "[#{key_types_str}, #{subtypes_str}]"
96
146
  end
97
147
 
98
148
  def generic?
99
149
  name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
100
150
  end
101
151
 
102
-
103
152
  # @param generics_to_resolve [Enumerable<String>]
104
153
  # @param context_type [UniqueType, nil]
105
154
  # @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
@@ -182,39 +231,34 @@ module Solargraph
182
231
  end
183
232
 
184
233
  # @param new_name [String, nil]
234
+ # @param make_rooted [Boolean, nil]
185
235
  # @param new_key_types [Array<UniqueType>, nil]
236
+ # @param rooted [Boolean, nil]
186
237
  # @param new_subtypes [Array<UniqueType>, nil]
187
238
  # @return [self]
188
- def recreate(new_name: nil, new_key_types: nil, new_subtypes: nil)
239
+ def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
240
+ raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
189
241
  new_name ||= name
190
242
  new_key_types ||= @key_types
191
243
  new_subtypes ||= @subtypes
192
- if new_key_types.none?(&:defined?) && new_subtypes.none?(&:defined?)
193
- # if all subtypes are undefined, erase down to the non-parametric type
194
- UniqueType.new(new_name)
195
- elsif new_key_types.empty? && new_subtypes.empty?
196
- UniqueType.new(new_name)
197
- elsif hash_parameters?
198
- UniqueType.new(new_name, "{#{new_key_types.join(', ')} => #{new_subtypes.join(', ')}}")
199
- elsif @substring.start_with?('<(')
200
- # @todo This clause is probably wrong, and if so, fixing it
201
- # will be some level of breaking change. Probably best
202
- # handled before real tuple support is rolled out and
203
- # folks start relying on it more.
204
- #
205
- # (String) is a one element tuple in https://yardoc.org/types
206
- # <String> is an array of zero or more Strings in https://yardoc.org/types
207
- # Array<(String)> could be an Array of one-element tuples or a
208
- # one element tuple. https://yardoc.org/types treats it
209
- # as the former.
210
- # Array<(String), Integer> is not ambiguous if we accept
211
- # (String) as a tuple type, but not currently understood
212
- # by Solargraph.
213
- UniqueType.new(new_name, "<(#{new_subtypes.join(', ')})>")
214
- elsif fixed_parameters?
215
- UniqueType.new(new_name, "(#{new_subtypes.join(', ')})")
216
- else
217
- UniqueType.new(new_name, "<#{new_subtypes.join(', ')}>")
244
+ make_rooted = @rooted if make_rooted.nil?
245
+ UniqueType.new(new_name, new_key_types, new_subtypes, rooted: make_rooted, parameters_type: parameters_type)
246
+ end
247
+
248
+ # @return [String]
249
+ def rooted_tags
250
+ rooted_tag
251
+ end
252
+
253
+ # @return [String]
254
+ def tags
255
+ tag
256
+ end
257
+
258
+ # @return [self]
259
+ def force_rooted
260
+ transform do |t|
261
+ t.recreate(make_rooted: true)
218
262
  end
219
263
  end
220
264
 
@@ -225,9 +269,16 @@ module Solargraph
225
269
  # @yieldreturn [self]
226
270
  # @return [self]
227
271
  def transform(new_name = nil, &transform_type)
228
- new_key_types = @key_types.flat_map { |ct| ct.map { |ut| ut.transform(&transform_type) } }.compact
229
- new_subtypes = @subtypes.flat_map { |ct| ct.map { |ut| ut.transform(&transform_type) } }.compact
230
- new_type = recreate(new_name: new_name || rooted_name, new_key_types: new_key_types, new_subtypes: new_subtypes)
272
+ raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
273
+ if name == ComplexType::GENERIC_TAG_NAME
274
+ # doesn't make sense to manipulate the name of the generic
275
+ new_key_types = @key_types
276
+ new_subtypes = @subtypes
277
+ else
278
+ new_key_types = @key_types.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
279
+ new_subtypes = @subtypes.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
280
+ end
281
+ new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes)
231
282
  yield new_type
232
283
  end
233
284
 
@@ -245,8 +296,8 @@ module Solargraph
245
296
  @name == 'self' || @key_types.any?(&:selfy?) || @subtypes.any?(&:selfy?)
246
297
  end
247
298
 
248
- UNDEFINED = UniqueType.new('undefined')
249
- BOOLEAN = UniqueType.new('Boolean')
299
+ UNDEFINED = UniqueType.new('undefined', rooted: false)
300
+ BOOLEAN = UniqueType.new('Boolean', rooted: true)
250
301
  end
251
302
  end
252
303
  end
@@ -11,7 +11,7 @@ module Solargraph
11
11
  autoload :TypeMethods, 'solargraph/complex_type/type_methods'
12
12
  autoload :UniqueType, 'solargraph/complex_type/unique_type'
13
13
 
14
- # @param types [Array<[UniqueType, ComplexType]>]
14
+ # @param types [Array<UniqueType, ComplexType>]
15
15
  def initialize types = [UniqueType::UNDEFINED]
16
16
  # @todo @items here should not need an annotation
17
17
  # @type [Array<UniqueType>]
@@ -86,6 +86,10 @@ module Solargraph
86
86
  @items
87
87
  end
88
88
 
89
+ def tags
90
+ @items.map(&:tag).join(', ')
91
+ end
92
+
89
93
  # @param index [Integer]
90
94
  # @return [UniqueType]
91
95
  def [](index)
@@ -126,6 +130,10 @@ module Solargraph
126
130
  map(&:tag).join(', ')
127
131
  end
128
132
 
133
+ def rooted_tags
134
+ map(&:rooted_tag).join(', ')
135
+ end
136
+
129
137
  def all? &block
130
138
  @items.all? &block
131
139
  end
@@ -147,15 +155,23 @@ module Solargraph
147
155
  # @yieldreturn [UniqueType]
148
156
  # @return [ComplexType]
149
157
  def transform(new_name = nil, &transform_type)
158
+ raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
150
159
  ComplexType.new(map { |ut| ut.transform(new_name, &transform_type) })
151
160
  end
152
161
 
162
+ # @return [self]
163
+ def force_rooted
164
+ transform do |t|
165
+ t.recreate(make_rooted: true)
166
+ end
167
+ end
168
+
153
169
  # @param definitions [Pin::Namespace, Pin::Method]
154
170
  # @param context_type [ComplexType]
155
171
  # @return [ComplexType]
156
172
  def resolve_generics definitions, context_type
157
173
  result = @items.map { |i| i.resolve_generics(definitions, context_type) }
158
- ComplexType.parse(*result.map(&:tag))
174
+ ComplexType.try_parse(*result.map(&:tag))
159
175
  end
160
176
 
161
177
  # @param dst [String]
@@ -164,7 +180,7 @@ module Solargraph
164
180
  return self unless selfy?
165
181
  red = reduce_class(dst)
166
182
  result = @items.map { |i| i.self_to red }
167
- ComplexType.parse(*result.map(&:tag))
183
+ ComplexType.try_parse(*result.map(&:tag))
168
184
  end
169
185
 
170
186
  def nullable?
@@ -190,21 +206,6 @@ module Solargraph
190
206
  @items.all?(&:bot?)
191
207
  end
192
208
 
193
- private
194
-
195
- # @todo This is a quick and dirty hack that forces `self` keywords
196
- # to reference an instance of their class and never the class itself.
197
- # This behavior may change depending on which result is expected
198
- # from YARD conventions. See https://github.com/lsegal/yard/issues/1257
199
- # @param dst [String]
200
- # @return [String]
201
- def reduce_class dst
202
- while dst =~ /^(Class|Module)\<(.*?)\>$/
203
- dst = dst.sub(/^(Class|Module)\</, '').sub(/\>$/, '')
204
- end
205
- dst
206
- end
207
-
208
209
  class << self
209
210
  # Parse type strings into a ComplexType.
210
211
  #
@@ -250,7 +251,7 @@ module Solargraph
250
251
  elsif base.end_with?('=')
251
252
  raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
252
253
  # types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])
253
- types.push UniqueType.new(base[0..-2].strip)
254
+ types.push UniqueType.parse(base[0..-2].strip, subtype_string)
254
255
  # @todo this should either expand key_type's type
255
256
  # automatically or complain about not being
256
257
  # compatible with key_type's type in type checking
@@ -281,7 +282,7 @@ module Solargraph
281
282
  next
282
283
  elsif char == ',' && point_stack == 0 && curly_stack == 0 && paren_stack == 0
283
284
  # types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])
284
- types.push UniqueType.new(base.strip, subtype_string.strip)
285
+ types.push UniqueType.parse(base.strip, subtype_string.strip)
285
286
  base.clear
286
287
  subtype_string.clear
287
288
  next
@@ -294,7 +295,7 @@ module Solargraph
294
295
  end
295
296
  raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 || curly_stack != 0 || paren_stack != 0
296
297
  # types.push ComplexType.new([UniqueType.new(base, subtype_string)])
297
- types.push UniqueType.new(base.strip, subtype_string.strip)
298
+ types.push UniqueType.parse(base.strip, subtype_string.strip)
298
299
  end
299
300
  unless key_types.nil?
300
301
  raise ComplexTypeError, "Invalid use of key/value parameters" unless partial
@@ -311,18 +312,33 @@ module Solargraph
311
312
  def try_parse *strings
312
313
  parse *strings
313
314
  rescue ComplexTypeError => e
314
- Solargraph.logger.info "Error parsing complex type: #{e.message}"
315
+ Solargraph.logger.info "Error parsing complex type `#{strings.join(', ')}`: #{e.message}"
315
316
  ComplexType::UNDEFINED
316
317
  end
317
318
  end
318
319
 
319
320
  VOID = ComplexType.parse('void')
320
321
  UNDEFINED = ComplexType.parse('undefined')
321
- SYMBOL = ComplexType.parse('Symbol')
322
- ROOT = ComplexType.parse('Class<>')
322
+ SYMBOL = ComplexType.parse('::Symbol')
323
+ ROOT = ComplexType.parse('::Class<>')
323
324
  NIL = ComplexType.parse('nil')
324
325
  SELF = ComplexType.parse('self')
325
- BOOLEAN = ComplexType.parse('Boolean')
326
+ BOOLEAN = ComplexType.parse('::Boolean')
326
327
  BOT = ComplexType.parse('bot')
328
+
329
+ private
330
+
331
+ # @todo This is a quick and dirty hack that forces `self` keywords
332
+ # to reference an instance of their class and never the class itself.
333
+ # This behavior may change depending on which result is expected
334
+ # from YARD conventions. See https://github.com/lsegal/yard/issues/1257
335
+ # @param dst [String]
336
+ # @return [String]
337
+ def reduce_class dst
338
+ while dst =~ /^(Class|Module)\<(.*?)\>$/
339
+ dst = dst.sub(/^(Class|Module)\</, '').sub(/\>$/, '')
340
+ end
341
+ dst
342
+ end
327
343
  end
328
344
  end
@@ -18,9 +18,11 @@ module Solargraph
18
18
 
19
19
  # @param requires [Array<String>]
20
20
  # @param preferences [Array<Gem::Specification>]
21
- def initialize(requires, preferences)
21
+ # @param rbs_path [String, Pathname, nil]
22
+ def initialize(requires, preferences, rbs_path = nil)
22
23
  @requires = requires.compact
23
24
  @preferences = preferences.compact
25
+ @rbs_path = rbs_path
24
26
  generate
25
27
  end
26
28
 
@@ -39,6 +41,7 @@ module Solargraph
39
41
  @gems_in_memory ||= {}
40
42
  end
41
43
 
44
+ # @return [Set<Gem::Specification>]
42
45
  def dependencies
43
46
  @dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
44
47
  end
@@ -57,6 +60,7 @@ module Solargraph
57
60
  end
58
61
  end
59
62
  dependencies.each { |dep| try_cache dep }
63
+ @uncached_gemspecs.uniq!
60
64
  end
61
65
 
62
66
  # @return [Hash{String => Gem::Specification, nil}]
@@ -75,7 +79,8 @@ module Solargraph
75
79
  return if try_gem_in_memory(gemspec)
76
80
  cache_file = File.join('gems', "#{gemspec.name}-#{gemspec.version}.ser")
77
81
  if Cache.exist?(cache_file)
78
- gempins = Cache.load(cache_file)
82
+ cached = Cache.load(cache_file)
83
+ gempins = update_from_collection(gemspec, cached)
79
84
  self.class.gems_in_memory[gemspec] = gempins
80
85
  @pins.concat gempins
81
86
  else
@@ -93,7 +98,7 @@ module Solargraph
93
98
  @pins.concat map.pins
94
99
  else
95
100
  # @todo Temporarily ignoring unresolved `require 'set'`
96
- Solargraph.logger.warn "Require path #{path} could not be resolved" unless path == 'set'
101
+ Solargraph.logger.debug "Require path #{path} could not be resolved" unless path == 'set'
97
102
  end
98
103
  end
99
104
 
@@ -107,6 +112,17 @@ module Solargraph
107
112
  true
108
113
  end
109
114
 
115
+ def update_from_collection gemspec, gempins
116
+ return gempins unless @rbs_path && File.directory?(@rbs_path)
117
+ return gempins if RbsMap.new(gemspec.name, gemspec.version).resolved?
118
+
119
+ rbs_map = RbsMap.new(gemspec.name, gemspec.version, directories: [@rbs_path])
120
+ return gempins unless rbs_map.resolved?
121
+
122
+ Solargraph.logger.info "Updating #{gemspec.name} #{gemspec.version} from collection"
123
+ GemPins.combine(gempins, rbs_map)
124
+ end
125
+
110
126
  # @param path [String]
111
127
  # @return [Gem::Specification, nil]
112
128
  def resolve_path_to_gemspec path
@@ -16,13 +16,21 @@ module Solargraph
16
16
  def self.build(gemspec)
17
17
  yard_pins = build_yard_pins(gemspec)
18
18
  rbs_map = RbsMap.from_gemspec(gemspec)
19
+ combine yard_pins, rbs_map
20
+ end
21
+
22
+ # @param yard_pins [Array<Pin::Base>]
23
+ # @param rbs_map [RbsMap]
24
+ # @return [Array<Pin::Base>]
25
+ def self.combine(yard_pins, rbs_map)
19
26
  in_yard = Set.new
20
27
  combined = yard_pins.map do |yard|
21
28
  in_yard.add yard.path
22
29
  next yard unless yard.is_a?(Pin::Method)
30
+
23
31
  rbs = rbs_map.path_pin(yard.path, Pin::Method)
24
32
  next yard unless rbs
25
- # @todo Could not include: attribute and anon_splat
33
+
26
34
  # @sg-ignore
27
35
  yard.class.new(
28
36
  location: yard.location,
@@ -34,7 +34,7 @@ module Solargraph
34
34
  def update_libraries uri
35
35
  src = sources.find(uri)
36
36
  using = libraries.select { |lib| lib.contain?(src.filename) }
37
- using.push generic_library_for(uri) if using.empty?
37
+ using.push library_for(uri) if using.empty?
38
38
  using.each { |lib| lib.merge src }
39
39
  diagnoser.schedule uri
40
40
  end
@@ -114,6 +114,13 @@ module Solargraph
114
114
  # @return [Library]
115
115
  def generic_library
116
116
  @generic_library ||= Solargraph::Library.new(Solargraph::Workspace.new('', nil, options), nil)
117
+ .tap { |lib| lib.add_observer self }
118
+ end
119
+
120
+ # @param library [Solargraph::Library]
121
+ # @return [void]
122
+ def update progress
123
+ progress&.send(self)
117
124
  end
118
125
  end
119
126
  end
@@ -11,54 +11,10 @@ module Solargraph
11
11
  include Observable
12
12
  include UriHelpers
13
13
 
14
- def initialize
15
- @mutex = Mutex.new
16
- @stopped = true
17
- @has_uri = ConditionVariable.new
18
- end
19
-
20
- def stopped?
21
- @stopped
22
- end
23
-
24
- # @return [void]
25
- def start
26
- return unless @stopped
27
- @stopped = false
28
- Thread.new do
29
- tick until stopped?
30
- end
31
- end
32
-
33
- # @return [void]
34
- def tick
35
- uri = mutex.synchronize { next_uri }
36
-
37
- return if queue.include?(uri)
38
- mutex.synchronize do
39
- nxt = open_source_hash[uri].finish_synchronize
40
- open_source_hash[uri] = nxt
41
- changed
42
- notify_observers uri
43
- end
44
- end
45
-
46
14
  # @param uri [String]
47
15
  # @return [void]
48
16
  def add_uri(uri)
49
17
  queue.push(uri)
50
- @has_uri.signal
51
- end
52
-
53
- # @return [String]
54
- def next_uri
55
- @has_uri.wait(mutex) if queue.empty?
56
- queue.shift
57
- end
58
-
59
- # @return [void]
60
- def stop
61
- @stopped = true
62
18
  end
63
19
 
64
20
  # Open a source.
@@ -89,20 +45,7 @@ module Solargraph
89
45
  # @return [void]
90
46
  def update uri, updater
91
47
  src = find(uri)
92
- mutex.synchronize { open_source_hash[uri] = src.synchronize(updater) }
93
- changed
94
- notify_observers uri
95
- end
96
-
97
- # @param uri [String]
98
- # @param updater [Source::Updater]
99
- # @return [void]
100
- def async_update uri, updater
101
- src = find(uri)
102
- mutex.synchronize do
103
- open_source_hash[uri] = src.start_synchronize(updater)
104
- add_uri(uri)
105
- end
48
+ open_source_hash[uri] = src.synchronize(updater)
106
49
  changed
107
50
  notify_observers uri
108
51
  end
@@ -144,9 +87,6 @@ module Solargraph
144
87
  @open_source_hash ||= {}
145
88
  end
146
89
 
147
- # @return [Mutex]
148
- attr_reader :mutex
149
-
150
90
  # An array of source URIs that are waiting to finish synchronizing.
151
91
  #
152
92
  # @return [::Array<String>]