solargraph 0.14.2 → 0.14.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ca2ed2f74501e75cb81ff97f3db0a8553800887f
4
- data.tar.gz: 1c9299750fb4c356ef8239f59fa37c7742e4dcb6
3
+ metadata.gz: 9b19cc5d128d5ad59344c60240530466594888a3
4
+ data.tar.gz: db5e6a4c0f05e070c1b14d1c22d6ae32f1ac61e6
5
5
  SHA512:
6
- metadata.gz: b25e723d7e22460204e71c48552f54bbc586abd088d9244f93a60496cfab37e2fce9fe1810c9d3cfec321ea956cd9fbd97ab9c0a6d5bb207dae220c6f6a4f0f7
7
- data.tar.gz: 5384d1df973aa083e140b0e877d112d639ddcc5e38c18eddc7d9d1e4a17ecb9fea2773853d04967a085d09aeb8cbadf7805bf14065556b88e45c1a019852fdc8
6
+ metadata.gz: 12d90c3ac837e6a3669e91dbdcc3101edfac58010f1dde7471caf7f6808529c64fbfcb31cf28859e6f11d52b91040cbd4929124295016e999a03627f6e2295af
7
+ data.tar.gz: 3fe26bbd2699603487702b765734ae63df345d4afced95b1139e7bafdb2eef419fcd19e1778268b91b84193ea30da0b96ef609aabcb95a26abce46545f8e4e34
@@ -11,7 +11,6 @@ module Solargraph
11
11
  autoload :Snippets, 'solargraph/snippets'
12
12
  autoload :Server, 'solargraph/server'
13
13
  autoload :YardMap, 'solargraph/yard_map'
14
- autoload :YardMethods, 'solargraph/yard_methods'
15
14
  autoload :Pin, 'solargraph/pin'
16
15
  autoload :LiveMap, 'solargraph/live_map'
17
16
  autoload :ServerMethods, 'solargraph/server_methods'
@@ -23,7 +23,6 @@ module Solargraph
23
23
  ].freeze
24
24
 
25
25
  include NodeMethods
26
- include YardMethods
27
26
 
28
27
  # The root directory of the project. The ApiMap will search here for
29
28
  # additional files to parse and analyze.
@@ -35,20 +34,14 @@ module Solargraph
35
34
  def initialize workspace = nil
36
35
  @workspace = workspace.gsub(/\\/, '/') unless workspace.nil?
37
36
  clear
38
- # @todo Instead of requiring extensions to be listed in the config,
39
- # we're experimenting with automatically loading them.
40
- #self.config.extensions.each do |ext|
41
- # require ext
42
- #end
43
37
  require_extensions
44
- @workspace_files = []
45
38
  unless @workspace.nil?
46
- @workspace_files.concat (self.config.included - self.config.excluded)
47
- @workspace_files.each do |wf|
39
+ workspace_files.concat (self.config.included - self.config.excluded)
40
+ workspace_files.each do |wf|
48
41
  begin
49
42
  @@source_cache[wf] ||= Source.load(wf)
50
- rescue
51
- STDERR.puts "Failed to load #{wf}"
43
+ rescue Exception => e
44
+ STDERR.puts "Failed to load #{wf}: #{e.message}"
52
45
  end
53
46
  end
54
47
  end
@@ -60,10 +53,21 @@ module Solargraph
60
53
  yard_map
61
54
  end
62
55
 
63
- def config
64
- @config ||= ApiMap::Config.new(@workspace)
56
+ # @return [Solargraph::ApiMap::Config]
57
+ def config reload = false
58
+ @config = ApiMap::Config.new(@workspace) if @config.nil? or reload
59
+ @config
65
60
  end
66
61
 
62
+ # An array of all workspace files included in the map.
63
+ #
64
+ # @return[Array<String>]
65
+ def workspace_files
66
+ @workspace_files ||= []
67
+ end
68
+
69
+ # An array of required paths in the workspace.
70
+ #
67
71
  # @return [Array<String>]
68
72
  def required
69
73
  @required ||= []
@@ -83,16 +87,36 @@ module Solargraph
83
87
  @live_map ||= Solargraph::LiveMap.new(self)
84
88
  end
85
89
 
90
+ # @todo Get rid of the cursor parameter. Tracking stubbed lines is the
91
+ # better option.
92
+ #
93
+ # @param code [String]
94
+ # @param filename [String]
86
95
  # @return [Solargraph::ApiMap::Source]
87
96
  def virtualize code, filename = nil, cursor = nil
88
- unless @virtual_source.nil? or @virtual_filename == filename or @workspace_files.include?(@virtual_filename)
89
- eliminate @virtual_filename
97
+ workspace_files.delete_if do |f|
98
+ if File.exist?(f)
99
+ false
100
+ else
101
+ eliminate f
102
+ true
103
+ end
104
+ end
105
+ if filename.nil? or filename.end_with?('.rb')
106
+ eliminate @virtual_filename unless @virtual_source.nil? or @virtual_filename == filename or workspace_files.include?(@virtual_filename)
107
+ @virtual_filename = filename
108
+ @virtual_source = Source.fix(code, filename, cursor)
109
+ unless filename.nil? or workspace_files.include?(filename)
110
+ current_files = @workspace_files
111
+ @workspace_files = config(true).calculated
112
+ (current_files - @workspace_files).each { |f| eliminate f }
113
+ end
114
+ process_virtual
115
+ else
116
+ unless filename.nil?
117
+ # @todo Handle special files like .solargraph.yml
118
+ end
90
119
  end
91
- #refresh
92
- @virtual_filename = filename
93
- @virtual_source = Source.fix(code, filename, cursor)
94
- process_virtual
95
- #@stale = true
96
120
  @virtual_source
97
121
  end
98
122
 
@@ -109,12 +133,17 @@ module Solargraph
109
133
  #
110
134
  # @param node [AST::Node]
111
135
  # @return [YARD::Docstring]
112
- def get_comment_for node
136
+ def get_docstring_for node
113
137
  filename = get_filename_for(node)
114
138
  return nil if @sources[filename].nil?
115
139
  @sources[filename].docstring_for(node)
116
140
  end
117
141
 
142
+ # @deprecated Use get_docstring_for instead.
143
+ def get_comment_for node
144
+ get_docstring_for node
145
+ end
146
+
118
147
  # @return [Array<Solargraph::Suggestion>]
119
148
  def self.get_keywords
120
149
  @keyword_suggestions ||= KEYWORDS.map{ |s|
@@ -122,6 +151,7 @@ module Solargraph
122
151
  }.freeze
123
152
  end
124
153
 
154
+ # @return [Array<String>]
125
155
  def namespaces
126
156
  refresh
127
157
  namespace_map.keys
@@ -131,14 +161,9 @@ module Solargraph
131
161
  !find_fully_qualified_namespace(name, root).nil?
132
162
  end
133
163
 
164
+ # @deprecated Use get_constants instead.
134
165
  def namespaces_in name, root = ''
135
- refresh
136
- result = []
137
- result += inner_namespaces_in(name, root, [])
138
- result += yard_map.get_constants name, root
139
- strings = result.map(&:to_s)
140
- result.concat live_map.get_constants(name, root)
141
- result
166
+ get_constants name, root
142
167
  end
143
168
 
144
169
  # @return [Array<Solargraph::Pin::Constant>]
@@ -148,16 +173,32 @@ module Solargraph
148
173
  end
149
174
 
150
175
  # @return [Array<Solargraph::Suggestion>]
151
- def get_constants namespace, root
176
+ def get_constants namespace, root = ''
152
177
  result = []
178
+ skip = []
153
179
  fqns = find_fully_qualified_namespace(namespace, root)
154
- cp = @const_pins[fqns]
155
- unless cp.nil?
156
- cp.each do |pin|
157
- result.push pin_to_suggestion(pin)
180
+ if fqns.empty?
181
+ result.concat inner_get_constants('', skip, false)
182
+ else
183
+ parts = fqns.split('::')
184
+ resolved = find_namespace_pins(parts.join('::'))
185
+ resolved.each do |pin|
186
+ result.concat inner_get_constants(pin.path, skip, true)
158
187
  end
159
188
  end
160
189
  result.concat yard_map.get_constants(fqns)
190
+ result
191
+ end
192
+
193
+ def find_namespace_pins fqns
194
+ set = nil
195
+ if fqns.include?('::')
196
+ set = @namespace_pins[fqns.split('::')[0..-2].join('::')]
197
+ else
198
+ set = @namespace_pins['']
199
+ end
200
+ return [] if set.nil?
201
+ set.select{|p| p.path == fqns}
161
202
  end
162
203
 
163
204
  # @return [String]
@@ -218,9 +259,7 @@ module Solargraph
218
259
  result = []
219
260
  ip = @ivar_pins[namespace]
220
261
  unless ip.nil?
221
- ip.select{ |pin| pin.scope == scope }.each do |pin|
222
- result.push pin_to_suggestion(pin)
223
- end
262
+ result.concat suggest_unique_variables(ip.select{ |pin| pin.scope == scope })
224
263
  end
225
264
  result
226
265
  end
@@ -235,11 +274,9 @@ module Solargraph
235
274
  def get_class_variables(namespace)
236
275
  refresh
237
276
  result = []
238
- ip = @cvar_pins[namespace]
239
- unless ip.nil?
240
- ip.each do |pin|
241
- result.push pin_to_suggestion(pin)
242
- end
277
+ cp = @cvar_pins[namespace]
278
+ unless cp.nil?
279
+ result.concat suggest_unique_variables(cp)
243
280
  end
244
281
  result
245
282
  end
@@ -258,6 +295,14 @@ module Solargraph
258
295
  nil
259
296
  end
260
297
 
298
+ # @return [Solargraph::ApiMap::Source]
299
+ def get_source_for(node)
300
+ @sources.each do |filename, source|
301
+ return source if source.include?(node)
302
+ end
303
+ nil
304
+ end
305
+
261
306
  # @return [String]
262
307
  def infer_instance_variable(var, namespace, scope)
263
308
  refresh
@@ -281,20 +326,18 @@ module Solargraph
281
326
 
282
327
  # @return [Array<Solargraph::Suggestion>]
283
328
  def get_global_variables
284
- result = []
329
+ globals = []
285
330
  @sources.values.each do |s|
286
- s.global_variable_pins.each do |p|
287
- result.push pin_to_suggestion(p)
288
- end
331
+ globals.concat s.global_variable_pins
289
332
  end
290
- result
333
+ suggest_unique_variables globals
291
334
  end
292
335
 
293
336
  # @return [String]
294
337
  def infer_assignment_node_type node, namespace
295
338
  type = cache.get_assignment_node_type(node, namespace)
296
339
  if type.nil?
297
- cmnt = get_comment_for(node)
340
+ cmnt = get_docstring_for(node)
298
341
  if cmnt.nil?
299
342
  name_i = (node.type == :casgn ? 1 : 0)
300
343
  sig_i = (node.type == :casgn ? 2 : 1)
@@ -321,6 +364,7 @@ module Solargraph
321
364
 
322
365
  # @return [String]
323
366
  def infer_signature_type signature, namespace, scope: :class
367
+ namespace ||= ''
324
368
  if cache.has_signature_type?(signature, namespace, scope)
325
369
  return cache.get_signature_type(signature, namespace, scope)
326
370
  end
@@ -453,13 +497,14 @@ module Solargraph
453
497
  meths
454
498
  end
455
499
 
500
+ # @return [Array<String>]
456
501
  def get_include_strings_from *nodes
457
502
  arr = []
458
503
  nodes.each { |node|
459
504
  next unless node.kind_of?(AST::Node)
460
505
  arr.push unpack_name(node.children[2]) if (node.type == :send and node.children[1] == :include)
461
506
  node.children.each { |n|
462
- arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module
507
+ arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module and n.type != :sclass
463
508
  }
464
509
  }
465
510
  arr
@@ -467,16 +512,27 @@ module Solargraph
467
512
 
468
513
  def update filename
469
514
  filename.gsub!(/\\/, '/')
470
- eliminate filename
471
- @@source_cache[filename] = Source.load(filename)
472
- rebuild_local_yardoc #if @workspace_files.include?(filename)
473
- @stale = true
515
+ if filename.end_with?('.rb')
516
+ if @workspace_files.include?(filename)
517
+ eliminate filename
518
+ @@source_cache[filename] = Source.load(filename)
519
+ rebuild_local_yardoc #if @workspace_files.include?(filename)
520
+ @stale = true
521
+ else
522
+ @workspace_files = config(true).calculated
523
+ update filename if @workspace_files.include?(filename)
524
+ end
525
+ elsif File.basename(filename) == '.solargraph.yml'
526
+ # @todo Finish refreshing the map
527
+ @workspace_files = config(true).calculated
528
+ end
474
529
  end
475
530
 
476
531
  def sources
477
532
  @sources.values
478
533
  end
479
534
 
535
+ # @return [Array<String>]
480
536
  def get_path_suggestions path
481
537
  refresh
482
538
  result = []
@@ -490,9 +546,10 @@ module Solargraph
490
546
  result = get_methods(parts[0], '', visibility: [:public, :private, :protected]).select{|s| s.label == parts[1]}
491
547
  else
492
548
  # It's a class or module
493
- get_namespace_nodes(path).each do |node|
494
- # TODO This is way underimplemented
495
- result.push Suggestion.new(path, kind: Suggestion::CLASS)
549
+ parts = path.split('::')
550
+ np = @namespace_pins[parts[0..-2].join('::')]
551
+ unless np.nil?
552
+ result.concat np.select{|p| p.name == parts.last}.map{|p| pin_to_suggestion(p)}
496
553
  end
497
554
  result.concat yard_map.objects(path)
498
555
  end
@@ -506,17 +563,10 @@ module Solargraph
506
563
  @namespace_map ||= {}
507
564
  end
508
565
 
509
- # @return [Hash]
510
- def namespace_tree
511
- @namespace_tree ||= {}
512
- end
513
-
514
566
  def clear
515
567
  @stale = false
516
- @parent_stack = {}
517
568
  namespace_map.clear
518
- namespace_tree.clear
519
- required.clear
569
+ @required = config.required.clone
520
570
  end
521
571
 
522
572
  def process_maps
@@ -530,10 +580,9 @@ module Solargraph
530
580
  @attr_pins = {}
531
581
  @namespace_includes = {}
532
582
  @superclasses = {}
533
- @parent_stack = {}
583
+ @namespace_pins = {}
534
584
  namespace_map.clear
535
- namespace_tree.clear
536
- @required = []
585
+ @required = config.required.clone
537
586
  @pin_suggestions = {}
538
587
  unless @virtual_source.nil?
539
588
  @sources[@virtual_filename] = @virtual_source
@@ -542,7 +591,6 @@ module Solargraph
542
591
  s.namespace_nodes.each_pair do |k, v|
543
592
  namespace_map[k] ||= []
544
593
  namespace_map[k].concat v
545
- add_to_namespace_tree k.split('::')
546
594
  end
547
595
  end
548
596
  @sources.values.each { |s|
@@ -561,13 +609,13 @@ module Solargraph
561
609
 
562
610
  def process_workspace_files
563
611
  @sources.clear
564
- @workspace_files.each do |f|
612
+ workspace_files.each do |f|
565
613
  if File.file?(f)
566
614
  begin
567
615
  @@source_cache[f] ||= Source.load(f)
568
616
  @sources[f] = @@source_cache[f]
569
- rescue
570
- STDERR.puts "Failed to load #{f}"
617
+ rescue Exception => e
618
+ STDERR.puts "Failed to load #{f}: #{e.message}"
571
619
  end
572
620
  end
573
621
  end
@@ -577,13 +625,11 @@ module Solargraph
577
625
  unless @virtual_source.nil?
578
626
  cache.clear
579
627
  namespace_map.clear
580
- namespace_tree.clear
581
628
  @sources[@virtual_filename] = @virtual_source
582
629
  @sources.values.each do |s|
583
630
  s.namespace_nodes.each_pair do |k, v|
584
631
  namespace_map[k] ||= []
585
632
  namespace_map[k].concat v
586
- add_to_namespace_tree k.split('::')
587
633
  end
588
634
  end
589
635
  eliminate @virtual_filename
@@ -592,7 +638,7 @@ module Solargraph
592
638
  end
593
639
 
594
640
  def eliminate filename
595
- [@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values].each do |pinsets|
641
+ [@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values, @namespace_pins.values].each do |pinsets|
596
642
  pinsets.each do |pins|
597
643
  pins.delete_if{|pin| pin.filename == filename}
598
644
  end
@@ -632,6 +678,10 @@ module Solargraph
632
678
  source.superclasses.each_pair do |cls, sup|
633
679
  @superclasses[cls] = sup
634
680
  end
681
+ source.namespace_pins.each do |pin|
682
+ @namespace_pins[pin.namespace] ||= []
683
+ @namespace_pins[pin.namespace].push pin
684
+ end
635
685
  source.required.each do |r|
636
686
  required.push r
637
687
  end
@@ -707,50 +757,6 @@ module Solargraph
707
757
  meths.uniq
708
758
  end
709
759
 
710
- def inner_namespaces_in name, root, skip
711
- result = []
712
- fqns = find_fully_qualified_namespace(name, root)
713
- unless fqns.nil? or skip.include?(fqns)
714
- skip.push fqns
715
- nodes = get_namespace_nodes(fqns)
716
- unless nodes.empty?
717
- cursor = namespace_tree
718
- parts = fqns.split('::')
719
- parts.each { |p|
720
- cursor = cursor[p]
721
- }
722
- unless cursor.nil?
723
- cursor.keys.each { |k|
724
- type = get_namespace_type("#{fqns == '' ? '' : fqns + '::'}#{k}")
725
- kind = nil
726
- detail = nil
727
- if type == :class
728
- kind = Suggestion::CLASS
729
- detail = 'Class'
730
- elsif type == :module
731
- kind = Suggestion::MODULE
732
- detail = 'Module'
733
- end
734
- result.push Suggestion.new(k, kind: kind, detail: detail)
735
- }
736
- cp = @const_pins[fqns]
737
- unless cp.nil?
738
- cp.each do |pin|
739
- result.push pin_to_suggestion(pin)
740
- end
741
- end
742
- inc = @namespace_includes[fqns]
743
- unless inc.nil?
744
- inc.each do |i|
745
- result.concat inner_namespaces_in(i, fqns, skip)
746
- end
747
- end
748
- end
749
- end
750
- end
751
- result
752
- end
753
-
754
760
  # Get a fully qualified namespace for the given signature.
755
761
  # The signature should be in the form of a method chain, e.g.,
756
762
  # method1.method2
@@ -804,12 +810,31 @@ module Solargraph
804
810
  type
805
811
  end
806
812
 
807
- def add_to_namespace_tree tree
808
- cursor = namespace_tree
809
- tree.each { |t|
810
- cursor[t.to_s] ||= {}
811
- cursor = cursor[t.to_s]
812
- }
813
+ def inner_get_constants here, skip = [], deep = true
814
+ return [] if skip.include?(here)
815
+ skip.push here
816
+ result = []
817
+ cp = @const_pins[here]
818
+ unless cp.nil?
819
+ cp.each do |pin|
820
+ result.push pin_to_suggestion(pin)
821
+ end
822
+ end
823
+ np = @namespace_pins[here]
824
+ unless np.nil?
825
+ np.each do |pin|
826
+ result.push pin_to_suggestion(pin)
827
+ if deep
828
+ get_include_strings_from(pin.node).each do |i|
829
+ result.concat inner_get_constants(i, skip, false)
830
+ end
831
+ end
832
+ end
833
+ end
834
+ get_include_strings_from(*get_namespace_nodes(here)).each do |i|
835
+ result.concat inner_get_constants(i, skip, false)
836
+ end
837
+ result
813
838
  end
814
839
 
815
840
  def file_nodes
@@ -837,5 +862,25 @@ module Solargraph
837
862
  require n.match(/^(solargraph\-[a-z0-9_\-]*?\-ext)\-[0-9\.]*$/)[1]
838
863
  end
839
864
  end
865
+
866
+ def suggest_unique_variables pins
867
+ result = []
868
+ nil_pins = []
869
+ val_names = []
870
+ pins.each do |pin|
871
+ if pin.nil_assignment? and pin.return_type.nil?
872
+ nil_pins.push pin
873
+ else
874
+ unless val_names.include?(pin.name)
875
+ result.push pin_to_suggestion(pin)
876
+ val_names.push pin.name
877
+ end
878
+ end
879
+ end
880
+ nil_pins.reject{|p| val_names.include?(p.name)}.each do |pin|
881
+ result.push pin_to_suggestion(pin)
882
+ end
883
+ result
884
+ end
840
885
  end
841
886
  end