solargraph 0.27.1 → 0.28.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 +8 -17
- data/lib/solargraph/api_map.rb +4 -3
- data/lib/solargraph/api_map/cache.rb +5 -5
- data/lib/solargraph/api_map/source_to_yard.rb +3 -2
- data/lib/solargraph/api_map/store.rb +25 -13
- data/lib/solargraph/complex_type.rb +3 -0
- data/lib/solargraph/diagnostics/update_errors.rb +21 -1
- data/lib/solargraph/language_server/host.rb +4 -3
- data/lib/solargraph/language_server/message/text_document/rename.rb +1 -1
- data/lib/solargraph/library.rb +12 -4
- data/lib/solargraph/pin.rb +5 -1
- data/lib/solargraph/pin/base.rb +0 -10
- data/lib/solargraph/pin/conversions.rb +1 -1
- data/lib/solargraph/pin/documenting.rb +0 -9
- data/lib/solargraph/pin/duck_method.rb +1 -1
- data/lib/solargraph/pin/keyword.rb +0 -5
- data/lib/solargraph/pin/namespace.rb +3 -16
- data/lib/solargraph/pin/reference.rb +13 -26
- data/lib/solargraph/pin/reference/extend.rb +11 -0
- data/lib/solargraph/pin/reference/include.rb +11 -0
- data/lib/solargraph/pin/reference/require.rb +15 -0
- data/lib/solargraph/pin/reference/superclass.rb +11 -0
- data/lib/solargraph/pin/symbol.rb +0 -4
- data/lib/solargraph/pin/yard_pin/namespace.rb +14 -14
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -4
- data/lib/solargraph/position.rb +7 -0
- data/lib/solargraph/source.rb +7 -28
- data/lib/solargraph/source/chain.rb +0 -1
- data/lib/solargraph/source/chain/call.rb +1 -1
- data/lib/solargraph/source/chain/constant.rb +13 -4
- data/lib/solargraph/source/change.rb +7 -1
- data/lib/solargraph/source/cursor.rb +1 -5
- data/lib/solargraph/source/node_chainer.rb +5 -6
- data/lib/solargraph/source/source_chainer.rb +14 -12
- data/lib/solargraph/source_map.rb +5 -6
- data/lib/solargraph/source_map/clip.rb +16 -29
- data/lib/solargraph/source_map/mapper.rb +26 -21
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +1 -2
- data/lib/solargraph/workspace/config.rb +10 -5
- data/lib/solargraph/yard_map.rb +3 -1
- metadata +6 -3
- data/lib/solargraph/source/chain/definition.rb +0 -20
@@ -9,20 +9,20 @@ module Solargraph
|
|
9
9
|
# @todo This method of superclass detection is a bit of a hack. If
|
10
10
|
# the superclass is a Proxy, it is assumed to be undefined in its
|
11
11
|
# yardoc and converted to a fully qualified namespace.
|
12
|
-
if code_object.is_a?(YARD::CodeObjects::ClassObject) && code_object.superclass
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
super(location, code_object.namespace.to_s, code_object.name.to_s, comments_from(code_object), namespace_type(code_object), code_object.visibility
|
20
|
-
code_object.class_mixins.each do |m|
|
21
|
-
|
22
|
-
end
|
23
|
-
code_object.instance_mixins.each do |m|
|
24
|
-
|
25
|
-
end
|
12
|
+
# if code_object.is_a?(YARD::CodeObjects::ClassObject) && code_object.superclass
|
13
|
+
# if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
|
14
|
+
# superclass = "::#{code_object.superclass}"
|
15
|
+
# else
|
16
|
+
# superclass = code_object.superclass.to_s
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
super(location, code_object.namespace.to_s, code_object.name.to_s, comments_from(code_object), namespace_type(code_object), code_object.visibility)
|
20
|
+
# code_object.class_mixins.each do |m|
|
21
|
+
# extend_references.push Pin::Reference.new(location, path, m.path)
|
22
|
+
# end
|
23
|
+
# code_object.instance_mixins.each do |m|
|
24
|
+
# include_references.push Pin::Reference.new(location, path, m.path)
|
25
|
+
# end
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
data/lib/solargraph/position.rb
CHANGED
@@ -89,6 +89,13 @@ module Solargraph
|
|
89
89
|
Position.new(line, character)
|
90
90
|
end
|
91
91
|
|
92
|
+
# A helper method for generating positions from arrays of integers. The
|
93
|
+
# original parameter is returned if it is already a position.
|
94
|
+
#
|
95
|
+
# @raise [ArgumentError] if the object cannot be converted to a position.
|
96
|
+
#
|
97
|
+
# @param object [Position, Array(Integer, Integer)]
|
98
|
+
# @return [Position]
|
92
99
|
def self.normalize object
|
93
100
|
return object if object.is_a?(Position)
|
94
101
|
return Position.new(object[0], object[1]) if object.is_a?(Array)
|
data/lib/solargraph/source.rb
CHANGED
@@ -97,24 +97,19 @@ module Solargraph
|
|
97
97
|
def synchronize updater
|
98
98
|
raise 'Invalid synchronization' unless updater.filename == filename
|
99
99
|
real_code = updater.write(@code)
|
100
|
-
incr_code = updater.write(@code, true)
|
101
100
|
if real_code == @code
|
102
101
|
@version = updater.version
|
103
102
|
return self
|
104
103
|
end
|
105
|
-
synced = Source.new(
|
104
|
+
synced = Source.new(real_code, filename)
|
106
105
|
if synced.parsed?
|
107
|
-
synced.
|
108
|
-
|
109
|
-
synced.error_ranges.concat combine_errors(error_ranges + updater.changes.map(&:range))
|
110
|
-
end
|
111
|
-
else
|
112
|
-
new_repair = updater.repair(@repaired)
|
113
|
-
synced = Source.new(new_repair, filename)
|
114
|
-
synced.error_ranges.concat combine_errors(error_ranges + updater.changes.map(&:range))
|
115
|
-
synced.parsed = false
|
116
|
-
synced.code = real_code
|
106
|
+
synced.version = updater.version
|
107
|
+
return synced
|
117
108
|
end
|
109
|
+
incr_code = updater.repair(@repaired)
|
110
|
+
synced = Source.new(incr_code, filename)
|
111
|
+
synced.error_ranges.concat (error_ranges + updater.changes.map(&:range))
|
112
|
+
synced.code = real_code
|
118
113
|
synced.version = updater.version
|
119
114
|
synced
|
120
115
|
end
|
@@ -226,22 +221,6 @@ module Solargraph
|
|
226
221
|
result
|
227
222
|
end
|
228
223
|
|
229
|
-
# @param ranges [Array<Range>]
|
230
|
-
# @return [Array<Range>]
|
231
|
-
def combine_errors ranges
|
232
|
-
result = []
|
233
|
-
lines = []
|
234
|
-
ranges.sort{|a, b| a.start.line <=> b.start.line}.each do |rng|
|
235
|
-
next if rng.nil? || lines.include?(rng.start.line)
|
236
|
-
lines.push rng.start.line
|
237
|
-
next if comment_at?(rng.start) || rng.start.line >= code.lines.length
|
238
|
-
fcol = code.lines[rng.start.line].index(/[^\s]/) || 0
|
239
|
-
ecol = code.lines[rng.start.line].length
|
240
|
-
result.push Range.from_to(rng.start.line, fcol, rng.start.line, ecol)
|
241
|
-
end
|
242
|
-
result
|
243
|
-
end
|
244
|
-
|
245
224
|
protected
|
246
225
|
|
247
226
|
# @return [Integer]
|
@@ -12,7 +12,6 @@ module Solargraph
|
|
12
12
|
autoload :InstanceVariable, 'solargraph/source/chain/instance_variable'
|
13
13
|
autoload :GlobalVariable, 'solargraph/source/chain/global_variable'
|
14
14
|
autoload :Literal, 'solargraph/source/chain/literal'
|
15
|
-
autoload :Definition, 'solargraph/source/chain/definition'
|
16
15
|
autoload :Head, 'solargraph/source/chain/head'
|
17
16
|
|
18
17
|
UNDEFINED_CALL = Chain::Call.new('<undefined>')
|
@@ -61,7 +61,7 @@ module Solargraph
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def external_constructor? pin, context
|
64
|
-
pin.path == 'Class#new' || (pin.name == 'new' && pin.scope == :class && pin.
|
64
|
+
pin.path == 'Class#new' || (pin.name == 'new' && pin.scope == :class && pin.return_type != context)
|
65
65
|
end
|
66
66
|
|
67
67
|
# @param pin [Pin::Method]
|
@@ -8,10 +8,19 @@ module Solargraph
|
|
8
8
|
|
9
9
|
def resolve api_map, name_pin, locals
|
10
10
|
return [Pin::ROOT_PIN] if word.empty?
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
if word.start_with?('::')
|
12
|
+
context = ''
|
13
|
+
bottom = word[2..-1]
|
14
|
+
else
|
15
|
+
context = name_pin.context.namespace
|
16
|
+
bottom = word
|
17
|
+
end
|
18
|
+
if bottom.include?('::')
|
19
|
+
ns = bottom.split('::')[0..-2].join('::')
|
20
|
+
else
|
21
|
+
ns = ''
|
22
|
+
end
|
23
|
+
api_map.get_constants(ns, context).select{|p| p.path.end_with?(bottom)}
|
15
24
|
end
|
16
25
|
end
|
17
26
|
end
|
@@ -55,7 +55,13 @@ module Solargraph
|
|
55
55
|
if range.nil?
|
56
56
|
fixed
|
57
57
|
else
|
58
|
-
commit text, fixed
|
58
|
+
result = commit text, fixed
|
59
|
+
off = Position.to_offset(text, range.start)
|
60
|
+
match = result[0..off].match(/[\.:]+\z/)
|
61
|
+
if match
|
62
|
+
result = result[0..off].sub(/#{match[0]}\z/, ' ' * match[0].length) + result[off..-1]
|
63
|
+
end
|
64
|
+
result
|
59
65
|
end
|
60
66
|
end
|
61
67
|
|
@@ -14,11 +14,7 @@ module Solargraph
|
|
14
14
|
# @param position [Position, Array(Integer, Integer)]
|
15
15
|
def initialize source, position
|
16
16
|
@source = source
|
17
|
-
@position =
|
18
|
-
Position.new(position[0], position[1])
|
19
|
-
else
|
20
|
-
position
|
21
|
-
end
|
17
|
+
@position = Position.normalize(position)
|
22
18
|
end
|
23
19
|
|
24
20
|
# @return [String]
|
@@ -73,10 +73,11 @@ module Solargraph
|
|
73
73
|
elsif n.type == :const
|
74
74
|
# result.push Chain::Constant.new(unpack_name(n))
|
75
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)
|
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)
|
80
|
+
result.push Chain::Constant.new(const)
|
80
81
|
elsif [:lvar, :lvasgn].include?(n.type)
|
81
82
|
result.push Chain::Call.new(n.children[0].to_s)
|
82
83
|
elsif [:ivar, :ivasgn].include?(n.type)
|
@@ -86,8 +87,6 @@ module Solargraph
|
|
86
87
|
elsif [:gvar, :gvasgn].include?(n.type)
|
87
88
|
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
88
89
|
elsif [:class, :module, :def, :defs].include?(n.type)
|
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
90
|
# @todo Undefined or what?
|
92
91
|
result.push Chain::UNDEFINED_CALL
|
93
92
|
else
|
@@ -35,13 +35,15 @@ module Solargraph
|
|
35
35
|
# @return [Source::Chain]
|
36
36
|
def chain
|
37
37
|
return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
|
38
|
+
# return Chain.new([Chain::UNDEFINED_CALL]) unless infer_literal_node_type(source.node_at(position.line, position.column)).nil?
|
38
39
|
begin
|
39
|
-
|
40
|
-
|
41
|
-
elsif source.parsed?
|
40
|
+
return Chain.new([]) if phrase.end_with?('..')
|
41
|
+
if !source.repaired? && source.parsed?
|
42
42
|
node = source.node_at(position.line, position.column)
|
43
43
|
else
|
44
|
-
node =
|
44
|
+
node = nil
|
45
|
+
node = source.node_at(fixed_position.line, fixed_position.column) unless source.error_ranges.any?{|r| r.include?(fixed_position)}
|
46
|
+
node = Source.parse(fixed_phrase) if node.nil?
|
45
47
|
end
|
46
48
|
rescue Parser::SyntaxError
|
47
49
|
return Chain.new([Chain::UNDEFINED_CALL])
|
@@ -54,15 +56,13 @@ module Solargraph
|
|
54
56
|
elsif end_of_phrase.strip == '::'
|
55
57
|
chain.links.push Chain::UNDEFINED_CONSTANT
|
56
58
|
end
|
57
|
-
elsif end_of_phrase.strip == '::'
|
58
|
-
chain.links.pop
|
59
|
-
chain.links.push Chain::UNDEFINED_CONSTANT
|
60
59
|
end
|
61
60
|
chain
|
62
61
|
end
|
63
62
|
|
64
63
|
private
|
65
64
|
|
65
|
+
# @return [Position]
|
66
66
|
attr_reader :position
|
67
67
|
|
68
68
|
# The zero-based line number of the fragment's location.
|
@@ -78,18 +78,22 @@ module Solargraph
|
|
78
78
|
# @return [Solargraph::Source]
|
79
79
|
attr_reader :source
|
80
80
|
|
81
|
+
# @return [String]
|
81
82
|
def phrase
|
82
83
|
@phrase ||= source.code[signature_data[0]..offset-1]
|
83
84
|
end
|
84
85
|
|
86
|
+
# @return [String]
|
85
87
|
def fixed_phrase
|
86
88
|
@fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
|
87
89
|
end
|
88
90
|
|
91
|
+
# @return [Position]
|
89
92
|
def fixed_position
|
90
93
|
@fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
|
91
94
|
end
|
92
95
|
|
96
|
+
# @return [String]
|
93
97
|
def end_of_phrase
|
94
98
|
@end_of_phrase ||= begin
|
95
99
|
match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
|
@@ -108,11 +112,6 @@ module Solargraph
|
|
108
112
|
@column
|
109
113
|
end
|
110
114
|
|
111
|
-
# @return [Position]
|
112
|
-
def position
|
113
|
-
@position ||= Position.new(line, column)
|
114
|
-
end
|
115
|
-
|
116
115
|
# True if the current offset is inside a string.
|
117
116
|
#
|
118
117
|
# @return [Boolean]
|
@@ -126,6 +125,9 @@ module Solargraph
|
|
126
125
|
@offset ||= get_offset(line, column)
|
127
126
|
end
|
128
127
|
|
128
|
+
# @param line [Integer]
|
129
|
+
# @param column [Integer]
|
130
|
+
# @return [Integer]
|
129
131
|
def get_offset line, column
|
130
132
|
Position.line_char_to_offset(@source.code, line, column)
|
131
133
|
end
|
@@ -15,16 +15,11 @@ module Solargraph
|
|
15
15
|
# @return [Array<Pin::Base>]
|
16
16
|
attr_reader :locals
|
17
17
|
|
18
|
-
|
19
|
-
attr_reader :requires
|
20
|
-
|
21
|
-
def initialize source, pins, locals, requires, symbols
|
18
|
+
def initialize source, pins, locals
|
22
19
|
# HACK: Keep the library from changing this
|
23
20
|
@source = source.dup
|
24
21
|
@pins = pins
|
25
22
|
@locals = locals
|
26
|
-
@requires = requires
|
27
|
-
@pins.concat symbols
|
28
23
|
end
|
29
24
|
|
30
25
|
def filename
|
@@ -35,6 +30,10 @@ module Solargraph
|
|
35
30
|
source.code
|
36
31
|
end
|
37
32
|
|
33
|
+
def requires
|
34
|
+
@requires ||= pins.select{|p| p.kind == Pin::REQUIRE_REFERENCE}
|
35
|
+
end
|
36
|
+
|
38
37
|
# @param position [Position]
|
39
38
|
# @return [Boolean]
|
40
39
|
def string_at? position
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Solargraph
|
2
2
|
class SourceMap
|
3
|
+
# A static analysis tool for obtaining definitions, completions,
|
4
|
+
# signatures, and type inferences from a cursor.
|
5
|
+
#
|
3
6
|
class Clip
|
4
7
|
# @param api_map [ApiMap]
|
5
8
|
# @param cursor [Source::Cursor]
|
6
9
|
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
10
|
@api_map = api_map
|
10
11
|
@cursor = cursor
|
11
12
|
end
|
@@ -36,7 +37,7 @@ module Solargraph
|
|
36
37
|
elsif cursor.word.start_with?('$')
|
37
38
|
return package_completions(api_map.get_global_variable_pins)
|
38
39
|
end
|
39
|
-
result.concat
|
40
|
+
result.concat locals
|
40
41
|
result.concat api_map.get_constants('', context_pin.context.namespace)
|
41
42
|
result.concat api_map.get_methods(context_pin.context.namespace, scope: context_pin.context.scope, visibility: [:public, :private, :protected])
|
42
43
|
result.concat api_map.get_methods('Kernel')
|
@@ -53,17 +54,11 @@ module Solargraph
|
|
53
54
|
clip.define.select{|pin| pin.kind == Pin::METHOD}
|
54
55
|
end
|
55
56
|
|
57
|
+
# @return [ComplexType]
|
56
58
|
def infer
|
57
59
|
cursor.chain.infer(api_map, context_pin, locals)
|
58
60
|
end
|
59
61
|
|
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
62
|
# Get an array of all the locals that are visible from the cursors's
|
68
63
|
# position. Locals can be local variables, method parameters, or block
|
69
64
|
# parameters. The array starts with the nearest local pin.
|
@@ -93,31 +88,23 @@ module Solargraph
|
|
93
88
|
@block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
|
94
89
|
end
|
95
90
|
|
96
|
-
#
|
91
|
+
# The context at the current position.
|
92
|
+
#
|
93
|
+
# @return [Pin::Base]
|
94
|
+
def context_pin
|
95
|
+
@context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
|
96
|
+
end
|
97
|
+
|
97
98
|
# @param result [Array<Pin::Base>]
|
98
99
|
# @return [Completion]
|
99
100
|
def package_completions result
|
100
101
|
frag_start = cursor.start_of_word.to_s.downcase
|
101
|
-
filtered = result.uniq(&:name).select{|s|
|
102
|
+
filtered = result.uniq(&:name).select { |s|
|
103
|
+
s.name.downcase.start_with?(frag_start) &&
|
104
|
+
(s.kind != Pin::METHOD || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
|
105
|
+
}
|
102
106
|
Completion.new(filtered, cursor.range)
|
103
107
|
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
108
|
end
|
122
109
|
end
|
123
110
|
end
|