solargraph 0.26.1 → 0.27.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +5 -2
  3. data/lib/solargraph/api_map.rb +236 -234
  4. data/lib/solargraph/api_map/store.rb +18 -53
  5. data/lib/solargraph/bundle.rb +22 -0
  6. data/lib/solargraph/complex_type.rb +9 -5
  7. data/lib/solargraph/complex_type/type_methods.rb +113 -0
  8. data/lib/solargraph/complex_type/unique_type.rb +35 -0
  9. data/lib/solargraph/core_fills.rb +1 -0
  10. data/lib/solargraph/diagnostics.rb +6 -4
  11. data/lib/solargraph/diagnostics/base.rb +3 -0
  12. data/lib/solargraph/diagnostics/require_not_found.rb +2 -1
  13. data/lib/solargraph/diagnostics/rubocop.rb +21 -6
  14. data/lib/solargraph/diagnostics/type_not_defined.rb +4 -3
  15. data/lib/solargraph/diagnostics/update_errors.rb +18 -0
  16. data/lib/solargraph/language_server/host.rb +90 -222
  17. data/lib/solargraph/language_server/host/cataloger.rb +68 -0
  18. data/lib/solargraph/language_server/host/diagnoser.rb +85 -0
  19. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +35 -24
  20. data/lib/solargraph/language_server/message/text_document/completion.rb +6 -8
  21. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
  22. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +0 -1
  23. data/lib/solargraph/language_server/transport/socket.rb +4 -6
  24. data/lib/solargraph/language_server/transport/stdio.rb +4 -6
  25. data/lib/solargraph/library.rb +152 -99
  26. data/lib/solargraph/live_map.rb +1 -1
  27. data/lib/solargraph/location.rb +28 -0
  28. data/lib/solargraph/pin.rb +2 -0
  29. data/lib/solargraph/pin/attribute.rb +26 -12
  30. data/lib/solargraph/pin/base.rb +15 -35
  31. data/lib/solargraph/pin/base_variable.rb +7 -15
  32. data/lib/solargraph/pin/block.rb +5 -9
  33. data/lib/solargraph/pin/block_parameter.rb +9 -7
  34. data/lib/solargraph/pin/conversions.rb +5 -5
  35. data/lib/solargraph/pin/duck_method.rb +1 -1
  36. data/lib/solargraph/pin/instance_variable.rb +0 -4
  37. data/lib/solargraph/pin/keyword.rb +4 -0
  38. data/lib/solargraph/pin/localized.rb +5 -3
  39. data/lib/solargraph/pin/method.rb +11 -0
  40. data/lib/solargraph/pin/namespace.rb +7 -3
  41. data/lib/solargraph/pin/proxy_type.rb +3 -7
  42. data/lib/solargraph/pin/reference.rb +2 -2
  43. data/lib/solargraph/pin/symbol.rb +1 -1
  44. data/lib/solargraph/pin/yard_pin/method.rb +2 -2
  45. data/lib/solargraph/pin/yard_pin/namespace.rb +16 -7
  46. data/lib/solargraph/position.rb +103 -0
  47. data/lib/solargraph/range.rb +70 -0
  48. data/lib/solargraph/source.rb +159 -328
  49. data/lib/solargraph/source/chain.rb +38 -55
  50. data/lib/solargraph/source/chain/call.rb +47 -29
  51. data/lib/solargraph/source/chain/class_variable.rb +2 -2
  52. data/lib/solargraph/source/chain/constant.rb +3 -3
  53. data/lib/solargraph/source/chain/definition.rb +7 -3
  54. data/lib/solargraph/source/chain/global_variable.rb +1 -1
  55. data/lib/solargraph/source/chain/head.rb +22 -9
  56. data/lib/solargraph/source/chain/instance_variable.rb +2 -2
  57. data/lib/solargraph/source/chain/link.rb +4 -4
  58. data/lib/solargraph/source/chain/literal.rb +1 -1
  59. data/lib/solargraph/source/chain/variable.rb +2 -2
  60. data/lib/solargraph/source/change.rb +0 -6
  61. data/lib/solargraph/source/cursor.rb +161 -0
  62. data/lib/solargraph/source/encoding_fixes.rb +1 -1
  63. data/lib/solargraph/source/node_chainer.rb +28 -21
  64. data/lib/solargraph/source/node_methods.rb +1 -1
  65. data/lib/solargraph/source/source_chainer.rb +217 -0
  66. data/lib/solargraph/source_map.rb +138 -0
  67. data/lib/solargraph/source_map/clip.rb +123 -0
  68. data/lib/solargraph/{source → source_map}/completion.rb +3 -3
  69. data/lib/solargraph/{source → source_map}/mapper.rb +143 -41
  70. data/lib/solargraph/version.rb +1 -1
  71. data/lib/solargraph/workspace.rb +13 -20
  72. data/lib/solargraph/yard_map.rb +77 -48
  73. metadata +17 -11
  74. data/lib/solargraph/basic_type.rb +0 -33
  75. data/lib/solargraph/basic_type_methods.rb +0 -111
  76. data/lib/solargraph/source/call_chainer.rb +0 -273
  77. data/lib/solargraph/source/fragment.rb +0 -342
  78. data/lib/solargraph/source/location.rb +0 -23
  79. data/lib/solargraph/source/position.rb +0 -95
  80. data/lib/solargraph/source/range.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54749425491eea537bc8a0ef4878e21fd17aee1c88e3575a44fecbdbfe323498
4
- data.tar.gz: 2c61f75cb843a534dc8779245a5395f3d38f411efd3cb0350cfc473b53d7e290
3
+ metadata.gz: 46fca036521e6830f95550138d35e1c504cec3f75c04b45ff9ce3cf06cbafc30
4
+ data.tar.gz: 32fd1c0b308a3c5b89f00bbd4b8f804aba057d8277ccafb5505f7e787dca3fb3
5
5
  SHA512:
6
- metadata.gz: 76bb57c0cc0843d3a71c8ee3afa65d4f14282455d43f3fcd0fa471387ff547873476cb39c5164f8ea0499d1586d7e34f1dbb14c701c7aab02abfc9de06fad676
7
- data.tar.gz: 37cc582ea792270dbe447e356b575ef2d81e76b4af9805428048589b59ef0a6f20a3c70b169631a83a1fdfb328b0ce39550b14d497fb5aad6b8f89b67a2c5a96
6
+ metadata.gz: '07263532728a958734568023619dedbd8b2fcc1c5b84aa9a4432c4af8c247f5cf47343861ee15ef8b377371c35ed96e05367d34781fbb49b1dcf120cc5f1893b'
7
+ data.tar.gz: 1bc3fddcfc98cee8f0287b46e1792f4ff87c51c45bc6ed1281e88ea8473470ef062eebe2e3ac112d63d639c647015c702072840732464b271f68574cf329cf66
@@ -24,8 +24,12 @@ module Solargraph
24
24
  end
25
25
  end
26
26
 
27
+ autoload :Position, 'solargraph/position'
28
+ autoload :Range, 'solargraph/range'
29
+ autoload :Location, 'solargraph/location'
27
30
  autoload :Shell, 'solargraph/shell'
28
31
  autoload :Source, 'solargraph/source'
32
+ autoload :SourceMap, 'solargraph/source_map'
29
33
  autoload :ApiMap, 'solargraph/api_map'
30
34
  autoload :YardMap, 'solargraph/yard_map'
31
35
  autoload :Pin, 'solargraph/pin'
@@ -38,9 +42,8 @@ module Solargraph
38
42
  autoload :Page, 'solargraph/page'
39
43
  autoload :Library, 'solargraph/library'
40
44
  autoload :Diagnostics, 'solargraph/diagnostics'
41
- autoload :BasicTypeMethods, 'solargraph/basic_type_methods'
42
- autoload :BasicType, 'solargraph/basic_type'
43
45
  autoload :ComplexType, 'solargraph/complex_type'
46
+ autoload :Bundle, 'solargraph/bundle'
44
47
 
45
48
  YARDOC_PATH = File.join(File.realpath(File.dirname(__FILE__)), '..', 'yardoc')
46
49
  YARD_EXTENSION_FILE = File.join(File.realpath(File.dirname(__FILE__)), 'yard-solargraph.rb')
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'set'
3
- require 'time'
4
3
 
5
4
  module Solargraph
6
5
  # An aggregate provider for information about workspaces, sources, gems, and
@@ -12,132 +11,147 @@ module Solargraph
12
11
  autoload :Store, 'solargraph/api_map/store'
13
12
 
14
13
  include Solargraph::ApiMap::SourceToYard
15
- include CoreFills
16
-
17
- # The workspace to analyze and process.
18
- #
19
- # @return [Solargraph::Workspace]
20
- attr_reader :workspace
21
14
 
22
15
  # Get a LiveMap associated with the current workspace.
23
16
  #
24
17
  # @return [Solargraph::LiveMap]
25
18
  attr_reader :live_map
26
19
 
27
- # @param workspace [Solargraph::Workspace]
28
- def initialize workspace = Solargraph::Workspace.new(nil)
29
- @workspace = workspace
30
- require_extensions
31
- @virtual_source = nil
32
- @sources = workspace.sources
33
- refresh_store_and_maps
34
- end
35
-
36
- # Create an ApiMap with a workspace in the specified directory.
37
- #
38
- # @param directory [String]
39
- # @return [ApiMap]
40
- def self.load directory
41
- self.new(Solargraph::Workspace.new(directory))
42
- end
43
-
44
- # @return [Array<Solargraph::Pin::Base>]
45
- def pins
46
- store.pins
47
- end
48
-
49
20
  # @return [Array<String>]
50
- def domains
51
- @domains ||= []
52
- end
21
+ attr_reader :unresolved_requires
53
22
 
54
- # An array of required paths in the workspace.
23
+ # @param pins [Array<Solargraph::Pin::Base>]
24
+ # @param yard_map [YardMap]
25
+ # def initialize workspace = Solargraph::Workspace.new(nil)
26
+ def initialize pins: []
27
+ # @todo Extensions don't work yet
28
+ # require_extensions
29
+ @source_map_hash = {}
30
+ @cache = Cache.new
31
+ @mutex = Mutex.new
32
+ index pins
33
+ end
34
+
35
+ # @param pins [Array<Pin::Base>]
36
+ # @return [self]
37
+ def index pins
38
+ @mutex.synchronize {
39
+ @source_map_hash.clear
40
+ @cache.clear
41
+ @store = Store.new(pins + YardMap.new.pins)
42
+ @unresolved_requires = []
43
+ }
44
+ self
45
+ end
46
+
47
+ # @param source [Source]
48
+ # @return [self]
49
+ def map source
50
+ catalog Bundle.new(sources: [source])
51
+ self
52
+ end
53
+
54
+ # Catalog a workspace. Additional sources that need to be mapped can be
55
+ # included in an optional array.
55
56
  #
56
- # @return [Array<String>]
57
- def required
58
- result = []
59
- @sources.each do |s|
60
- result.concat s.required.map(&:name)
57
+ # @param bundle [Bundle]
58
+ # @return [self]
59
+ def catalog bundle
60
+ # @todo This can be more efficient. We don't need to remap sources that
61
+ # are already here.
62
+ # all_sources = (workspace.sources + others).uniq
63
+ new_map_hash = {}
64
+ unmerged = false
65
+ bundle.sources.each do |source|
66
+ if source_map_hash.has_key?(source.filename)
67
+ if source_map_hash[source.filename].code == source.code
68
+ new_map_hash[source.filename] = source_map_hash[source.filename]
69
+ else
70
+ map = Solargraph::SourceMap.map(source)
71
+ if source_map_hash[source.filename].try_merge!(map)
72
+ new_map_hash[source.filename] = source_map_hash[source.filename]
73
+ else
74
+ new_map_hash[source.filename] = map
75
+ unmerged = true
76
+ end
77
+ end
78
+ else
79
+ map = Solargraph::SourceMap.map(source)
80
+ new_map_hash[source.filename] = map
81
+ unmerged = true
82
+ end
61
83
  end
62
- result.concat workspace.config.required
63
- result.uniq
64
- end
65
-
66
- # Declare a virtual source that will be included in the map regardless of
67
- # whether it's in the workspace.
68
- #
69
- # If the source is in the workspace, virtualizing it has no effect. Only
70
- # one source can be virtualized at a time.
71
- #
72
- # @param source [Solargraph::Source]
73
- # @return [Solargraph::Source]
74
- def virtualize source
75
- # @todo Confirm the correct way to handle caches
76
- cache.clear if (source.nil? and !@virtual_source.nil?) or (!source.nil? and !@virtual_source.nil? and source.pins != @virtual_source.pins)
77
- store.remove @virtual_source unless @virtual_source.nil?
78
- domains.clear
79
- domains.concat workspace.config.domains
80
- domains.concat source.domains unless source.nil?
81
- domains.uniq!
82
- if workspace.has_source?(source)
83
- @sources = workspace.sources
84
- @virtual_source = nil
85
- else
86
- @virtual_source = source
87
- @sources = workspace.sources
88
- unless @virtual_source.nil?
89
- @sources.push @virtual_source
90
- process_virtual
84
+ return self unless unmerged
85
+ pins = []
86
+ reqs = []
87
+ # @param map [SourceMap]
88
+ new_map_hash.values.each do |map|
89
+ pins.concat map.pins
90
+ reqs.concat map.requires.map(&:name)
91
+ end
92
+ reqs.concat bundle.required
93
+ unless bundle.load_paths.empty?
94
+ reqs.delete_if do |r|
95
+ result = false
96
+ bundle.load_paths.each do |l|
97
+ if new_map_hash.keys.include?(File.join(l, "#{r}.rb"))
98
+ result = true
99
+ break
100
+ end
101
+ end
102
+ result
91
103
  end
92
104
  end
93
- source
105
+ bundle.yard_map.change(reqs)
106
+ new_store = Store.new(pins + bundle.yard_map.pins)
107
+ @mutex.synchronize {
108
+ @cache.clear
109
+ @source_map_hash = new_map_hash
110
+ @store = new_store
111
+ @unresolved_requires = bundle.yard_map.unresolved_requires
112
+ }
113
+ self
94
114
  end
95
115
 
96
- # Create a Source from the code and filename, and virtualize the result.
97
- # This method can be useful for directly testing the ApiMap. In practice,
98
- # applications should use a Library to synchronize the ApiMap to a
99
- # workspace.
100
- #
101
- # @param code [String]
102
116
  # @param filename [String]
103
- # @return [Solargraph::Source]
104
- def virtualize_string code, filename = nil
105
- source = Source.load_string(code, filename)
106
- virtualize source
117
+ # @param position [Position]
118
+ # @return [Source::Cursor]
119
+ def cursor_at filename, position
120
+ raise "File not found: #{filename}" unless source_map_hash.has_key?(filename)
121
+ source_map_hash[filename].cursor_at(position)
107
122
  end
108
123
 
109
- # Refresh the ApiMap. This method checks for pending changes before
110
- # performing the refresh unless the `force` parameter is true.
124
+ # Get a clip by filename and position.
111
125
  #
112
- # @param force [Boolean] Perform a refresh even if the map is not "stale."
113
- # @return [Boolean] True if a refresh was performed.
114
- def refresh force = false
115
- return false unless force or changed?
116
- if force
117
- refresh_store_and_maps
118
- else
119
- update_store_and_maps
120
- end
121
- true
126
+ # @param filename [String]
127
+ # @param position [Position]
128
+ # @return [SourceMap::Clip]
129
+ def clip_at filename, position
130
+ SourceMap::Clip.new(self, cursor_at(filename, position))
122
131
  end
123
132
 
124
- # True if a workspace file has been created, modified, or deleted since
125
- # the last time the map was processed.
133
+ # Create an ApiMap with a workspace in the specified directory.
126
134
  #
127
- # @return [Boolean]
128
- def changed?
129
- return true if current_workspace_sources.length != workspace.sources.length
130
- return true if @stime.nil?
131
- return true if workspace.stime > @stime
132
- return true if !@virtual_source.nil? and @virtual_source.stime > @stime
133
- false
135
+ # @param directory [String]
136
+ # @return [ApiMap]
137
+ def self.load directory
138
+ # @todo How should this work?
139
+ api_map = self.new #(Solargraph::Workspace.new(directory))
140
+ workspace = Solargraph::Workspace.new(directory)
141
+ api_map.catalog Bundle.new(sources: workspace.sources)
142
+ api_map
143
+ end
144
+
145
+ # @return [Array<Solargraph::Pin::Base>]
146
+ def pins
147
+ store.pins
134
148
  end
135
149
 
136
150
  # An array of suggestions based on Ruby keywords (`if`, `end`, etc.).
137
151
  #
138
152
  # @return [Array<Solargraph::Pin::Keyword>]
139
153
  def self.keywords
140
- @keywords ||= KEYWORDS.map{ |s|
154
+ @keywords ||= CoreFills::KEYWORDS.map{ |s|
141
155
  Pin::Keyword.new(s)
142
156
  }.freeze
143
157
  end
@@ -190,34 +204,26 @@ module Solargraph
190
204
  # Get a fully qualified namespace name. This method will start the search
191
205
  # in the specified context until it finds a match for the name.
192
206
  #
193
- # @param namespace [String] The namespace to match
207
+ # @param namespace [String, nil] The namespace to match
194
208
  # @param context [String] The context to search
195
209
  # @return [String]
196
210
  def qualify namespace, context = ''
197
211
  # @todo The return for self might work better elsewhere
212
+ return nil if namespace.nil?
198
213
  return qualify(context) if namespace == 'self'
199
214
  cached = cache.get_qualified_namespace(namespace, context)
200
215
  return cached.clone unless cached.nil?
201
- result = inner_qualify(namespace, context, [])
216
+ # result = inner_qualify(namespace, context, [])
217
+ # result = result[2..-1] if !result.nil? && result.start_with?('::')
218
+ if namespace.start_with?('::')
219
+ result = inner_qualify(namespace[2..-1], '', [])
220
+ else
221
+ result = inner_qualify(namespace, context, [])
222
+ end
202
223
  cache.set_qualified_namespace(namespace, context, result)
203
224
  result
204
225
  end
205
226
 
206
- def fragment_at(location)
207
- @sources.each do |source|
208
- return source.fragment_at(location.range.start.line, location.range.start.column) if source.filename == location.filename
209
- end
210
- nil
211
- end
212
-
213
- # @deprecated Use #qualify instead
214
- # @param namespace [String]
215
- # @param context [String]
216
- # @return [String]
217
- def find_fully_qualified_namespace namespace, context = ''
218
- qualify namespace, context
219
- end
220
-
221
227
  # Get an array of instance variable pins defined in specified namespace
222
228
  # and scope.
223
229
  #
@@ -225,7 +231,14 @@ module Solargraph
225
231
  # @param scope [Symbol] :instance or :class
226
232
  # @return [Array<Solargraph::Pin::InstanceVariable>]
227
233
  def get_instance_variable_pins(namespace, scope = :instance)
228
- store.get_instance_variables(namespace, scope)
234
+ result = []
235
+ result.concat store.get_instance_variables(namespace, scope)
236
+ sc = qualify(store.get_superclass(namespace), namespace)
237
+ until sc.nil?
238
+ result.concat store.get_instance_variables(sc, scope)
239
+ sc = qualify(store.get_superclass(sc), sc)
240
+ end
241
+ result
229
242
  end
230
243
 
231
244
  # Get an array of class variable pins for a namespace.
@@ -241,21 +254,10 @@ module Solargraph
241
254
  store.get_symbols
242
255
  end
243
256
 
244
- # @todo Make this better
245
- def get_source filename
246
- @sources.each do |s|
247
- return s if s.filename == filename
248
- end
249
- nil
250
- end
251
-
252
257
  # @return [Array<Solargraph::Pin::GlobalVariable>]
253
258
  def get_global_variable_pins
254
- globals = []
255
- @sources.each do |s|
256
- globals.concat s.global_variable_pins
257
- end
258
- globals
259
+ # @todo Slow version
260
+ pins.select{|p| p.kind == Pin::GLOBAL_VARIABLE}
259
261
  end
260
262
 
261
263
  # Get an array of methods available in a particular context.
@@ -271,21 +273,22 @@ module Solargraph
271
273
  result = []
272
274
  skip = []
273
275
  if fqns == ''
274
- domains.each do |domain|
275
- type = ComplexType.parse(domain).first
276
- result.concat inner_get_methods(type.name, type.scope, [:public], deep, skip)
277
- end
276
+ # @todo Implement domains
277
+ # domains.each do |domain|
278
+ # type = ComplexType.parse(domain).first
279
+ # result.concat inner_get_methods(type.name, type.scope, [:public], deep, skip)
280
+ # end
278
281
  result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
279
282
  result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
280
283
  result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
281
284
  else
282
285
  result.concat inner_get_methods(fqns, scope, visibility, deep, skip)
283
286
  end
284
- live = live_map.get_methods(fqns, '', scope.to_s, visibility.include?(:private))
285
- unless live.empty?
286
- exist = result.map(&:name)
287
- result.concat live.reject{|p| exist.include?(p.name)}
288
- end
287
+ # live = live_map.get_methods(fqns, '', scope.to_s, visibility.include?(:private))
288
+ # unless live.empty?
289
+ # exist = result.map(&:name)
290
+ # result.concat live.reject{|p| exist.include?(p.name)}
291
+ # end
289
292
  cache.set_methods(fqns, scope, visibility, deep, result)
290
293
  result
291
294
  end
@@ -296,21 +299,17 @@ module Solargraph
296
299
  # @param context [String]
297
300
  # @return [Array<Solargraph::Pin::Base>]
298
301
  def get_complex_type_methods type, context = '', internal = false
299
- return [] if type.undefined? or type.void?
302
+ return [] if type.undefined? || type.void?
300
303
  result = []
301
304
  if type.duck_type?
302
305
  type.select(&:duck_type?).each do |t|
303
306
  result.push Pin::DuckMethod.new(nil, t.tag[1..-1])
304
307
  end
305
308
  else
306
- unless type.nil? or type.name == 'void'
309
+ unless type.nil? || type.name == 'void'
307
310
  namespace = qualify(type.namespace, context)
308
- if ['Class', 'Module'].include?(namespace) and !type.subtypes.empty?
309
- subtype = qualify(type.subtypes.first.name, context)
310
- result.concat get_methods(subtype, scope: :class)
311
- end
312
311
  visibility = [:public]
313
- if namespace == context or super_and_sub?(namespace, context)
312
+ if namespace == context || super_and_sub?(namespace, context)
314
313
  visibility.push :protected
315
314
  visibility.push :private if internal
316
315
  end
@@ -333,9 +332,9 @@ module Solargraph
333
332
  # @param scope [Symbol] :instance or :class
334
333
  # @return [Array<Solargraph::Pin::Base>]
335
334
  def get_method_stack fqns, name, scope: :instance
336
- # @todo Caches don't work on this query
335
+ # @todo This cache is still causing problems.
337
336
  # cached = cache.get_method_stack(fqns, name, scope)
338
- # return cached.clone unless cached.nil?
337
+ # return cached unless cached.nil?
339
338
  result = get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select{|p| p.name == name}
340
339
  # cache.set_method_stack(fqns, name, scope, result)
341
340
  result
@@ -343,19 +342,29 @@ module Solargraph
343
342
 
344
343
  # Get an array of all suggestions that match the specified path.
345
344
  #
345
+ # @deprecated Use #get_path_pins instead.
346
+ #
346
347
  # @param path [String] The path to find
347
348
  # @return [Array<Solargraph::Pin::Base>]
348
349
  def get_path_suggestions path
349
350
  return [] if path.nil?
350
351
  result = []
351
352
  result.concat store.get_path_pins(path)
352
- if result.empty?
353
- lp = live_map.get_path_pin(path)
354
- result.push lp unless lp.nil?
355
- end
353
+ # if result.empty?
354
+ # lp = live_map.get_path_pin(path)
355
+ # result.push lp unless lp.nil?
356
+ # end
356
357
  result
357
358
  end
358
359
 
360
+ # Get an array of pins that match the specified path.
361
+ #
362
+ # @param path [String]
363
+ # @return [Array<Pin::Base>]
364
+ def get_path_pins path
365
+ get_path_suggestions(path)
366
+ end
367
+
359
368
  # Get a list of documented paths that match the query.
360
369
  #
361
370
  # @example
@@ -364,11 +373,10 @@ module Solargraph
364
373
  # @param query [String] The text to match
365
374
  # @return [Array<String>]
366
375
  def search query
367
- rake_yard(store) if @yard_stale
368
- @yard_stale = false
376
+ rake_yard(store)
369
377
  found = []
370
378
  code_object_paths.each do |k|
371
- if found.empty? or (query.include?('.') or query.include?('#')) or !(k.include?('.') or k.include?('#'))
379
+ if found.empty? || (query.include?('.') || query.include?('#')) || !(k.include?('.') || k.include?('#'))
372
380
  found.push k if k.downcase.include?(query.downcase)
373
381
  end
374
382
  end
@@ -383,8 +391,7 @@ module Solargraph
383
391
  # @param path [String] The path to find
384
392
  # @return [Array<YARD::CodeObject::Base>]
385
393
  def document path
386
- rake_yard(store) if @yard_stale
387
- @yard_stale = false
394
+ rake_yard(store)
388
395
  docs = []
389
396
  docs.push code_object_at(path) unless code_object_at(path).nil?
390
397
  docs
@@ -396,74 +403,68 @@ module Solargraph
396
403
  # @return [Array<Pin::Base>]
397
404
  def query_symbols query
398
405
  result = []
399
- @sources.each do |s|
406
+ source_map_hash.values.each do |s|
400
407
  result.concat s.query_symbols(query)
401
408
  end
402
409
  result
403
410
  end
404
411
 
405
- # @param location [Solargraph::Source::Location]
412
+ # @param location [Solargraph::Location]
406
413
  # @return [Solargraph::Pin::Base]
407
414
  def locate_pin location
408
- @sources.each do |source|
409
- pin = source.locate_pin(location)
410
- return pin unless pin.nil?
411
- end
412
- nil
415
+ return nil if location.nil? || !source_map_hash.has_key?(location.filename)
416
+ source_map_hash[location.filename].locate_pin(location)
413
417
  end
414
418
 
415
- # @return [Array<String>]
416
- def unresolved_requires
417
- yard_map.unresolved_requires
419
+ # @raise [FileNotFoundError] if the cursor's file is not in the ApiMap
420
+ # @param cursor [Source::Cursor]
421
+ # @return [SourceMap::Clip]
422
+ def clip cursor
423
+ raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.has_key?(cursor.filename)
424
+ SourceMap::Clip.new(self, cursor)
418
425
  end
419
426
 
420
- private
421
-
422
- # @return [ApiMap::Store]
423
- def store
424
- @store ||= ApiMap::Store.new(@sources, yard_map.pins)
427
+ # Get an array of document symbols from a file.
428
+ #
429
+ # @param filename [String]
430
+ # @return [Array<Pin::Symbol>]
431
+ def document_symbols filename
432
+ return [] unless source_map_hash.has_key?(filename) # @todo Raise error?
433
+ source_map_hash[filename].document_symbols
425
434
  end
426
435
 
427
- # @return [void]
428
- def refresh_store_and_maps
429
- @yard_stale = true
430
- @live_map = Solargraph::LiveMap.new(self)
431
- store.update_yard(yard_map.pins) if yard_map.change(required)
432
- cache.clear
433
- @stime = Time.now
436
+ # Get a source map by filename.
437
+ #
438
+ # @param filename [String]
439
+ # @return [SourceMap]
440
+ def source_map filename
441
+ raise FileNotFoundError, "Source map for `#{filename}` not found" unless source_map_hash.has_key?(filename)
442
+ source_map_hash[filename]
434
443
  end
435
444
 
436
- # @return [void]
437
- def update_store_and_maps
438
- @yard_stale = true
439
- store.remove *(current_workspace_sources.reject{ |s| workspace.sources.include?(s) })
440
- @sources = workspace.sources
441
- @sources.push @virtual_source unless @virtual_source.nil?
442
- store.update *(@sources.select{ |s| @stime.nil? or s.stime > @stime })
443
- store.update_yard(yard_map.pins) if yard_map.change(required)
444
- cache.clear
445
- @stime = Time.now
446
- end
445
+ private
447
446
 
448
- # @return [void]
449
- def process_virtual
450
- map_source @virtual_source unless @virtual_source.nil?
451
- if yard_map.change(required)
452
- store.update_yard(yard_map.pins)
453
- end
454
- cache.clear
447
+ # A hash of source maps with filename keys.
448
+ #
449
+ # @return [Hash{String => SourceMap}]
450
+ def source_map_hash
451
+ @mutex.synchronize {
452
+ @source_map_hash
453
+ }
455
454
  end
456
455
 
457
- # @param source [Solargraph::Source]
458
- # @return [void]
459
- def map_source source
460
- store.update source
461
- path_macros.merge! source.path_macros
456
+ # @return [ApiMap::Store]
457
+ def store
458
+ @mutex.synchronize {
459
+ @store
460
+ }
462
461
  end
463
462
 
464
463
  # @return [Solargraph::ApiMap::Cache]
465
464
  def cache
466
- @cache ||= Cache.new
465
+ @mutex.synchronize {
466
+ @cache
467
+ }
467
468
  end
468
469
 
469
470
  # @param fqns [String] A fully qualified namespace
@@ -471,34 +472,41 @@ module Solargraph
471
472
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
472
473
  # @param deep [Boolean]
473
474
  # @param skip [Array<String>]
475
+ # @param no_core [Boolean] Skip core classes if true
474
476
  # @return [Array<Pin::Base>]
475
- def inner_get_methods fqns, scope, visibility, deep, skip
477
+ def inner_get_methods fqns, scope, visibility, deep, skip, no_core = false
478
+ return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module|Kernel)$/
476
479
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
477
480
  return [] if skip.include?(reqstr)
478
481
  skip.push reqstr
479
482
  result = []
480
- result.concat store.get_attrs(fqns, scope)
481
483
  result.concat store.get_methods(fqns, scope: scope, visibility: visibility)
482
484
  if deep
483
485
  sc = store.get_superclass(fqns)
484
486
  unless sc.nil?
485
- fqsc = qualify(sc, fqns)
486
- result.concat inner_get_methods(fqsc, scope, visibility, true, skip) unless fqsc.nil?
487
+ fqsc = qualify(sc, fqns.split('::')[0..-2].join('::'))
488
+ result.concat inner_get_methods(fqsc, scope, visibility, true, skip, true) unless fqsc.nil?
487
489
  end
488
490
  if scope == :instance
489
- store.get_includes(fqns).each do |im|
491
+ store.get_includes(fqns).reverse.each do |im|
490
492
  fqim = qualify(im, fqns)
491
- result.concat inner_get_methods(fqim, scope, visibility, deep, skip) unless fqim.nil?
493
+ result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
492
494
  end
493
- result.concat inner_get_methods('Object', :instance, [:public], deep, skip) unless fqns == 'Object'
495
+ result.concat inner_get_methods('Object', :instance, [:public], deep, skip, no_core)
494
496
  else
495
- store.get_extends(fqns).each do |em|
497
+ store.get_extends(fqns).reverse.each do |em|
496
498
  fqem = qualify(em, fqns)
497
- result.concat inner_get_methods(fqem, :instance, visibility, deep, skip) unless fqem.nil?
499
+ result.concat inner_get_methods(fqem, :instance, visibility, deep, skip, true) unless fqem.nil?
498
500
  end
499
- type = get_namespace_type(fqns)
500
- result.concat inner_get_methods('Class', :instance, fqns == '' ? [:public] : visibility, deep, skip) if type == :class
501
- result.concat inner_get_methods('Module', :instance, fqns == '' ? [:public] : visibility, deep, skip) #if type == :module
501
+ unless no_core || fqns.empty?
502
+ type = get_namespace_type(fqns)
503
+ result.concat inner_get_methods('Class', :instance, visibility, deep, skip, no_core) if type == :class
504
+ result.concat inner_get_methods('Module', :instance,visibility, deep, skip, no_core)
505
+ end
506
+ end
507
+ store.domains(fqns).each do |d|
508
+ dt = ComplexType.parse(d)
509
+ result.concat inner_get_methods(dt.namespace, dt.scope, [:public], deep, skip)
502
510
  end
503
511
  end
504
512
  result
@@ -517,7 +525,7 @@ module Solargraph
517
525
  fqis = qualify(is, fqns)
518
526
  result.concat inner_get_constants(fqis, [:public], skip) unless fqis.nil?
519
527
  end
520
- result.concat live_map.get_constants(fqns)
528
+ # result.concat live_map.get_constants(fqns)
521
529
  result
522
530
  end
523
531
 
@@ -538,11 +546,6 @@ module Solargraph
538
546
  @path_macros ||= {}
539
547
  end
540
548
 
541
- # @return [Array<Solargraph::Source>]
542
- def current_workspace_sources
543
- @sources - [@virtual_source]
544
- end
545
-
546
549
  # @param name [String]
547
550
  # @param root [String]
548
551
  # @param skip [Array<String>]
@@ -571,7 +574,7 @@ module Solargraph
571
574
  return name if store.namespace_exists?(name)
572
575
  end
573
576
  end
574
- live_map.get_fqns(name, root)
577
+ # live_map.get_fqns(name, root)
575
578
  end
576
579
 
577
580
  # Get the namespace's type (Class or Module).
@@ -585,13 +588,6 @@ module Solargraph
585
588
  pin.type
586
589
  end
587
590
 
588
- # Get a YardMap associated with the current workspace.
589
- #
590
- # @return [Solargraph::YardMap]
591
- def yard_map
592
- @yard_map ||= Solargraph::YardMap.new(required: required, workspace: workspace)
593
- end
594
-
595
591
  # Sort an array of pins to put nil or undefined variables last.
596
592
  #
597
593
  # @param pins [Array<Solargraph::Pin::Base>]
@@ -600,7 +596,7 @@ module Solargraph
600
596
  result = []
601
597
  nil_pins = []
602
598
  pins.each do |pin|
603
- if pin.variable? and pin.nil_assignment?
599
+ if pin.variable? && pin.nil_assignment?
604
600
  nil_pins.push pin
605
601
  else
606
602
  result.push pin
@@ -609,11 +605,17 @@ module Solargraph
609
605
  result + nil_pins
610
606
  end
611
607
 
608
+ # Check if a class is a superclass of another class.
609
+ #
610
+ # @param sup [String] The superclass
611
+ # @param sub [String] The subclass
612
+ # @return [Boolean]
612
613
  def super_and_sub?(sup, sub)
613
- cls = store.get_superclass(sub)
614
+ fqsup = qualify(sup)
615
+ cls = qualify(store.get_superclass(sub), sub)
614
616
  until cls.nil?
615
- return true if cls == sup
616
- cls = store.get_superclass(cls)
617
+ return true if cls == fqsup
618
+ cls = qualify(store.get_superclass(cls), cls)
617
619
  end
618
620
  false
619
621
  end