solargraph 0.39.0 → 0.40.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -7
- data/CHANGELOG.md +984 -0
- data/Rakefile +12 -1
- data/SPONSORS.md +6 -0
- data/lib/.rubocop.yml +21 -0
- data/lib/solargraph/api_map/cache.rb +4 -0
- data/lib/solargraph/api_map/store.rb +35 -51
- data/lib/solargraph/api_map.rb +94 -87
- data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
- data/lib/solargraph/compat.rb +23 -0
- data/lib/solargraph/complex_type.rb +2 -2
- data/lib/solargraph/convention/base.rb +16 -8
- data/lib/solargraph/convention/gemfile.rb +2 -5
- data/lib/solargraph/convention/gemspec.rb +3 -6
- data/lib/solargraph/convention/rspec.rb +3 -6
- data/lib/solargraph/convention.rb +14 -5
- data/lib/solargraph/diagnostics/rubocop.rb +2 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
- data/lib/solargraph/documentor.rb +4 -0
- data/lib/solargraph/environ.rb +11 -6
- data/lib/solargraph/language_server/host.rb +1 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +6 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/formatting.rb +7 -3
- data/lib/solargraph/language_server/uri_helpers.rb +23 -3
- data/lib/solargraph/library.rb +22 -8
- data/lib/solargraph/parser/legacy/class_methods.rb +4 -0
- data/lib/solargraph/parser/legacy/node_chainer.rb +10 -7
- data/lib/solargraph/parser/legacy/node_methods.rb +16 -3
- data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/legacy/node_processors/send_node.rb +48 -23
- data/lib/solargraph/parser/node_processor/base.rb +3 -0
- data/lib/solargraph/parser/rubyvm/class_methods.rb +6 -2
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +11 -9
- data/lib/solargraph/parser/rubyvm/node_methods.rb +6 -1
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +35 -11
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +6 -1
- data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +6 -1
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +52 -67
- data/lib/solargraph/parser/rubyvm/node_processors.rb +2 -0
- data/lib/solargraph/pin/base.rb +2 -2
- data/lib/solargraph/pin/base_variable.rb +1 -1
- data/lib/solargraph/pin/block.rb +28 -14
- data/lib/solargraph/pin/closure.rb +1 -1
- data/lib/solargraph/pin/common.rb +1 -1
- data/lib/solargraph/pin/constant.rb +1 -1
- data/lib/solargraph/pin/conversions.rb +3 -4
- data/lib/solargraph/pin/documenting.rb +6 -11
- data/lib/solargraph/pin/local_variable.rb +1 -1
- data/lib/solargraph/pin/method.rb +143 -9
- data/lib/solargraph/pin/method_alias.rb +2 -2
- data/lib/solargraph/pin/namespace.rb +1 -1
- data/lib/solargraph/pin/parameter.rb +2 -2
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin.rb +0 -3
- data/lib/solargraph/position.rb +2 -14
- data/lib/solargraph/shell.rb +2 -1
- data/lib/solargraph/source/chain/call.rb +9 -0
- data/lib/solargraph/source/chain/head.rb +14 -8
- data/lib/solargraph/source/chain/z_super.rb +30 -0
- data/lib/solargraph/source/chain.rb +19 -36
- data/lib/solargraph/source/source_chainer.rb +2 -1
- data/lib/solargraph/source.rb +24 -9
- data/lib/solargraph/source_map/clip.rb +78 -44
- data/lib/solargraph/source_map/mapper.rb +41 -21
- data/lib/solargraph/source_map.rb +20 -2
- data/lib/solargraph/type_checker/param_def.rb +1 -1
- data/lib/solargraph/type_checker.rb +61 -42
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_name_type_tag.erb +1 -1
- data/lib/solargraph/workspace.rb +1 -1
- data/lib/solargraph/yard_map/core_fills.rb +185 -0
- data/lib/solargraph/yard_map/helpers.rb +16 -0
- data/lib/solargraph/{pin/yard_pin/constant.rb → yard_map/mapper/to_constant.rb} +6 -6
- data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
- data/lib/solargraph/{pin/yard_pin/namespace.rb → yard_map/mapper/to_namespace.rb} +6 -6
- data/lib/solargraph/yard_map/mapper.rb +17 -8
- data/lib/solargraph/yard_map/rdoc_to_yard.rb +26 -15
- data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
- data/lib/solargraph/yard_map/to_method.rb +79 -0
- data/lib/solargraph/yard_map.rb +140 -92
- data/lib/solargraph.rb +5 -4
- data/solargraph.gemspec +5 -5
- data/yardoc/2.2.2.tar.gz +0 -0
- metadata +29 -41
- data/.rubocop.yml +0 -6
- data/lib/solargraph/core_fills.rb +0 -159
- data/lib/solargraph/pin/attribute.rb +0 -49
- data/lib/solargraph/pin/base_method.rb +0 -141
- data/lib/solargraph/pin/yard_pin/method.rb +0 -65
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -26
- data/lib/solargraph/pin/yard_pin.rb +0 -12
- data/lib/solargraph/stdlib_fills.rb +0 -32
- data/travis-bundler.rb +0 -11
|
@@ -20,6 +20,7 @@ module Solargraph
|
|
|
20
20
|
autoload :Head, 'solargraph/source/chain/head'
|
|
21
21
|
autoload :Or, 'solargraph/source/chain/or'
|
|
22
22
|
autoload :BlockVariable, 'solargraph/source/chain/block_variable'
|
|
23
|
+
autoload :ZSuper, 'solargraph/source/chain/z_super'
|
|
23
24
|
|
|
24
25
|
@@inference_stack = []
|
|
25
26
|
@@inference_depth = 0
|
|
@@ -56,7 +57,6 @@ module Solargraph
|
|
|
56
57
|
# @param locals [Array<Pin::Base>]
|
|
57
58
|
# @return [Array<Pin::Base>]
|
|
58
59
|
def define api_map, name_pin, locals
|
|
59
|
-
rebind_block name_pin, api_map, locals
|
|
60
60
|
return [] if undefined?
|
|
61
61
|
working_pin = name_pin
|
|
62
62
|
links[0..-2].each do |link|
|
|
@@ -78,7 +78,6 @@ module Solargraph
|
|
|
78
78
|
# @param locals [Array<Pin::Base>]
|
|
79
79
|
# @return [ComplexType]
|
|
80
80
|
def infer api_map, name_pin, locals
|
|
81
|
-
rebind_block name_pin, api_map, locals
|
|
82
81
|
pins = define(api_map, name_pin, locals)
|
|
83
82
|
infer_first_defined(pins, links.last.last_context, api_map)
|
|
84
83
|
end
|
|
@@ -111,18 +110,21 @@ module Solargraph
|
|
|
111
110
|
# @param api_map [ApiMap]
|
|
112
111
|
# @return [ComplexType]
|
|
113
112
|
def infer_first_defined pins, context, api_map
|
|
114
|
-
|
|
113
|
+
possibles = []
|
|
115
114
|
pins.each do |pin|
|
|
116
115
|
# Avoid infinite recursion
|
|
117
116
|
next if @@inference_stack.include?(pin.identity)
|
|
118
117
|
@@inference_stack.push pin.identity
|
|
119
118
|
type = pin.typify(api_map)
|
|
120
119
|
@@inference_stack.pop
|
|
121
|
-
|
|
120
|
+
if type.defined?
|
|
121
|
+
possibles.push type
|
|
122
|
+
break if pin.is_a?(Pin::Method)
|
|
123
|
+
end
|
|
122
124
|
end
|
|
123
|
-
if
|
|
125
|
+
if possibles.empty?
|
|
124
126
|
# Limit method inference recursion
|
|
125
|
-
return
|
|
127
|
+
return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
|
|
126
128
|
@@inference_depth += 1
|
|
127
129
|
pins.each do |pin|
|
|
128
130
|
# Avoid infinite recursion
|
|
@@ -130,41 +132,22 @@ module Solargraph
|
|
|
130
132
|
@@inference_stack.push pin.identity
|
|
131
133
|
type = pin.probe(api_map)
|
|
132
134
|
@@inference_stack.pop
|
|
133
|
-
|
|
135
|
+
if type.defined?
|
|
136
|
+
possibles.push type
|
|
137
|
+
break if pin.is_a?(Pin::Method)
|
|
138
|
+
end
|
|
134
139
|
end
|
|
135
140
|
@@inference_depth -= 1
|
|
136
141
|
end
|
|
137
|
-
return
|
|
138
|
-
type.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def skippable_block_receivers api_map
|
|
142
|
-
@@skippable_block_receivers ||= (
|
|
143
|
-
api_map.get_methods('Array', deep: false).map(&:name) +
|
|
144
|
-
api_map.get_methods('Enumerable', deep: false).map(&:name) +
|
|
145
|
-
api_map.get_methods('Hash', deep: false).map(&:name) +
|
|
146
|
-
['new']
|
|
147
|
-
).to_set
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def rebind_block pin, api_map, locals
|
|
151
|
-
return unless pin.is_a?(Pin::Block) && pin.receiver && !pin.rebound?
|
|
152
|
-
# This first rebind just sets the block pin's rebound state
|
|
153
|
-
pin.rebind ComplexType::UNDEFINED
|
|
154
|
-
chain = Parser.chain(pin.receiver, pin.location.filename)
|
|
155
|
-
return if skippable_block_receivers(api_map).include?(chain.links.last.word)
|
|
156
|
-
if ['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec'].include?(chain.links.last.word)
|
|
157
|
-
type = chain.base.infer(api_map, pin, locals)
|
|
158
|
-
pin.rebind type
|
|
142
|
+
return ComplexType::UNDEFINED if possibles.empty?
|
|
143
|
+
type = if possibles.length > 1
|
|
144
|
+
sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
|
|
145
|
+
ComplexType.parse(*sorted)
|
|
159
146
|
else
|
|
160
|
-
|
|
161
|
-
return if receiver_pin.nil? || receiver_pin.docstring.nil?
|
|
162
|
-
ys = receiver_pin.docstring.tag(:yieldself)
|
|
163
|
-
unless ys.nil? || ys.types.nil? || ys.types.empty?
|
|
164
|
-
ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
|
|
165
|
-
pin.rebind ysct
|
|
166
|
-
end
|
|
147
|
+
possibles.first
|
|
167
148
|
end
|
|
149
|
+
return type if context.nil? || context.return_type.undefined?
|
|
150
|
+
type.self_to(context.return_type.namespace)
|
|
168
151
|
end
|
|
169
152
|
end
|
|
170
153
|
end
|
|
@@ -17,7 +17,6 @@ module Solargraph
|
|
|
17
17
|
# @param position [Position]
|
|
18
18
|
# @return [Source::Chain]
|
|
19
19
|
def chain source, position
|
|
20
|
-
# raise "Not a source" unless source.is_a?(Source)
|
|
21
20
|
new(source, position).chain
|
|
22
21
|
end
|
|
23
22
|
end
|
|
@@ -32,6 +31,8 @@ module Solargraph
|
|
|
32
31
|
|
|
33
32
|
# @return [Source::Chain]
|
|
34
33
|
def chain
|
|
34
|
+
# Special handling for files that end with an integer and a period
|
|
35
|
+
return Chain.new([Chain::Literal.new('Integer'), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
|
|
35
36
|
return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
|
|
36
37
|
begin
|
|
37
38
|
return Chain.new([]) if phrase.end_with?('..')
|
data/lib/solargraph/source.rb
CHANGED
|
@@ -284,7 +284,7 @@ module Solargraph
|
|
|
284
284
|
|
|
285
285
|
FOLDING_NODE_TYPES = if Parser.rubyvm?
|
|
286
286
|
%i[
|
|
287
|
-
CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR
|
|
287
|
+
CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR HASH ARRAY LIST
|
|
288
288
|
].freeze
|
|
289
289
|
else
|
|
290
290
|
%i[
|
|
@@ -338,25 +338,29 @@ module Solargraph
|
|
|
338
338
|
|
|
339
339
|
def first_not_empty_from line
|
|
340
340
|
cursor = line
|
|
341
|
-
cursor += 1 while cursor <
|
|
342
|
-
cursor = line if cursor >
|
|
341
|
+
cursor += 1 while cursor < code_lines.length && code_lines[cursor].strip.empty?
|
|
342
|
+
cursor = line if cursor > code_lines.length - 1
|
|
343
343
|
cursor
|
|
344
344
|
end
|
|
345
345
|
|
|
346
346
|
# @param top [Parser::AST::Node]
|
|
347
347
|
# @param result [Array<Range>]
|
|
348
|
+
# @param parent [Symbol]
|
|
348
349
|
# @return [void]
|
|
349
|
-
def inner_folding_ranges top, result = []
|
|
350
|
+
def inner_folding_ranges top, result = [], parent = nil
|
|
350
351
|
# return unless top.is_a?(::Parser::AST::Node)
|
|
351
352
|
return unless Parser.is_ast_node?(top)
|
|
352
353
|
if FOLDING_NODE_TYPES.include?(top.type)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
# @todo Smelly exception for hash's first-level array in RubyVM
|
|
355
|
+
unless [:ARRAY, :LIST].include?(top.type) && parent == :HASH
|
|
356
|
+
range = Range.from_node(top)
|
|
357
|
+
if result.empty? || range.start.line > result.last.start.line
|
|
358
|
+
result.push range unless range.ending.line - range.start.line < 2
|
|
359
|
+
end
|
|
356
360
|
end
|
|
357
361
|
end
|
|
358
362
|
top.children.each do |child|
|
|
359
|
-
inner_folding_ranges(child, result)
|
|
363
|
+
inner_folding_ranges(child, result, top.type)
|
|
360
364
|
end
|
|
361
365
|
end
|
|
362
366
|
|
|
@@ -468,8 +472,12 @@ module Solargraph
|
|
|
468
472
|
# @return [Integer]
|
|
469
473
|
attr_writer :version
|
|
470
474
|
|
|
475
|
+
# @param val [String]
|
|
471
476
|
# @return [String]
|
|
472
|
-
|
|
477
|
+
def code=(val)
|
|
478
|
+
@code_lines= nil
|
|
479
|
+
@code = val
|
|
480
|
+
end
|
|
473
481
|
|
|
474
482
|
# @return [Parser::AST::Node]
|
|
475
483
|
attr_writer :node
|
|
@@ -492,6 +500,13 @@ module Solargraph
|
|
|
492
500
|
# @return [Source::Updater]
|
|
493
501
|
attr_accessor :last_updater
|
|
494
502
|
|
|
503
|
+
private
|
|
504
|
+
|
|
505
|
+
# @return [Array<String>]
|
|
506
|
+
def code_lines
|
|
507
|
+
@code_lines ||= code.lines
|
|
508
|
+
end
|
|
509
|
+
|
|
495
510
|
class << self
|
|
496
511
|
# @param filename [String]
|
|
497
512
|
# @return [Solargraph::Source]
|
|
@@ -25,51 +25,12 @@ module Solargraph
|
|
|
25
25
|
def complete
|
|
26
26
|
return package_completions([]) if !source_map.source.parsed? || cursor.string?
|
|
27
27
|
return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
|
|
28
|
-
return Completion.new([], cursor.range) if cursor.chain.literal?
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if cursor.chain.constant? || cursor.start_of_constant?
|
|
32
|
-
full = cursor.chain.links.first.word
|
|
33
|
-
type = if cursor.chain.undefined?
|
|
34
|
-
cursor.chain.base.infer(api_map, context_pin, locals)
|
|
35
|
-
else
|
|
36
|
-
if full.include?('::') && cursor.chain.links.length == 1
|
|
37
|
-
ComplexType.try_parse(full.split('::')[0..-2].join('::'))
|
|
38
|
-
elsif cursor.chain.links.length > 1
|
|
39
|
-
ComplexType.try_parse(full)
|
|
40
|
-
else
|
|
41
|
-
ComplexType::UNDEFINED
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
if type.undefined?
|
|
45
|
-
if full.include?('::')
|
|
46
|
-
result.concat api_map.get_constants(full, *gates)
|
|
47
|
-
else
|
|
48
|
-
result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
|
|
49
|
-
end
|
|
50
|
-
else
|
|
51
|
-
result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
|
|
52
|
-
end
|
|
28
|
+
return Completion.new([], cursor.range) if cursor.chain.literal?
|
|
29
|
+
if cursor.comment?
|
|
30
|
+
tag_complete
|
|
53
31
|
else
|
|
54
|
-
|
|
55
|
-
result.concat api_map.get_complex_type_methods(type, block.binder.namespace, cursor.chain.links.length == 1)
|
|
56
|
-
if cursor.chain.links.length == 1
|
|
57
|
-
if cursor.word.start_with?('@@')
|
|
58
|
-
return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
|
|
59
|
-
elsif cursor.word.start_with?('@')
|
|
60
|
-
return package_completions(api_map.get_instance_variable_pins(block.binder.namespace, block.binder.scope))
|
|
61
|
-
elsif cursor.word.start_with?('$')
|
|
62
|
-
return package_completions(api_map.get_global_variable_pins)
|
|
63
|
-
end
|
|
64
|
-
result.concat locals
|
|
65
|
-
result.concat api_map.get_constants(context_pin.context.namespace, *gates)
|
|
66
|
-
result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
|
|
67
|
-
result.concat api_map.get_methods('Kernel')
|
|
68
|
-
result.concat ApiMap.keywords
|
|
69
|
-
result.concat yielded_self_pins
|
|
70
|
-
end
|
|
32
|
+
code_complete
|
|
71
33
|
end
|
|
72
|
-
package_completions(result)
|
|
73
34
|
end
|
|
74
35
|
|
|
75
36
|
# @return [Array<Pin::Base>]
|
|
@@ -111,6 +72,13 @@ module Solargraph
|
|
|
111
72
|
end
|
|
112
73
|
end
|
|
113
74
|
|
|
75
|
+
# @param phrase [String]
|
|
76
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
77
|
+
def translate phrase
|
|
78
|
+
chain = Parser.chain(Parser.parse(phrase))
|
|
79
|
+
chain.define(api_map, block, locals)
|
|
80
|
+
end
|
|
81
|
+
|
|
114
82
|
private
|
|
115
83
|
|
|
116
84
|
# @return [ApiMap]
|
|
@@ -181,10 +149,76 @@ module Solargraph
|
|
|
181
149
|
frag_start = cursor.start_of_word.to_s.downcase
|
|
182
150
|
filtered = result.uniq(&:name).select { |s|
|
|
183
151
|
s.name.downcase.start_with?(frag_start) &&
|
|
184
|
-
(!s.is_a?(Pin::
|
|
152
|
+
(!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
|
|
185
153
|
}
|
|
186
154
|
Completion.new(filtered, cursor.range)
|
|
187
155
|
end
|
|
156
|
+
|
|
157
|
+
def tag_complete
|
|
158
|
+
result = []
|
|
159
|
+
match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
|
|
160
|
+
if match
|
|
161
|
+
full = match[1]
|
|
162
|
+
if full.include?('::')
|
|
163
|
+
if full.end_with?('::')
|
|
164
|
+
result.concat api_map.get_constants(full[0..-3], *gates)
|
|
165
|
+
else
|
|
166
|
+
result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates)
|
|
167
|
+
end
|
|
168
|
+
else
|
|
169
|
+
result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
package_completions(result)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def code_complete
|
|
176
|
+
result = []
|
|
177
|
+
result.concat complete_keyword_parameters
|
|
178
|
+
if cursor.chain.constant? || cursor.start_of_constant?
|
|
179
|
+
full = cursor.chain.links.first.word
|
|
180
|
+
type = if cursor.chain.undefined?
|
|
181
|
+
cursor.chain.base.infer(api_map, context_pin, locals)
|
|
182
|
+
else
|
|
183
|
+
if full.include?('::') && cursor.chain.links.length == 1
|
|
184
|
+
ComplexType.try_parse(full.split('::')[0..-2].join('::'))
|
|
185
|
+
elsif cursor.chain.links.length > 1
|
|
186
|
+
ComplexType.try_parse(full)
|
|
187
|
+
else
|
|
188
|
+
ComplexType::UNDEFINED
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
if type.undefined?
|
|
192
|
+
if full.include?('::')
|
|
193
|
+
result.concat api_map.get_constants(full, *gates)
|
|
194
|
+
else
|
|
195
|
+
result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
|
|
196
|
+
end
|
|
197
|
+
else
|
|
198
|
+
result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
|
|
199
|
+
end
|
|
200
|
+
else
|
|
201
|
+
type = cursor.chain.base.infer(api_map, block, locals)
|
|
202
|
+
result.concat api_map.get_complex_type_methods(type, block.binder.namespace, cursor.chain.links.length == 1)
|
|
203
|
+
if cursor.chain.links.length == 1
|
|
204
|
+
if cursor.word.start_with?('@@')
|
|
205
|
+
return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
|
|
206
|
+
elsif cursor.word.start_with?('@')
|
|
207
|
+
return package_completions(api_map.get_instance_variable_pins(block.binder.namespace, block.binder.scope))
|
|
208
|
+
elsif cursor.word.start_with?('$')
|
|
209
|
+
return package_completions(api_map.get_global_variable_pins)
|
|
210
|
+
end
|
|
211
|
+
result.concat locals
|
|
212
|
+
result.concat api_map.get_constants(context_pin.context.namespace, *gates)
|
|
213
|
+
result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
|
|
214
|
+
result.concat api_map.get_methods('Kernel')
|
|
215
|
+
# result.concat ApiMap.keywords
|
|
216
|
+
result.concat api_map.keyword_pins
|
|
217
|
+
result.concat yielded_self_pins
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
package_completions(result)
|
|
221
|
+
end
|
|
188
222
|
end
|
|
189
223
|
end
|
|
190
224
|
end
|
|
@@ -68,7 +68,7 @@ module Solargraph
|
|
|
68
68
|
# @param d [YARD::Tags::Directive]
|
|
69
69
|
parse.directives.each do |d|
|
|
70
70
|
line_num = find_directive_line_number(cmnt, d.tag.tag_name, last_line)
|
|
71
|
-
pos = Solargraph::Position.new(comment_position.line + line_num, comment_position.column)
|
|
71
|
+
pos = Solargraph::Position.new(comment_position.line + line_num - 1, comment_position.column)
|
|
72
72
|
process_directive(source_position, pos, d)
|
|
73
73
|
last_line = line_num + 1
|
|
74
74
|
# @todo The below call assumes the topmost comment line. The above
|
|
@@ -79,7 +79,11 @@ module Solargraph
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
# @param comment [String]
|
|
83
|
+
# @return [Integer]
|
|
82
84
|
def find_directive_line_number comment, tag, start
|
|
85
|
+
# Avoid overruning the index
|
|
86
|
+
return start unless start < comment.lines.length
|
|
83
87
|
num = comment.lines[start..-1].find_index do |line|
|
|
84
88
|
# Legacy method directives might be `@method` instead of `@!method`
|
|
85
89
|
# @todo Legacy syntax should probably emit a warning
|
|
@@ -91,23 +95,24 @@ module Solargraph
|
|
|
91
95
|
# @param source_position [Position]
|
|
92
96
|
# @param comment_position [Position]
|
|
93
97
|
# @param directive [YARD::Tags::Directive]
|
|
98
|
+
# @return [void]
|
|
94
99
|
def process_directive source_position, comment_position, directive
|
|
95
100
|
docstring = Solargraph::Source.parse_docstring(directive.tag.text).to_docstring
|
|
96
101
|
location = Location.new(@filename, Range.new(comment_position, comment_position))
|
|
97
102
|
case directive.tag.tag_name
|
|
98
103
|
when 'method'
|
|
99
|
-
namespace = closure_at(source_position)
|
|
104
|
+
namespace = closure_at(source_position) || @pins.first
|
|
100
105
|
if namespace.location.range.start.line < comment_position.line
|
|
101
106
|
namespace = closure_at(comment_position)
|
|
102
107
|
end
|
|
103
|
-
region = Parser::Region.new(source: @source, closure: namespace)
|
|
104
108
|
begin
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
src = Solargraph::Source.load_string("def #{directive.tag.name};end", @source.filename)
|
|
110
|
+
region = Parser::Region.new(source: src, closure: namespace)
|
|
111
|
+
gen_pin = Parser.process_node(src.node, region).first.last
|
|
107
112
|
return if gen_pin.nil?
|
|
108
|
-
# Move the location to the end of the line so
|
|
109
|
-
#
|
|
110
|
-
shifted = Solargraph::Position.new(comment_position.line, @code.lines[comment_position.line].chomp.length)
|
|
113
|
+
# Move the location to the end of the line so it gets recognized
|
|
114
|
+
# as originating from a comment
|
|
115
|
+
shifted = Solargraph::Position.new(comment_position.line, @code.lines[comment_position.line].to_s.chomp.length)
|
|
111
116
|
# @todo: Smelly instance variable access
|
|
112
117
|
gen_pin.instance_variable_set(:@comments, docstring.all.to_s)
|
|
113
118
|
gen_pin.instance_variable_set(:@location, Solargraph::Location.new(@filename, Range.new(shifted, shifted)))
|
|
@@ -121,35 +126,50 @@ module Solargraph
|
|
|
121
126
|
namespace = closure_at(source_position)
|
|
122
127
|
t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
|
|
123
128
|
if t.nil? || t.include?('r')
|
|
124
|
-
pins.push Solargraph::Pin::
|
|
129
|
+
pins.push Solargraph::Pin::Method.new(
|
|
125
130
|
location: location,
|
|
126
131
|
closure: namespace,
|
|
127
132
|
name: directive.tag.name,
|
|
128
133
|
comments: docstring.all.to_s,
|
|
129
|
-
access: :reader,
|
|
130
134
|
scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
|
|
131
135
|
visibility: :public,
|
|
132
|
-
explicit: false
|
|
136
|
+
explicit: false,
|
|
137
|
+
attribute: true
|
|
133
138
|
)
|
|
134
139
|
end
|
|
135
140
|
if t.nil? || t.include?('w')
|
|
136
|
-
pins.push Solargraph::Pin::
|
|
141
|
+
pins.push Solargraph::Pin::Method.new(
|
|
137
142
|
location: location,
|
|
138
143
|
closure: namespace,
|
|
139
144
|
name: "#{directive.tag.name}=",
|
|
140
145
|
comments: docstring.all.to_s,
|
|
141
|
-
access: :writer,
|
|
142
146
|
scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
|
|
143
|
-
visibility: :public
|
|
147
|
+
visibility: :public,
|
|
148
|
+
attribute: true
|
|
144
149
|
)
|
|
150
|
+
pins.last.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
|
151
|
+
if pins.last.return_type.defined?
|
|
152
|
+
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
|
|
153
|
+
end
|
|
145
154
|
end
|
|
146
155
|
when 'parse'
|
|
147
|
-
ns = closure_at(source_position)
|
|
148
|
-
region = Parser::Region.new(source: @source, closure: ns)
|
|
149
156
|
begin
|
|
150
|
-
|
|
157
|
+
ns = closure_at(source_position)
|
|
158
|
+
src = Solargraph::Source.load_string(directive.tag.text, @source.filename)
|
|
159
|
+
region = Parser::Region.new(source: src, closure: ns)
|
|
151
160
|
# @todo These pins may need to be marked not explicit
|
|
152
|
-
|
|
161
|
+
index = @pins.length
|
|
162
|
+
loff = if @code.lines[comment_position.line].strip.end_with?('@!parse')
|
|
163
|
+
comment_position.line + 1
|
|
164
|
+
else
|
|
165
|
+
comment_position.line
|
|
166
|
+
end
|
|
167
|
+
Parser.process_node(src.node, region, @pins)
|
|
168
|
+
@pins[index..-1].each do |p|
|
|
169
|
+
# @todo Smelly instance variable access
|
|
170
|
+
p.location.range.start.instance_variable_set(:@line, p.location.range.start.line + loff)
|
|
171
|
+
p.location.range.ending.instance_variable_set(:@line, p.location.range.ending.line + loff)
|
|
172
|
+
end
|
|
153
173
|
rescue Parser::SyntaxError => e
|
|
154
174
|
# @todo Handle parser errors in !parse directives
|
|
155
175
|
end
|
|
@@ -183,10 +203,10 @@ module Solargraph
|
|
|
183
203
|
# @return [void]
|
|
184
204
|
def process_comment_directives
|
|
185
205
|
return unless @code =~ MACRO_REGEXP
|
|
186
|
-
|
|
206
|
+
code_lines = @code.lines
|
|
187
207
|
@source.associated_comments.each do |line, comments|
|
|
188
|
-
src_pos = line ? Position.new(line,
|
|
189
|
-
com_pos = Position.new(line -
|
|
208
|
+
src_pos = line ? Position.new(line, code_lines[line].to_s.chomp.index(/[^\s]/) || 0) : Position.new(code_lines.length, 0)
|
|
209
|
+
com_pos = Position.new(line + 1 - comments.lines.length, 0)
|
|
190
210
|
process_comment(src_pos, com_pos, comments)
|
|
191
211
|
end
|
|
192
212
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'jaro_winkler'
|
|
4
4
|
require 'yard'
|
|
5
5
|
require 'yard-solargraph'
|
|
6
|
+
require 'set'
|
|
6
7
|
|
|
7
8
|
module Solargraph
|
|
8
9
|
# An index of pins and other ApiMap-related data for a Source.
|
|
@@ -29,7 +30,20 @@ module Solargraph
|
|
|
29
30
|
@source = source.dup
|
|
30
31
|
@pins = pins
|
|
31
32
|
@locals = locals
|
|
32
|
-
environ.merge Convention.
|
|
33
|
+
environ.merge Convention.for_local(self) unless filename.nil?
|
|
34
|
+
@pin_class_hash = pins.to_set.classify(&:class).transform_values(&:to_a)
|
|
35
|
+
@pin_select_cache = {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def pins_by_class klass
|
|
39
|
+
@pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def rebindable_method_names
|
|
43
|
+
@rebindable_method_names ||= pins_by_class(Pin::Method)
|
|
44
|
+
.select { |pin| pin.comments && pin.comments.include?('@yieldself') }
|
|
45
|
+
.map(&:name)
|
|
46
|
+
.to_set
|
|
33
47
|
end
|
|
34
48
|
|
|
35
49
|
# @return [String]
|
|
@@ -44,7 +58,7 @@ module Solargraph
|
|
|
44
58
|
|
|
45
59
|
# @return [Array<Pin::Reference::Require>]
|
|
46
60
|
def requires
|
|
47
|
-
|
|
61
|
+
pins_by_class(Pin::Reference::Require)
|
|
48
62
|
end
|
|
49
63
|
|
|
50
64
|
# @return [Environ]
|
|
@@ -62,6 +76,7 @@ module Solargraph
|
|
|
62
76
|
# @param query [String]
|
|
63
77
|
# @return [Array<Pin::Base>]
|
|
64
78
|
def query_symbols query
|
|
79
|
+
return document_symbols if query && query.empty?
|
|
65
80
|
document_symbols.select{ |pin| fuzzy_string_match(pin.path, query) || fuzzy_string_match(pin.name, query) }
|
|
66
81
|
end
|
|
67
82
|
|
|
@@ -153,6 +168,9 @@ module Solargraph
|
|
|
153
168
|
position = Position.new(line, character)
|
|
154
169
|
found = nil
|
|
155
170
|
pins.each do |pin|
|
|
171
|
+
# @todo Attribute pins should not be treated like closures, but
|
|
172
|
+
# there's probably a better way to handle it
|
|
173
|
+
next if pin.is_a?(Pin::Method) && pin.attribute?
|
|
156
174
|
found = pin if (klasses.empty? || klasses.any? { |kls| pin.is_a?(kls) } ) && pin.location.range.contain?(position)
|
|
157
175
|
break if pin.location.range.start.line > line
|
|
158
176
|
end
|