solargraph 0.18.3 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/solargraph/api_map/probe.rb +222 -0
- data/lib/solargraph/api_map/source_to_yard.rb +3 -3
- data/lib/solargraph/api_map/store.rb +135 -0
- data/lib/solargraph/api_map.rb +169 -609
- data/lib/solargraph/diagnostics/rubocop.rb +4 -4
- data/lib/solargraph/language_server/host.rb +53 -19
- data/lib/solargraph/language_server/message/extended/document.rb +1 -1
- data/lib/solargraph/language_server/message/extended/search.rb +1 -1
- data/lib/solargraph/language_server/message/method_not_found.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -15
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -15
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +3 -15
- data/lib/solargraph/language_server/message_types.rb +10 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +8 -0
- data/lib/solargraph/node_methods.rb +6 -1
- data/lib/solargraph/page.rb +2 -1
- data/lib/solargraph/pin/attribute.rb +8 -12
- data/lib/solargraph/pin/base.rb +20 -95
- data/lib/solargraph/pin/base_variable.rb +15 -74
- data/lib/solargraph/pin/block.rb +21 -0
- data/lib/solargraph/pin/block_parameter.rb +30 -44
- data/lib/solargraph/pin/class_variable.rb +3 -0
- data/lib/solargraph/pin/constant.rb +4 -8
- data/lib/solargraph/pin/conversions.rb +4 -3
- data/lib/solargraph/pin/documenting.rb +27 -0
- data/lib/solargraph/pin/global_variable.rb +3 -0
- data/lib/solargraph/pin/instance_variable.rb +5 -4
- data/lib/solargraph/pin/local_variable.rb +8 -15
- data/lib/solargraph/pin/localized.rb +12 -0
- data/lib/solargraph/pin/method.rb +6 -67
- data/lib/solargraph/pin/method_parameter.rb +24 -11
- data/lib/solargraph/pin/namespace.rb +26 -35
- data/lib/solargraph/pin/reference.rb +15 -8
- data/lib/solargraph/pin/symbol.rb +34 -3
- data/lib/solargraph/pin/yard_object.rb +11 -4
- data/lib/solargraph/pin.rb +16 -2
- data/lib/solargraph/server.rb +2 -2
- data/lib/solargraph/source/change.rb +10 -13
- data/lib/solargraph/source/fragment.rb +42 -94
- data/lib/solargraph/source/location.rb +13 -0
- data/lib/solargraph/source/mapper.rb +426 -0
- data/lib/solargraph/source/position.rb +1 -0
- data/lib/solargraph/source/range.rb +11 -3
- data/lib/solargraph/source.rb +93 -284
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +59 -60
- data/lib/solargraph/views/_name_type_tag.erb +10 -0
- data/lib/solargraph/views/_namespace.erb +26 -26
- data/lib/solargraph/views/document.erb +23 -16
- data/lib/solargraph/views/layout.erb +38 -10
- data/lib/solargraph/views/search.erb +12 -11
- data/lib/solargraph/workspace/config.rb +27 -6
- data/lib/solargraph/workspace.rb +10 -2
- data/lib/solargraph.rb +10 -2
- data/lib/yard-solargraph.rb +3 -0
- metadata +25 -20
- data/lib/solargraph/pin/directed/attribute.rb +0 -20
- data/lib/solargraph/pin/directed/method.rb +0 -22
- data/lib/solargraph/pin/directed.rb +0 -9
- data/lib/solargraph/pin/parameter.rb +0 -23
data/lib/solargraph/api_map.rb
CHANGED
@@ -7,6 +7,8 @@ module Solargraph
|
|
7
7
|
autoload :Cache, 'solargraph/api_map/cache'
|
8
8
|
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
9
9
|
autoload :Completion, 'solargraph/api_map/completion'
|
10
|
+
autoload :Probe, 'solargraph/api_map/probe'
|
11
|
+
autoload :Store, 'solargraph/api_map/store'
|
10
12
|
|
11
13
|
include Solargraph::ApiMap::SourceToYard
|
12
14
|
include CoreFills
|
@@ -17,27 +19,41 @@ module Solargraph
|
|
17
19
|
attr_reader :workspace
|
18
20
|
|
19
21
|
# @param workspace [Solargraph::Workspace]
|
20
|
-
def initialize workspace = nil
|
21
|
-
# @todo Deprecate strings for the workspace parameter
|
22
|
-
workspace = Solargraph::Workspace.new(workspace) if workspace.kind_of?(String)
|
23
|
-
workspace = Solargraph::Workspace.new(nil) if workspace.nil?
|
22
|
+
def initialize workspace = Solargraph::Workspace.new(nil)
|
24
23
|
@workspace = workspace
|
25
24
|
require_extensions
|
26
25
|
@virtual_source = nil
|
27
26
|
@yard_stale = true
|
28
|
-
process_maps
|
27
|
+
# process_maps
|
28
|
+
@sources = workspace.sources
|
29
29
|
yard_map
|
30
30
|
end
|
31
31
|
|
32
|
+
# Create an ApiMap with a workspace in the specified directory.
|
33
|
+
#
|
34
|
+
# @return [ApiMap]
|
32
35
|
def self.load directory
|
33
36
|
self.new(Solargraph::Workspace.new(directory))
|
34
37
|
end
|
35
38
|
|
39
|
+
# @return [ApiMap::Store]
|
40
|
+
def store
|
41
|
+
@store ||= ApiMap::Store.new(@sources)
|
42
|
+
end
|
43
|
+
|
44
|
+
def pins
|
45
|
+
store.pins
|
46
|
+
end
|
47
|
+
|
36
48
|
# An array of required paths in the workspace.
|
37
49
|
#
|
38
50
|
# @return [Array<String>]
|
39
51
|
def required
|
40
|
-
|
52
|
+
result = []
|
53
|
+
@sources.each do |s|
|
54
|
+
result.concat s.required
|
55
|
+
end
|
56
|
+
result.uniq
|
41
57
|
end
|
42
58
|
|
43
59
|
# Get a YardMap associated with the current workspace.
|
@@ -65,8 +81,9 @@ module Solargraph
|
|
65
81
|
# one source can be virtualized at a time.
|
66
82
|
#
|
67
83
|
# @param source [Solargraph::Source]
|
84
|
+
# @return [Solargraph::Source]
|
68
85
|
def virtualize source
|
69
|
-
|
86
|
+
store.remove @virtual_source unless @virtual_source.nil?
|
70
87
|
if workspace.has_source?(source)
|
71
88
|
@sources = workspace.sources
|
72
89
|
@virtual_source = nil
|
@@ -78,10 +95,18 @@ module Solargraph
|
|
78
95
|
process_virtual
|
79
96
|
end
|
80
97
|
end
|
98
|
+
source
|
81
99
|
end
|
82
100
|
|
83
|
-
#
|
84
|
-
|
101
|
+
# Create a Source from the code and filename, and virtualize the result.
|
102
|
+
# This method can be useful for directly testing the ApiMap. In practice,
|
103
|
+
# applications should use a Library to synchronize the ApiMap to a
|
104
|
+
# workspace.
|
105
|
+
#
|
106
|
+
# @param code [String]
|
107
|
+
# @param filename [String]
|
108
|
+
# @return [Solargraph::Source]
|
109
|
+
def virtualize_string code, filename = nil
|
85
110
|
source = Source.load_string(code, filename)
|
86
111
|
virtualize source
|
87
112
|
end
|
@@ -92,27 +117,12 @@ module Solargraph
|
|
92
117
|
def refresh force = false
|
93
118
|
return unless @force or changed?
|
94
119
|
if force
|
95
|
-
|
120
|
+
@api_map = ApiMap::Store.new(@sources)
|
96
121
|
else
|
97
|
-
current_workspace_sources.reject{|s| workspace.sources.include?(s)}
|
98
|
-
eliminate source
|
99
|
-
end
|
122
|
+
store.remove *(current_workspace_sources.reject{ |s| workspace.sources.include?(s) })
|
100
123
|
@sources = workspace.sources
|
101
124
|
@sources.push @virtual_source unless @virtual_source.nil?
|
102
|
-
|
103
|
-
namespace_map.clear
|
104
|
-
@sources.each do |s|
|
105
|
-
s.namespaces.each do |n|
|
106
|
-
namespace_map[n] ||= []
|
107
|
-
namespace_map[n].concat s.namespace_pins(n)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
@sources.each do |source|
|
111
|
-
if @stime.nil? or source.stime > @stime
|
112
|
-
eliminate source
|
113
|
-
map_source source
|
114
|
-
end
|
115
|
-
end
|
125
|
+
store.update *(@sources.select{ |s| @stime.nil? or s.stime > @stime })
|
116
126
|
end
|
117
127
|
@stime = Time.new
|
118
128
|
end
|
@@ -142,8 +152,7 @@ module Solargraph
|
|
142
152
|
#
|
143
153
|
# @return [Array<String>]
|
144
154
|
def namespaces
|
145
|
-
|
146
|
-
namespace_map.keys
|
155
|
+
store.namespaces
|
147
156
|
end
|
148
157
|
|
149
158
|
# True if the namespace exists.
|
@@ -152,14 +161,14 @@ module Solargraph
|
|
152
161
|
# @param root [String] The context to search
|
153
162
|
# @return [Boolean]
|
154
163
|
def namespace_exists? name, root = ''
|
155
|
-
!
|
164
|
+
!qualify(name, root).nil?
|
156
165
|
end
|
157
166
|
|
158
167
|
# Get suggestions for constants in the specified namespace. The result
|
159
168
|
# may contain both constant and namespace pins.
|
160
169
|
#
|
161
|
-
# @param
|
162
|
-
# @param
|
170
|
+
# @param namespace [String] The namespace
|
171
|
+
# @param context [String] The context
|
163
172
|
# @return [Array<Solargraph::Pin::Base>]
|
164
173
|
def get_constants namespace, context = ''
|
165
174
|
namespace ||= ''
|
@@ -168,13 +177,13 @@ module Solargraph
|
|
168
177
|
bases = context.split('::')
|
169
178
|
while bases.length > 0
|
170
179
|
built = bases.join('::')
|
171
|
-
fqns =
|
180
|
+
fqns = qualify(namespace, built)
|
172
181
|
visibility = [:public]
|
173
182
|
visibility.push :private if fqns == context
|
174
183
|
result.concat inner_get_constants(fqns, visibility, skip)
|
175
184
|
bases.pop
|
176
185
|
end
|
177
|
-
fqns =
|
186
|
+
fqns = qualify(namespace, '')
|
178
187
|
visibility = [:public]
|
179
188
|
visibility.push :private if fqns == context
|
180
189
|
result.concat inner_get_constants(fqns, visibility, skip)
|
@@ -182,54 +191,18 @@ module Solargraph
|
|
182
191
|
end
|
183
192
|
|
184
193
|
# Get a fully qualified namespace name. This method will start the search
|
185
|
-
# in the specified
|
194
|
+
# in the specified context until it finds a match for the name.
|
186
195
|
#
|
187
|
-
# @param
|
188
|
-
# @param
|
196
|
+
# @param namespace [String] The namespace to match
|
197
|
+
# @param context [String] The context to search
|
189
198
|
# @return [String]
|
190
|
-
def
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
return ''
|
198
|
-
else
|
199
|
-
return find_fully_qualified_namespace(root, '', skip)
|
200
|
-
end
|
201
|
-
else
|
202
|
-
if (root == '')
|
203
|
-
return name unless namespace_map[name].nil?
|
204
|
-
im = @namespace_includes['']
|
205
|
-
unless im.nil?
|
206
|
-
im.each do |i|
|
207
|
-
i.resolve self
|
208
|
-
return i.name unless i.name.nil?
|
209
|
-
end
|
210
|
-
end
|
211
|
-
else
|
212
|
-
roots = root.to_s.split('::')
|
213
|
-
while roots.length > 0
|
214
|
-
fqns = roots.join('::') + '::' + name
|
215
|
-
return fqns unless namespace_map[fqns].nil?
|
216
|
-
roots.pop
|
217
|
-
end
|
218
|
-
return name unless namespace_map[name].nil?
|
219
|
-
im = @namespace_includes['']
|
220
|
-
unless im.nil?
|
221
|
-
im.each do |i|
|
222
|
-
i.resolve self
|
223
|
-
return i.name unless i.name.nil?
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
result = yard_map.find_fully_qualified_namespace(name, root)
|
229
|
-
if result.nil?
|
230
|
-
result = live_map.get_fqns(name, root)
|
231
|
-
end
|
232
|
-
result
|
199
|
+
def qualify namespace, context = ''
|
200
|
+
inner_qualify namespace, context, []
|
201
|
+
end
|
202
|
+
|
203
|
+
# @deprecated Use #qualify instead
|
204
|
+
def find_fully_qualified_namespace namespace, context = ''
|
205
|
+
qualify namespace, context
|
233
206
|
end
|
234
207
|
|
235
208
|
# Get an array of instance variable pins defined in specified namespace
|
@@ -239,13 +212,7 @@ module Solargraph
|
|
239
212
|
# @param scope [Symbol] :instance or :class
|
240
213
|
# @return [Array<Solargraph::Pin::InstanceVariable>]
|
241
214
|
def get_instance_variable_pins(namespace, scope = :instance)
|
242
|
-
|
243
|
-
return [] if raw.nil?
|
244
|
-
# @todo This is a crazy workaround because instance variables in the
|
245
|
-
# global namespace might be in either scope
|
246
|
-
pins = prefer_non_nil_variables(raw)
|
247
|
-
return pins if namespace.empty?
|
248
|
-
pins.select{ |pin| pin.scope == scope }
|
215
|
+
store.get_instance_variables(namespace, scope)
|
249
216
|
end
|
250
217
|
|
251
218
|
# Get an array of class variable pins for a namespace.
|
@@ -258,221 +225,7 @@ module Solargraph
|
|
258
225
|
|
259
226
|
# @return [Array<Solargraph::Pin::Base>]
|
260
227
|
def get_symbols
|
261
|
-
|
262
|
-
@symbol_pins
|
263
|
-
end
|
264
|
-
|
265
|
-
# Find a class, instance, or global variable by name in the provided
|
266
|
-
# namespace and scope.
|
267
|
-
#
|
268
|
-
# @param name [String] The variable name, e.g., `@foo`, `@@bar`, or `$baz`
|
269
|
-
# @param fqns [String] The fully qualified namespace
|
270
|
-
# @param scope [Symbol] :class or :instance
|
271
|
-
# @return [Solargraph::Pin::BaseVariable]
|
272
|
-
def find_variable_pin name, fqns, scope
|
273
|
-
var = nil
|
274
|
-
return nil if name.nil?
|
275
|
-
if name.start_with?('@@')
|
276
|
-
# class variable
|
277
|
-
var = get_class_variable_pins(fqns).select{|pin| pin.name == name}.first
|
278
|
-
return nil if var.nil?
|
279
|
-
elsif name.start_with?('@')
|
280
|
-
# instance variable
|
281
|
-
var = get_instance_variable_pins(fqns, scope).select{|pin| pin.name == name}.first
|
282
|
-
return nil if var.nil?
|
283
|
-
elsif name.start_with?('$')
|
284
|
-
# global variable
|
285
|
-
var = get_global_variable_pins.select{|pin| pin.name == name}.first
|
286
|
-
return nil if var.nil?
|
287
|
-
end
|
288
|
-
var
|
289
|
-
end
|
290
|
-
|
291
|
-
def find_namespace_pin fqns
|
292
|
-
crawl_constants fqns, '', [:public, :private]
|
293
|
-
end
|
294
|
-
|
295
|
-
def crawl_constants name, fqns, visibility
|
296
|
-
return nil if name.nil?
|
297
|
-
chain = name.split('::')
|
298
|
-
cursor = chain.shift
|
299
|
-
return nil if cursor.nil?
|
300
|
-
unless fqns.empty?
|
301
|
-
bases = fqns.split('::')
|
302
|
-
result = nil
|
303
|
-
until bases.empty?
|
304
|
-
built = bases.join('::')
|
305
|
-
result = get_constants(built, '').select{|pin| pin.name == cursor and visibility.include?(pin.visibility)}.first
|
306
|
-
break unless result.nil?
|
307
|
-
bases.pop
|
308
|
-
visibility -= [:private]
|
309
|
-
end
|
310
|
-
return nil if result.nil?
|
311
|
-
end
|
312
|
-
result = get_constants(fqns, '').select{|pin| pin.name == cursor and visibility.include?(pin.visibility)}.first
|
313
|
-
visibility -= [:private]
|
314
|
-
until chain.empty? or result.nil?
|
315
|
-
fqns = result.path
|
316
|
-
cursor = chain.shift
|
317
|
-
result = get_constants(fqns, '').select{|pin| pin.name == cursor and visibility.include?(pin.visibility)}.first
|
318
|
-
end
|
319
|
-
result
|
320
|
-
end
|
321
|
-
|
322
|
-
# This method checks the signature from the namespace's internal context,
|
323
|
-
# i.e., the first word in the signature can be a private or protected
|
324
|
-
# method, a private constant, an instance variable, or a class variable.
|
325
|
-
# Local variables are not accessible.
|
326
|
-
#
|
327
|
-
# @return [String]
|
328
|
-
def infer_type signature, namespace = '', scope: :instance
|
329
|
-
context = combine_type(namespace, scope)
|
330
|
-
parts = signature.split('.')
|
331
|
-
base = parts.shift
|
332
|
-
return nil if base.nil?
|
333
|
-
type = infer_word_type(base, context, true)
|
334
|
-
return nil if type.nil?
|
335
|
-
until parts.empty?
|
336
|
-
word = parts.shift
|
337
|
-
type = infer_method_type(word, type)
|
338
|
-
return nil if type.nil?
|
339
|
-
end
|
340
|
-
type
|
341
|
-
end
|
342
|
-
|
343
|
-
# @return [Solargraph::Pin::Base]
|
344
|
-
def tail_pins signature, fqns, scope, visibility
|
345
|
-
return [] if signature.nil?
|
346
|
-
type = combine_type(fqns, scope)
|
347
|
-
return infer_word_pins(signature, type, true) unless signature.include?('.')
|
348
|
-
parts = signature.split('.')
|
349
|
-
last = parts.pop
|
350
|
-
base = parts.join('.')
|
351
|
-
type = infer_type(base, fqns, scope: scope)
|
352
|
-
return [] if type.nil?
|
353
|
-
infer_word_pins(last, type, true)
|
354
|
-
end
|
355
|
-
|
356
|
-
# @return [Solargraph::Pin::Base]
|
357
|
-
def tail_pin signature, fqns, scope, visibility
|
358
|
-
tail_pins(signature, fqns, scope, visibility).first
|
359
|
-
end
|
360
|
-
|
361
|
-
# Get an array of pins for a word in the provided context. A word can be
|
362
|
-
# a constant, a global variable, or a method name. Private and protected
|
363
|
-
# words are excluded by default. Set the `internal` parameter to `true` to
|
364
|
-
# to include private and protected methods, private constants, instance
|
365
|
-
# variables, and class variables.
|
366
|
-
#
|
367
|
-
# @param word [String]
|
368
|
-
# @param base_type [String]
|
369
|
-
# @param internal [Boolean]
|
370
|
-
# @return [Array<Solargraph::Pin::Base>]
|
371
|
-
def infer_word_pins word, base_type, internal = false
|
372
|
-
pins = []
|
373
|
-
namespace, scope = extract_namespace_and_scope(base_type)
|
374
|
-
if word == 'self' and internal
|
375
|
-
context = (internal ? namespace.split('::')[0..-2].join(';;') : '')
|
376
|
-
fqns = find_fully_qualified_namespace(namespace, context)
|
377
|
-
pins.concat get_path_suggestions(fqns) unless fqns.nil?
|
378
|
-
return pins
|
379
|
-
end
|
380
|
-
fqns = find_fully_qualified_namespace(word, namespace)
|
381
|
-
unless fqns.nil?
|
382
|
-
pins.concat get_path_suggestions(fqns) unless fqns.nil?
|
383
|
-
return pins
|
384
|
-
end
|
385
|
-
if internal
|
386
|
-
if word.start_with?('@@')
|
387
|
-
pins.concat get_class_variable_pins(namespace).select{|pin| pin.name == word}
|
388
|
-
return pins
|
389
|
-
elsif word.start_with?('@')
|
390
|
-
pins.concat get_instance_variable_pins(namespace, scope).select{|pin| pin.name == word}
|
391
|
-
return pins
|
392
|
-
end
|
393
|
-
end
|
394
|
-
if word.start_with?('$')
|
395
|
-
pins.concat get_global_variable_pins.select{|pin| pin.name == word}
|
396
|
-
return pins
|
397
|
-
end
|
398
|
-
pins.concat get_constants(namespace, (internal ? namespace : '')).select{|pin| pin.name == word}
|
399
|
-
if pins.empty?
|
400
|
-
pins.concat get_type_methods(base_type, (internal ? base_type : '')).select{|pin| pin.name == word}
|
401
|
-
pins.concat get_type_methods('Kernel').select{|pin| pin.name == word}
|
402
|
-
end
|
403
|
-
pins
|
404
|
-
end
|
405
|
-
|
406
|
-
# @return [Solargraph::Pin::Base]
|
407
|
-
def infer_word_pin word, base_type, internal = false
|
408
|
-
infer_word_pins(word, base_type, internal).first
|
409
|
-
end
|
410
|
-
|
411
|
-
# @return [String]
|
412
|
-
def infer_word_type word, base_type, internal = false
|
413
|
-
return base_type if word == 'self' and internal
|
414
|
-
if word == 'new'
|
415
|
-
namespace, scope = extract_namespace_and_scope(base_type)
|
416
|
-
return namespace if scope == :class
|
417
|
-
end
|
418
|
-
pin = infer_word_pin(word, base_type, internal)
|
419
|
-
return nil if pin.nil?
|
420
|
-
pin.resolve self
|
421
|
-
pin.return_type
|
422
|
-
end
|
423
|
-
|
424
|
-
# Get an array of pins for a method name in the provided context. Private
|
425
|
-
# and protected methods are excluded by default. Set the `internal`
|
426
|
-
# parameter to `true` to include all methods.
|
427
|
-
#
|
428
|
-
# @param method_name [String] The name of the method
|
429
|
-
# @param base_type [String] The context type (e.g., `String` or `Class<String>`)
|
430
|
-
# @param internal [Boolean] True if the call came from inside the base type
|
431
|
-
# @return [Array<Solargraph::Pin::Base>]
|
432
|
-
def infer_method_pins method_name, base_type, internal = false
|
433
|
-
get_type_methods(base_type, (internal ? base_type : '')).select{|pin| pin.name == method_name}
|
434
|
-
end
|
435
|
-
|
436
|
-
# Get the first pin that matches a method name in the provided context.
|
437
|
-
# Private and protected methods are excluded by default. Set the `internal`
|
438
|
-
# parameter to `true` to include all methods.
|
439
|
-
#
|
440
|
-
# @param method_name [String] The name of the method
|
441
|
-
# @param base_type [String] The context type (e.g., `String` or `Class<String>`)
|
442
|
-
# @param internal [Boolean] True if the call came from inside the base type
|
443
|
-
# @return [Solargraph::Pin::Base]
|
444
|
-
def infer_method_pin method_name, base_type, internal = false
|
445
|
-
infer_method_pins(method_name, base_type, internal).first
|
446
|
-
end
|
447
|
-
|
448
|
-
# Infer the type returned by a method in the provided context. Private and
|
449
|
-
# protected methods are excluded by default. Set the `internal` parameter
|
450
|
-
# to `true` to include all methods.
|
451
|
-
#
|
452
|
-
# @param method_name [String] The name of the method
|
453
|
-
# @param base_type [String] The context type (e.g., `String` or `Class<String>`)
|
454
|
-
# @param internal [Boolean] True if the call came from inside the base type
|
455
|
-
# @return [String]
|
456
|
-
def infer_method_type method_name, base_type, internal = false
|
457
|
-
namespace, scope = extract_namespace_and_scope(base_type)
|
458
|
-
method = infer_method_pin(method_name, base_type, internal)
|
459
|
-
return nil if method.nil?
|
460
|
-
method.resolve self
|
461
|
-
return namespace if method.name == 'new' and scope == :class
|
462
|
-
return base_type if method.return_type == 'self'
|
463
|
-
method.return_type
|
464
|
-
end
|
465
|
-
|
466
|
-
def infer_deep_signature_type chain, base_type
|
467
|
-
return nil if base_type.nil?
|
468
|
-
internal = true
|
469
|
-
until chain.empty?
|
470
|
-
base = chain.shift
|
471
|
-
base_type = infer_method_type(base, base_type, internal)
|
472
|
-
return nil if base_type.nil?
|
473
|
-
internal = false
|
474
|
-
end
|
475
|
-
base_type
|
228
|
+
store.get_symbols
|
476
229
|
end
|
477
230
|
|
478
231
|
# @return [Array<Solargraph::Pin::GlobalVariable>]
|
@@ -484,17 +237,6 @@ module Solargraph
|
|
484
237
|
globals
|
485
238
|
end
|
486
239
|
|
487
|
-
def get_type_methods type, context = ''
|
488
|
-
return [] if type.nil?
|
489
|
-
namespace, scope = extract_namespace_and_scope(type)
|
490
|
-
base = extract_namespace(context)
|
491
|
-
fqns = find_fully_qualified_namespace(namespace, base)
|
492
|
-
return [] if fqns.nil?
|
493
|
-
visibility = [:public]
|
494
|
-
visibility.push :private, :protected if fqns == base
|
495
|
-
get_methods fqns, scope: scope, visibility: visibility
|
496
|
-
end
|
497
|
-
|
498
240
|
def get_methods fqns, scope: :instance, visibility: [:public], deep: true
|
499
241
|
result = []
|
500
242
|
skip = []
|
@@ -511,9 +253,9 @@ module Solargraph
|
|
511
253
|
# @param fragment [Solargraph::Source::Fragment]
|
512
254
|
# @return [ApiMap::Completion]
|
513
255
|
def complete fragment
|
514
|
-
return Completion.new([], fragment.whole_word_range) if fragment.string? or fragment.comment?
|
256
|
+
return Completion.new([], fragment.whole_word_range) if fragment.string? or fragment.comment?
|
515
257
|
result = []
|
516
|
-
if !fragment.signature.include?('.')
|
258
|
+
if !fragment.signature.include?('.') and !fragment.base_literal?
|
517
259
|
if fragment.signature.start_with?('@@')
|
518
260
|
result.concat get_class_variable_pins(fragment.namespace)
|
519
261
|
elsif fragment.signature.start_with?('@')
|
@@ -524,34 +266,38 @@ module Solargraph
|
|
524
266
|
result.concat get_symbols
|
525
267
|
else
|
526
268
|
unless fragment.signature.include?('::')
|
527
|
-
result.concat prefer_non_nil_variables(fragment.
|
528
|
-
result.concat
|
529
|
-
result.concat
|
269
|
+
result.concat prefer_non_nil_variables(fragment.locals)
|
270
|
+
result.concat get_methods(fragment.namespace, scope: fragment.scope, visibility: [:public, :private, :protected])
|
271
|
+
result.concat get_methods('Kernel')
|
530
272
|
result.concat ApiMap.keywords
|
531
273
|
end
|
532
274
|
result.concat get_constants(fragment.base, fragment.namespace)
|
533
275
|
end
|
534
276
|
else
|
535
|
-
if fragment.
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
277
|
+
if fragment.base_literal?
|
278
|
+
pin = get_path_suggestions(fragment.base_literal).select{|pin| pin.kind == Pin::NAMESPACE}.first
|
279
|
+
unless pin.nil?
|
280
|
+
if fragment.base.empty?
|
281
|
+
result.concat get_methods(pin.path)
|
282
|
+
else
|
283
|
+
type = probe.infer_signature_type(fragment.base, pin, fragment.locals)
|
284
|
+
unless type.nil?
|
285
|
+
namespace, scope = extract_namespace_and_scope(type)
|
286
|
+
result.concat get_methods(namespace, scope: scope)
|
287
|
+
end
|
288
|
+
end
|
542
289
|
end
|
543
|
-
|
544
|
-
|
290
|
+
elsif fragment.signature.include?('::') and !fragment.signature.include?('.')
|
291
|
+
result.concat get_constants(fragment.base, fragment.namespace)
|
292
|
+
else
|
293
|
+
type = probe.infer_signature_type(fragment.base, fragment.named_path, fragment.locals)
|
545
294
|
unless type.nil?
|
546
|
-
|
547
|
-
|
548
|
-
next if type.nil?
|
549
|
-
end
|
550
|
-
result.concat get_type_methods(type) unless type.nil?
|
295
|
+
namespace, scope = extract_namespace_and_scope(type)
|
296
|
+
result.concat get_methods(namespace, scope: scope)
|
551
297
|
end
|
552
298
|
end
|
553
299
|
end
|
554
|
-
filtered = result.uniq(&:identifier).select{|s| s.kind !=
|
300
|
+
filtered = result.uniq(&:identifier).select{|s| s.kind != Pin::METHOD or s.name.match(/^[a-z0-9_]*(\!|\?|=)?$/i)}.sort_by.with_index{ |x, idx| [x.name, idx] }
|
555
301
|
Completion.new(filtered, fragment.whole_word_range)
|
556
302
|
end
|
557
303
|
|
@@ -559,74 +305,25 @@ module Solargraph
|
|
559
305
|
# @return [Array<Solargraph::Pin::Base>]
|
560
306
|
def define fragment
|
561
307
|
return [] if fragment.string? or fragment.comment?
|
562
|
-
|
563
|
-
end
|
564
|
-
|
565
|
-
def infer_fragment_type fragment
|
566
|
-
parts = fragment.whole_signature.split('.')
|
567
|
-
base = parts.shift
|
568
|
-
type = nil
|
569
|
-
lvar = prefer_non_nil_variables(fragment.local_variable_pins(base)).first
|
570
|
-
unless lvar.nil?
|
571
|
-
lvar.resolve self
|
572
|
-
type = lvar.return_type
|
573
|
-
return nil if type.nil?
|
574
|
-
end
|
575
|
-
type = infer_word_type(base, fragment.namespace, fragment.scope) if type.nil?
|
576
|
-
return nil if type.nil?
|
577
|
-
until parts.empty?
|
578
|
-
meth = parts.shift
|
579
|
-
type = infer_word_type(meth, type)
|
580
|
-
return nil if type.nil?
|
581
|
-
end
|
582
|
-
type
|
308
|
+
probe.infer_signature_pins fragment.whole_signature, fragment.named_path, fragment.locals
|
583
309
|
end
|
584
310
|
|
311
|
+
# Infer a return type from a fragment. This method will attempt to resolve
|
312
|
+
# signatures.
|
313
|
+
#
|
585
314
|
# @param fragment [Solargraph::Source::Fragment]
|
315
|
+
# @return [String]
|
316
|
+
def infer_type fragment
|
317
|
+
return nil if fragment.string? or fragment.comment?
|
318
|
+
probe.infer_signature_type fragment.whole_signature, fragment.named_path, fragment.locals
|
319
|
+
end
|
320
|
+
|
321
|
+
# @param fragment [Solargraph::Source::Fragment]
|
322
|
+
# @return [Array<Solargraph::Pin::Base>]
|
586
323
|
def signify fragment
|
587
324
|
return [] unless fragment.argument?
|
588
325
|
return [] if fragment.recipient.whole_signature.nil? or fragment.recipient.whole_signature.empty?
|
589
|
-
|
590
|
-
return infer_word_pins(base, fragment.recipient.namespace, true) if rest.nil?
|
591
|
-
type = nil
|
592
|
-
lvar = prefer_non_nil_variables(fragment.local_variable_pins(base)).first
|
593
|
-
unless lvar.nil?
|
594
|
-
lvar.resolve self
|
595
|
-
type = lvar.return_type
|
596
|
-
return [] if type.nil?
|
597
|
-
end
|
598
|
-
type = infer_word_type(base, fragment.namespace, fragment.scope) if type.nil?
|
599
|
-
return [] if type.nil?
|
600
|
-
ns, sc = extract_namespace_and_scope(type)
|
601
|
-
tail_pins(rest, ns, sc, [:public, :private, :protected])
|
602
|
-
end
|
603
|
-
|
604
|
-
# Get the namespace's type (Class or Module).
|
605
|
-
#
|
606
|
-
# @param [String] A fully qualified namespace
|
607
|
-
# @return [Symbol] :class, :module, or nil
|
608
|
-
def get_namespace_type fqns
|
609
|
-
pin = @namespace_path_pins[fqns]
|
610
|
-
return yard_map.get_namespace_type(fqns) if pin.nil?
|
611
|
-
pin.first.type
|
612
|
-
end
|
613
|
-
|
614
|
-
# Convert a namespace and scope into a type.
|
615
|
-
#
|
616
|
-
# @example
|
617
|
-
# combine_type('String', :instance) => 'String'
|
618
|
-
# combine_type('String', :class) => 'Class<String>'
|
619
|
-
#
|
620
|
-
# @param namespace [String]
|
621
|
-
# @param scope [Symbol] :class or :instance
|
622
|
-
def combine_type namespace, scope
|
623
|
-
return '' if namespace.empty?
|
624
|
-
if scope == :instance
|
625
|
-
namespace
|
626
|
-
else
|
627
|
-
type = get_namespace_type(namespace)
|
628
|
-
"#{type == :class ? 'Class' : 'Module'}<#{namespace}>"
|
629
|
-
end
|
326
|
+
probe.infer_signature_pins fragment.recipient.whole_signature, fragment.named_path, fragment.locals
|
630
327
|
end
|
631
328
|
|
632
329
|
# Get an array of all suggestions that match the specified path.
|
@@ -635,28 +332,10 @@ module Solargraph
|
|
635
332
|
# @return [Array<Solargraph::Pin::Base>]
|
636
333
|
def get_path_suggestions path
|
637
334
|
return [] if path.nil?
|
638
|
-
# refresh
|
639
335
|
result = []
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
result = get_methods(parts[0], visibility: [:public, :private, :protected]).select{|s| s.name == parts[1]}
|
644
|
-
elsif path.include?('.')
|
645
|
-
# It's a class method
|
646
|
-
parts = path.split('.')
|
647
|
-
result = get_methods(parts[0], scope: :class, visibility: [:public, :private, :protected]).select{|s| s.name == parts[1]}
|
648
|
-
else
|
649
|
-
# It's a class or module
|
650
|
-
parts = path.split('::')
|
651
|
-
np = @namespace_pins[parts[0..-2].join('::')]
|
652
|
-
unless np.nil?
|
653
|
-
result.concat np.select{|p| p.name == parts.last}
|
654
|
-
end
|
655
|
-
result.concat yard_map.objects(path)
|
656
|
-
end
|
657
|
-
# @todo Resolve the pins?
|
658
|
-
result.map{|pin| pin.resolve(self); pin}
|
659
|
-
# result
|
336
|
+
result.concat store.get_path_pins(path)
|
337
|
+
result.concat yard_map.objects(path)
|
338
|
+
result
|
660
339
|
end
|
661
340
|
|
662
341
|
# Get a list of documented paths that match the query.
|
@@ -702,145 +381,33 @@ module Solargraph
|
|
702
381
|
result
|
703
382
|
end
|
704
383
|
|
705
|
-
def superclass_of fqns
|
706
|
-
found = @superclasses[fqns]
|
707
|
-
return nil if found.nil?
|
708
|
-
found.resolve self
|
709
|
-
found.name
|
710
|
-
end
|
711
|
-
|
712
384
|
def locate_pin location
|
713
385
|
@sources.each do |source|
|
714
386
|
pin = source.locate_pin(location)
|
715
387
|
unless pin.nil?
|
716
|
-
pin.resolve self
|
388
|
+
# pin.resolve self
|
717
389
|
return pin
|
718
390
|
end
|
719
391
|
end
|
720
392
|
nil
|
721
393
|
end
|
722
394
|
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
def namespace_map
|
727
|
-
@namespace_map ||= {}
|
395
|
+
# @return [Probe]
|
396
|
+
def probe
|
397
|
+
@probe ||= Probe.new(self)
|
728
398
|
end
|
729
399
|
|
730
|
-
|
731
|
-
@sources = workspace.sources
|
732
|
-
@sources.push @virtual_source unless @virtual_source.nil?
|
733
|
-
cache.clear
|
734
|
-
@ivar_pins = {}
|
735
|
-
@cvar_pins = {}
|
736
|
-
@const_pins = {}
|
737
|
-
@method_pins = {}
|
738
|
-
@symbol_pins = []
|
739
|
-
@attr_pins = {}
|
740
|
-
@namespace_includes = {}
|
741
|
-
@namespace_extends = {}
|
742
|
-
@superclasses = {}
|
743
|
-
@namespace_pins = {}
|
744
|
-
@namespace_path_pins = {}
|
745
|
-
namespace_map.clear
|
746
|
-
@required = workspace.config.required.clone
|
747
|
-
@sources.each do |s|
|
748
|
-
s.namespaces.each do |n|
|
749
|
-
namespace_map[n] ||= []
|
750
|
-
namespace_map[n].concat s.namespace_pins(n)
|
751
|
-
end
|
752
|
-
end
|
753
|
-
@sources.each do |s|
|
754
|
-
map_source s
|
755
|
-
end
|
756
|
-
@required.uniq!
|
757
|
-
live_map.refresh
|
758
|
-
@yard_stale = true
|
759
|
-
@stime = Time.now
|
760
|
-
end
|
761
|
-
|
762
|
-
def rebuild_local_yardoc
|
763
|
-
return if workspace.nil? or !File.exist?(File.join(workspace, '.yardoc'))
|
764
|
-
STDERR.puts "Rebuilding local yardoc for #{workspace}"
|
765
|
-
Dir.chdir(workspace) { Process.spawn('yardoc') }
|
766
|
-
end
|
400
|
+
private
|
767
401
|
|
768
402
|
def process_virtual
|
769
403
|
unless @virtual_source.nil?
|
770
|
-
cache.clear
|
771
|
-
namespace_map.clear
|
772
|
-
@sources.each do |s|
|
773
|
-
s.namespace_pins.each do |pin|
|
774
|
-
namespace_map[pin.path] ||= []
|
775
|
-
namespace_map[pin.path].push pin
|
776
|
-
end
|
777
|
-
end
|
778
404
|
map_source @virtual_source
|
779
405
|
end
|
780
406
|
end
|
781
407
|
|
782
|
-
def eliminate source
|
783
|
-
[@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values, @namespace_pins.values].each do |pinsets|
|
784
|
-
pinsets.each do |pins|
|
785
|
-
pins.delete_if{|pin| pin.filename == source.filename}
|
786
|
-
end
|
787
|
-
end
|
788
|
-
[@namespace_includes.values, @namespace_extends.values].each do |refsets|
|
789
|
-
refsets.each do |refs|
|
790
|
-
refs.delete_if{|ref| ref.pin.filename == source.filename}
|
791
|
-
end
|
792
|
-
end
|
793
|
-
@superclasses.delete_if{|key, ref| ref.pin.filename == source.filename}
|
794
|
-
@symbol_pins.delete_if{|pin| pin.filename == source.filename}
|
795
|
-
end
|
796
|
-
|
797
408
|
# @param [Solargraph::Source]
|
798
409
|
def map_source source
|
799
|
-
|
800
|
-
@method_pins[pin.namespace] ||= []
|
801
|
-
@method_pins[pin.namespace].push pin
|
802
|
-
end
|
803
|
-
source.attribute_pins.each do |pin|
|
804
|
-
@attr_pins[pin.namespace] ||= []
|
805
|
-
@attr_pins[pin.namespace].push pin
|
806
|
-
end
|
807
|
-
source.instance_variable_pins.each do |pin|
|
808
|
-
@ivar_pins[pin.namespace] ||= []
|
809
|
-
@ivar_pins[pin.namespace].push pin
|
810
|
-
end
|
811
|
-
source.class_variable_pins.each do |pin|
|
812
|
-
@cvar_pins[pin.namespace] ||= []
|
813
|
-
@cvar_pins[pin.namespace].push pin
|
814
|
-
end
|
815
|
-
source.constant_pins.each do |pin|
|
816
|
-
@const_pins[pin.namespace] ||= []
|
817
|
-
@const_pins[pin.namespace].push pin
|
818
|
-
end
|
819
|
-
source.symbol_pins.each do |pin|
|
820
|
-
@symbol_pins.push pin
|
821
|
-
end
|
822
|
-
source.namespace_pins.each do |pin|
|
823
|
-
@namespace_path_pins[pin.path] ||= []
|
824
|
-
@namespace_path_pins[pin.path].push pin
|
825
|
-
@namespace_pins[pin.namespace] ||= []
|
826
|
-
@namespace_pins[pin.namespace].push pin
|
827
|
-
# @todo Determine whether references should be resolve here or
|
828
|
-
# dynamically during queries
|
829
|
-
unless pin.superclass_reference.nil?
|
830
|
-
@superclasses[pin.path] = pin.superclass_reference
|
831
|
-
# pin.superclass_reference.resolve self
|
832
|
-
end
|
833
|
-
pin.include_references.each do |ref|
|
834
|
-
@namespace_includes[pin.path] ||= []
|
835
|
-
@namespace_includes[pin.path].push ref
|
836
|
-
# ref.resolve self
|
837
|
-
end
|
838
|
-
pin.extend_references.each do |ref|
|
839
|
-
@namespace_extends[pin.path] ||= []
|
840
|
-
@namespace_extends[pin.path].push ref
|
841
|
-
# ref.resolve self
|
842
|
-
end
|
843
|
-
end
|
410
|
+
store.update source
|
844
411
|
path_macros.merge! source.path_macros
|
845
412
|
source.required.each do |r|
|
846
413
|
required.push r
|
@@ -858,44 +425,28 @@ module Solargraph
|
|
858
425
|
skip.push reqstr
|
859
426
|
result = []
|
860
427
|
if scope == :instance
|
861
|
-
|
862
|
-
result.concat aps unless aps.nil?
|
863
|
-
end
|
864
|
-
mps = @method_pins[fqns]
|
865
|
-
result.concat mps.select{|pin| (pin.scope == scope or fqns == '') and visibility.include?(pin.visibility)} unless mps.nil?
|
866
|
-
if fqns != '' and scope == :class and !result.map(&:path).include?("#{fqns}.new")
|
867
|
-
# Create a [Class].new method pin from [Class]#initialize
|
868
|
-
init = inner_get_methods(fqns, :instance, [:private], deep, skip - [fqns]).select{|pin| pin.name == 'initialize'}.first
|
869
|
-
unless init.nil?
|
870
|
-
result.unshift Solargraph::Pin::Directed::Method.new(init.source, init.node, init.namespace, :class, :public, init.docstring, 'new', init.namespace)
|
871
|
-
end
|
428
|
+
result.concat store.get_attrs(fqns)
|
872
429
|
end
|
430
|
+
result.concat store.get_methods(fqns, scope: scope, visibility: visibility)
|
873
431
|
if deep
|
874
|
-
|
875
|
-
unless
|
432
|
+
sc = store.get_superclass(fqns)
|
433
|
+
unless sc.nil?
|
434
|
+
fqsc = qualify(sc, fqns)
|
876
435
|
sc_visi = [:public]
|
877
436
|
sc_visi.push :protected if visibility.include?(:protected)
|
878
|
-
|
879
|
-
scref.resolve self
|
880
|
-
result.concat inner_get_methods(scref.name, scope, sc_visi, true, skip) unless scref.name.nil?
|
437
|
+
result.concat inner_get_methods(fqsc, scope, sc_visi, true, skip) unless fqsc.nil?
|
881
438
|
end
|
882
439
|
if scope == :instance
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
i.resolve self
|
887
|
-
result.concat inner_get_methods(i.name, scope, visibility, deep, skip) unless i.name.nil?
|
888
|
-
end
|
440
|
+
store.get_includes(fqns).each do |im|
|
441
|
+
fqim = qualify(im, fqns)
|
442
|
+
result.concat inner_get_methods(fqim, scope, visibility, deep, skip) unless fqim.nil?
|
889
443
|
end
|
890
444
|
result.concat yard_map.get_instance_methods(fqns, visibility: visibility)
|
891
445
|
result.concat inner_get_methods('Object', :instance, [:public], deep, skip) unless fqns == 'Object'
|
892
446
|
else
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
e.resolve self
|
897
|
-
result.concat inner_get_methods(e.name, :instance, visibility, deep, skip) unless e.name.nil?
|
898
|
-
end
|
447
|
+
store.get_extends(fqns).each do |em|
|
448
|
+
fqem = qualify(em, fqns)
|
449
|
+
result.concat inner_get_methods(fqem, :instance, visibility, deep, skip) unless fqem.nil?
|
899
450
|
end
|
900
451
|
result.concat yard_map.get_methods(fqns, '', visibility: visibility)
|
901
452
|
type = get_namespace_type(fqns)
|
@@ -913,49 +464,15 @@ module Solargraph
|
|
913
464
|
return [] if skip.include?(fqns)
|
914
465
|
skip.push fqns
|
915
466
|
result = []
|
916
|
-
result.concat
|
917
|
-
result.concat @namespace_pins[fqns] if @namespace_pins.has_key?(fqns)
|
918
|
-
result.keep_if{|pin| !pin.name.empty? and visibility.include?(pin.visibility)}
|
467
|
+
result.concat store.get_constants(fqns, visibility)
|
919
468
|
result.concat yard_map.get_constants(fqns)
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
i.resolve self
|
924
|
-
result.concat inner_get_constants(i.name, [:public], skip) unless i.name.nil?
|
925
|
-
end
|
469
|
+
store.get_includes(fqns).each do |is|
|
470
|
+
fqis = qualify(is, fqns)
|
471
|
+
result.concat inner_get_constants(fqis, [:public], skip) unless fqis.nil?
|
926
472
|
end
|
927
473
|
result
|
928
474
|
end
|
929
475
|
|
930
|
-
# Extract a namespace from a type.
|
931
|
-
#
|
932
|
-
# @example
|
933
|
-
# extract_namespace('String') => 'String'
|
934
|
-
# extract_namespace('Class<String>') => 'String'
|
935
|
-
#
|
936
|
-
# @return [String]
|
937
|
-
def extract_namespace type
|
938
|
-
extract_namespace_and_scope(type)[0]
|
939
|
-
end
|
940
|
-
|
941
|
-
# Extract a namespace and a scope (:instance or :class) from a type.
|
942
|
-
#
|
943
|
-
# @example
|
944
|
-
# extract_namespace('String') #=> ['String', :instance]
|
945
|
-
# extract_namespace('Class<String>') #=> ['String', :class]
|
946
|
-
# extract_namespace('Module<Enumerable') #=> ['Enumberable', :class]
|
947
|
-
#
|
948
|
-
# @return [Array] The namespace (String) and scope (Symbol).
|
949
|
-
def extract_namespace_and_scope type
|
950
|
-
scope = :instance
|
951
|
-
result = type.to_s.gsub(/<.*$/, '')
|
952
|
-
if (result == 'Class' or result == 'Module') and type.include?('<')
|
953
|
-
result = type.match(/<([a-z0-9:_]*)/i)[1]
|
954
|
-
scope = :class
|
955
|
-
end
|
956
|
-
[result, scope]
|
957
|
-
end
|
958
|
-
|
959
476
|
def require_extensions
|
960
477
|
Gem::Specification.all_names.select{|n| n.match(/^solargraph\-[a-z0-9_\-]*?\-ext\-[0-9\.]*$/)}.each do |n|
|
961
478
|
STDERR.puts "Loading extension #{n}"
|
@@ -968,7 +485,7 @@ module Solargraph
|
|
968
485
|
result = []
|
969
486
|
nil_pins = []
|
970
487
|
pins.each do |pin|
|
971
|
-
if pin.
|
488
|
+
if pin.variable? and pin.nil_assignment?
|
972
489
|
nil_pins.push pin
|
973
490
|
else
|
974
491
|
result.push pin
|
@@ -977,14 +494,6 @@ module Solargraph
|
|
977
494
|
result + nil_pins
|
978
495
|
end
|
979
496
|
|
980
|
-
# @todo DRY this method. It's duplicated in CodeMap
|
981
|
-
def get_subtypes type
|
982
|
-
return [] if type.nil?
|
983
|
-
match = type.match(/<([a-z0-9_:, ]*)>/i)
|
984
|
-
return [] if match.nil?
|
985
|
-
match[1].split(',').map(&:strip)
|
986
|
-
end
|
987
|
-
|
988
497
|
# @return [Hash]
|
989
498
|
def path_macros
|
990
499
|
@path_macros ||= {}
|
@@ -993,5 +502,56 @@ module Solargraph
|
|
993
502
|
def current_workspace_sources
|
994
503
|
@sources - [@virtual_source]
|
995
504
|
end
|
505
|
+
|
506
|
+
def inner_qualify name, root, skip
|
507
|
+
return nil if name.nil?
|
508
|
+
return nil if skip.include?(root)
|
509
|
+
skip.push root
|
510
|
+
if name == ''
|
511
|
+
if root == ''
|
512
|
+
return ''
|
513
|
+
else
|
514
|
+
return inner_qualify(root, '', skip)
|
515
|
+
end
|
516
|
+
else
|
517
|
+
if (root == '')
|
518
|
+
return name if store.namespace_exists?(name)
|
519
|
+
# @todo What to do about the @namespace_includes stuff above?
|
520
|
+
else
|
521
|
+
roots = root.to_s.split('::')
|
522
|
+
while roots.length > 0
|
523
|
+
fqns = roots.join('::') + '::' + name
|
524
|
+
return fqns if store.namespace_exists?(fqns)
|
525
|
+
roots.pop
|
526
|
+
end
|
527
|
+
return name if store.namespace_exists?(name)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
result = yard_map.find_fully_qualified_namespace(name, root)
|
531
|
+
if result.nil?
|
532
|
+
result = live_map.get_fqns(name, root)
|
533
|
+
end
|
534
|
+
result
|
535
|
+
end
|
536
|
+
|
537
|
+
# Get the namespace's type (Class or Module).
|
538
|
+
#
|
539
|
+
# @param [String] A fully qualified namespace
|
540
|
+
# @return [Symbol] :class, :module, or nil
|
541
|
+
def get_namespace_type fqns
|
542
|
+
pin = store.get_path_pins(fqns).first
|
543
|
+
return yard_map.get_namespace_type(fqns) if pin.nil?
|
544
|
+
pin.type
|
545
|
+
end
|
546
|
+
|
547
|
+
def extract_namespace_and_scope type
|
548
|
+
scope = :instance
|
549
|
+
result = type.to_s.gsub(/<.*$/, '')
|
550
|
+
if (result == 'Class' or result == 'Module') and type.include?('<')
|
551
|
+
result = type.match(/<([a-z0-9:_]*)/i)[1]
|
552
|
+
scope = :class
|
553
|
+
end
|
554
|
+
[result, scope]
|
555
|
+
end
|
996
556
|
end
|
997
557
|
end
|