solargraph 0.27.1 → 0.28.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 +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
|