solargraph 0.18.2 → 0.18.3
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 +33 -28
- data/lib/solargraph/api_map.rb +997 -1044
- data/lib/solargraph/api_map/source_to_yard.rb +4 -3
- data/lib/solargraph/diagnostics/rubocop.rb +4 -3
- data/lib/solargraph/language_server/host.rb +140 -70
- data/lib/solargraph/language_server/message/base.rb +1 -0
- data/lib/solargraph/language_server/message/client.rb +6 -2
- data/lib/solargraph/language_server/message/text_document/completion.rb +34 -39
- data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/did_close.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/did_save.rb +1 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/hover.rb +25 -30
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +8 -7
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +1 -1
- data/lib/solargraph/language_server/transport/socket.rb +15 -17
- data/lib/solargraph/library.rb +34 -16
- data/lib/solargraph/node_methods.rb +96 -96
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/pin/base.rb +2 -1
- data/lib/solargraph/pin/base_variable.rb +45 -5
- data/lib/solargraph/pin/block_parameter.rb +5 -2
- data/lib/solargraph/pin/method.rb +22 -0
- data/lib/solargraph/pin/namespace.rb +32 -2
- data/lib/solargraph/pin/reference.rb +21 -0
- data/lib/solargraph/pin/yard_object.rb +9 -0
- data/lib/solargraph/shell.rb +136 -136
- data/lib/solargraph/source.rb +134 -188
- data/lib/solargraph/source/change.rb +70 -0
- data/lib/solargraph/source/fragment.rb +120 -66
- data/lib/solargraph/source/position.rb +41 -0
- data/lib/solargraph/source/updater.rb +48 -0
- data/lib/solargraph/version.rb +3 -3
- data/lib/solargraph/workspace/config.rb +4 -9
- data/lib/solargraph/yard_map/core_docs.rb +0 -1
- metadata +5 -2
@@ -0,0 +1,70 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class Source
|
3
|
+
# A change to be applied to text.
|
4
|
+
#
|
5
|
+
class Change
|
6
|
+
# @return [Range]
|
7
|
+
attr_reader :range
|
8
|
+
|
9
|
+
# @return [String]
|
10
|
+
attr_reader :new_text
|
11
|
+
|
12
|
+
# @param range [Range] The starting and ending positions of the change.
|
13
|
+
# If nil, the original text will be overwritten.
|
14
|
+
# @param new_text [String] The text to be changed.
|
15
|
+
def initialize range, new_text
|
16
|
+
@range = range
|
17
|
+
@new_text = new_text
|
18
|
+
end
|
19
|
+
|
20
|
+
# Write the change to the specified text.
|
21
|
+
#
|
22
|
+
# @param text [String] The text to be changed.
|
23
|
+
# @param nullable [Boolean] If true, minor changes that could generate
|
24
|
+
# syntax errors will be repaired.
|
25
|
+
# @return [String] The updated text.
|
26
|
+
def write text, nullable = false
|
27
|
+
if nullable and !range.nil? and new_text.match(/[\.\[\{\(@\$:]$/)
|
28
|
+
commit text, "#{new_text[0..-2]} "
|
29
|
+
elsif range.nil?
|
30
|
+
new_text
|
31
|
+
else
|
32
|
+
commit text, new_text
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Repair an update by replacing the new text with similarly formatted
|
37
|
+
# whitespace.
|
38
|
+
#
|
39
|
+
# @param text [String] The text to be changed.
|
40
|
+
# @return [String] The updated text.
|
41
|
+
def repair text
|
42
|
+
fixed = new_text.gsub(/[^\s]/, ' ')
|
43
|
+
if range.nil?
|
44
|
+
fixed
|
45
|
+
else
|
46
|
+
commit text, fixed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def commit text, insert
|
53
|
+
start_offset = get_offset(text, range.start.line, range.start.character)
|
54
|
+
end_offset = get_offset(text, range.end.line, range.end.character)
|
55
|
+
(start_offset == 0 ? '' : text[0..start_offset-1].to_s) + insert.force_encoding('utf-8') + text[end_offset..-1].to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_offset text, line, column
|
59
|
+
offset = 0
|
60
|
+
feed = 0
|
61
|
+
text.lines.each do |l|
|
62
|
+
break if line == feed
|
63
|
+
offset += l.length
|
64
|
+
feed += 1
|
65
|
+
end
|
66
|
+
offset + column
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -33,11 +33,6 @@ module Solargraph
|
|
33
33
|
#
|
34
34
|
# @return [String]
|
35
35
|
def namespace
|
36
|
-
# if @namespace.nil?
|
37
|
-
# base = @source.parent_node_from(line, column, :class, :module, :def, :defs)
|
38
|
-
# @namespace ||= @source.namespace_for(base)
|
39
|
-
# end
|
40
|
-
# @namespace
|
41
36
|
if @namespace.nil?
|
42
37
|
parts = []
|
43
38
|
@tree.each do |n|
|
@@ -56,6 +51,17 @@ module Solargraph
|
|
56
51
|
@argument ||= !signature_position.nil?
|
57
52
|
end
|
58
53
|
|
54
|
+
def chained?
|
55
|
+
if @chained.nil?
|
56
|
+
@chained = false
|
57
|
+
@tree.each do |n|
|
58
|
+
@chained = true if n.type == :send
|
59
|
+
break
|
60
|
+
end
|
61
|
+
end
|
62
|
+
@chained
|
63
|
+
end
|
64
|
+
|
59
65
|
# @return [Fragment]
|
60
66
|
def recipient
|
61
67
|
return nil if signature_position.nil?
|
@@ -90,6 +96,14 @@ module Solargraph
|
|
90
96
|
@signature ||= signature_data[1]
|
91
97
|
end
|
92
98
|
|
99
|
+
def valid?
|
100
|
+
@source.parsed?
|
101
|
+
end
|
102
|
+
|
103
|
+
def broken?
|
104
|
+
!valid?
|
105
|
+
end
|
106
|
+
|
93
107
|
# Get the signature before the current word. Given the signature
|
94
108
|
# `String.new.split`, the base is `String.new`.
|
95
109
|
#
|
@@ -116,6 +130,26 @@ module Solargraph
|
|
116
130
|
@base
|
117
131
|
end
|
118
132
|
|
133
|
+
# @return [String]
|
134
|
+
def root
|
135
|
+
@root ||= signature.split('.').first
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [String]
|
139
|
+
def chain
|
140
|
+
@chain ||= signature.split('.')[1..-1].join('.')
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [String]
|
144
|
+
def base_chain
|
145
|
+
@base_chain ||= signature.split('.')[1..-2].join('.')
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [String]
|
149
|
+
def whole_chain
|
150
|
+
@whole_chain ||= whole_signature.split('.')[1..-1].join('.')
|
151
|
+
end
|
152
|
+
|
119
153
|
# Get the remainder of the word after the current offset. Given the text
|
120
154
|
# `foobar` with an offset of 3, the remainder is `bar`.
|
121
155
|
#
|
@@ -159,8 +193,6 @@ module Solargraph
|
|
159
193
|
#
|
160
194
|
# @return [Boolean]
|
161
195
|
def string?
|
162
|
-
# @string = @source.string_at?(offset) if @string.nil?
|
163
|
-
# @string
|
164
196
|
@string ||= (node.type == :str or node.type == :dstr)
|
165
197
|
end
|
166
198
|
|
@@ -191,25 +223,91 @@ module Solargraph
|
|
191
223
|
# from the current offset.
|
192
224
|
#
|
193
225
|
# @return [Array<Solargraph::Pin::LocalVariable>]
|
194
|
-
def local_variable_pins
|
195
|
-
@local_variable_pins ||= @source.local_variable_pins.select{|pin| pin.visible_from?(node)}
|
226
|
+
def local_variable_pins name = nil
|
227
|
+
@local_variable_pins ||= prefer_non_nil_variables(@source.local_variable_pins.select{|pin| pin.visible_from?(node)})
|
228
|
+
return @local_variable_pins if name.nil?
|
229
|
+
@local_variable_pins.select{|pin| pin.name == name}
|
230
|
+
end
|
231
|
+
|
232
|
+
def calculated_signature
|
233
|
+
@calculated_signature ||= calculate
|
234
|
+
end
|
235
|
+
|
236
|
+
def calculated_whole_signature
|
237
|
+
@calculated_whole_signature ||= calculated_signature + remainder
|
238
|
+
end
|
239
|
+
|
240
|
+
def calculated_base
|
241
|
+
if @calculated_base.nil?
|
242
|
+
@calculated_base = calculated_signature[0..-2] if calculated_signature.end_with?('.')
|
243
|
+
@calculated_base ||= calculated_signature.split('.')[0..-2].join('.')
|
244
|
+
end
|
245
|
+
@calculated_base
|
196
246
|
end
|
197
247
|
|
198
248
|
private
|
199
249
|
|
250
|
+
def calculate
|
251
|
+
return signature if signature.empty? or signature.nil?
|
252
|
+
if signature.start_with?('.')
|
253
|
+
return signature if column < 2
|
254
|
+
# @todo Smelly exceptional case for arrays
|
255
|
+
return signature.sub(/^\.\[\]/, 'Array.new') if signature.start_with?('.[].')
|
256
|
+
pn = @source.node_at(line, column - 2)
|
257
|
+
unless pn.nil?
|
258
|
+
literal = infer_literal_node_type(pn)
|
259
|
+
unless literal.nil?
|
260
|
+
return "#{literal}.new#{signature}"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
return signature
|
264
|
+
end
|
265
|
+
# @todo Smelly exceptional case for integers
|
266
|
+
base, rest = signature.split('.', 2)
|
267
|
+
base.sub!(/^[0-9]+?$/, 'Integer.new')
|
268
|
+
var = local_variable_pins(base).first
|
269
|
+
unless var.nil?
|
270
|
+
done = []
|
271
|
+
until var.nil?
|
272
|
+
break if done.include?(var)
|
273
|
+
done.push var
|
274
|
+
type = var.calculated_signature
|
275
|
+
break if type.nil?
|
276
|
+
base = type
|
277
|
+
var = local_variable_pins(base).first
|
278
|
+
end
|
279
|
+
end
|
280
|
+
base = @source.qualify(base, namespace)
|
281
|
+
base + (rest.nil? ? '' : ".#{rest}")
|
282
|
+
end
|
283
|
+
|
284
|
+
# @todo DRY this method. It exists in ApiMap.
|
285
|
+
# @return [Array<Solargraph::Pin::Base>]
|
286
|
+
def prefer_non_nil_variables pins
|
287
|
+
result = []
|
288
|
+
nil_pins = []
|
289
|
+
pins.each do |pin|
|
290
|
+
if pin.nil_assignment? and pin.return_type.nil?
|
291
|
+
nil_pins.push pin
|
292
|
+
else
|
293
|
+
result.push pin
|
294
|
+
end
|
295
|
+
end
|
296
|
+
result + nil_pins
|
297
|
+
end
|
298
|
+
|
200
299
|
# @return [Integer]
|
201
300
|
def offset
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
@offset
|
301
|
+
@offset ||= get_offset(line, column)
|
302
|
+
end
|
303
|
+
|
304
|
+
def get_offset line, column
|
305
|
+
Position.line_char_to_offset(@code, line, column)
|
306
|
+
end
|
307
|
+
|
308
|
+
def get_position_at(offset)
|
309
|
+
pos = Position.from_offset(@code, offset)
|
310
|
+
[pos.line, pos.character]
|
213
311
|
end
|
214
312
|
|
215
313
|
def signature_data
|
@@ -228,6 +326,7 @@ module Solargraph
|
|
228
326
|
unless !in_whitespace and string?
|
229
327
|
break if brackets > 0 or parens > 0 or squares > 0
|
230
328
|
char = @code[index, 1]
|
329
|
+
break if char.nil? # @todo Is this the right way to handle this?
|
231
330
|
if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
|
232
331
|
in_whitespace = true
|
233
332
|
else
|
@@ -267,22 +366,7 @@ module Solargraph
|
|
267
366
|
end
|
268
367
|
index -= 1
|
269
368
|
end
|
270
|
-
|
271
|
-
# @todo Smelly exceptional case for arrays
|
272
|
-
if signature.start_with?('.[].')
|
273
|
-
signature.sub!(/^\.\[\]/, 'Array.new')
|
274
|
-
else
|
275
|
-
line, col = get_position_at(index - 1)
|
276
|
-
pn = @source.node_at(line, col)
|
277
|
-
unless pn.nil?
|
278
|
-
literal = infer_literal_node_type(pn)
|
279
|
-
unless literal.nil?
|
280
|
-
signature = "#{literal}.new#{signature}"
|
281
|
-
# @todo Determine the index from the beginning of the literal node?
|
282
|
-
end
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
369
|
+
# @todo Smelly exceptional case for numbers
|
286
370
|
[index + 1, signature]
|
287
371
|
end
|
288
372
|
|
@@ -364,36 +448,6 @@ module Solargraph
|
|
364
448
|
@code[index..cursor-1]
|
365
449
|
end
|
366
450
|
|
367
|
-
def get_position_at(offset)
|
368
|
-
cursor = 0
|
369
|
-
line = 0
|
370
|
-
col = nil
|
371
|
-
@code.lines.each do |l|
|
372
|
-
if cursor + l.length > offset
|
373
|
-
col = offset - cursor
|
374
|
-
break
|
375
|
-
end
|
376
|
-
if cursor + l.length == offset
|
377
|
-
if l.end_with?("\n")
|
378
|
-
col = 0
|
379
|
-
line += 1
|
380
|
-
break
|
381
|
-
else
|
382
|
-
col = l.length
|
383
|
-
break
|
384
|
-
end
|
385
|
-
end
|
386
|
-
if cursor + l.length - 1 == offset and !l.end_with?("\n")
|
387
|
-
col = l.length - 1
|
388
|
-
break
|
389
|
-
end
|
390
|
-
cursor += l.length
|
391
|
-
line += 1
|
392
|
-
end
|
393
|
-
raise "Invalid offset" if col.nil?
|
394
|
-
[line, col]
|
395
|
-
end
|
396
|
-
|
397
451
|
def signature_position
|
398
452
|
if @signature_position.nil?
|
399
453
|
open_parens = 0
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module Solargraph
|
2
|
+
|
2
3
|
class Source
|
3
4
|
class Position
|
4
5
|
# @return [Integer]
|
@@ -21,6 +22,46 @@ module Solargraph
|
|
21
22
|
character: character
|
22
23
|
}
|
23
24
|
end
|
25
|
+
|
26
|
+
def self.to_offset text, position
|
27
|
+
result = 0
|
28
|
+
feed = 0
|
29
|
+
line = position.line
|
30
|
+
column = position.character
|
31
|
+
text.lines.each do |l|
|
32
|
+
line_length = l.length
|
33
|
+
char_length = l.chomp.length
|
34
|
+
if feed == line
|
35
|
+
result += column
|
36
|
+
break
|
37
|
+
end
|
38
|
+
result += line_length
|
39
|
+
feed += 1
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.line_char_to_offset text, line, character
|
45
|
+
to_offset(text, Position.new(line, character))
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.from_offset text, offset
|
49
|
+
cursor = 0
|
50
|
+
line = 0
|
51
|
+
character = nil
|
52
|
+
text.lines.each do |l|
|
53
|
+
line_length = l.length
|
54
|
+
char_length = l.chomp.length
|
55
|
+
if cursor + char_length >= offset
|
56
|
+
character = offset - cursor
|
57
|
+
break
|
58
|
+
end
|
59
|
+
cursor += line_length
|
60
|
+
line += 1
|
61
|
+
end
|
62
|
+
raise InvalidOffsetError if character.nil?
|
63
|
+
Position.new(line, character)
|
64
|
+
end
|
24
65
|
end
|
25
66
|
end
|
26
67
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class Source
|
3
|
+
# Updaters contain changes to be applied to a source. The source applies
|
4
|
+
# the update via the Source#synchronize method.
|
5
|
+
#
|
6
|
+
class Updater
|
7
|
+
# @return [String]
|
8
|
+
attr_reader :filename
|
9
|
+
|
10
|
+
# @return [Integer]
|
11
|
+
attr_reader :version
|
12
|
+
|
13
|
+
# @return [Array<Change>]
|
14
|
+
attr_reader :changes
|
15
|
+
|
16
|
+
# @param filename [String] The file to update.
|
17
|
+
# @param version [Integer] A version number associated with this update.
|
18
|
+
# @param changes [Array<Solargraph::Source::Change>] The changes.
|
19
|
+
def initialize filename, version, changes
|
20
|
+
@filename = filename
|
21
|
+
@version = version
|
22
|
+
@changes = changes
|
23
|
+
@input = nil
|
24
|
+
@did_nullify = nil
|
25
|
+
@output = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def write text, nullable = false
|
29
|
+
can_nullify = (nullable and changes.length == 1)
|
30
|
+
return @output if @input == text and can_nullify == @did_nullify
|
31
|
+
@input = text
|
32
|
+
@output = text
|
33
|
+
@did_nullify = can_nullify
|
34
|
+
changes.each do |ch|
|
35
|
+
@output = ch.write(@output, can_nullify)
|
36
|
+
end
|
37
|
+
@output
|
38
|
+
end
|
39
|
+
|
40
|
+
def repair text
|
41
|
+
changes.each do |ch|
|
42
|
+
text = ch.repair(text)
|
43
|
+
end
|
44
|
+
text
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/solargraph/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Solargraph
|
2
|
-
VERSION = '0.18.
|
3
|
-
end
|
1
|
+
module Solargraph
|
2
|
+
VERSION = '0.18.3'
|
3
|
+
end
|
@@ -16,15 +16,10 @@ module Solargraph
|
|
16
16
|
unless @workspace.nil?
|
17
17
|
sfile = File.join(@workspace, '.solargraph.yml')
|
18
18
|
if File.file?(sfile)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
exclude_globs = conf['exclude'] || []
|
24
|
-
rescue Exception => e
|
25
|
-
STDERR.puts "Unable to read .solargraph.yml: #{e.class} #{e.message}"
|
26
|
-
@raw_data = {}
|
27
|
-
end
|
19
|
+
@raw_data = YAML.load(File.read(sfile))
|
20
|
+
conf = YAML.load(File.read(sfile))
|
21
|
+
include_globs = conf['include'] || include_globs
|
22
|
+
exclude_globs = conf['exclude'] || []
|
28
23
|
end
|
29
24
|
end
|
30
25
|
@raw_data ||= {}
|