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
@@ -9,7 +9,7 @@ module Solargraph
|
|
9
9
|
# @return [String]
|
10
10
|
def normalize string
|
11
11
|
begin
|
12
|
-
string.force_encoding('UTF-8')
|
12
|
+
string.clone.force_encoding('UTF-8')
|
13
13
|
rescue ::Encoding::CompatibilityError, ::Encoding::UndefinedConversionError, ::Encoding::InvalidByteSequenceError => e
|
14
14
|
# @todo Improve error handling
|
15
15
|
STDERR.puts "Normalize error: #{e.message}"
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Solargraph
|
2
2
|
class Source
|
3
3
|
class NodeChainer
|
4
|
-
include NodeMethods
|
4
|
+
include Source::NodeMethods
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@filename = filename
|
6
|
+
def initialize node, filename = nil
|
8
7
|
@node = node
|
8
|
+
@filename = filename
|
9
9
|
# @source = source
|
10
10
|
# @line = line
|
11
11
|
# @column = column
|
@@ -14,23 +14,23 @@ module Solargraph
|
|
14
14
|
# @return [Source::Chain]
|
15
15
|
def chain
|
16
16
|
links = generate_links(@node)
|
17
|
-
Chain.new(
|
17
|
+
Chain.new(links)
|
18
18
|
end
|
19
19
|
|
20
20
|
class << self
|
21
|
-
# @param
|
22
|
-
# @param
|
23
|
-
# @
|
24
|
-
|
25
|
-
|
26
|
-
NodeChainer.new(filename, node).chain
|
21
|
+
# @param node [Parser::AST::Node]
|
22
|
+
# @param filename [String]
|
23
|
+
# @return [Chain]
|
24
|
+
def chain node, filename = nil
|
25
|
+
NodeChainer.new(node, filename).chain
|
27
26
|
end
|
28
27
|
|
29
28
|
# @param code [String]
|
29
|
+
# @param filename [String, nil]
|
30
30
|
# @return [Chain]
|
31
|
-
def load_string(
|
32
|
-
node = Source.
|
33
|
-
chain =
|
31
|
+
def load_string(code)
|
32
|
+
node = Source.parse(code.sub(/\.$/, ''))
|
33
|
+
chain = NodeChainer.new(node).chain
|
34
34
|
chain.links.push(Chain::Link.new) if code.end_with?('.')
|
35
35
|
chain
|
36
36
|
end
|
@@ -54,24 +54,29 @@ module Solargraph
|
|
54
54
|
result.concat generate_links(n.children[0])
|
55
55
|
args = []
|
56
56
|
n.children[2..-1].each do |c|
|
57
|
-
|
58
|
-
# args.push Chain.new(source, c.loc.last_line - 1, c.loc.column)
|
57
|
+
args.push NodeChainer.chain(c)
|
59
58
|
end
|
60
59
|
result.push Chain::Call.new(n.children[1].to_s, args)
|
61
60
|
elsif n.children[0].nil?
|
62
61
|
args = []
|
63
62
|
n.children[2..-1].each do |c|
|
64
|
-
|
65
|
-
# args.push Chain.new(source, c.loc.last_line - 1, c.loc.column)
|
63
|
+
args.push NodeChainer.chain(c)
|
66
64
|
end
|
67
65
|
result.push Chain::Call.new(n.children[1].to_s, args)
|
68
66
|
else
|
69
67
|
raise "No idea what to do with #{n}"
|
70
68
|
end
|
71
69
|
elsif n.type == :self
|
72
|
-
result.push Chain::
|
70
|
+
result.push Chain::Head.new('self')
|
71
|
+
elsif n.type == :zsuper
|
72
|
+
result.push Chain::Head.new('super')
|
73
73
|
elsif n.type == :const
|
74
|
-
result.push Chain::Constant.new(unpack_name(n))
|
74
|
+
# result.push Chain::Constant.new(unpack_name(n))
|
75
|
+
const = unpack_name(n)
|
76
|
+
parts = const.split('::')
|
77
|
+
last = parts.pop
|
78
|
+
result.push Chain::Constant.new(parts.join('::')) unless parts.empty?
|
79
|
+
result.push Chain::Constant.new(last)
|
75
80
|
elsif [:lvar, :lvasgn].include?(n.type)
|
76
81
|
result.push Chain::Call.new(n.children[0].to_s)
|
77
82
|
elsif [:ivar, :ivasgn].include?(n.type)
|
@@ -81,8 +86,10 @@ module Solargraph
|
|
81
86
|
elsif [:gvar, :gvasgn].include?(n.type)
|
82
87
|
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
83
88
|
elsif [:class, :module, :def, :defs].include?(n.type)
|
84
|
-
location = Solargraph::
|
85
|
-
result.push Chain::Definition.new(location)
|
89
|
+
# location = Solargraph::Location.new(@filename, Range.from_to(n.loc.expression.line, n.loc.expression.column, n.loc.expression.last_line, n.loc.expression.last_column))
|
90
|
+
# result.push Chain::Definition.new(location)
|
91
|
+
# @todo Undefined or what?
|
92
|
+
result.push Chain::UNDEFINED_CALL
|
86
93
|
else
|
87
94
|
lit = infer_literal_node_type(n)
|
88
95
|
result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class Source
|
3
|
+
# Information about a location in a source, including the location's word
|
4
|
+
# and signature, literal values at the base of signatures, and whether the
|
5
|
+
# location is inside a string or comment. ApiMaps use Fragments to provide
|
6
|
+
# results for completion and definition queries.
|
7
|
+
#
|
8
|
+
class SourceChainer
|
9
|
+
include Source::NodeMethods
|
10
|
+
|
11
|
+
private_class_method :new
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# @param source [Source]
|
15
|
+
# @param position [Position]
|
16
|
+
# @return [Source::Chain]
|
17
|
+
def chain source, position
|
18
|
+
raise "Not a source" unless source.is_a?(Source)
|
19
|
+
new(source, position).chain
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param source [Source]
|
24
|
+
# @param position [Position]
|
25
|
+
def initialize source, position
|
26
|
+
@source = source
|
27
|
+
# @source.code = source.code
|
28
|
+
@position = position
|
29
|
+
# @todo Get rid of line/column
|
30
|
+
@line = position.line
|
31
|
+
@column = position.column
|
32
|
+
@calculated_literal = false
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Source::Chain]
|
36
|
+
def chain
|
37
|
+
return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
|
38
|
+
begin
|
39
|
+
if source.repaired? && source.parsed?
|
40
|
+
node = source.node_at(fixed_position.line, fixed_position.column)
|
41
|
+
elsif source.parsed?
|
42
|
+
node = source.node_at(position.line, position.column)
|
43
|
+
else
|
44
|
+
node = Source.parse(fixed_phrase)
|
45
|
+
end
|
46
|
+
rescue Parser::SyntaxError
|
47
|
+
return Chain.new([Chain::UNDEFINED_CALL])
|
48
|
+
end
|
49
|
+
return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
|
50
|
+
chain = NodeChainer.chain(node, source.filename)
|
51
|
+
if source.repaired? || !source.parsed?
|
52
|
+
if end_of_phrase.strip == '.'
|
53
|
+
chain.links.push Chain::UNDEFINED_CALL
|
54
|
+
elsif end_of_phrase.strip == '::'
|
55
|
+
chain.links.push Chain::UNDEFINED_CONSTANT
|
56
|
+
end
|
57
|
+
elsif end_of_phrase.strip == '::'
|
58
|
+
chain.links.pop
|
59
|
+
chain.links.push Chain::UNDEFINED_CONSTANT
|
60
|
+
end
|
61
|
+
chain
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
attr_reader :position
|
67
|
+
|
68
|
+
# The zero-based line number of the fragment's location.
|
69
|
+
#
|
70
|
+
# @return [Integer]
|
71
|
+
attr_reader :line
|
72
|
+
|
73
|
+
# The zero-based column number of the fragment's location.
|
74
|
+
#
|
75
|
+
# @return [Integer]
|
76
|
+
attr_reader :column
|
77
|
+
|
78
|
+
# @return [Solargraph::Source]
|
79
|
+
attr_reader :source
|
80
|
+
|
81
|
+
def phrase
|
82
|
+
@phrase ||= source.code[signature_data[0]..offset-1]
|
83
|
+
end
|
84
|
+
|
85
|
+
def fixed_phrase
|
86
|
+
@fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
|
87
|
+
end
|
88
|
+
|
89
|
+
def fixed_position
|
90
|
+
@fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
|
91
|
+
end
|
92
|
+
|
93
|
+
def end_of_phrase
|
94
|
+
@end_of_phrase ||= begin
|
95
|
+
match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
|
96
|
+
if match
|
97
|
+
match[0]
|
98
|
+
else
|
99
|
+
''
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# An alias for #column.
|
105
|
+
#
|
106
|
+
# @return [Integer]
|
107
|
+
def character
|
108
|
+
@column
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Position]
|
112
|
+
def position
|
113
|
+
@position ||= Position.new(line, column)
|
114
|
+
end
|
115
|
+
|
116
|
+
# True if the current offset is inside a string.
|
117
|
+
#
|
118
|
+
# @return [Boolean]
|
119
|
+
def string?
|
120
|
+
# @string ||= (node.type == :str or node.type == :dstr)
|
121
|
+
@string ||= @source.string_at?(position)
|
122
|
+
end
|
123
|
+
|
124
|
+
# @return [Integer]
|
125
|
+
def offset
|
126
|
+
@offset ||= get_offset(line, column)
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_offset line, column
|
130
|
+
Position.line_char_to_offset(@source.code, line, column)
|
131
|
+
end
|
132
|
+
|
133
|
+
def signature_data
|
134
|
+
@signature_data ||= get_signature_data_at(offset)
|
135
|
+
end
|
136
|
+
|
137
|
+
def get_signature_data_at index
|
138
|
+
brackets = 0
|
139
|
+
squares = 0
|
140
|
+
parens = 0
|
141
|
+
signature = ''
|
142
|
+
index -=1
|
143
|
+
in_whitespace = false
|
144
|
+
while index >= 0
|
145
|
+
pos = Position.from_offset(@source.code, index)
|
146
|
+
break if index > 0 and @source.comment_at?(pos)
|
147
|
+
unless !in_whitespace and string?
|
148
|
+
break if brackets > 0 or parens > 0 or squares > 0
|
149
|
+
char = @source.code[index, 1]
|
150
|
+
break if char.nil? # @todo Is this the right way to handle this?
|
151
|
+
if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
|
152
|
+
in_whitespace = true
|
153
|
+
else
|
154
|
+
if brackets.zero? and parens.zero? and squares.zero? and in_whitespace
|
155
|
+
unless char == '.' or @source.code[index+1..-1].strip.start_with?('.')
|
156
|
+
old = @source.code[index+1..-1]
|
157
|
+
nxt = @source.code[index+1..-1].lstrip
|
158
|
+
index += (@source.code[index+1..-1].length - @source.code[index+1..-1].lstrip.length)
|
159
|
+
break
|
160
|
+
end
|
161
|
+
end
|
162
|
+
if char == ')'
|
163
|
+
parens -=1
|
164
|
+
elsif char == ']'
|
165
|
+
squares -=1
|
166
|
+
elsif char == '}'
|
167
|
+
brackets -= 1
|
168
|
+
elsif char == '('
|
169
|
+
parens += 1
|
170
|
+
elsif char == '{'
|
171
|
+
brackets += 1
|
172
|
+
elsif char == '['
|
173
|
+
squares += 1
|
174
|
+
signature = ".[]#{signature}" if parens.zero? and brackets.zero? and squares.zero? and @source.code[index-2] != '%'
|
175
|
+
end
|
176
|
+
if brackets.zero? and parens.zero? and squares.zero?
|
177
|
+
break if ['"', "'", ',', ';', '%'].include?(char)
|
178
|
+
signature = char + signature if char.match(/[a-z0-9:\._@\$\?\!]/i) and @source.code[index - 1] != '%'
|
179
|
+
break if char == '$'
|
180
|
+
if char == '@'
|
181
|
+
signature = "@#{signature}" if @source.code[index-1, 1] == '@'
|
182
|
+
break
|
183
|
+
end
|
184
|
+
elsif parens == 1 || brackets == 1 || squares == 1
|
185
|
+
break
|
186
|
+
end
|
187
|
+
in_whitespace = false
|
188
|
+
end
|
189
|
+
end
|
190
|
+
index -= 1
|
191
|
+
end
|
192
|
+
# @todo Smelly exceptional case for integer literals
|
193
|
+
# match = signature.match(/^[0-9]+/)
|
194
|
+
# if match
|
195
|
+
# index += match[0].length
|
196
|
+
# signature = signature[match[0].length..-1].to_s
|
197
|
+
# @base_literal = 'Integer'
|
198
|
+
# # @todo Smelly exceptional case for array literals
|
199
|
+
# elsif signature.start_with?('.[]')
|
200
|
+
# index += 2
|
201
|
+
# signature = signature[3..-1].to_s
|
202
|
+
# @base_literal = 'Array'
|
203
|
+
# elsif signature.start_with?('.')
|
204
|
+
# pos = Position.from_offset(@source.code, index)
|
205
|
+
# node = @source.node_at(pos.line, pos.character)
|
206
|
+
# lit = infer_literal_node_type(node)
|
207
|
+
# unless lit.nil?
|
208
|
+
# signature = signature[1..-1].to_s
|
209
|
+
# index += 1
|
210
|
+
# @base_literal = lit
|
211
|
+
# end
|
212
|
+
# end
|
213
|
+
[index + 1, signature]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Solargraph
|
2
|
+
# An index of pins and other ApiMap-related data for a Source.
|
3
|
+
#
|
4
|
+
class SourceMap
|
5
|
+
autoload :Mapper, 'solargraph/source_map/mapper'
|
6
|
+
autoload :Clip, 'solargraph/source_map/clip'
|
7
|
+
autoload :Completion, 'solargraph/source_map/completion'
|
8
|
+
|
9
|
+
# @return [Source]
|
10
|
+
attr_reader :source
|
11
|
+
|
12
|
+
# @return [Array<Pin::Base>]
|
13
|
+
attr_reader :pins
|
14
|
+
|
15
|
+
# @return [Array<Pin::Base>]
|
16
|
+
attr_reader :locals
|
17
|
+
|
18
|
+
# @return [Array<Pin::Reference>]
|
19
|
+
attr_reader :requires
|
20
|
+
|
21
|
+
def initialize source, pins, locals, requires, symbols
|
22
|
+
# HACK: Keep the library from changing this
|
23
|
+
@source = source.dup
|
24
|
+
@pins = pins
|
25
|
+
@locals = locals
|
26
|
+
@requires = requires
|
27
|
+
@pins.concat symbols
|
28
|
+
end
|
29
|
+
|
30
|
+
def filename
|
31
|
+
source.filename
|
32
|
+
end
|
33
|
+
|
34
|
+
def code
|
35
|
+
source.code
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param position [Position]
|
39
|
+
# @return [Boolean]
|
40
|
+
def string_at? position
|
41
|
+
@source.string_at?(position)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param position [Position]
|
45
|
+
# @return [Boolean]
|
46
|
+
def comment_at? position
|
47
|
+
@source.comment_at?(position)
|
48
|
+
end
|
49
|
+
|
50
|
+
def document_symbols
|
51
|
+
@document_symbols ||= pins.select { |pin|
|
52
|
+
[Pin::ATTRIBUTE, Pin::CONSTANT, Pin::METHOD, Pin::NAMESPACE].include?(pin.kind) and !pin.path.empty?
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def query_symbols query
|
57
|
+
document_symbols.select{|pin| pin.path.include?(query)}
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param position [Position]
|
61
|
+
# @return [Solargraph::SourceMap::Fragment]
|
62
|
+
def cursor_at position
|
63
|
+
Source::Cursor.new(source, position)
|
64
|
+
end
|
65
|
+
|
66
|
+
def first_pin path
|
67
|
+
pins.select { |p| p.path == path }.first
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param location [Solargraph::Location]
|
71
|
+
# @return [Solargraph::Pin::Base]
|
72
|
+
def locate_pin location
|
73
|
+
# return nil unless location.start_with?("#{filename}:")
|
74
|
+
pins.select{|pin| pin.location == location}.first
|
75
|
+
end
|
76
|
+
|
77
|
+
def locate_named_path_pin line, character
|
78
|
+
_locate_pin line, character, Pin::NAMESPACE, Pin::METHOD
|
79
|
+
end
|
80
|
+
|
81
|
+
def locate_block_pin line, character
|
82
|
+
_locate_pin line, character, Pin::NAMESPACE, Pin::METHOD, Pin::BLOCK
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param other_map [SourceMap]
|
86
|
+
def try_merge! other_map
|
87
|
+
return false if pins.length != other_map.pins.length || locals.length != other_map.locals.length || requires.map(&:name).uniq.sort != other_map.requires.map(&:name).uniq.sort
|
88
|
+
pins.each_index do |i|
|
89
|
+
return false unless pins[i].try_merge!(other_map.pins[i])
|
90
|
+
end
|
91
|
+
locals.each_index do |i|
|
92
|
+
return false unless locals[i].try_merge!(other_map.locals[i])
|
93
|
+
end
|
94
|
+
@source = other_map.source
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
# @param name [String]
|
99
|
+
# @return [Array<Location>]
|
100
|
+
def references name
|
101
|
+
source.references name
|
102
|
+
end
|
103
|
+
|
104
|
+
class << self
|
105
|
+
# @return [SourceMap]
|
106
|
+
def load filename
|
107
|
+
source = Solargraph::Source.load(filename)
|
108
|
+
SourceMap.map(source)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [SourceMap]
|
112
|
+
def load_string code, filename = nil
|
113
|
+
source = Solargraph::Source.load_string(code, filename)
|
114
|
+
SourceMap.map(source)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param source [Source]
|
118
|
+
# @return [SourceMap]
|
119
|
+
def map source
|
120
|
+
result = SourceMap::Mapper.map(source)
|
121
|
+
new(source, *result)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def _locate_pin line, character, *kinds
|
128
|
+
position = Position.new(line, character)
|
129
|
+
found = nil
|
130
|
+
pins.each do |pin|
|
131
|
+
found = pin if (kinds.empty? || kinds.include?(pin.kind)) && pin.location.range.contain?(position)
|
132
|
+
break if pin.location.range.start.line > line
|
133
|
+
end
|
134
|
+
# @todo Assuming the root pin is always valid
|
135
|
+
found || pins.first
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|