solargraph 0.26.1 → 0.27.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.rb +5 -2
- data/lib/solargraph/api_map.rb +236 -234
- data/lib/solargraph/api_map/store.rb +18 -53
- data/lib/solargraph/bundle.rb +22 -0
- data/lib/solargraph/complex_type.rb +9 -5
- data/lib/solargraph/complex_type/type_methods.rb +113 -0
- data/lib/solargraph/complex_type/unique_type.rb +35 -0
- data/lib/solargraph/core_fills.rb +1 -0
- data/lib/solargraph/diagnostics.rb +6 -4
- data/lib/solargraph/diagnostics/base.rb +3 -0
- data/lib/solargraph/diagnostics/require_not_found.rb +2 -1
- data/lib/solargraph/diagnostics/rubocop.rb +21 -6
- data/lib/solargraph/diagnostics/type_not_defined.rb +4 -3
- data/lib/solargraph/diagnostics/update_errors.rb +18 -0
- data/lib/solargraph/language_server/host.rb +90 -222
- data/lib/solargraph/language_server/host/cataloger.rb +68 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +85 -0
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +35 -24
- data/lib/solargraph/language_server/message/text_document/completion.rb +6 -8
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +0 -1
- data/lib/solargraph/language_server/transport/socket.rb +4 -6
- data/lib/solargraph/language_server/transport/stdio.rb +4 -6
- data/lib/solargraph/library.rb +152 -99
- data/lib/solargraph/live_map.rb +1 -1
- data/lib/solargraph/location.rb +28 -0
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin/attribute.rb +26 -12
- data/lib/solargraph/pin/base.rb +15 -35
- data/lib/solargraph/pin/base_variable.rb +7 -15
- data/lib/solargraph/pin/block.rb +5 -9
- data/lib/solargraph/pin/block_parameter.rb +9 -7
- data/lib/solargraph/pin/conversions.rb +5 -5
- data/lib/solargraph/pin/duck_method.rb +1 -1
- data/lib/solargraph/pin/instance_variable.rb +0 -4
- data/lib/solargraph/pin/keyword.rb +4 -0
- data/lib/solargraph/pin/localized.rb +5 -3
- data/lib/solargraph/pin/method.rb +11 -0
- data/lib/solargraph/pin/namespace.rb +7 -3
- data/lib/solargraph/pin/proxy_type.rb +3 -7
- data/lib/solargraph/pin/reference.rb +2 -2
- data/lib/solargraph/pin/symbol.rb +1 -1
- data/lib/solargraph/pin/yard_pin/method.rb +2 -2
- data/lib/solargraph/pin/yard_pin/namespace.rb +16 -7
- data/lib/solargraph/position.rb +103 -0
- data/lib/solargraph/range.rb +70 -0
- data/lib/solargraph/source.rb +159 -328
- data/lib/solargraph/source/chain.rb +38 -55
- data/lib/solargraph/source/chain/call.rb +47 -29
- data/lib/solargraph/source/chain/class_variable.rb +2 -2
- data/lib/solargraph/source/chain/constant.rb +3 -3
- data/lib/solargraph/source/chain/definition.rb +7 -3
- data/lib/solargraph/source/chain/global_variable.rb +1 -1
- data/lib/solargraph/source/chain/head.rb +22 -9
- data/lib/solargraph/source/chain/instance_variable.rb +2 -2
- data/lib/solargraph/source/chain/link.rb +4 -4
- data/lib/solargraph/source/chain/literal.rb +1 -1
- data/lib/solargraph/source/chain/variable.rb +2 -2
- data/lib/solargraph/source/change.rb +0 -6
- data/lib/solargraph/source/cursor.rb +161 -0
- data/lib/solargraph/source/encoding_fixes.rb +1 -1
- data/lib/solargraph/source/node_chainer.rb +28 -21
- data/lib/solargraph/source/node_methods.rb +1 -1
- data/lib/solargraph/source/source_chainer.rb +217 -0
- data/lib/solargraph/source_map.rb +138 -0
- data/lib/solargraph/source_map/clip.rb +123 -0
- data/lib/solargraph/{source → source_map}/completion.rb +3 -3
- data/lib/solargraph/{source → source_map}/mapper.rb +143 -41
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +13 -20
- data/lib/solargraph/yard_map.rb +77 -48
- metadata +17 -11
- data/lib/solargraph/basic_type.rb +0 -33
- data/lib/solargraph/basic_type_methods.rb +0 -111
- data/lib/solargraph/source/call_chainer.rb +0 -273
- data/lib/solargraph/source/fragment.rb +0 -342
- data/lib/solargraph/source/location.rb +0 -23
- data/lib/solargraph/source/position.rb +0 -95
- data/lib/solargraph/source/range.rb +0 -64
@@ -0,0 +1,123 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class SourceMap
|
3
|
+
class Clip
|
4
|
+
# @param api_map [ApiMap]
|
5
|
+
# @param cursor [Source::Cursor]
|
6
|
+
def initialize api_map, cursor
|
7
|
+
# @todo Just some temporary stuff while I make sure this works
|
8
|
+
raise "Not a cursor: #{cursor.class}" unless cursor.is_a?(Source::Cursor)
|
9
|
+
@api_map = api_map
|
10
|
+
@cursor = cursor
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Array<Pin::Base>]
|
14
|
+
def define
|
15
|
+
return [] if cursor.chain.literal?
|
16
|
+
result = cursor.chain.define(api_map, context_pin, locals)
|
17
|
+
result.concat(source_map.pins.select{ |p| p.location.range.start.line == cursor.position.line }) if result.empty?
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Completion]
|
22
|
+
def complete
|
23
|
+
return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
|
24
|
+
return Completion.new([], cursor.range) if cursor.chain.literal? || cursor.comment?
|
25
|
+
result = []
|
26
|
+
type = cursor.chain.base.infer(api_map, context_pin, locals)
|
27
|
+
if cursor.chain.constant? || cursor.start_of_constant?
|
28
|
+
result.concat api_map.get_constants(type.undefined? ? '' : type.namespace, cursor.start_of_constant? ? '' : context_pin.context.namespace)
|
29
|
+
else
|
30
|
+
result.concat api_map.get_complex_type_methods(type, context_pin.context.namespace, cursor.chain.links.length == 1)
|
31
|
+
if cursor.chain.links.length == 1
|
32
|
+
if cursor.word.start_with?('@@')
|
33
|
+
return package_completions(api_map.get_class_variable_pins(context_pin.context.namespace))
|
34
|
+
elsif cursor.word.start_with?('@')
|
35
|
+
return package_completions(api_map.get_instance_variable_pins(context_pin.context.namespace, context_pin.context.scope))
|
36
|
+
elsif cursor.word.start_with?('$')
|
37
|
+
return package_completions(api_map.get_global_variable_pins)
|
38
|
+
end
|
39
|
+
result.concat prefer_non_nil_variables(locals)
|
40
|
+
result.concat api_map.get_constants('', context_pin.context.namespace)
|
41
|
+
result.concat api_map.get_methods(context_pin.context.namespace, scope: context_pin.context.scope, visibility: [:public, :private, :protected])
|
42
|
+
result.concat api_map.get_methods('Kernel')
|
43
|
+
result.concat ApiMap.keywords
|
44
|
+
end
|
45
|
+
end
|
46
|
+
package_completions(result)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array<Pin::Base>]
|
50
|
+
def signify
|
51
|
+
return [] unless cursor.argument?
|
52
|
+
clip = Clip.new(api_map, cursor.recipient)
|
53
|
+
clip.define.select{|pin| pin.kind == Pin::METHOD}
|
54
|
+
end
|
55
|
+
|
56
|
+
def infer
|
57
|
+
cursor.chain.infer(api_map, context_pin, locals)
|
58
|
+
end
|
59
|
+
|
60
|
+
# The context at the current position.
|
61
|
+
#
|
62
|
+
# @return [Pin::Base]
|
63
|
+
def context_pin
|
64
|
+
@context ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get an array of all the locals that are visible from the cursors's
|
68
|
+
# position. Locals can be local variables, method parameters, or block
|
69
|
+
# parameters. The array starts with the nearest local pin.
|
70
|
+
#
|
71
|
+
# @return [Array<Solargraph::Pin::Base>]
|
72
|
+
def locals
|
73
|
+
@locals ||= source_map.locals.select { |pin|
|
74
|
+
pin.visible_from?(block, Position.new(cursor.position.line, (cursor.position.column.zero? ? 0 : cursor.position.column - 1)))
|
75
|
+
}.reverse
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# @return [ApiMap]
|
81
|
+
attr_reader :api_map
|
82
|
+
|
83
|
+
# @return [Source::Cursor]
|
84
|
+
attr_reader :cursor
|
85
|
+
|
86
|
+
# @return [SourceMap]
|
87
|
+
def source_map
|
88
|
+
@source_map ||= api_map.source_map(cursor.filename)
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [Solargraph::Pin::Base]
|
92
|
+
def block
|
93
|
+
@block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param cursor [cursor]
|
97
|
+
# @param result [Array<Pin::Base>]
|
98
|
+
# @return [Completion]
|
99
|
+
def package_completions result
|
100
|
+
frag_start = cursor.start_of_word.to_s.downcase
|
101
|
+
filtered = result.uniq(&:name).select{|s| s.name.downcase.start_with?(frag_start) and (s.kind != Pin::METHOD or s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))}
|
102
|
+
Completion.new(filtered, cursor.range)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Sort an array of pins to put nil or undefined variables last.
|
106
|
+
#
|
107
|
+
# @param pins [Array<Pin::Base>]
|
108
|
+
# @return [Array<Pin::Base>]
|
109
|
+
def prefer_non_nil_variables pins
|
110
|
+
result = []
|
111
|
+
nil_pins = []
|
112
|
+
pins.each do |pin|
|
113
|
+
if pin.variable? and pin.nil_assignment?
|
114
|
+
nil_pins.push pin
|
115
|
+
else
|
116
|
+
result.push pin
|
117
|
+
end
|
118
|
+
end
|
119
|
+
result + nil_pins
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Solargraph
|
2
|
-
class
|
2
|
+
class SourceMap
|
3
3
|
# The result of a completion request containing the pins that describe
|
4
4
|
# completion options and the range to be replaced.
|
5
5
|
#
|
@@ -7,11 +7,11 @@ module Solargraph
|
|
7
7
|
# @return [Array<Solargraph::Pin::Base>]
|
8
8
|
attr_reader :pins
|
9
9
|
|
10
|
-
# @return [Solargraph::
|
10
|
+
# @return [Solargraph::Range]
|
11
11
|
attr_reader :range
|
12
12
|
|
13
13
|
# @param pins [Array<Solargraph::Pin::Base>]
|
14
|
-
# @param range [Solargraph::
|
14
|
+
# @param range [Solargraph::Range]
|
15
15
|
def initialize pins, range
|
16
16
|
@pins = pins
|
17
17
|
@range = range
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Solargraph
|
2
|
-
class
|
3
|
-
# The Mapper generates pins and other data for
|
2
|
+
class SourceMap
|
3
|
+
# The Mapper generates pins and other data for SourceMaps.
|
4
4
|
#
|
5
|
-
# This class is used internally by the
|
6
|
-
#
|
7
|
-
# call it directly.
|
5
|
+
# This class is used internally by the SourceMap class. Users should not
|
6
|
+
# normally need to call it directly.
|
8
7
|
#
|
9
8
|
class Mapper
|
10
|
-
include NodeMethods
|
9
|
+
include Source::NodeMethods
|
11
10
|
|
12
11
|
private_class_method :new
|
13
12
|
|
@@ -18,10 +17,11 @@ module Solargraph
|
|
18
17
|
@filename = filename
|
19
18
|
@code = code
|
20
19
|
@node = node
|
20
|
+
@comments = comments
|
21
21
|
@node_stack = []
|
22
22
|
@directives = {}
|
23
23
|
@comment_ranges = comments.map do |c|
|
24
|
-
|
24
|
+
Range.from_to(c.loc.expression.line, c.loc.expression.column, c.loc.expression.last_line, c.loc.expression.last_column)
|
25
25
|
end
|
26
26
|
@node_comments = associate_comments(node, comments)
|
27
27
|
@pins = []
|
@@ -30,25 +30,29 @@ module Solargraph
|
|
30
30
|
@locals = []
|
31
31
|
@strings = []
|
32
32
|
|
33
|
-
@used_comment_locs = []
|
34
|
-
|
35
33
|
# HACK make sure the first node gets processed
|
36
34
|
root = AST::Node.new(:source, [filename])
|
37
35
|
root = root.append node
|
38
36
|
# @todo Is the root namespace a class or a module? Assuming class for now.
|
39
37
|
@pins.push Pin::Namespace.new(get_node_location(nil), '', '', nil, :class, :public, nil)
|
40
38
|
process root
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
process_comment_directives
|
40
|
+
[@pins, @locals, @requires, @symbols]
|
41
|
+
end
|
44
42
|
|
45
|
-
|
43
|
+
def unmap filename, code
|
44
|
+
s = Position.new(0, 0)
|
45
|
+
e = Position.from_offset(code, code.length)
|
46
|
+
location = Location.new(filename, Range.new(s, e))
|
47
|
+
[[Pin::Namespace.new(location, '', '', '', :class, :public, nil)], [], [], []]
|
46
48
|
end
|
47
49
|
|
48
50
|
class << self
|
51
|
+
# @param source [Source]
|
49
52
|
# @return [Array]
|
50
|
-
def map
|
51
|
-
new.
|
53
|
+
def map source
|
54
|
+
return new.unmap(source.filename, source.code) unless source.parsed?
|
55
|
+
new.map source.filename, source.code, source.node, source.comments
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
@@ -59,8 +63,8 @@ module Solargraph
|
|
59
63
|
# slightly more efficient than calculating offsets.
|
60
64
|
b = node.location.expression.begin.begin_pos
|
61
65
|
e = node.location.expression.end.end_pos
|
62
|
-
# b =
|
63
|
-
# e =
|
66
|
+
# b = Position.line_char_to_offset(@code, node.location.line - 1, node.location.column)
|
67
|
+
# e = Position.line_char_to_offset(@code, node.location.last_line - 1, node.location.last_column)
|
64
68
|
frag = source_from_parser[b..e-1].to_s
|
65
69
|
frag.strip.gsub(/,$/, '')
|
66
70
|
end
|
@@ -78,10 +82,7 @@ module Solargraph
|
|
78
82
|
# @param node [Parser::AST::Node]
|
79
83
|
def process node, tree = [], visibility = :public, scope = :instance, fqn = '', stack = []
|
80
84
|
return unless node.is_a?(AST::Node)
|
81
|
-
if node.type == :str
|
82
|
-
@strings.push Source::Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
|
83
|
-
return
|
84
|
-
end
|
85
|
+
return if node.type == :str
|
85
86
|
stack.push node
|
86
87
|
if node.kind_of?(AST::Node)
|
87
88
|
@node_stack.unshift node
|
@@ -89,6 +90,7 @@ module Solargraph
|
|
89
90
|
visibility = :public
|
90
91
|
if node.children[0].kind_of?(AST::Node) and node.children[0].children[0].kind_of?(AST::Node) and node.children[0].children[0].type == :cbase
|
91
92
|
tree = pack_name(node.children[0])
|
93
|
+
tree.shift if tree.first.empty?
|
92
94
|
else
|
93
95
|
tree = tree + pack_name(node.children[0])
|
94
96
|
end
|
@@ -104,22 +106,22 @@ module Solargraph
|
|
104
106
|
if c.kind_of?(AST::Node)
|
105
107
|
if c.type == :ivasgn
|
106
108
|
here = get_node_start_position(c)
|
107
|
-
|
109
|
+
named_path = get_named_path_pin(here)
|
108
110
|
if c.children[1].nil?
|
109
111
|
ora = find_parent(stack, :or_asgn)
|
110
112
|
unless ora.nil?
|
111
113
|
u = c.updated(:ivasgn, c.children + ora.children[1..-1], nil)
|
112
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), context)
|
113
|
-
if visibility == :module_function and
|
114
|
-
other =
|
115
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), other) unless other.nil?
|
114
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), named_path.context)
|
115
|
+
if visibility == :module_function and named_path.kind == Pin::METHOD
|
116
|
+
other = ComplexType.parse("Module<#{named_path.context.namespace}>")
|
117
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), other) #unless other.nil?
|
116
118
|
end
|
117
119
|
end
|
118
120
|
else
|
119
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context)
|
120
|
-
if visibility == :module_function and
|
121
|
-
other =
|
122
|
-
|
121
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), named_path.context)
|
122
|
+
if visibility == :module_function and named_path.kind == Pin::METHOD
|
123
|
+
other = ComplexType.parse("Module<#{named_path.context.namespace}>")
|
124
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), other)
|
123
125
|
end
|
124
126
|
end
|
125
127
|
elsif c.type == :cvasgn
|
@@ -138,18 +140,26 @@ module Solargraph
|
|
138
140
|
here = get_node_start_position(c)
|
139
141
|
context = get_named_path_pin(here)
|
140
142
|
block = get_block_pin(here)
|
141
|
-
presence =
|
143
|
+
presence = Range.new(here, block.location.range.ending)
|
142
144
|
if c.children[1].nil?
|
143
145
|
ora = find_parent(stack, :or_asgn)
|
144
146
|
unless ora.nil?
|
145
147
|
u = c.updated(:lvasgn, c.children + ora.children[1..-1], nil)
|
146
|
-
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(ora),
|
148
|
+
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(ora), u.children[1], infer_literal_node_type(c.children[1]), context, block, presence)
|
147
149
|
end
|
148
150
|
else
|
149
151
|
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context, block, presence)
|
150
152
|
end
|
151
153
|
elsif c.type == :gvasgn
|
152
|
-
|
154
|
+
if c.children[1].nil?
|
155
|
+
ora = find_parent(stack, :or_asgn)
|
156
|
+
unless ora.nil?
|
157
|
+
u = c.updated(:gvasgn, c.children + ora.children[1..-1], nil)
|
158
|
+
pins.push Solargraph::Pin::GlobalVariable.new(get_node_location(c), fqn, u.children[0].to_s, comments_for(c), u.children[1], infer_literal_node_type(c.children[1]), @pins.first)
|
159
|
+
end
|
160
|
+
else
|
161
|
+
pins.push Solargraph::Pin::GlobalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), @pins.first)
|
162
|
+
end
|
153
163
|
elsif c.type == :sym
|
154
164
|
@symbols.push Solargraph::Pin::Symbol.new(get_node_location(c), ":#{c.children[0]}")
|
155
165
|
elsif c.type == :casgn
|
@@ -224,7 +234,7 @@ module Solargraph
|
|
224
234
|
mm = Solargraph::Pin::Method.new(ref.location, ref.namespace, ref.name, ref.comments, :class, :public, ref.parameters)
|
225
235
|
cm = Solargraph::Pin::Method.new(ref.location, ref.namespace, ref.name, ref.comments, :instance, :private, ref.parameters)
|
226
236
|
pins.push mm, cm
|
227
|
-
pins.select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.context == ref}.each do |ivar|
|
237
|
+
pins.select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.context == ref.context}.each do |ivar|
|
228
238
|
pins.delete ivar
|
229
239
|
pins.push Solargraph::Pin::InstanceVariable.new(ivar.location, ivar.namespace, ivar.name, ivar.comments, ivar.signature, ivar.instance_variable_get(:@literal), mm)
|
230
240
|
pins.push Solargraph::Pin::InstanceVariable.new(ivar.location, ivar.namespace, ivar.name, ivar.comments, ivar.signature, ivar.instance_variable_get(:@literal), cm)
|
@@ -268,10 +278,10 @@ module Solargraph
|
|
268
278
|
elsif c.type == :send and [:attr_reader, :attr_writer, :attr_accessor].include?(c.children[1])
|
269
279
|
c.children[2..-1].each do |a|
|
270
280
|
if c.children[1] == :attr_reader or c.children[1] == :attr_accessor
|
271
|
-
pins.push Solargraph::Pin::Attribute.new(get_node_location(c), fqn || '', "#{a.children[0]}", comments_for(c), :reader, scope)
|
281
|
+
pins.push Solargraph::Pin::Attribute.new(get_node_location(c), fqn || '', "#{a.children[0]}", comments_for(c), :reader, scope, visibility)
|
272
282
|
end
|
273
283
|
if c.children[1] == :attr_writer or c.children[1] == :attr_accessor
|
274
|
-
pins.push Solargraph::Pin::Attribute.new(get_node_location(c), fqn || '', "#{a.children[0]}=", comments_for(c), :writer, scope)
|
284
|
+
pins.push Solargraph::Pin::Attribute.new(get_node_location(c), fqn || '', "#{a.children[0]}=", comments_for(c), :writer, scope, visibility)
|
275
285
|
end
|
276
286
|
end
|
277
287
|
elsif c.type == :sclass and c.children[0].type == :self
|
@@ -296,12 +306,14 @@ module Solargraph
|
|
296
306
|
here = get_node_start_position(u)
|
297
307
|
context = get_named_path_pin(here)
|
298
308
|
block = get_block_pin(here)
|
299
|
-
presence =
|
309
|
+
presence = Range.new(here, block.location.range.ending)
|
300
310
|
@locals.push Solargraph::Pin::MethodParameter.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(c), resolve_node_signature(u.children[1]), infer_literal_node_type(u.children[1]), context, block, presence)
|
301
311
|
end
|
302
312
|
end
|
303
313
|
elsif c.type == :block
|
304
|
-
|
314
|
+
here = get_node_start_position(c)
|
315
|
+
named_path = get_named_path_pin(here)
|
316
|
+
@pins.push Solargraph::Pin::Block.new(get_node_location(c), fqn || '', '', comments_for(c), c.children[0], named_path.context)
|
305
317
|
end
|
306
318
|
process c, tree, visibility, scope, fqn, stack
|
307
319
|
end
|
@@ -329,16 +341,19 @@ module Solargraph
|
|
329
341
|
@pins.select{|pin| [Pin::NAMESPACE, Pin::METHOD].include?(pin.kind) and pin.location.range.contain?(position)}.last
|
330
342
|
end
|
331
343
|
|
344
|
+
def get_namespace_pin position
|
345
|
+
@pins.select{|pin| pin.kind == Pin::NAMESPACE and pin.location.range.contain?(position)}.last
|
346
|
+
end
|
347
|
+
|
332
348
|
# @return [String]
|
333
349
|
def comments_for node
|
334
350
|
result = @node_comments[node.loc]
|
335
351
|
return nil if result.nil?
|
336
|
-
@used_comment_locs.push node.loc
|
337
352
|
result
|
338
353
|
end
|
339
354
|
|
340
355
|
# @param node [Parser::AST::Node]
|
341
|
-
# @return [Solargraph::
|
356
|
+
# @return [Solargraph::Location]
|
342
357
|
def get_node_location(node)
|
343
358
|
if node.nil?
|
344
359
|
st = Position.new(0, 0)
|
@@ -382,7 +397,11 @@ module Solargraph
|
|
382
397
|
# @param node [Parser::AST::Node]
|
383
398
|
# @return [Solargraph::Pin::Namespace]
|
384
399
|
def namespace_for(node)
|
385
|
-
position =
|
400
|
+
position = Position.new(node.loc.line, node.loc.column)
|
401
|
+
namespace_at(position)
|
402
|
+
end
|
403
|
+
|
404
|
+
def namespace_at(position)
|
386
405
|
@pins.select{|pin| pin.kind == Pin::NAMESPACE and pin.location.range.contain?(position)}.last
|
387
406
|
end
|
388
407
|
|
@@ -425,6 +444,89 @@ module Solargraph
|
|
425
444
|
def source_from_parser
|
426
445
|
@source_from_parser ||= @code.gsub(/\r\n/, "\n")
|
427
446
|
end
|
447
|
+
|
448
|
+
def process_comment position, comment
|
449
|
+
cmnt = remove_inline_comment_hashes(comment)
|
450
|
+
return unless cmnt =~ /(@\!method|@\!attribute|@\!domain|@\!macro)/
|
451
|
+
parse = YARD::Docstring.parser.parse(cmnt)
|
452
|
+
parse.directives.each { |d| process_directive(position, d) }
|
453
|
+
end
|
454
|
+
|
455
|
+
# @param position [Position]
|
456
|
+
# @param directive [YARD::Tags::Directive]
|
457
|
+
def process_directive position, directive
|
458
|
+
docstring = YARD::Docstring.parser.parse(directive.tag.text).to_docstring
|
459
|
+
location = Location.new(@filename, Range.new(position, position))
|
460
|
+
case directive.tag.tag_name
|
461
|
+
when 'method'
|
462
|
+
namespace = namespace_at(position)
|
463
|
+
gen_src = Solargraph::SourceMap.load_string("def #{directive.tag.name};end")
|
464
|
+
gen_pin = gen_src.pins.last # Method is last pin after root namespace
|
465
|
+
@pins.push Solargraph::Pin::Method.new(location, namespace.path, gen_pin.name, docstring.all, :instance, :public, gen_pin.parameters)
|
466
|
+
when 'attribute'
|
467
|
+
namespace = namespace_at(position)
|
468
|
+
t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
|
469
|
+
if t.nil? or t.include?('r')
|
470
|
+
# location, namespace, name, docstring, access
|
471
|
+
pins.push Solargraph::Pin::Attribute.new(location, namespace.path, directive.tag.name, docstring.all, :reader, :instance, :public)
|
472
|
+
end
|
473
|
+
if t.nil? or t.include?('w')
|
474
|
+
pins.push Solargraph::Pin::Attribute.new(location, namespace.path, "#{directive.tag.name}=", docstring.all, :writer, :instance, :public)
|
475
|
+
end
|
476
|
+
when 'domain'
|
477
|
+
namespace = namespace_at(position)
|
478
|
+
namespace.domains.push directive.tag.text
|
479
|
+
when 'macro'
|
480
|
+
nxt_pos = Position.new(position.line + 1, @code.lines[position.line + 1].length)
|
481
|
+
path_pin = get_named_path_pin(nxt_pos)
|
482
|
+
path_pin.macros.push directive
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
def remove_inline_comment_hashes comment
|
487
|
+
ctxt = ''
|
488
|
+
num = nil
|
489
|
+
started = false
|
490
|
+
comment.lines.each { |l|
|
491
|
+
# Trim the comment and minimum leading whitespace
|
492
|
+
p = l.gsub(/^#/, '')
|
493
|
+
if num.nil? and !p.strip.empty?
|
494
|
+
num = p.index(/[^ ]/)
|
495
|
+
started = true
|
496
|
+
elsif started and !p.strip.empty?
|
497
|
+
cur = p.index(/[^ ]/)
|
498
|
+
num = cur if cur < num
|
499
|
+
end
|
500
|
+
ctxt += "#{p[num..-1]}\n" if started
|
501
|
+
}
|
502
|
+
ctxt
|
503
|
+
end
|
504
|
+
|
505
|
+
def process_comment_directives
|
506
|
+
current = []
|
507
|
+
last_line = nil
|
508
|
+
@comments.each do |cmnt|
|
509
|
+
if cmnt.inline?
|
510
|
+
if last_line.nil? || cmnt.loc.expression.line == last_line + 1
|
511
|
+
if cmnt.loc.expression.column.zero? || @code.lines[cmnt.loc.expression.line][0..cmnt.loc.expression.column-1].strip.empty?
|
512
|
+
current.push cmnt
|
513
|
+
else
|
514
|
+
# @todo Connected to a line of code. Handle separately
|
515
|
+
end
|
516
|
+
elsif !current.empty?
|
517
|
+
process_comment Position.new(current.last.loc.expression.line, current.last.loc.expression.column), current.map(&:text).join("\n")
|
518
|
+
current.clear
|
519
|
+
current.push cmnt
|
520
|
+
end
|
521
|
+
else
|
522
|
+
# @todo Handle block comments
|
523
|
+
end
|
524
|
+
last_line = cmnt.loc.expression.line
|
525
|
+
end
|
526
|
+
unless current.empty?
|
527
|
+
process_comment Position.new(current.last.loc.expression.line, current.last.loc.expression.column), current.map(&:text).join("\n")
|
528
|
+
end
|
529
|
+
end
|
428
530
|
end
|
429
531
|
end
|
430
532
|
end
|