solargraph 0.54.0 → 0.54.2
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/CHANGELOG.md +27 -0
- data/lib/solargraph/api_map/store.rb +8 -4
- data/lib/solargraph/api_map.rb +74 -23
- data/lib/solargraph/complex_type/type_methods.rb +17 -11
- data/lib/solargraph/complex_type/unique_type.rb +72 -9
- data/lib/solargraph/complex_type.rb +66 -17
- data/lib/solargraph/language_server/host/message_worker.rb +45 -5
- data/lib/solargraph/language_server/host.rb +10 -10
- data/lib/solargraph/language_server/message/base.rb +18 -11
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +19 -2
- data/lib/solargraph/library.rb +29 -39
- data/lib/solargraph/location.rb +14 -1
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -7
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +8 -2
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
- data/lib/solargraph/parser.rb +2 -5
- data/lib/solargraph/pin/base.rb +16 -3
- data/lib/solargraph/pin/base_variable.rb +1 -1
- data/lib/solargraph/pin/block.rb +6 -26
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +8 -3
- data/lib/solargraph/pin/common.rb +2 -6
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/method.rb +51 -31
- data/lib/solargraph/pin/namespace.rb +4 -4
- data/lib/solargraph/pin/parameter.rb +9 -11
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin/signature.rb +3 -129
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/range.rb +2 -4
- data/lib/solargraph/rbs_map/conversions.rb +76 -37
- data/lib/solargraph/rbs_map/core_fills.rb +6 -6
- data/lib/solargraph/shell.rb +17 -2
- data/lib/solargraph/source/chain/array.rb +6 -5
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +81 -51
- data/lib/solargraph/source/chain/link.rb +9 -0
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +41 -17
- data/lib/solargraph/source/cursor.rb +14 -2
- data/lib/solargraph/source.rb +102 -85
- data/lib/solargraph/source_map/clip.rb +4 -4
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map.rb +28 -16
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +7 -7
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/solargraph.gemspec +4 -4
- metadata +20 -24
@@ -3,7 +3,9 @@
|
|
3
3
|
module Solargraph
|
4
4
|
class Source
|
5
5
|
class Chain
|
6
|
-
class Call < Link
|
6
|
+
class Call < Chain::Link
|
7
|
+
include Solargraph::Parser::NodeMethods
|
8
|
+
|
7
9
|
# @return [String]
|
8
10
|
attr_reader :word
|
9
11
|
|
@@ -28,7 +30,7 @@ module Solargraph
|
|
28
30
|
end
|
29
31
|
|
30
32
|
# @param api_map [ApiMap]
|
31
|
-
# @param name_pin [Pin::
|
33
|
+
# @param name_pin [Pin::Closure] name_pin.binder should give us the object on which 'word' will be invoked
|
32
34
|
# @param locals [::Array<Pin::LocalVariable>]
|
33
35
|
def resolve api_map, name_pin, locals
|
34
36
|
return super_pins(api_map, name_pin) if word == 'super'
|
@@ -38,23 +40,23 @@ module Solargraph
|
|
38
40
|
else
|
39
41
|
[]
|
40
42
|
end
|
41
|
-
return inferred_pins(found, api_map, name_pin
|
42
|
-
# @param [ComplexType::UniqueType]
|
43
|
+
return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
|
43
44
|
pins = name_pin.binder.each_unique_type.flat_map do |context|
|
44
|
-
|
45
|
+
ns = context.namespace == '' ? '' : context.namespace_type.tag
|
46
|
+
api_map.get_method_stack(ns, word, scope: context.scope)
|
45
47
|
end
|
46
48
|
return [] if pins.empty?
|
47
|
-
inferred_pins(pins, api_map, name_pin
|
49
|
+
inferred_pins(pins, api_map, name_pin, locals)
|
48
50
|
end
|
49
51
|
|
50
52
|
private
|
51
53
|
|
52
54
|
# @param pins [::Enumerable<Pin::Method>]
|
53
55
|
# @param api_map [ApiMap]
|
54
|
-
# @param
|
56
|
+
# @param name_pin [Pin::Base]
|
55
57
|
# @param locals [::Array<Pin::LocalVariable>]
|
56
58
|
# @return [::Array<Pin::Base>]
|
57
|
-
def inferred_pins pins, api_map,
|
59
|
+
def inferred_pins pins, api_map, name_pin, locals
|
58
60
|
result = pins.map do |p|
|
59
61
|
next p unless p.is_a?(Pin::Method)
|
60
62
|
overloads = p.signatures
|
@@ -68,7 +70,7 @@ module Solargraph
|
|
68
70
|
sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
|
69
71
|
new_signature_pin = nil
|
70
72
|
sorted_overloads.each do |ol|
|
71
|
-
next unless arity_matches?(arguments,
|
73
|
+
next unless ol.arity_matches?(arguments, with_block?)
|
72
74
|
match = true
|
73
75
|
|
74
76
|
atypes = []
|
@@ -78,10 +80,13 @@ module Solargraph
|
|
78
80
|
match = ol.parameters.any?(&:restarg?)
|
79
81
|
break
|
80
82
|
end
|
81
|
-
atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
|
83
|
+
atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context), locals)
|
84
|
+
# make sure we get types from up the method
|
85
|
+
# inheritance chain if we don't have them on this pin
|
86
|
+
ptype = param.typify api_map
|
82
87
|
# @todo Weak type comparison
|
83
88
|
# unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
|
84
|
-
unless
|
89
|
+
unless ptype.undefined? || atype.name == ptype.name || ptype.any? { |current_ptype| api_map.super_and_sub?(current_ptype.name, atype.name) } || ptype.generic? || param.restarg?
|
85
90
|
match = false
|
86
91
|
break
|
87
92
|
end
|
@@ -89,11 +94,16 @@ module Solargraph
|
|
89
94
|
if match
|
90
95
|
if ol.block && with_block?
|
91
96
|
block_atypes = ol.block.parameters.map(&:return_type)
|
92
|
-
|
97
|
+
if block.links.map(&:class) == [BlockSymbol]
|
98
|
+
# like the bar in foo(&:bar)
|
99
|
+
blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
|
100
|
+
else
|
101
|
+
blocktype = block_call_type(api_map, name_pin, locals)
|
102
|
+
end
|
93
103
|
end
|
94
104
|
new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
|
95
105
|
new_return_type = new_signature_pin.return_type
|
96
|
-
type = with_params(new_return_type.
|
106
|
+
type = with_params(new_return_type.self_to_type(name_pin.context), name_pin.context).qualify(api_map, name_pin.context.namespace) if new_return_type.defined?
|
97
107
|
type ||= ComplexType::UNDEFINED
|
98
108
|
end
|
99
109
|
break if type.defined?
|
@@ -101,20 +111,21 @@ module Solargraph
|
|
101
111
|
p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
|
102
112
|
next p.proxy(type) if type.defined?
|
103
113
|
if !p.macros.empty?
|
104
|
-
result = process_macro(p, api_map, context, locals)
|
114
|
+
result = process_macro(p, api_map, name_pin.context, locals)
|
105
115
|
next result unless result.return_type.undefined?
|
106
116
|
elsif !p.directives.empty?
|
107
|
-
result = process_directive(p, api_map, context, locals)
|
117
|
+
result = process_directive(p, api_map, name_pin.context, locals)
|
108
118
|
next result unless result.return_type.undefined?
|
109
119
|
end
|
110
120
|
p
|
111
121
|
end
|
112
122
|
result.map do |pin|
|
113
|
-
if pin.path == 'Class#new' && context.tag != 'Class'
|
114
|
-
|
123
|
+
if pin.path == 'Class#new' && name_pin.context.tag != 'Class'
|
124
|
+
reduced_context = name_pin.context.reduce_class_type
|
125
|
+
pin.proxy(reduced_context)
|
115
126
|
else
|
116
127
|
next pin if pin.return_type.undefined?
|
117
|
-
selfy = pin.return_type.
|
128
|
+
selfy = pin.return_type.self_to_type(name_pin.context)
|
118
129
|
selfy == pin.return_type ? pin : pin.proxy(selfy)
|
119
130
|
end
|
120
131
|
end
|
@@ -192,24 +203,24 @@ module Solargraph
|
|
192
203
|
nil
|
193
204
|
end
|
194
205
|
|
195
|
-
# @param
|
196
|
-
# @
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
|
205
|
-
true
|
206
|
+
# @param name_pin [Pin::Base]
|
207
|
+
# @return [Pin::Method, nil]
|
208
|
+
def find_method_pin(name_pin)
|
209
|
+
method_pin = name_pin
|
210
|
+
until method_pin.is_a?(Pin::Method)
|
211
|
+
method_pin = method_pin.closure
|
212
|
+
return if method_pin.nil?
|
213
|
+
end
|
214
|
+
method_pin
|
206
215
|
end
|
207
216
|
|
208
217
|
# @param api_map [ApiMap]
|
209
218
|
# @param name_pin [Pin::Base]
|
210
219
|
# @return [::Array<Pin::Base>]
|
211
220
|
def super_pins api_map, name_pin
|
212
|
-
|
221
|
+
method_pin = find_method_pin(name_pin)
|
222
|
+
return [] if method_pin.nil?
|
223
|
+
pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
|
213
224
|
pins.reject{|p| p.path == name_pin.path}
|
214
225
|
end
|
215
226
|
|
@@ -217,10 +228,13 @@ module Solargraph
|
|
217
228
|
# @param name_pin [Pin::Base]
|
218
229
|
# @return [::Array<Pin::Base>]
|
219
230
|
def yield_pins api_map, name_pin
|
220
|
-
method_pin =
|
221
|
-
return []
|
231
|
+
method_pin = find_method_pin(name_pin)
|
232
|
+
return [] unless method_pin
|
222
233
|
|
223
|
-
method_pin.signatures.map(&:block).compact
|
234
|
+
method_pin.signatures.map(&:block).compact.map do |signature_pin|
|
235
|
+
return_type = signature_pin.return_type.qualify(api_map, name_pin.namespace)
|
236
|
+
signature_pin.proxy(return_type)
|
237
|
+
end
|
224
238
|
end
|
225
239
|
|
226
240
|
# @param type [ComplexType]
|
@@ -228,7 +242,7 @@ module Solargraph
|
|
228
242
|
# @return [ComplexType]
|
229
243
|
def with_params type, context
|
230
244
|
return type unless type.to_s.include?('$')
|
231
|
-
ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:
|
245
|
+
ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
|
232
246
|
end
|
233
247
|
|
234
248
|
# @return [void]
|
@@ -242,25 +256,41 @@ module Solargraph
|
|
242
256
|
# @param block_parameter_types [::Array<ComplexType>]
|
243
257
|
# @param locals [::Array<Pin::LocalVariable>]
|
244
258
|
# @return [ComplexType, nil]
|
245
|
-
def
|
259
|
+
def block_symbol_call_type(api_map, context, block_parameter_types, locals)
|
260
|
+
# Ruby's shorthand for sending the passed in method name
|
261
|
+
# to the first yield parameter with no arguments
|
262
|
+
block_symbol_name = block.links.first.word
|
263
|
+
block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
|
264
|
+
callee = api_map.get_path_pins(block_symbol_call_path).first
|
265
|
+
return_type = callee&.return_type
|
266
|
+
# @todo: Figure out why we get unresolved generics at
|
267
|
+
# this point and need to assume method return types
|
268
|
+
# based on the generic type
|
269
|
+
return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
|
270
|
+
return_type || ComplexType::UNDEFINED
|
271
|
+
end
|
272
|
+
|
273
|
+
# @param api_map [ApiMap]
|
274
|
+
# @return [Pin::Block, nil]
|
275
|
+
def find_block_pin(api_map)
|
276
|
+
node_location = Solargraph::Location.from_node(block.node)
|
277
|
+
return if node_location.nil?
|
278
|
+
block_pins = api_map.get_block_pins
|
279
|
+
block_pins.find { |pin| pin.location.contain?(node_location) }
|
280
|
+
end
|
281
|
+
|
282
|
+
# @param api_map [ApiMap]
|
283
|
+
# @param name_pin [Pin::Base]
|
284
|
+
# @param block_parameter_types [::Array<ComplexType>]
|
285
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
286
|
+
# @return [ComplexType, nil]
|
287
|
+
def block_call_type(api_map, name_pin, locals)
|
246
288
|
return nil unless with_block?
|
247
289
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
block_symbol_name = block.links.first.word
|
253
|
-
block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
|
254
|
-
callee = api_map.get_path_pins(block_symbol_call_path).first
|
255
|
-
return_type = callee&.return_type
|
256
|
-
# @todo: Figure out why we get unresolved generics at
|
257
|
-
# this point and need to assume method return types
|
258
|
-
# based on the generic type
|
259
|
-
return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
|
260
|
-
return_type || ComplexType::UNDEFINED
|
261
|
-
else
|
262
|
-
block.infer(api_map, Pin::ProxyType.anonymous(context), locals)
|
263
|
-
end
|
290
|
+
block_context_pin = name_pin
|
291
|
+
block_pin = find_block_pin(api_map)
|
292
|
+
block_context_pin = block_pin.closure if block_pin
|
293
|
+
block.infer(api_map, block_context_pin, locals)
|
264
294
|
end
|
265
295
|
end
|
266
296
|
end
|
@@ -61,6 +61,15 @@ module Solargraph
|
|
61
61
|
false
|
62
62
|
end
|
63
63
|
|
64
|
+
# debugging description of contents; not for machine use
|
65
|
+
def desc
|
66
|
+
word
|
67
|
+
end
|
68
|
+
|
69
|
+
def inspect
|
70
|
+
"#<#{self.class} - `#{self.desc}`>"
|
71
|
+
end
|
72
|
+
|
64
73
|
protected
|
65
74
|
|
66
75
|
# Mark whether this link is the head of a chain
|
@@ -15,7 +15,7 @@ module Solargraph
|
|
15
15
|
|
16
16
|
def resolve api_map, name_pin, locals
|
17
17
|
types = @links.map { |link| link.infer(api_map, name_pin, locals) }
|
18
|
-
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.
|
18
|
+
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq))]
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -5,10 +5,19 @@ require 'solargraph/source/chain/link'
|
|
5
5
|
|
6
6
|
module Solargraph
|
7
7
|
class Source
|
8
|
-
#
|
9
|
-
#
|
8
|
+
#
|
9
|
+
# Represents an expression as a single call chain at the parse
|
10
|
+
# tree level, made up of constants, variables, and method calls,
|
11
|
+
# each represented as a Link object.
|
12
|
+
#
|
13
|
+
# Computes Pins and/or ComplexTypes representing the interpreted
|
14
|
+
# expression.
|
10
15
|
#
|
11
16
|
class Chain
|
17
|
+
#
|
18
|
+
# A chain of constants, variables, and method calls for inferring types of
|
19
|
+
# values.
|
20
|
+
#
|
12
21
|
autoload :Link, 'solargraph/source/chain/link'
|
13
22
|
autoload :Call, 'solargraph/source/chain/call'
|
14
23
|
autoload :QCall, 'solargraph/source/chain/q_call'
|
@@ -61,13 +70,31 @@ module Solargraph
|
|
61
70
|
@base ||= Chain.new(links[0..-2])
|
62
71
|
end
|
63
72
|
|
73
|
+
# Determine potential Pins returned by this chain of words
|
74
|
+
#
|
64
75
|
# @param api_map [ApiMap]
|
65
|
-
# @param name_pin [Pin::
|
66
|
-
#
|
76
|
+
# @param name_pin [Pin::Closure] the surrounding closure pin for
|
77
|
+
# the statement represented by this chain for type resolution
|
78
|
+
# and method pin lookup.
|
79
|
+
#
|
80
|
+
# For method calls (Chain::Call objects) as the first element
|
81
|
+
# in the chain, 'name_pin.binder' should return the
|
82
|
+
# ComplexType representing the LHS / "self type" of the call.
|
83
|
+
#
|
84
|
+
# @param locals [::Enumerable<Pin::LocalVariable>] Any local
|
85
|
+
# variables / method parameters etc visible by the statement
|
67
86
|
#
|
68
|
-
# @return [::Array<Pin::Base>]
|
87
|
+
# @return [::Array<Pin::Base>] Pins representing possible return
|
88
|
+
# types of this method.
|
69
89
|
def define api_map, name_pin, locals
|
70
90
|
return [] if undefined?
|
91
|
+
|
92
|
+
# working_pin is the surrounding closure pin for the link
|
93
|
+
# being processed, whose #binder method will provide the LHS /
|
94
|
+
# 'self type' of the next link (same as the #return_type method
|
95
|
+
# --the type of the result so far).
|
96
|
+
#
|
97
|
+
# @todo ProxyType uses 'type' for the binder, but '
|
71
98
|
working_pin = name_pin
|
72
99
|
links[0..-2].each do |link|
|
73
100
|
pins = link.resolve(api_map, working_pin, locals)
|
@@ -75,12 +102,12 @@ module Solargraph
|
|
75
102
|
return [] if type.undefined?
|
76
103
|
working_pin = Pin::ProxyType.anonymous(type)
|
77
104
|
end
|
78
|
-
links.last.last_context =
|
105
|
+
links.last.last_context = working_pin
|
79
106
|
links.last.resolve(api_map, working_pin, locals)
|
80
107
|
end
|
81
108
|
|
82
109
|
# @param api_map [ApiMap]
|
83
|
-
# @param name_pin [Pin::Base]
|
110
|
+
# @param name_pin [Pin::Base] The pin for the closure in which this code runs
|
84
111
|
# @param locals [::Enumerable<Pin::LocalVariable>]
|
85
112
|
# @return [ComplexType]
|
86
113
|
# @sg-ignore
|
@@ -102,10 +129,6 @@ module Solargraph
|
|
102
129
|
# @param locals [::Enumerable<Pin::LocalVariable>]
|
103
130
|
# @return [ComplexType]
|
104
131
|
def infer_uncached api_map, name_pin, locals
|
105
|
-
from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
|
106
|
-
if from_here
|
107
|
-
name_pin = name_pin.proxy(from_here)
|
108
|
-
end
|
109
132
|
pins = define(api_map, name_pin, locals)
|
110
133
|
type = infer_first_defined(pins, links.last.last_context, api_map, locals)
|
111
134
|
maybe_nil(type)
|
@@ -161,7 +184,7 @@ module Solargraph
|
|
161
184
|
# @todo even at strong, no typechecking complaint
|
162
185
|
# happens when a [Pin::Base,nil] is passed into a method
|
163
186
|
# that accepts only [Pin::Namespace] as an argument
|
164
|
-
type = type.resolve_generics(pin.closure, context.
|
187
|
+
type = type.resolve_generics(pin.closure, context.binder)
|
165
188
|
end
|
166
189
|
if type.defined?
|
167
190
|
possibles.push type
|
@@ -192,14 +215,15 @@ module Solargraph
|
|
192
215
|
return ComplexType::UNDEFINED if possibles.empty?
|
193
216
|
|
194
217
|
type = if possibles.length > 1
|
195
|
-
|
196
|
-
|
218
|
+
# Move nil to the end by convention
|
219
|
+
sorted = possibles.sort { |a, _| a.tag == 'nil' ? 1 : 0 }
|
220
|
+
ComplexType.new(sorted.uniq)
|
197
221
|
else
|
198
|
-
ComplexType.
|
222
|
+
ComplexType.new(possibles)
|
199
223
|
end
|
200
224
|
return type if context.nil? || context.return_type.undefined?
|
201
225
|
|
202
|
-
type.
|
226
|
+
type.self_to_type(context.return_type)
|
203
227
|
end
|
204
228
|
|
205
229
|
# @param type [ComplexType]
|
@@ -207,7 +231,7 @@ module Solargraph
|
|
207
231
|
def maybe_nil type
|
208
232
|
return type if type.undefined? || type.void? || type.nullable?
|
209
233
|
return type unless nullable?
|
210
|
-
ComplexType.
|
234
|
+
ComplexType.new(type.items + [ComplexType::NIL])
|
211
235
|
end
|
212
236
|
end
|
213
237
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Solargraph
|
4
4
|
class Source
|
5
|
-
# Information about a
|
6
|
-
# there.
|
5
|
+
# Information about a single Position in a Source, including the
|
6
|
+
# word located there.
|
7
7
|
#
|
8
8
|
class Cursor
|
9
9
|
# @return [Position]
|
@@ -35,6 +35,7 @@ module Solargraph
|
|
35
35
|
# The part of the word before the current position. Given the text
|
36
36
|
# `foo.bar`, the start_of_word at position(0, 6) is `ba`.
|
37
37
|
#
|
38
|
+
# @sg-ignore Improve resolution of String#match below
|
38
39
|
# @return [String]
|
39
40
|
def start_of_word
|
40
41
|
@start_of_word ||= begin
|
@@ -103,6 +104,17 @@ module Solargraph
|
|
103
104
|
@string ||= source.string_at?(position)
|
104
105
|
end
|
105
106
|
|
107
|
+
|
108
|
+
# True if the cursor's chain is an assignment to a variable.
|
109
|
+
#
|
110
|
+
# When the chain is an assignment, `Cursor#word` will contain the
|
111
|
+
# variable name.
|
112
|
+
#
|
113
|
+
# @return [Boolean]
|
114
|
+
def assign?
|
115
|
+
[:lvasgn, :ivasgn, :gvasgn, :cvasgn].include? chain&.node&.type
|
116
|
+
end
|
117
|
+
|
106
118
|
# Get a cursor pointing to the method that receives the current statement
|
107
119
|
# as an argument.
|
108
120
|
#
|