solargraph 0.30.2 → 0.31.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 +7 -0
- data/lib/solargraph/api_map.rb +31 -38
- data/lib/solargraph/api_map/store.rb +7 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +2 -1
- data/lib/solargraph/language_server/host.rb +34 -83
- data/lib/solargraph/language_server/host/cataloger.rb +17 -7
- data/lib/solargraph/language_server/host/diagnoser.rb +19 -10
- data/lib/solargraph/language_server/host/dispatch.rb +110 -0
- data/lib/solargraph/language_server/host/sources.rb +100 -1
- data/lib/solargraph/language_server/message/base.rb +15 -11
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
- data/lib/solargraph/language_server/message/initialize.rb +32 -27
- data/lib/solargraph/language_server/message/text_document/completion.rb +1 -8
- data/lib/solargraph/language_server/transport/adapter.rb +26 -15
- data/lib/solargraph/language_server/transport/data_reader.rb +2 -2
- data/lib/solargraph/library.rb +30 -58
- data/lib/solargraph/live_map.rb +1 -1
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/pin/base.rb +1 -1
- data/lib/solargraph/pin/base_method.rb +1 -1
- data/lib/solargraph/pin/method.rb +1 -1
- data/lib/solargraph/pin/method_alias.rb +15 -4
- data/lib/solargraph/plugin/process.rb +1 -1
- data/lib/solargraph/position.rb +1 -2
- data/lib/solargraph/server_methods.rb +1 -0
- data/lib/solargraph/shell.rb +0 -28
- data/lib/solargraph/source.rb +116 -20
- data/lib/solargraph/source/encoding_fixes.rb +1 -1
- data/lib/solargraph/source/source_chainer.rb +16 -8
- data/lib/solargraph/source_map.rb +11 -2
- data/lib/solargraph/source_map/clip.rb +1 -1
- data/lib/solargraph/source_map/mapper.rb +8 -5
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -0
- data/lib/solargraph/workspace.rb +17 -14
- data/lib/solargraph/workspace/config.rb +1 -1
- data/lib/solargraph/yard_map.rb +6 -5
- data/lib/solargraph/yard_map/core_docs.rb +68 -18
- data/lib/solargraph/yard_map/core_gen.rb +47 -0
- data/lib/yard-coregen.rb +16 -0
- data/lib/yard-solargraph.rb +10 -1
- metadata +21 -4
@@ -4,13 +4,6 @@ module Solargraph
|
|
4
4
|
module TextDocument
|
5
5
|
class Completion < Base
|
6
6
|
def process
|
7
|
-
inner_process
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
# @return [void]
|
13
|
-
def inner_process
|
14
7
|
filename = uri_to_file(params['textDocument']['uri'])
|
15
8
|
line = params['position']['line']
|
16
9
|
col = params['position']['character']
|
@@ -39,7 +32,7 @@ module Solargraph
|
|
39
32
|
items: items
|
40
33
|
)
|
41
34
|
rescue InvalidOffsetError => e
|
42
|
-
|
35
|
+
Logging.logger.info "Completion ignored invalid offset: #{filename}, line #{line}, character #{col}"
|
43
36
|
set_result empty_result
|
44
37
|
end
|
45
38
|
end
|
@@ -4,20 +4,20 @@ module Solargraph
|
|
4
4
|
# A common module for running language servers in Backport.
|
5
5
|
#
|
6
6
|
module Adapter
|
7
|
+
@@timer_is_running = false
|
8
|
+
|
7
9
|
def opening
|
8
10
|
@host = Solargraph::LanguageServer::Host.new
|
11
|
+
@host.start
|
9
12
|
@data_reader = Solargraph::LanguageServer::Transport::DataReader.new
|
10
13
|
@data_reader.set_message_handler do |message|
|
11
14
|
process message
|
12
15
|
end
|
13
|
-
|
16
|
+
start_timer
|
14
17
|
end
|
15
18
|
|
16
|
-
def
|
17
|
-
|
18
|
-
message.send_response
|
19
|
-
tmp = @host.flush
|
20
|
-
write tmp unless tmp.empty?
|
19
|
+
def closing
|
20
|
+
@host.stop
|
21
21
|
end
|
22
22
|
|
23
23
|
# @param data [String]
|
@@ -27,19 +27,30 @@ module Solargraph
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
# @param request [String]
|
31
|
+
# @return [void]
|
32
|
+
def process request
|
33
|
+
message = @host.receive(request)
|
34
|
+
message.send_response
|
35
|
+
tmp = @host.flush
|
36
|
+
write tmp unless tmp.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_timer
|
40
|
+
Backport.prepare_interval 0.1 do |server|
|
34
41
|
if @host.stopped?
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
server.stop
|
43
|
+
shutdown
|
44
|
+
else
|
45
|
+
tmp = @host.flush
|
46
|
+
write tmp unless tmp.empty?
|
40
47
|
end
|
41
48
|
end
|
42
49
|
end
|
50
|
+
|
51
|
+
def shutdown
|
52
|
+
Backport.stop unless @host.options['transport'] == 'external'
|
53
|
+
end
|
43
54
|
end
|
44
55
|
end
|
45
56
|
end
|
@@ -52,8 +52,8 @@ module Solargraph
|
|
52
52
|
msg = JSON.parse(@buffer)
|
53
53
|
@message_handler.call msg unless @message_handler.nil?
|
54
54
|
rescue JSON::ParserError => e
|
55
|
-
|
56
|
-
|
55
|
+
Solargraph::Logging.logger.info "Failed to parse request: #{e.message}"
|
56
|
+
Solargraph::Logging.logger.debug "Buffer: #{@buffer}"
|
57
57
|
ensure
|
58
58
|
@buffer.clear
|
59
59
|
@in_header = true
|
data/lib/solargraph/library.rb
CHANGED
@@ -20,6 +20,11 @@ module Solargraph
|
|
20
20
|
@catalog_mutex = Mutex.new
|
21
21
|
end
|
22
22
|
|
23
|
+
def inspect
|
24
|
+
# Let's not deal with insane data dumps in spec failures
|
25
|
+
to_s
|
26
|
+
end
|
27
|
+
|
23
28
|
# True if the ApiMap is up to date with the library's workspace and open
|
24
29
|
# files.
|
25
30
|
#
|
@@ -28,23 +33,6 @@ module Solargraph
|
|
28
33
|
@synchronized
|
29
34
|
end
|
30
35
|
|
31
|
-
# Open a file in the library. Opening a file will make it available for
|
32
|
-
# checkout and merge it into the workspace if applicable.
|
33
|
-
#
|
34
|
-
# @deprecated The library should not be responsible for this. Instead, it
|
35
|
-
# should accept a source and determine whether or not to merge it.
|
36
|
-
#
|
37
|
-
# @param filename [String]
|
38
|
-
# @param text [String]
|
39
|
-
# @param version [Integer]
|
40
|
-
# @return [void]
|
41
|
-
def open filename, text, version
|
42
|
-
logger.warn "Library#open is deprecated"
|
43
|
-
source = Solargraph::Source.load_string(text, filename, version)
|
44
|
-
merge source
|
45
|
-
attach source
|
46
|
-
end
|
47
|
-
|
48
36
|
# Open a file from disk and try to merge it into the workspace.
|
49
37
|
#
|
50
38
|
# @param filename [String]
|
@@ -60,7 +48,7 @@ module Solargraph
|
|
60
48
|
# library will include it in the ApiMap while it's attached. Only one
|
61
49
|
# source can be attached to the library at a time.
|
62
50
|
#
|
63
|
-
# @param source [Source]
|
51
|
+
# @param source [Source, nil]
|
64
52
|
# @return [void]
|
65
53
|
def attach source
|
66
54
|
mutex.synchronize do
|
@@ -78,6 +66,16 @@ module Solargraph
|
|
78
66
|
end
|
79
67
|
alias open? attached?
|
80
68
|
|
69
|
+
# Detach the specified file if it is currently attached to the library.
|
70
|
+
#
|
71
|
+
# @param filename [String]
|
72
|
+
# @return [Boolean] True if the specified file was detached
|
73
|
+
def detach filename
|
74
|
+
return false if @current.nil? || @current.filename != filename
|
75
|
+
attach nil
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
81
79
|
# True if the specified file is included in the workspace (but not
|
82
80
|
# necessarily open).
|
83
81
|
#
|
@@ -130,11 +128,10 @@ module Solargraph
|
|
130
128
|
# @param filename [String]
|
131
129
|
# @return [void]
|
132
130
|
def delete filename
|
131
|
+
detach filename
|
133
132
|
mutex.synchronize do
|
134
|
-
|
135
|
-
@
|
136
|
-
workspace.remove filename
|
137
|
-
# catalog
|
133
|
+
result = workspace.remove(filename)
|
134
|
+
@synchronized = !result if synchronized?
|
138
135
|
end
|
139
136
|
end
|
140
137
|
|
@@ -206,7 +203,7 @@ module Solargraph
|
|
206
203
|
return [] if pins.empty?
|
207
204
|
result = []
|
208
205
|
pins.uniq.each do |pin|
|
209
|
-
(workspace.sources + (@current ? [@current] : [])).uniq.each do |source|
|
206
|
+
(workspace.sources + (@current ? [@current] : [])).uniq(&:filename).each do |source|
|
210
207
|
found = source.references(pin.name)
|
211
208
|
found.select! do |loc|
|
212
209
|
referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
|
@@ -223,7 +220,7 @@ module Solargraph
|
|
223
220
|
end)
|
224
221
|
end
|
225
222
|
end
|
226
|
-
result
|
223
|
+
result.uniq
|
227
224
|
end
|
228
225
|
|
229
226
|
# Get the pin at the specified location or nil if the pin does not exist.
|
@@ -256,7 +253,10 @@ module Solargraph
|
|
256
253
|
checked = read(filename)
|
257
254
|
@synchronized = (checked == @current) if synchronized?
|
258
255
|
@current = checked
|
259
|
-
|
256
|
+
# Cataloging is necessary to avoid FileNotFoundErrors when the file is
|
257
|
+
# not in the workspace. Otherwise it should be safe to defer
|
258
|
+
# synchronization.
|
259
|
+
catalog unless workspace.has_file?(filename)
|
260
260
|
@current
|
261
261
|
end
|
262
262
|
|
@@ -303,30 +303,6 @@ module Solargraph
|
|
303
303
|
api_map.get_path_suggestions(path)
|
304
304
|
end
|
305
305
|
|
306
|
-
# Update a source in the library from the provided updater.
|
307
|
-
#
|
308
|
-
# @note This method will not update the library's ApiMap. See
|
309
|
-
# Library#synchronized? and Library#catalog for more information.
|
310
|
-
#
|
311
|
-
# @deprecated The library should not be responsible for this. Instead, it
|
312
|
-
# should accept a source and determine whether or not to merge it.
|
313
|
-
#
|
314
|
-
# @raise [FileNotFoundError] if the updater's file is not available.
|
315
|
-
# @param updater [Solargraph::Source::Updater]
|
316
|
-
# @return [void]
|
317
|
-
def update updater
|
318
|
-
logger.warn 'Library#update is deprecated'
|
319
|
-
mutex.synchronize do
|
320
|
-
if workspace.has_file?(updater.filename)
|
321
|
-
workspace.synchronize!(updater)
|
322
|
-
@current = workspace.source(updater.filename) if @current && @current.filename == updater.filename
|
323
|
-
elsif @current && @current.filename == updater.filename
|
324
|
-
@current = @current.synchronize(updater)
|
325
|
-
end
|
326
|
-
@synchronized = false
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
306
|
# Get the current text of a file in the library.
|
331
307
|
#
|
332
308
|
# @param filename [String]
|
@@ -366,25 +342,21 @@ module Solargraph
|
|
366
342
|
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
367
343
|
api_map.catalog bundle
|
368
344
|
@synchronized = true
|
345
|
+
logger.info "Catalog complete (#{api_map.pins.length} pins)"
|
369
346
|
end
|
370
347
|
end
|
371
348
|
|
372
349
|
# Get an array of foldable ranges for the specified file.
|
373
350
|
#
|
351
|
+
# @deprecated The library should not need to handle folding ranges. The
|
352
|
+
# source itself has all the information it needs.
|
353
|
+
#
|
374
354
|
# @param filename [String]
|
375
355
|
# @return [Array<Range>]
|
376
356
|
def folding_ranges filename
|
377
357
|
read(filename).folding_ranges
|
378
358
|
end
|
379
359
|
|
380
|
-
# @deprecated Libraries are no longer responsible for tracking open files.
|
381
|
-
#
|
382
|
-
# @return [Array<Source>]
|
383
|
-
def open_sources
|
384
|
-
logger.warn 'Library#open_sources is deprecated'
|
385
|
-
@current ? [@current] : []
|
386
|
-
end
|
387
|
-
|
388
360
|
# Create a library from a directory.
|
389
361
|
#
|
390
362
|
# @param directory [String] The path to be used for the workspace
|
@@ -403,7 +375,7 @@ module Solargraph
|
|
403
375
|
result = nil
|
404
376
|
mutex.synchronize do
|
405
377
|
result = workspace.merge(source)
|
406
|
-
@synchronized = result if synchronized?
|
378
|
+
@synchronized = !result if synchronized?
|
407
379
|
end
|
408
380
|
result
|
409
381
|
end
|
data/lib/solargraph/live_map.rb
CHANGED
data/lib/solargraph/pin.rb
CHANGED
data/lib/solargraph/pin/base.rb
CHANGED
@@ -167,7 +167,7 @@ module Solargraph
|
|
167
167
|
# @param api_map [ApiMap]
|
168
168
|
# @return [ComplexType]
|
169
169
|
def infer api_map
|
170
|
-
|
170
|
+
Solargraph::Logging.logger.warn "WARNING: Pin #infer methods are deprecated. Use #typify or #probe instead."
|
171
171
|
type = typify(api_map)
|
172
172
|
return type unless type.undefined?
|
173
173
|
probe api_map
|
@@ -82,7 +82,7 @@ module Solargraph
|
|
82
82
|
|
83
83
|
# @deprecated Use #typify and/or #probe instead
|
84
84
|
def infer api_map
|
85
|
-
|
85
|
+
Solargraph::Logging.logger.warn 'WARNING: Pin #infer methods are deprecated. Use #typify or #probe instead.'
|
86
86
|
type = typify(api_map)
|
87
87
|
return type unless type.undefined?
|
88
88
|
probe api_map
|
@@ -1,19 +1,30 @@
|
|
1
1
|
module Solargraph
|
2
2
|
module Pin
|
3
3
|
# Use this class to track method aliases for later remapping. Common
|
4
|
-
# examples are aliases for superclass methods or
|
5
|
-
# modules.
|
4
|
+
# examples that defer mapping are aliases for superclass methods or
|
5
|
+
# methods from included modules.
|
6
6
|
#
|
7
|
-
class MethodAlias <
|
7
|
+
class MethodAlias < Base
|
8
|
+
attr_reader :scope
|
9
|
+
|
8
10
|
attr_reader :original
|
9
11
|
|
10
12
|
def initialize location, namespace, name, scope, original
|
11
13
|
# @todo Determine how to handle these parameters. Among other things,
|
12
14
|
# determine if the visibility is defined by the location of the
|
13
15
|
# alias call or the original method.
|
14
|
-
super(location, namespace, name, ''
|
16
|
+
super(location, namespace, name, '')
|
17
|
+
@scope = scope
|
15
18
|
@original = original
|
16
19
|
end
|
20
|
+
|
21
|
+
def kind
|
22
|
+
Pin::METHOD_ALIAS
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
@path ||= namespace + (scope == :instance ? '#' : '.') + name
|
27
|
+
end
|
17
28
|
end
|
18
29
|
end
|
19
30
|
end
|
@@ -48,7 +48,7 @@ module Solargraph
|
|
48
48
|
require p
|
49
49
|
@required.push p
|
50
50
|
rescue Exception => e
|
51
|
-
|
51
|
+
Solargraph::Logging.logger.info "Failed to require #{p}: #{e.message}"
|
52
52
|
errors.push "Failed to require #{p}: #{e.class} #{e.message}"
|
53
53
|
end
|
54
54
|
end
|
data/lib/solargraph/position.rb
CHANGED
@@ -44,7 +44,6 @@ module Solargraph
|
|
44
44
|
column = position.character
|
45
45
|
text.lines.each do |l|
|
46
46
|
line_length = l.length
|
47
|
-
char_length = l.chomp.length
|
48
47
|
if feed == line
|
49
48
|
result += column
|
50
49
|
break
|
@@ -85,7 +84,7 @@ module Solargraph
|
|
85
84
|
cursor += line_length
|
86
85
|
line += 1
|
87
86
|
end
|
88
|
-
character = 0 if character.nil? and offset
|
87
|
+
character = 0 if character.nil? and (cursor - offset).between?(0, 1)
|
89
88
|
raise InvalidOffsetError if character.nil?
|
90
89
|
Position.new(line, character)
|
91
90
|
end
|
data/lib/solargraph/shell.rb
CHANGED
@@ -48,34 +48,6 @@ module Solargraph
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
desc 'suggest', 'Get code suggestions for the provided input'
|
52
|
-
long_desc <<-LONGDESC
|
53
|
-
Analyze a Ruby file and output a list of code suggestions in JSON format.
|
54
|
-
LONGDESC
|
55
|
-
option :line, type: :numeric, aliases: :l, desc: 'Zero-based line number', required: true
|
56
|
-
option :column, type: :numeric, aliases: [:c, :col], desc: 'Zero-based column number', required: true
|
57
|
-
option :filename, type: :string, aliases: :f, desc: 'File name', required: false
|
58
|
-
def suggest(*filenames)
|
59
|
-
STDERR.puts "WARNING: The `solargraph suggest` command is a candidate for deprecation. It will either change drastically or not exist in a future version."
|
60
|
-
# HACK: The ARGV array needs to be manipulated for ARGF.read to work
|
61
|
-
ARGV.clear
|
62
|
-
ARGV.concat filenames
|
63
|
-
text = ARGF.read
|
64
|
-
filename = options[:filename] || filenames[0]
|
65
|
-
begin
|
66
|
-
code_map = CodeMap.new(code: text, filename: filename)
|
67
|
-
offset = code_map.get_offset(options[:line], options[:column])
|
68
|
-
sugg = code_map.suggest_at(offset, filtered: true)
|
69
|
-
result = { "status" => "ok", "suggestions" => sugg }.to_json
|
70
|
-
STDOUT.puts result
|
71
|
-
rescue Exception => e
|
72
|
-
STDERR.puts e
|
73
|
-
STDERR.puts e.backtrace.join("\n")
|
74
|
-
result = { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
|
75
|
-
STDOUT.puts result
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
51
|
desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
|
80
52
|
option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
|
81
53
|
def config(directory = '.')
|
data/lib/solargraph/source.rb
CHANGED
@@ -18,6 +18,9 @@ module Solargraph
|
|
18
18
|
include EncodingFixes
|
19
19
|
include NodeMethods
|
20
20
|
|
21
|
+
# @return [String]
|
22
|
+
attr_reader :filename
|
23
|
+
|
21
24
|
# @return [String]
|
22
25
|
attr_reader :code
|
23
26
|
|
@@ -27,9 +30,6 @@ module Solargraph
|
|
27
30
|
# @return [Array<Parser::Source::Comment>]
|
28
31
|
attr_reader :comments
|
29
32
|
|
30
|
-
# @return [String]
|
31
|
-
attr_reader :filename
|
32
|
-
|
33
33
|
# @todo Deprecate?
|
34
34
|
# @return [Integer]
|
35
35
|
attr_reader :version
|
@@ -64,10 +64,16 @@ module Solargraph
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# @param range [Solargraph::Range]
|
67
|
+
# @return [String]
|
67
68
|
def at range
|
68
69
|
from_to range.start.line, range.start.character, range.ending.line, range.ending.character
|
69
70
|
end
|
70
71
|
|
72
|
+
# @param l1 [Integer]
|
73
|
+
# @param c1 [Integer]
|
74
|
+
# @param l2 [Integer]
|
75
|
+
# @param c2 [Integer]
|
76
|
+
# @return [String]
|
71
77
|
def from_to l1, c1, l2, c2
|
72
78
|
b = Solargraph::Position.line_char_to_offset(@code, l1, c1)
|
73
79
|
e = Solargraph::Position.line_char_to_offset(@code, l2, c2)
|
@@ -97,8 +103,53 @@ module Solargraph
|
|
97
103
|
stack
|
98
104
|
end
|
99
105
|
|
106
|
+
# Start synchronizing the source. This method updates the code without
|
107
|
+
# parsing a new AST. The resulting Source object will be marked not
|
108
|
+
# synchronized (#synchronized? == false).
|
109
|
+
#
|
110
|
+
# @param updater [Source::Updater]
|
111
|
+
# @return [Source]
|
112
|
+
def start_synchronize updater
|
113
|
+
raise 'Invalid synchronization' unless updater.filename == filename
|
114
|
+
real_code = updater.write(@code)
|
115
|
+
src = Source.allocate
|
116
|
+
src.filename = filename
|
117
|
+
src.code = real_code
|
118
|
+
src.version = updater.version
|
119
|
+
src.parsed = parsed?
|
120
|
+
src.repaired = updater.repair(@repaired)
|
121
|
+
src.synchronized = false
|
122
|
+
src.node = @node
|
123
|
+
src.comments = @comments
|
124
|
+
src.error_ranges = error_ranges
|
125
|
+
src.last_updater = updater
|
126
|
+
src
|
127
|
+
end
|
128
|
+
|
129
|
+
# Finish synchronizing a source that was updated via #start_synchronize.
|
130
|
+
# This method returns self if the source is already synchronized. Otherwise
|
131
|
+
# it parses the AST and returns a new synchronized Source.
|
132
|
+
#
|
133
|
+
# @return [Source]
|
134
|
+
def finish_synchronize
|
135
|
+
return self if synchronized?
|
136
|
+
synced = Source.new(@code, filename)
|
137
|
+
if synced.parsed?
|
138
|
+
synced.version = version
|
139
|
+
return synced
|
140
|
+
end
|
141
|
+
synced = Source.new(@repaired, filename)
|
142
|
+
synced.error_ranges.concat (error_ranges + last_updater.changes.map(&:range))
|
143
|
+
synced.code = @code
|
144
|
+
synced.synchronized = true
|
145
|
+
synced.version = version
|
146
|
+
synced
|
147
|
+
end
|
148
|
+
|
149
|
+
# Synchronize the Source with an update. This method applies changes to the
|
150
|
+
# code, parses the new code's AST, and returns the resulting Source object.
|
151
|
+
#
|
100
152
|
# @param updater [Source::Updater]
|
101
|
-
# @param reparse [Boolean]
|
102
153
|
# @return [Source]
|
103
154
|
def synchronize updater
|
104
155
|
raise 'Invalid synchronization' unless updater.filename == filename
|
@@ -177,11 +228,9 @@ module Solargraph
|
|
177
228
|
@error_ranges ||= []
|
178
229
|
end
|
179
230
|
|
231
|
+
# @param node [Parser::AST::Node]
|
232
|
+
# @return [String]
|
180
233
|
def code_for(node)
|
181
|
-
# @todo Using node locations on code with converted EOLs seems
|
182
|
-
# slightly more efficient than calculating offsets.
|
183
|
-
# b = node.location.expression.begin.begin_pos
|
184
|
-
# e = node.location.expression.end.end_pos
|
185
234
|
b = Position.line_char_to_offset(@code, node.location.line, node.location.column)
|
186
235
|
e = Position.line_char_to_offset(@code, node.location.last_line, node.location.last_column)
|
187
236
|
frag = code[b..e-1].to_s
|
@@ -191,8 +240,10 @@ module Solargraph
|
|
191
240
|
# @param node [Parser::AST::Node]
|
192
241
|
# @return [String]
|
193
242
|
def comments_for node
|
194
|
-
|
195
|
-
|
243
|
+
stringified_comments[node.loc.line] ||= begin
|
244
|
+
arr = associated_comments[node.loc.line]
|
245
|
+
arr ? stringify_comment_array(arr) : nil
|
246
|
+
end
|
196
247
|
end
|
197
248
|
|
198
249
|
# A location representing the file in its entirety.
|
@@ -219,11 +270,16 @@ module Solargraph
|
|
219
270
|
@folding_ranges ||= begin
|
220
271
|
result = []
|
221
272
|
inner_folding_ranges node, result
|
222
|
-
result.concat
|
273
|
+
result.concat foldable_comment_block_ranges
|
223
274
|
result
|
224
275
|
end
|
225
276
|
end
|
226
277
|
|
278
|
+
def synchronized?
|
279
|
+
@synchronized = true if @synchronized.nil?
|
280
|
+
@synchronized
|
281
|
+
end
|
282
|
+
|
227
283
|
private
|
228
284
|
|
229
285
|
# @param top [Parser::AST::Node]
|
@@ -249,7 +305,7 @@ module Solargraph
|
|
249
305
|
@associated_comments ||= begin
|
250
306
|
result = {}
|
251
307
|
Parser::Source::Comment.associate_locations(node, comments).each_pair do |loc, all|
|
252
|
-
block = all
|
308
|
+
block = all #.select{ |l| l.document? || code.lines[l.loc.line].strip.start_with?('#')}
|
253
309
|
next if block.empty?
|
254
310
|
result[loc.line] ||= []
|
255
311
|
result[loc.line].concat block
|
@@ -266,6 +322,7 @@ module Solargraph
|
|
266
322
|
ctxt = ''
|
267
323
|
num = nil
|
268
324
|
started = false
|
325
|
+
last_line = nil
|
269
326
|
comments.each { |l|
|
270
327
|
# Trim the comment and minimum leading whitespace
|
271
328
|
p = l.text.gsub(/^#/, '')
|
@@ -276,11 +333,21 @@ module Solargraph
|
|
276
333
|
cur = p.index(/[^ ]/)
|
277
334
|
num = cur if cur < num
|
278
335
|
end
|
336
|
+
# Include blank lines between comments
|
337
|
+
ctxt += ("\n" * (l.loc.first_line - last_line - 1)) unless last_line.nil?
|
279
338
|
ctxt += "#{p[num..-1]}\n" if started
|
339
|
+
last_line = l.loc.last_line
|
280
340
|
}
|
281
341
|
ctxt
|
282
342
|
end
|
283
343
|
|
344
|
+
# A hash of line numbers and their associated comments.
|
345
|
+
#
|
346
|
+
# @return [Hash{Integer => Array<String>}]
|
347
|
+
def stringified_comments
|
348
|
+
@stringified_comments ||= {}
|
349
|
+
end
|
350
|
+
|
284
351
|
# @return [Array<Range>]
|
285
352
|
def string_ranges
|
286
353
|
@string_ranges ||= string_ranges_in(@node)
|
@@ -293,7 +360,12 @@ module Solargraph
|
|
293
360
|
end
|
294
361
|
end
|
295
362
|
|
296
|
-
|
363
|
+
# Get an array of foldable comment block ranges. Blocks are excluded if
|
364
|
+
# they are less than 3 lines long.
|
365
|
+
#
|
366
|
+
# @return [Array<Range>]
|
367
|
+
def foldable_comment_block_ranges
|
368
|
+
return [] unless synchronized?
|
297
369
|
result = []
|
298
370
|
grouped = []
|
299
371
|
# @param cmnt [Parser::Source::Comment]
|
@@ -304,13 +376,17 @@ module Solargraph
|
|
304
376
|
if grouped.empty? || cmnt.loc.expression.line == grouped.last.loc.expression.line + 1
|
305
377
|
grouped.push cmnt
|
306
378
|
else
|
307
|
-
result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0) unless grouped.
|
379
|
+
result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0) unless grouped.length < 3
|
308
380
|
grouped = [cmnt]
|
309
381
|
end
|
310
382
|
else
|
311
|
-
|
383
|
+
unless grouped.length < 3
|
384
|
+
result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0)
|
385
|
+
end
|
386
|
+
grouped.clear
|
312
387
|
end
|
313
388
|
end
|
389
|
+
result.push Range.from_to(grouped.first.loc.expression.line, 0, grouped.last.loc.expression.line, 0) unless grouped.length < 3
|
314
390
|
result
|
315
391
|
end
|
316
392
|
|
@@ -339,12 +415,13 @@ module Solargraph
|
|
339
415
|
end
|
340
416
|
end
|
341
417
|
|
418
|
+
# @param name [String]
|
419
|
+
# @param top [AST::Node]
|
420
|
+
# @return [Array<AST::Node>]
|
342
421
|
def inner_node_references name, top
|
343
422
|
result = []
|
344
|
-
if top.
|
345
|
-
if top.children.any?{|c| c.to_s == name}
|
346
|
-
result.push top
|
347
|
-
end
|
423
|
+
if top.is_a?(AST::Node)
|
424
|
+
result.push top if top.children.any? { |c| c.to_s == name }
|
348
425
|
top.children.each { |c| result.concat inner_node_references(name, c) }
|
349
426
|
end
|
350
427
|
result
|
@@ -352,18 +429,36 @@ module Solargraph
|
|
352
429
|
|
353
430
|
protected
|
354
431
|
|
432
|
+
# @return [String]
|
433
|
+
attr_writer :filename
|
434
|
+
|
355
435
|
# @return [Integer]
|
356
436
|
attr_writer :version
|
357
437
|
|
358
438
|
# @return [String]
|
359
439
|
attr_writer :code
|
360
440
|
|
441
|
+
# @return [Parser::AST::Node]
|
442
|
+
attr_writer :node
|
443
|
+
|
444
|
+
# @return [Array<Range>]
|
445
|
+
attr_writer :error_ranges
|
446
|
+
|
361
447
|
# @return [String]
|
362
448
|
attr_accessor :repaired
|
363
449
|
|
364
450
|
# @return [Boolean]
|
365
451
|
attr_writer :parsed
|
366
452
|
|
453
|
+
# @return [Array<Parser::Source::Comment>]
|
454
|
+
attr_writer :comments
|
455
|
+
|
456
|
+
# @return [Boolean]
|
457
|
+
attr_writer :synchronized
|
458
|
+
|
459
|
+
# @return [Source::Updater]
|
460
|
+
attr_accessor :last_updater
|
461
|
+
|
367
462
|
class << self
|
368
463
|
# @param filename [String]
|
369
464
|
# @return [Solargraph::Source]
|
@@ -392,7 +487,8 @@ module Solargraph
|
|
392
487
|
end
|
393
488
|
|
394
489
|
# @param code [String]
|
395
|
-
# @param filename [String]
|
490
|
+
# @param filename [String, nil]
|
491
|
+
# @param line [Integer]
|
396
492
|
# @return [Parser::AST::Node]
|
397
493
|
def parse code, filename = nil, line = 0
|
398
494
|
buffer = Parser::Source::Buffer.new(filename, line)
|