solargraph 0.28.4 → 0.29.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 (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