solargraph 0.26.1 → 0.27.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/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
|