solargraph 0.18.2 → 0.18.3
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 +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 ||= {}
|