solargraph 0.28.4 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph/api_map.rb +43 -10
  3. data/lib/solargraph/api_map/store.rb +13 -0
  4. data/lib/solargraph/bundle.rb +3 -0
  5. data/lib/solargraph/complex_type.rb +5 -4
  6. data/lib/solargraph/core_fills.rb +3 -2
  7. data/lib/solargraph/language_server/host.rb +0 -1
  8. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +4 -3
  9. data/lib/solargraph/language_server/message/extended/document_gems.rb +7 -0
  10. data/lib/solargraph/language_server/transport/socket.rb +7 -1
  11. data/lib/solargraph/library.rb +1 -1
  12. data/lib/solargraph/page.rb +1 -2
  13. data/lib/solargraph/pin.rb +1 -0
  14. data/lib/solargraph/pin/base.rb +8 -1
  15. data/lib/solargraph/pin/base_variable.rb +1 -1
  16. data/lib/solargraph/pin/block_parameter.rb +5 -0
  17. data/lib/solargraph/pin/conversions.rb +1 -1
  18. data/lib/solargraph/pin/method.rb +59 -1
  19. data/lib/solargraph/pin/method_alias.rb +19 -0
  20. data/lib/solargraph/pin/yard_pin/method.rb +2 -2
  21. data/lib/solargraph/source.rb +63 -1
  22. data/lib/solargraph/source/chain/call.rb +39 -20
  23. data/lib/solargraph/source/node_chainer.rb +1 -1
  24. data/lib/solargraph/source/node_methods.rb +81 -0
  25. data/lib/solargraph/source_map.rb +15 -0
  26. data/lib/solargraph/source_map/clip.rb +1 -1
  27. data/lib/solargraph/source_map/mapper.rb +9 -421
  28. data/lib/solargraph/source_map/node_processor.rb +75 -0
  29. data/lib/solargraph/source_map/node_processor/alias_node.rb +21 -0
  30. data/lib/solargraph/source_map/node_processor/args_node.rb +28 -0
  31. data/lib/solargraph/source_map/node_processor/base.rb +68 -0
  32. data/lib/solargraph/source_map/node_processor/begin_node.rb +11 -0
  33. data/lib/solargraph/source_map/node_processor/block_node.rb +14 -0
  34. data/lib/solargraph/source_map/node_processor/casgn_node.rb +14 -0
  35. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +14 -0
  36. data/lib/solargraph/source_map/node_processor/def_node.rb +54 -0
  37. data/lib/solargraph/source_map/node_processor/defs_node.rb +21 -0
  38. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +12 -0
  39. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +18 -0
  40. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +16 -0
  41. data/lib/solargraph/source_map/node_processor/namespace_node.rb +26 -0
  42. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +12 -0
  43. data/lib/solargraph/source_map/node_processor/sclass_node.rb +11 -0
  44. data/lib/solargraph/source_map/node_processor/send_node.rb +150 -0
  45. data/lib/solargraph/source_map/node_processor/sym_node.rb +11 -0
  46. data/lib/solargraph/source_map/region.rb +58 -0
  47. data/lib/solargraph/version.rb +1 -1
  48. data/lib/solargraph/yard_map.rb +17 -10
  49. data/lib/yard-solargraph.rb +0 -2
  50. metadata +24 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fd24fe0b737e17e14772aa13d7b948b5721ba99f3a0855682e78503ca337816
4
- data.tar.gz: 1e907c9e1f5fa10537c406fdd512574da4dce74354d0d16accb04d91794c29a4
3
+ metadata.gz: c715438f197d1c368427a61e4b745993ce0cca12b3db96d647f922be67c39e90
4
+ data.tar.gz: 1b82249c56fdb3014c69ec43e12cdac30b9f029cffb8d09896c4e19da7e24a81
5
5
  SHA512:
6
- metadata.gz: 77d273f6d65def59c5d4661a3479948fffce730fe9aebdff94cdc24dbefed1be8d60633e469a2d3f8c9941d1463980ed0db71eef7bdffe1182b6d9abc1835af6
7
- data.tar.gz: e836999b24c652aa457a32db9f29a46264b91401c1fe6f4a86dc62baf9fce78e49f8795b6e957919ddcca21924c7ccc57a54d030f6183095dfa5d1663ab650d6
6
+ metadata.gz: d9b8ed3db0337ef27ff07e1bb28c6bdac6e37bee655333b8465366a0ed3bf01c614dca4dcbaed4ddb1f535abd32639bd53553b3ab044fcb0b4311aa73778d732
7
+ data.tar.gz: 83f8266b77ff13d9750a889f04bbda44b15c39d2a2dbe0dca975f5a5af1835d3d78ee06e806906b65d7fb66dba08a7d09756df0ecbc7e69a9bc13fab29340e47
@@ -21,7 +21,6 @@ module Solargraph
21
21
  attr_reader :unresolved_requires
22
22
 
23
23
  # @param pins [Array<Solargraph::Pin::Base>]
24
- # def initialize workspace = Solargraph::Workspace.new(nil)
25
24
  def initialize pins: []
26
25
  # @todo Extensions don't work yet
27
26
  # require_extensions
@@ -40,9 +39,15 @@ module Solargraph
40
39
  @store = Store.new(pins + YardMap.new.pins)
41
40
  @unresolved_requires = []
42
41
  }
42
+ resolved = resolve_method_aliases
43
+ unless resolved.nil?
44
+ @mutex.synchronize { @store = Store.new(resolved) }
45
+ end
43
46
  self
44
47
  end
45
48
 
49
+ # Map a single source.
50
+ #
46
51
  # @param source [Source]
47
52
  # @return [self]
48
53
  def map source
@@ -50,8 +55,11 @@ module Solargraph
50
55
  self
51
56
  end
52
57
 
53
- # Catalog a workspace. Additional sources that need to be mapped can be
54
- # included in an optional array.
58
+ def named_macro name
59
+ store.named_macros[name]
60
+ end
61
+
62
+ # Catalog a bundle.
55
63
  #
56
64
  # @param bundle [Bundle]
57
65
  # @return [self]
@@ -106,6 +114,10 @@ module Solargraph
106
114
  @store = new_store
107
115
  @unresolved_requires = yard_map.unresolved_requires
108
116
  }
117
+ resolved = resolve_method_aliases
118
+ unless resolved.nil?
119
+ @mutex.synchronize { @store = Store.new(resolved) }
120
+ end
109
121
  self
110
122
  end
111
123
 
@@ -143,7 +155,7 @@ module Solargraph
143
155
  store.pins
144
156
  end
145
157
 
146
- # An array of suggestions based on Ruby keywords (`if`, `end`, etc.).
158
+ # An array of pins based on Ruby keywords (`if`, `end`, etc.).
147
159
  #
148
160
  # @return [Array<Solargraph::Pin::Keyword>]
149
161
  def self.keywords
@@ -305,7 +317,13 @@ module Solargraph
305
317
  result.concat get_methods('Object')
306
318
  else
307
319
  unless type.nil? || type.name == 'void'
308
- namespace = qualify(type.namespace, context)
320
+ # @todo This method does not qualify the complex type's namespace
321
+ # because it can cause namespace conflicts, e.g., `Foo` vs.
322
+ # `Other::Foo`. It still takes a context argument because it
323
+ # uses context to determine whether protected and private methods
324
+ # are visible.
325
+ # namespace = qualify(type.namespace, context)
326
+ namespace = type.namespace
309
327
  visibility = [:public]
310
328
  if namespace == context || super_and_sub?(namespace, context)
311
329
  visibility.push :protected
@@ -330,12 +348,13 @@ module Solargraph
330
348
  # @param scope [Symbol] :instance or :class
331
349
  # @return [Array<Solargraph::Pin::Base>]
332
350
  def get_method_stack fqns, name, scope: :instance
333
- # @todo This cache is still causing problems.
334
- cached = cache.get_method_stack(fqns, name, scope)
335
- return cached unless cached.nil?
351
+ # @todo This cache is still causing problems, but only when using
352
+ # Solargraph on Solargraph itself.
353
+ # cached = cache.get_method_stack(fqns, name, scope)
354
+ # return cached unless cached.nil?
336
355
  result = get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select{|p| p.name == name}
337
- cache.set_method_stack(fqns, name, scope, result)
338
- result
356
+ # cache.set_method_stack(fqns, name, scope, result)
357
+ # result
339
358
  end
340
359
 
341
360
  # Get an array of all suggestions that match the specified path.
@@ -621,5 +640,19 @@ module Solargraph
621
640
  end
622
641
  false
623
642
  end
643
+
644
+ # @return [Array<Pin::Base>, nil]
645
+ def resolve_method_aliases
646
+ aliased = false
647
+ result = pins.map do |pin|
648
+ next pin unless pin.is_a?(Pin::MethodAlias)
649
+ origin = get_method_stack(pin.namespace, pin.original, scope: pin.scope).select{|pin| pin.class == Pin::Method}.first
650
+ next pin if origin.nil?
651
+ aliased = true
652
+ Pin::Method.new(pin.location, pin.namespace, pin.name, origin.comments, origin.scope, origin.visibility, origin.parameters)
653
+ end
654
+ return nil unless aliased
655
+ result
656
+ end
624
657
  end
625
658
  end
@@ -109,6 +109,19 @@ module Solargraph
109
109
  result
110
110
  end
111
111
 
112
+ def named_macros
113
+ @named_macros ||= begin
114
+ result = {}
115
+ pins.each do |pin|
116
+ pin.macros.select{|m| m.tag.tag_name == 'macro'}.each do |macro|
117
+ next if macro.tag.name.nil? || macro.tag.name.empty?
118
+ result[macro.tag.name] = macro
119
+ end
120
+ end
121
+ result
122
+ end
123
+ end
124
+
112
125
  private
113
126
 
114
127
  # @param fqns [String]
@@ -1,4 +1,7 @@
1
1
  module Solargraph
2
+ # An aggregation of a workspace and additional sources to be cataloged in an
3
+ # ApiMap.
4
+ #
2
5
  class Bundle
3
6
  # @return [Workspace]
4
7
  attr_reader :workspace
@@ -28,6 +28,7 @@ module Solargraph
28
28
  end
29
29
 
30
30
  def method_missing name, *args, &block
31
+ return if first.nil?
31
32
  return first.send(name, *args, &block) if respond_to_missing?(name)
32
33
  super
33
34
  end
@@ -76,7 +77,7 @@ module Solargraph
76
77
  elsif char == '<'
77
78
  point_stack += 1
78
79
  elsif char == '>'
79
- if subtype_string.end_with?('=') and curly_stack > 0
80
+ if subtype_string.end_with?('=') && curly_stack > 0
80
81
  subtype_string += char
81
82
  elsif base.end_with?('=')
82
83
  raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
@@ -106,13 +107,13 @@ module Solargraph
106
107
  subtype_string += char if paren_stack == 0
107
108
  raise ComplexTypeError, "Invalid close in type #{type_string}" if paren_stack < 0
108
109
  next
109
- elsif char == ',' and point_stack == 0 and curly_stack == 0 and paren_stack == 0
110
+ elsif char == ',' && point_stack == 0 && curly_stack == 0 && paren_stack == 0
110
111
  types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])
111
112
  base = ''
112
113
  subtype_string = ''
113
114
  next
114
115
  end
115
- if point_stack == 0 and curly_stack == 0 and paren_stack == 0
116
+ if point_stack == 0 && curly_stack == 0 && paren_stack == 0
116
117
  base += char
117
118
  else
118
119
  subtype_string += char
@@ -120,7 +121,7 @@ module Solargraph
120
121
  end
121
122
  base.strip!
122
123
  subtype_string.strip!
123
- raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 or curly_stack != 0 or paren_stack != 0
124
+ raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 || curly_stack != 0 || paren_stack != 0
124
125
  types.push ComplexType.new([UniqueType.new(base, subtype_string)])
125
126
  end
126
127
  unless key_types.nil?
@@ -20,13 +20,14 @@ module Solargraph
20
20
  ].freeze
21
21
 
22
22
  METHODS_WITH_YIELDPARAM_SUBTYPES = %w[
23
- Array#each Array#map Array#any? Array#all?
23
+ Array#each Array#map Array#any? Array#all? Array#index
24
24
  Enumerable#each_entry Enumerable#map Enumerable#any? Enumerable#all?
25
25
  Set#each
26
26
  ].freeze
27
27
 
28
28
  CUSTOM_RETURN_TYPES = {
29
- 'String#split' => 'Array<String>'
29
+ 'String#split' => 'Array<String>',
30
+ 'String#lines' => 'Array<String>'
30
31
  }.freeze
31
32
  end
32
33
  end
@@ -322,7 +322,6 @@ module Solargraph
322
322
  end
323
323
 
324
324
  def locate_pin params
325
- pin = nil
326
325
  pin = nil
327
326
  unless params['data']['location'].nil?
328
327
  location = Location.new(
@@ -14,9 +14,9 @@ module Solargraph
14
14
  fetcher = Gem::SpecFetcher.new
15
15
  tuple = fetcher.search_for_dependency(Gem::Dependency.new('solargraph')).flatten.first
16
16
  if tuple.nil?
17
- msg = "An error occurred checking the Solargraph gem version."
17
+ msg = 'An error occurred checking the Solargraph gem version.'
18
18
  STDERR.puts msg
19
- host.show_message(msg, MessageTypes::ERROR) if params['verbose']
19
+ host.show_message(msg, MessageTypes::ERROR)
20
20
  else
21
21
  available = Gem::Version.new(tuple.version)
22
22
  current = Gem::Version.new(Solargraph::VERSION)
@@ -24,10 +24,11 @@ module Solargraph
24
24
  host.show_message_request "Solagraph gem version #{available} is available.",
25
25
  LanguageServer::MessageTypes::INFO,
26
26
  ['Update now'] do |result|
27
- break unless result == 'Update now'
27
+ next unless result == 'Update now'
28
28
  o, s = Open3.capture2("gem update solargraph")
29
29
  if s == 0
30
30
  host.show_message 'Successfully updated the Solargraph gem.', LanguageServer::MessageTypes::INFO
31
+ host.send_notification '$/solargraph/restart'
31
32
  else
32
33
  host.show_message 'An error occurred while updating the gem.', LanguageServer::MessageTypes::ERROR
33
34
  end
@@ -14,6 +14,13 @@ module Solargraph
14
14
  o, s = Open3.capture2(cmd)
15
15
  if s != 0
16
16
  host.show_message "An error occurred while building gem documentation.", LanguageServer::MessageTypes::ERROR
17
+ set_result({
18
+ status: 'err'
19
+ })
20
+ else
21
+ set_result({
22
+ status: 'ok'
23
+ })
17
24
  end
18
25
  end
19
26
  end
@@ -33,7 +33,13 @@ module Solargraph
33
33
  EventMachine.add_periodic_timer 0.1 do
34
34
  tmp = @host.flush
35
35
  send_data tmp unless tmp.empty?
36
- EventMachine.stop if @host.stopped?
36
+ if @host.stopped?
37
+ if @host.options['transport'] == 'external'
38
+ @host = Solargraph::LanguageServer::Host.new
39
+ else
40
+ EventMachine.stop
41
+ end
42
+ end
37
43
  end
38
44
  end
39
45
  end
@@ -174,7 +174,7 @@ module Solargraph
174
174
  referenced.any?{|r| r == pin}
175
175
  end
176
176
  # HACK for language clients that exclude special characters from the start of variable names
177
- if strip && match = cursor.word.match(/^[^a-z0-9_]+/)
177
+ if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
178
178
  found.map! do |loc|
179
179
  Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
180
180
  end
@@ -2,7 +2,6 @@ require 'ostruct'
2
2
  require 'tilt'
3
3
  require 'kramdown'
4
4
  require 'htmlentities'
5
- require 'coderay'
6
5
  require 'reverse_markdown'
7
6
 
8
7
  module Solargraph
@@ -25,7 +24,7 @@ module Solargraph
25
24
  entity_output: :symbolic,
26
25
  syntax_highlighter_opts: {
27
26
  block: {
28
- line_numbers: false,
27
+ line_numbers: false
29
28
  },
30
29
  default_lang: :ruby
31
30
  },
@@ -5,6 +5,7 @@ module Solargraph
5
5
  autoload :Conversions, 'solargraph/pin/conversions'
6
6
  autoload :Base, 'solargraph/pin/base'
7
7
  autoload :Method, 'solargraph/pin/method'
8
+ autoload :MethodAlias, 'solargraph/pin/method_alias'
8
9
  autoload :Attribute, 'solargraph/pin/attribute'
9
10
  autoload :BaseVariable, 'solargraph/pin/base_variable'
10
11
  autoload :InstanceVariable, 'solargraph/pin/instance_variable'
@@ -124,7 +124,7 @@ module Solargraph
124
124
 
125
125
  # @return [Array<YARD::Tags::MacroDirective>]
126
126
  def macros
127
- @macros ||= []
127
+ @macros ||= collect_macros
128
128
  end
129
129
 
130
130
  # Perform a quick check to see if this pin possibly includes YARD
@@ -220,6 +220,13 @@ module Solargraph
220
220
  t1.name == t2.name &&
221
221
  t1.types == t2.types
222
222
  end
223
+
224
+ # @return [Array<YARD::Tags::Handlers::Directive>]
225
+ def collect_macros
226
+ return [] unless maybe_directives?
227
+ parse = YARD::Docstring.parser.parse(comments)
228
+ parse.directives.select{ |d| d.tag.tag_name == 'macro' }
229
+ end
223
230
  end
224
231
  end
225
232
  end
@@ -65,7 +65,7 @@ module Solargraph
65
65
 
66
66
  def generate_complex_type
67
67
  tag = docstring.tag(:type)
68
- return ComplexType.parse(*tag.types) unless tag.nil?
68
+ return ComplexType.parse(*tag.types) unless tag.nil? || tag.types.nil? || tag.types.empty?
69
69
  return ComplexType.parse(@literal) unless @literal.nil?
70
70
  ComplexType.new
71
71
  end
@@ -56,9 +56,14 @@ module Solargraph
56
56
  params.each do |p|
57
57
  next unless p.name == name
58
58
  found = p
59
+ break
60
+ end
61
+ if found.nil? and !index.nil?
62
+ found = params[index] if params[index] && (params[index].name.nil? || params[index].name.empty?)
59
63
  end
60
64
  @return_complex_type = ComplexType.parse(*found.types) unless found.nil? or found.types.nil?
61
65
  end
66
+ super
62
67
  @return_complex_type
63
68
  end
64
69
 
@@ -70,8 +70,8 @@ module Solargraph
70
70
 
71
71
  def generate_link
72
72
  this_path = path || return_type.tag
73
+ return nil if this_path.nil? || this_path == 'undefined'
73
74
  return this_path if comments.empty?
74
- return nil if this_path.nil? or this_path == 'undefined'
75
75
  "[#{this_path.gsub('_', '\\\\_')}](solargraph:/document?query=#{URI.encode(this_path)})"
76
76
  end
77
77
  end
@@ -1,6 +1,8 @@
1
1
  module Solargraph
2
2
  module Pin
3
3
  class Method < Base
4
+ include Source::NodeMethods
5
+
4
6
  # @return [Symbol] :instance or :class
5
7
  attr_reader :scope
6
8
 
@@ -10,11 +12,15 @@ module Solargraph
10
12
  # @return [Array<String>]
11
13
  attr_reader :parameters
12
14
 
13
- def initialize location, namespace, name, comments, scope, visibility, args
15
+ # @return [Parser::AST::Node]
16
+ attr_reader :node
17
+
18
+ def initialize location, namespace, name, comments, scope, visibility, args, node = nil
14
19
  super(location, namespace, name, comments)
15
20
  @scope = scope
16
21
  @visibility = visibility
17
22
  @parameters = args
23
+ @node = node
18
24
  end
19
25
 
20
26
  # @return [Array<String>]
@@ -81,6 +87,20 @@ module Solargraph
81
87
  visibility == other.visibility
82
88
  end
83
89
 
90
+ def infer api_map
91
+ decl = super
92
+ return decl unless decl.undefined?
93
+ type = see_reference(api_map)
94
+ return type unless type.nil?
95
+ infer_from_return_nodes(api_map)
96
+ end
97
+
98
+ def try_merge! pin
99
+ return false unless super
100
+ @node = pin.node
101
+ true
102
+ end
103
+
84
104
  private
85
105
 
86
106
  # @return [ComplexType]
@@ -98,6 +118,44 @@ module Solargraph
98
118
  ComplexType::UNDEFINED
99
119
  end
100
120
  end
121
+
122
+ # @param api_map [ApiMap]
123
+ def infer_from_return_nodes api_map
124
+ return ComplexType::UNDEFINED if node.nil? ||
125
+ (node.type == :def && node.children[2].nil?) ||
126
+ (node.type == :defs && node.children[3].nil?)
127
+ result = []
128
+ nodes = node.type == :def ? returns_from(node.children[2]) : returns_from(node.children[3])
129
+ nodes.each do |n|
130
+ next if n.loc.nil?
131
+ clip = api_map.clip_at(location.filename, Solargraph::Position.new(n.loc.expression.last_line, n.loc.expression.last_column))
132
+ type = clip.infer
133
+ result.push type unless type.undefined?
134
+ end
135
+ return ComplexType::UNDEFINED if result.empty?
136
+ ComplexType.parse(*result.map(&:tag))
137
+ end
138
+
139
+ # @param [ApiMap]
140
+ def see_reference api_map
141
+ docstring.ref_tags.each do |ref|
142
+ next unless ref.tag_name == 'return' && ref.owner
143
+ parts = ref.owner.to_s.split(/[\.#]/)
144
+ if parts.first.empty?
145
+ path = "#{namespace}#{ref.owner.to_s}"
146
+ else
147
+ fqns = api_map.qualify(parts.first, namespace)
148
+ return ComplexType::UNDEFINED if fqns.nil?
149
+ path = fqns + ref.owner.to_s[parts.first.length] + parts.last
150
+ end
151
+ pins = api_map.get_path_pins(path)
152
+ pins.each do |pin|
153
+ type = pin.infer(api_map)
154
+ return type unless type.undefined?
155
+ end
156
+ end
157
+ nil
158
+ end
101
159
  end
102
160
  end
103
161
  end