solargraph 0.30.1 → 0.30.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/lib/solargraph/api_map.rb +1 -7
- data/lib/solargraph/api_map/cache.rb +0 -11
- data/lib/solargraph/diagnostics.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop.rb +44 -60
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +46 -0
- data/lib/solargraph/language_server/host.rb +114 -50
- data/lib/solargraph/language_server/host/sources.rb +39 -0
- data/lib/solargraph/language_server/message/initialize.rb +2 -8
- data/lib/solargraph/language_server/uri_helpers.rb +1 -1
- data/lib/solargraph/library.rb +69 -41
- data/lib/solargraph/pin/conversions.rb +2 -2
- data/lib/solargraph/source_map/node_processor/send_node.rb +14 -2
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map/core_docs.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61453319a056f4779bf21c852bb34b5f797207c19ff9266d422d25c724934bc1
|
4
|
+
data.tar.gz: 405c13271fce7df56c5daae95b95430f5933a66728d3e2f6fff11762d4f392d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dcd832eff27b926dd8d244feff2edc37398f0004fa62dd002f07981e325d6f5a88f7c93bc1ad91d1f0ce34954790afc0410ed9581936d5ad57a465f99cc2372
|
7
|
+
data.tar.gz: 246cb5bbb21a7134532512c0321e86633d21adcf4eebd24de3d33427ab3da39663dafba488b8e0a304abd252c874408513ced6370cdc8e88cde18187f1242b79
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -354,13 +354,7 @@ module Solargraph
|
|
354
354
|
# @param scope [Symbol] :instance or :class
|
355
355
|
# @return [Array<Solargraph::Pin::Base>]
|
356
356
|
def get_method_stack fqns, name, scope: :instance
|
357
|
-
|
358
|
-
# Solargraph on Solargraph itself.
|
359
|
-
# cached = cache.get_method_stack(fqns, name, scope)
|
360
|
-
# return cached unless cached.nil?
|
361
|
-
result = get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select{|p| p.name == name}
|
362
|
-
# cache.set_method_stack(fqns, name, scope, result)
|
363
|
-
# result
|
357
|
+
get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select{|p| p.name == name}
|
364
358
|
end
|
365
359
|
|
366
360
|
# Get an array of all suggestions that match the specified path.
|
@@ -3,7 +3,6 @@ module Solargraph
|
|
3
3
|
class Cache
|
4
4
|
def initialize
|
5
5
|
@methods = {}
|
6
|
-
@method_stacks = {}
|
7
6
|
@constants = {}
|
8
7
|
@qualified_namespaces = {}
|
9
8
|
end
|
@@ -16,14 +15,6 @@ module Solargraph
|
|
16
15
|
@methods[[fqns, scope, visibility.sort, deep]] = value
|
17
16
|
end
|
18
17
|
|
19
|
-
def get_method_stack fqns, name, scope
|
20
|
-
@method_stacks[[fqns, name, scope]]
|
21
|
-
end
|
22
|
-
|
23
|
-
def set_method_stack fqns, name, scope, value
|
24
|
-
@method_stacks[[fqns, name, scope]] = value
|
25
|
-
end
|
26
|
-
|
27
18
|
def get_constants namespace, context
|
28
19
|
@constants[[namespace, context]]
|
29
20
|
end
|
@@ -43,7 +34,6 @@ module Solargraph
|
|
43
34
|
# @return [void]
|
44
35
|
def clear
|
45
36
|
@methods.clear
|
46
|
-
@method_stacks.clear
|
47
37
|
@constants.clear
|
48
38
|
@qualified_namespaces.clear
|
49
39
|
end
|
@@ -51,7 +41,6 @@ module Solargraph
|
|
51
41
|
# @return [Boolean]
|
52
42
|
def empty?
|
53
43
|
@methods.empty? &&
|
54
|
-
@method_stacks.empty? &&
|
55
44
|
@constants.empty? &&
|
56
45
|
@qualified_namespaces.empty?
|
57
46
|
end
|
@@ -6,6 +6,7 @@ module Solargraph
|
|
6
6
|
autoload :Base, 'solargraph/diagnostics/base'
|
7
7
|
autoload :Severities, 'solargraph/diagnostics/severities'
|
8
8
|
autoload :Rubocop, 'solargraph/diagnostics/rubocop'
|
9
|
+
autoload :RubocopHelpers, 'solargraph/diagnostics/rubocop_helpers'
|
9
10
|
autoload :RequireNotFound, 'solargraph/diagnostics/require_not_found'
|
10
11
|
autoload :TypeNotDefined, 'solargraph/diagnostics/type_not_defined'
|
11
12
|
autoload :UpdateErrors, 'solargraph/diagnostics/update_errors'
|
@@ -6,6 +6,8 @@ module Solargraph
|
|
6
6
|
# This reporter provides linting through RuboCop.
|
7
7
|
#
|
8
8
|
class Rubocop < Base
|
9
|
+
include RubocopHelpers
|
10
|
+
|
9
11
|
# Conversion of RuboCop severity names to LSP constants
|
10
12
|
SEVERITIES = {
|
11
13
|
'refactor' => Severities::HINT,
|
@@ -16,46 +18,23 @@ module Solargraph
|
|
16
18
|
}
|
17
19
|
|
18
20
|
# @param source [Solargraph::Source]
|
19
|
-
# @param
|
21
|
+
# @param _api_map [Solargraph::ApiMap]
|
20
22
|
# @return [Array<Hash>]
|
21
|
-
def diagnose source,
|
23
|
+
def diagnose source, _api_map
|
22
24
|
options, paths = generate_options(source.filename, source.code)
|
23
25
|
runner = RuboCop::Runner.new(options, RuboCop::ConfigStore.new)
|
24
26
|
result = redirect_stdout{ runner.run(paths) }
|
25
27
|
make_array JSON.parse(result)
|
28
|
+
rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
|
29
|
+
raise DiagnosticsError, "Error in RuboCop configuration: #{e.message}"
|
26
30
|
rescue JSON::ParserError
|
27
31
|
raise DiagnosticsError, 'RuboCop returned invalid data'
|
28
32
|
end
|
29
33
|
|
30
34
|
private
|
31
35
|
|
32
|
-
# @
|
33
|
-
#
|
34
|
-
# @return [Array]
|
35
|
-
def generate_options filename, code
|
36
|
-
args = ['-f', 'j']
|
37
|
-
rubocop_file = find_rubocop_file(filename)
|
38
|
-
args.push('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
|
39
|
-
args.push filename
|
40
|
-
options, paths = RuboCop::Options.new.parse(args)
|
41
|
-
options[:stdin] = code
|
42
|
-
[options, paths]
|
43
|
-
end
|
44
|
-
|
45
|
-
# @param filename [String]
|
46
|
-
# @return [String, nil]
|
47
|
-
def find_rubocop_file filename
|
48
|
-
dir = File.dirname(filename)
|
49
|
-
until File.dirname(dir) == dir
|
50
|
-
here = File.join(dir, '.rubocop.yml')
|
51
|
-
return here if File.exist?(here)
|
52
|
-
dir = File.dirname(dir)
|
53
|
-
end
|
54
|
-
nil
|
55
|
-
end
|
56
|
-
|
57
|
-
# @todo This is a smelly way to redirect output, but the RuboCop specs do the
|
58
|
-
# same thing.
|
36
|
+
# @todo This is a smelly way to redirect output, but the RuboCop specs do
|
37
|
+
# the same thing.
|
59
38
|
# @return [String]
|
60
39
|
def redirect_stdout
|
61
40
|
redir = StringIO.new
|
@@ -71,43 +50,48 @@ module Solargraph
|
|
71
50
|
diagnostics = []
|
72
51
|
resp['files'].each do |file|
|
73
52
|
file['offenses'].each do |off|
|
74
|
-
|
75
|
-
last_line = off['location']['start_line']
|
76
|
-
last_column = 0
|
77
|
-
else
|
78
|
-
last_line = off['location']['last_line'] - 1
|
79
|
-
last_column = off['location']['last_column']
|
80
|
-
end
|
81
|
-
diag = {
|
82
|
-
range: {
|
83
|
-
start: {
|
84
|
-
line: off['location']['start_line'] - 1,
|
85
|
-
character: off['location']['start_column'] - 1
|
86
|
-
},
|
87
|
-
end: {
|
88
|
-
line: last_line,
|
89
|
-
character: last_column
|
90
|
-
}
|
91
|
-
},
|
92
|
-
# 1 = Error, 2 = Warning, 3 = Information, 4 = Hint
|
93
|
-
severity: SEVERITIES[off['severity']],
|
94
|
-
source: off['cop_name'],
|
95
|
-
message: off['message'].gsub(/^#{off['cop_name']}\:/, '')
|
96
|
-
}
|
97
|
-
diagnostics.push diag
|
53
|
+
diagnostics.push offense_to_diagnostic(off)
|
98
54
|
end
|
99
55
|
end
|
100
56
|
diagnostics
|
101
57
|
end
|
102
58
|
|
103
|
-
#
|
104
|
-
# so we need to convert the paths provided to the command.
|
59
|
+
# Convert a RuboCop offense to an LSP diagnostic
|
105
60
|
#
|
106
|
-
# @param
|
107
|
-
# @return [
|
108
|
-
def
|
109
|
-
|
110
|
-
|
61
|
+
# @param off [Hash] Offense received from Rubocop
|
62
|
+
# @return [Hash] LSP diagnostic
|
63
|
+
def offense_to_diagnostic off
|
64
|
+
{
|
65
|
+
range: offense_range(off).to_hash,
|
66
|
+
# 1 = Error, 2 = Warning, 3 = Information, 4 = Hint
|
67
|
+
severity: SEVERITIES[off['severity']],
|
68
|
+
source: off['cop_name'],
|
69
|
+
message: off['message'].gsub(/^#{off['cop_name']}\:/, '')
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param off [Hash]
|
74
|
+
# @return [Range]
|
75
|
+
def offense_range off
|
76
|
+
Range.new(offense_start_position(off), offense_ending_position(off))
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param off [Hash]
|
80
|
+
# @return [Position]
|
81
|
+
def offense_start_position off
|
82
|
+
Position.new(off['location']['start_line'] - 1, off['location']['start_column'] - 1)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param off [Hash]
|
86
|
+
# @return [Position]
|
87
|
+
def offense_ending_position off
|
88
|
+
if off['location']['start_line'] != off['location']['last_line']
|
89
|
+
Position.new(off['location']['start_line'], 0)
|
90
|
+
else
|
91
|
+
Position.new(
|
92
|
+
off['location']['start_line'] - 1, off['location']['last_column']
|
93
|
+
)
|
94
|
+
end
|
111
95
|
end
|
112
96
|
end
|
113
97
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Diagnostics
|
3
|
+
module RubocopHelpers
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Generate command-line options for the specified filename and code.
|
7
|
+
#
|
8
|
+
# @param filename [String]
|
9
|
+
# @param code [String]
|
10
|
+
# @return [Array(Array<String>, Array<String>)]
|
11
|
+
def generate_options filename, code
|
12
|
+
args = ['-f', 'j']
|
13
|
+
rubocop_file = find_rubocop_file(filename)
|
14
|
+
args.push('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
|
15
|
+
args.push filename
|
16
|
+
options, paths = RuboCop::Options.new.parse(args)
|
17
|
+
options[:stdin] = code
|
18
|
+
[options, paths]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Find a RuboCop configuration file in a file's directory tree.
|
22
|
+
#
|
23
|
+
# @param filename [String]
|
24
|
+
# @return [String, nil]
|
25
|
+
def find_rubocop_file filename
|
26
|
+
dir = File.dirname(filename)
|
27
|
+
until File.dirname(dir) == dir
|
28
|
+
here = File.join(dir, '.rubocop.yml')
|
29
|
+
return here if File.exist?(here)
|
30
|
+
dir = File.dirname(dir)
|
31
|
+
end
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# RuboCop internally uses capitalized drive letters for Windows paths,
|
36
|
+
# so we need to convert the paths provided to the command.
|
37
|
+
#
|
38
|
+
# @param path [String]
|
39
|
+
# @return [String]
|
40
|
+
def fix_drive_letter path
|
41
|
+
return path unless path.match(/^[a-z]:/)
|
42
|
+
path[0].upcase + path[1..-1]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -10,6 +10,7 @@ module Solargraph
|
|
10
10
|
class Host
|
11
11
|
autoload :Diagnoser, 'solargraph/language_server/host/diagnoser'
|
12
12
|
autoload :Cataloger, 'solargraph/language_server/host/cataloger'
|
13
|
+
autoload :Sources, 'solargraph/language_server/host/sources'
|
13
14
|
|
14
15
|
include Solargraph::LanguageServer::UriHelpers
|
15
16
|
include Logging
|
@@ -93,14 +94,17 @@ module Solargraph
|
|
93
94
|
end
|
94
95
|
|
95
96
|
# Respond to a notification that a file was created in the workspace.
|
96
|
-
# The
|
97
|
-
#
|
97
|
+
# The libraries will determine whether the file should be merged; see
|
98
|
+
# Solargraph::Library#create_from_disk.
|
98
99
|
#
|
99
100
|
# @param uri [String] The file uri.
|
101
|
+
# @return [Boolean] True if a library accepted the file.
|
100
102
|
def create uri
|
101
|
-
library = library_for(uri)
|
102
103
|
filename = uri_to_file(uri)
|
103
|
-
result =
|
104
|
+
result = false
|
105
|
+
libraries.each do |lib|
|
106
|
+
result = true if lib.create_from_disk filename
|
107
|
+
end
|
104
108
|
diagnoser.schedule uri if open?(uri)
|
105
109
|
result
|
106
110
|
end
|
@@ -109,9 +113,11 @@ module Solargraph
|
|
109
113
|
#
|
110
114
|
# @param uri [String] The file uri.
|
111
115
|
def delete uri
|
112
|
-
|
116
|
+
sources.close uri
|
113
117
|
filename = uri_to_file(uri)
|
114
|
-
|
118
|
+
libraries.each do |lib|
|
119
|
+
lib.delete filename
|
120
|
+
end
|
115
121
|
send_notification "textDocument/publishDiagnostics", {
|
116
122
|
uri: uri,
|
117
123
|
diagnostics: []
|
@@ -124,8 +130,10 @@ module Solargraph
|
|
124
130
|
# @param text [String] The contents of the file.
|
125
131
|
# @param version [Integer] A version number.
|
126
132
|
def open uri, text, version
|
127
|
-
|
128
|
-
|
133
|
+
src = sources.open(uri, text, version)
|
134
|
+
libraries.each do |lib|
|
135
|
+
lib.merge src
|
136
|
+
end
|
129
137
|
diagnoser.schedule uri
|
130
138
|
end
|
131
139
|
|
@@ -140,45 +148,58 @@ module Solargraph
|
|
140
148
|
# @param uri [String]
|
141
149
|
# @return [Boolean]
|
142
150
|
def open? uri
|
143
|
-
|
151
|
+
sources.include? uri
|
144
152
|
end
|
145
153
|
|
146
154
|
# Close the file specified by the URI.
|
147
155
|
#
|
148
156
|
# @param uri [String]
|
157
|
+
# @return [void]
|
149
158
|
def close uri
|
150
|
-
|
151
|
-
|
159
|
+
logger.info "Closing #{uri}"
|
160
|
+
sources.close uri
|
152
161
|
diagnoser.schedule uri
|
153
162
|
end
|
154
163
|
|
155
164
|
# @param uri [String]
|
165
|
+
# @return [void]
|
156
166
|
def diagnose uri
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
167
|
+
if sources.include?(uri)
|
168
|
+
logger.info "Diagnosing #{uri}"
|
169
|
+
library = library_for(uri)
|
170
|
+
begin
|
171
|
+
results = library.diagnose uri_to_file(uri)
|
172
|
+
send_notification "textDocument/publishDiagnostics", {
|
173
|
+
uri: uri,
|
174
|
+
diagnostics: results
|
175
|
+
}
|
176
|
+
rescue DiagnosticsError => e
|
177
|
+
logger.warn "Error in diagnostics: #{e.message}"
|
178
|
+
options['diagnostics'] = false
|
179
|
+
send_notification 'window/showMessage', {
|
180
|
+
type: LanguageServer::MessageTypes::ERROR,
|
181
|
+
message: "Error in diagnostics: #{e.message}"
|
182
|
+
}
|
183
|
+
end
|
184
|
+
else
|
185
|
+
send_notification 'textDocument/publishDiagnostics', {
|
162
186
|
uri: uri,
|
163
|
-
diagnostics:
|
164
|
-
}
|
165
|
-
rescue DiagnosticsError => e
|
166
|
-
STDERR.puts "Error in diagnostics: #{e.message}"
|
167
|
-
options['diagnostics'] = false
|
168
|
-
send_notification 'window/showMessage', {
|
169
|
-
type: LanguageServer::MessageTypes::ERROR,
|
170
|
-
message: "Error in diagnostics: #{e.message}"
|
187
|
+
diagnostics: []
|
171
188
|
}
|
172
189
|
end
|
173
190
|
end
|
174
191
|
|
192
|
+
# Update a document from the parameters of a textDocument/didChange
|
193
|
+
# method.
|
194
|
+
#
|
195
|
+
# @param params [Hash]
|
196
|
+
# @return [void]
|
175
197
|
def change params
|
176
|
-
library = library_for(params['textDocument']['uri'])
|
177
198
|
updater = generate_updater(params)
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
199
|
+
src = sources.update(params['textDocument']['uri'], updater)
|
200
|
+
libraries.each do |lib|
|
201
|
+
lib.merge src
|
202
|
+
end
|
182
203
|
diagnoser.schedule params['textDocument']['uri']
|
183
204
|
end
|
184
205
|
|
@@ -206,8 +227,12 @@ module Solargraph
|
|
206
227
|
# Prepare a library for the specified directory.
|
207
228
|
#
|
208
229
|
# @param directory [String]
|
209
|
-
# @param name [String]
|
230
|
+
# @param name [String, nil]
|
231
|
+
# @return [void]
|
210
232
|
def prepare directory, name = nil
|
233
|
+
# No need to create a library without a directory. The generic library
|
234
|
+
# will handle it.
|
235
|
+
return if directory.nil?
|
211
236
|
logger.info "Preparing library for #{directory}"
|
212
237
|
path = ''
|
213
238
|
path = normalize_separators(directory) unless directory.nil?
|
@@ -225,20 +250,26 @@ module Solargraph
|
|
225
250
|
cataloger.start
|
226
251
|
end
|
227
252
|
|
253
|
+
# Prepare multiple folders.
|
254
|
+
#
|
255
|
+
# @param array [Array<Hash{String => String}>]
|
256
|
+
# @return [void]
|
228
257
|
def prepare_folders array
|
258
|
+
return if array.nil?
|
229
259
|
array.each do |folder|
|
230
260
|
prepare uri_to_file(folder['uri']), folder['name']
|
231
261
|
end
|
232
262
|
end
|
233
263
|
|
264
|
+
# Remove a directory.
|
265
|
+
#
|
266
|
+
# @param directory [String]
|
267
|
+
# @return [void]
|
234
268
|
def remove directory
|
235
269
|
logger.info "Removing library for #{directory}"
|
236
270
|
# @param lib [Library]
|
237
271
|
libraries.delete_if do |lib|
|
238
272
|
next false if lib.workspace.directory != directory
|
239
|
-
lib.open_sources.each do |src|
|
240
|
-
orphan_library.open(src.filename, src.code, src.version)
|
241
|
-
end
|
242
273
|
true
|
243
274
|
end
|
244
275
|
end
|
@@ -299,6 +330,7 @@ module Solargraph
|
|
299
330
|
# that were not flagged for dynamic registration by the client.
|
300
331
|
#
|
301
332
|
# @param methods [Array<String>] The methods to register
|
333
|
+
# @return [void]
|
302
334
|
def register_capabilities methods
|
303
335
|
logger.debug "Registering capabilities: #{methods}"
|
304
336
|
@register_semaphore.synchronize do
|
@@ -320,6 +352,7 @@ module Solargraph
|
|
320
352
|
# that were not flagged for dynamic registration by the client.
|
321
353
|
#
|
322
354
|
# @param methods [Array<String>] The methods to unregister
|
355
|
+
# @return [void]
|
323
356
|
def unregister_capabilities methods
|
324
357
|
logger.debug "Unregistering capabilities: #{methods}"
|
325
358
|
@register_semaphore.synchronize do
|
@@ -338,6 +371,7 @@ module Solargraph
|
|
338
371
|
# Flag a method as available for dynamic registration.
|
339
372
|
#
|
340
373
|
# @param method [String] The method name, e.g., 'textDocument/completion'
|
374
|
+
# @return [void]
|
341
375
|
def allow_registration method
|
342
376
|
@register_semaphore.synchronize do
|
343
377
|
@dynamic_capabilities.add method
|
@@ -364,6 +398,7 @@ module Solargraph
|
|
364
398
|
cataloger.synchronizing?
|
365
399
|
end
|
366
400
|
|
401
|
+
# @return [void]
|
367
402
|
def stop
|
368
403
|
@stopped = true
|
369
404
|
cataloger.stop
|
@@ -454,15 +489,15 @@ module Solargraph
|
|
454
489
|
# @return [Array<Solargraph::Range>]
|
455
490
|
def references_from filename, line, column, strip: true
|
456
491
|
library = library_for(file_to_uri(filename))
|
457
|
-
|
492
|
+
library.references_from(filename, line, column, strip: strip)
|
458
493
|
end
|
459
494
|
|
460
495
|
# @param query [String]
|
461
496
|
# @return [Array<Solargraph::Pin::Base>]
|
462
497
|
def query_symbols query
|
463
498
|
result = []
|
464
|
-
libraries.each { |lib| result.concat lib.query_symbols(query) }
|
465
|
-
result
|
499
|
+
(libraries + [generic_library]).each { |lib| result.concat lib.query_symbols(query) }
|
500
|
+
result.uniq
|
466
501
|
end
|
467
502
|
|
468
503
|
# @param query [String]
|
@@ -492,6 +527,7 @@ module Solargraph
|
|
492
527
|
#
|
493
528
|
# @param text [String]
|
494
529
|
# @param type [Integer] A MessageType constant
|
530
|
+
# @return [void]
|
495
531
|
def show_message text, type = LanguageServer::MessageTypes::INFO
|
496
532
|
send_notification 'window/showMessage', {
|
497
533
|
type: type,
|
@@ -506,6 +542,7 @@ module Solargraph
|
|
506
542
|
# @param actions [Array<String>] Response options for the client
|
507
543
|
# @param &block The block that processes the response
|
508
544
|
# @yieldparam [String] The action received from the client
|
545
|
+
# @return [void]
|
509
546
|
def show_message_request text, type, actions, &block
|
510
547
|
send_request 'window/showMessageRequest', {
|
511
548
|
type: type,
|
@@ -546,6 +583,8 @@ module Solargraph
|
|
546
583
|
lib.catalog
|
547
584
|
end
|
548
585
|
|
586
|
+
# @param uri [String]
|
587
|
+
# @return [Array<Range>]
|
549
588
|
def folding_ranges uri
|
550
589
|
library = library_for(uri)
|
551
590
|
file = uri_to_file(uri)
|
@@ -559,26 +598,56 @@ module Solargraph
|
|
559
598
|
@libraries ||= []
|
560
599
|
end
|
561
600
|
|
601
|
+
# @return [Sources]
|
602
|
+
def sources
|
603
|
+
@sources ||= Sources.new
|
604
|
+
end
|
605
|
+
|
562
606
|
# @param uri [String]
|
563
607
|
# @return [Library]
|
564
608
|
def library_for uri
|
565
|
-
|
609
|
+
explicit_library_for(uri) ||
|
610
|
+
implicit_library_for(uri) ||
|
611
|
+
generic_library_for(uri)
|
612
|
+
end
|
613
|
+
|
614
|
+
# @param uri [String]
|
615
|
+
# @return [Library, nil]
|
616
|
+
def explicit_library_for uri
|
566
617
|
filename = uri_to_file(uri)
|
567
|
-
# Find a library with an explicit reference to the file
|
568
618
|
libraries.each do |lib|
|
569
|
-
|
619
|
+
if lib.contain?(filename) #|| lib.open?(filename)
|
620
|
+
lib.attach sources.find(uri) if sources.include?(uri)
|
621
|
+
return lib
|
622
|
+
end
|
570
623
|
end
|
571
|
-
|
624
|
+
nil
|
625
|
+
end
|
626
|
+
|
627
|
+
# @param uri [String]
|
628
|
+
# @return [Library, nil]
|
629
|
+
def implicit_library_for uri
|
630
|
+
filename = uri_to_file(uri)
|
572
631
|
libraries.each do |lib|
|
573
|
-
return lib if filename.start_with?(lib.workspace.directory)
|
632
|
+
# return lib if filename.start_with?(lib.workspace.directory)
|
633
|
+
if lib.open?(filename) || filename.start_with?(lib.workspace.directory)
|
634
|
+
lib.attach sources.find(uri)
|
635
|
+
return lib
|
636
|
+
end
|
574
637
|
end
|
575
|
-
|
576
|
-
|
638
|
+
nil
|
639
|
+
end
|
640
|
+
|
641
|
+
# @param uri [String]
|
642
|
+
# @return [Library]
|
643
|
+
def generic_library_for uri
|
644
|
+
generic_library.attach sources.find(uri)
|
645
|
+
generic_library
|
577
646
|
end
|
578
647
|
|
579
648
|
# @return [Library]
|
580
|
-
def
|
581
|
-
@
|
649
|
+
def generic_library
|
650
|
+
@generic_library ||= Solargraph::Library.new
|
582
651
|
end
|
583
652
|
|
584
653
|
# @return [Diagnoser]
|
@@ -591,11 +660,6 @@ module Solargraph
|
|
591
660
|
@cataloger ||= Cataloger.new(self)
|
592
661
|
end
|
593
662
|
|
594
|
-
def unsafe_open? uri
|
595
|
-
library = library_for(uri)
|
596
|
-
library.open?(uri_to_file(uri))
|
597
|
-
end
|
598
|
-
|
599
663
|
def requests
|
600
664
|
@requests ||= {}
|
601
665
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module LanguageServer
|
3
|
+
class Host
|
4
|
+
class Sources
|
5
|
+
include UriHelpers
|
6
|
+
|
7
|
+
def open uri, text, version
|
8
|
+
filename = uri_to_file(uri)
|
9
|
+
source = Solargraph::Source.new(text, filename, version)
|
10
|
+
open_source_hash[uri] = source
|
11
|
+
end
|
12
|
+
|
13
|
+
def update uri, updater
|
14
|
+
src = find(uri)
|
15
|
+
open_source_hash[uri] = src.synchronize(updater)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Source]
|
19
|
+
def find uri
|
20
|
+
open_source_hash[uri] || raise(Solargraph::FileNotFoundError, "Host could not find #{uri}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def close uri
|
24
|
+
open_source_hash.delete uri
|
25
|
+
end
|
26
|
+
|
27
|
+
def include? uri
|
28
|
+
open_source_hash.key? uri
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def open_source_hash
|
34
|
+
@open_source_hash ||= {}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -5,7 +5,6 @@ module Solargraph
|
|
5
5
|
def process
|
6
6
|
host.configure params['initializationOptions']
|
7
7
|
if support_workspace_folders?
|
8
|
-
# @todo Prepare multiple folders
|
9
8
|
host.prepare_folders params['workspaceFolders']
|
10
9
|
elsif params['rootUri']
|
11
10
|
host.prepare UriHelpers.uri_to_file(params['rootUri'])
|
@@ -42,7 +41,8 @@ module Solargraph
|
|
42
41
|
def support_workspace_folders?
|
43
42
|
params['capabilities'] &&
|
44
43
|
params['capabilities']['workspace'] &&
|
45
|
-
params['capabilities']['workspace']['workspaceFolders']
|
44
|
+
params['capabilities']['workspace']['workspaceFolders'] &&
|
45
|
+
params['workspaceFolders']
|
46
46
|
end
|
47
47
|
|
48
48
|
def static_completion
|
@@ -113,12 +113,6 @@ module Solargraph
|
|
113
113
|
}
|
114
114
|
end
|
115
115
|
|
116
|
-
def static_references
|
117
|
-
{
|
118
|
-
referencesProvider: true
|
119
|
-
}
|
120
|
-
end
|
121
|
-
|
122
116
|
def static_folding_range
|
123
117
|
{
|
124
118
|
foldingRangeProvider: true
|
data/lib/solargraph/library.rb
CHANGED
@@ -11,6 +11,7 @@ module Solargraph
|
|
11
11
|
attr_reader :name
|
12
12
|
|
13
13
|
# @param workspace [Solargraph::Workspace]
|
14
|
+
# @param name [String, nil]
|
14
15
|
def initialize workspace = Solargraph::Workspace.new, name = nil
|
15
16
|
@workspace = workspace
|
16
17
|
@name = name
|
@@ -30,37 +31,52 @@ module Solargraph
|
|
30
31
|
# Open a file in the library. Opening a file will make it available for
|
31
32
|
# checkout and merge it into the workspace if applicable.
|
32
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
|
+
#
|
33
37
|
# @param filename [String]
|
34
38
|
# @param text [String]
|
35
39
|
# @param version [Integer]
|
36
40
|
# @return [void]
|
37
41
|
def open filename, text, version
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
open_file_hash[filename] = source
|
43
|
-
checkout filename
|
44
|
-
end
|
42
|
+
logger.warn "Library#open is deprecated"
|
43
|
+
source = Solargraph::Source.load_string(text, filename, version)
|
44
|
+
merge source
|
45
|
+
attach source
|
45
46
|
end
|
46
47
|
|
48
|
+
# Open a file from disk and try to merge it into the workspace.
|
49
|
+
#
|
50
|
+
# @param filename [String]
|
51
|
+
# @return [Boolean] True if the file was merged into the source.
|
47
52
|
def open_from_disk filename
|
53
|
+
source = Solargraph::Source.load(filename)
|
54
|
+
merge source
|
55
|
+
end
|
56
|
+
|
57
|
+
# Attach a source to the library.
|
58
|
+
#
|
59
|
+
# The attached source does not need to be a part of the workspace. The
|
60
|
+
# library will include it in the ApiMap while it's attached. Only one
|
61
|
+
# source can be attached to the library at a time.
|
62
|
+
#
|
63
|
+
# @param source [Source]
|
64
|
+
# @return [void]
|
65
|
+
def attach source
|
48
66
|
mutex.synchronize do
|
49
|
-
@synchronized =
|
50
|
-
|
51
|
-
workspace.merge source
|
52
|
-
open_file_hash[filename] = source
|
53
|
-
checkout filename
|
67
|
+
@synchronized = (@current == source) if synchronized?
|
68
|
+
@current = source
|
54
69
|
end
|
55
70
|
end
|
56
71
|
|
57
|
-
# True if the specified file is currently
|
72
|
+
# True if the specified file is currently attached.
|
58
73
|
#
|
59
74
|
# @param filename [String]
|
60
75
|
# @return [Boolean]
|
61
|
-
def
|
62
|
-
|
76
|
+
def attached? filename
|
77
|
+
!@current.nil? && @current.filename == filename
|
63
78
|
end
|
79
|
+
alias open? attached?
|
64
80
|
|
65
81
|
# True if the specified file is included in the workspace (but not
|
66
82
|
# necessarily open).
|
@@ -84,7 +100,6 @@ module Solargraph
|
|
84
100
|
@synchronized = false
|
85
101
|
source = Solargraph::Source.load_string(text, filename)
|
86
102
|
workspace.merge(source)
|
87
|
-
catalog
|
88
103
|
result = true
|
89
104
|
end
|
90
105
|
result
|
@@ -103,9 +118,6 @@ module Solargraph
|
|
103
118
|
@synchronized = false
|
104
119
|
source = Solargraph::Source.load_string(File.read(filename), filename)
|
105
120
|
workspace.merge(source)
|
106
|
-
open_file_hash[filename] = source if open_file_hash.key?(filename)
|
107
|
-
@current = source if @current && @current.filename == source.filename
|
108
|
-
catalog
|
109
121
|
result = true
|
110
122
|
end
|
111
123
|
result
|
@@ -120,9 +132,9 @@ module Solargraph
|
|
120
132
|
def delete filename
|
121
133
|
mutex.synchronize do
|
122
134
|
@synchronized = false
|
123
|
-
|
135
|
+
@current = nil if @current && @current.filename == filename
|
124
136
|
workspace.remove filename
|
125
|
-
catalog
|
137
|
+
# catalog
|
126
138
|
end
|
127
139
|
end
|
128
140
|
|
@@ -134,7 +146,7 @@ module Solargraph
|
|
134
146
|
def close filename
|
135
147
|
mutex.synchronize do
|
136
148
|
@synchronized = false
|
137
|
-
|
149
|
+
@current = nil if @current && @current.filename == filename
|
138
150
|
catalog
|
139
151
|
end
|
140
152
|
end
|
@@ -194,13 +206,13 @@ module Solargraph
|
|
194
206
|
return [] if pins.empty?
|
195
207
|
result = []
|
196
208
|
pins.uniq.each do |pin|
|
197
|
-
(workspace.sources +
|
209
|
+
(workspace.sources + (@current ? [@current] : [])).uniq.each do |source|
|
198
210
|
found = source.references(pin.name)
|
199
211
|
found.select! do |loc|
|
200
212
|
referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
|
201
213
|
referenced.any?{|r| r == pin}
|
202
214
|
end
|
203
|
-
# HACK for language clients that exclude special characters from the start of variable names
|
215
|
+
# HACK: for language clients that exclude special characters from the start of variable names
|
204
216
|
if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
|
205
217
|
found.map! do |loc|
|
206
218
|
Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
|
@@ -242,7 +254,7 @@ module Solargraph
|
|
242
254
|
# @return [Source]
|
243
255
|
def checkout filename
|
244
256
|
checked = read(filename)
|
245
|
-
@synchronized = (checked
|
257
|
+
@synchronized = (checked == @current) if synchronized?
|
246
258
|
@current = checked
|
247
259
|
catalog
|
248
260
|
@current
|
@@ -281,7 +293,6 @@ module Solargraph
|
|
281
293
|
# @return [Array<Solargraph::Pin::Base>]
|
282
294
|
def document_symbols filename
|
283
295
|
checkout filename
|
284
|
-
return [] unless open_file_hash.key?(filename)
|
285
296
|
api_map.document_symbols(filename)
|
286
297
|
end
|
287
298
|
|
@@ -297,20 +308,21 @@ module Solargraph
|
|
297
308
|
# @note This method will not update the library's ApiMap. See
|
298
309
|
# Library#synchronized? and Library#catalog for more information.
|
299
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.
|
300
313
|
#
|
301
314
|
# @raise [FileNotFoundError] if the updater's file is not available.
|
302
315
|
# @param updater [Solargraph::Source::Updater]
|
303
316
|
# @return [void]
|
304
317
|
def update updater
|
318
|
+
logger.warn 'Library#update is deprecated'
|
305
319
|
mutex.synchronize do
|
306
320
|
if workspace.has_file?(updater.filename)
|
307
321
|
workspace.synchronize!(updater)
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
open_file_hash[updater.filename] = open_file_hash[updater.filename].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)
|
312
325
|
end
|
313
|
-
@current = open_file_hash[updater.filename] if @current && @current.filename == updater.filename
|
314
326
|
@synchronized = false
|
315
327
|
end
|
316
328
|
end
|
@@ -332,7 +344,9 @@ module Solargraph
|
|
332
344
|
# @todo Only open files get diagnosed. Determine whether anything or
|
333
345
|
# everything in the workspace should get diagnosed, or if there should
|
334
346
|
# be an option to do so.
|
347
|
+
#
|
335
348
|
return [] unless open?(filename)
|
349
|
+
catalog
|
336
350
|
result = []
|
337
351
|
source = read(filename)
|
338
352
|
workspace.config.reporters.each do |name|
|
@@ -355,23 +369,45 @@ module Solargraph
|
|
355
369
|
end
|
356
370
|
end
|
357
371
|
|
372
|
+
# Get an array of foldable ranges for the specified file.
|
373
|
+
#
|
374
|
+
# @param filename [String]
|
375
|
+
# @return [Array<Range>]
|
358
376
|
def folding_ranges filename
|
359
377
|
read(filename).folding_ranges
|
360
378
|
end
|
361
379
|
|
380
|
+
# @deprecated Libraries are no longer responsible for tracking open files.
|
381
|
+
#
|
362
382
|
# @return [Array<Source>]
|
363
383
|
def open_sources
|
364
|
-
|
384
|
+
logger.warn 'Library#open_sources is deprecated'
|
385
|
+
@current ? [@current] : []
|
365
386
|
end
|
366
387
|
|
367
388
|
# Create a library from a directory.
|
368
389
|
#
|
369
390
|
# @param directory [String] The path to be used for the workspace
|
391
|
+
# @param name [String, nil]
|
370
392
|
# @return [Solargraph::Library]
|
371
393
|
def self.load directory = '', name = nil
|
372
394
|
Solargraph::Library.new(Solargraph::Workspace.new(directory), name)
|
373
395
|
end
|
374
396
|
|
397
|
+
# Try to merge a source into the library's workspace. If the workspace is
|
398
|
+
# not configured to include the source, it gets ignored.
|
399
|
+
#
|
400
|
+
# @param source [Source]
|
401
|
+
# @return [Boolean] True if the source was merged into the workspace.
|
402
|
+
def merge source
|
403
|
+
result = nil
|
404
|
+
mutex.synchronize do
|
405
|
+
result = workspace.merge(source)
|
406
|
+
@synchronized = result if synchronized?
|
407
|
+
end
|
408
|
+
result
|
409
|
+
end
|
410
|
+
|
375
411
|
private
|
376
412
|
|
377
413
|
# @return [Mutex]
|
@@ -392,14 +428,6 @@ module Solargraph
|
|
392
428
|
)
|
393
429
|
end
|
394
430
|
|
395
|
-
# A collection of files that are currently open in the library. Open
|
396
|
-
# files do not need to be in the workspace.
|
397
|
-
#
|
398
|
-
# @return [Hash{String => Source}]
|
399
|
-
def open_file_hash
|
400
|
-
@open_file_hash ||= {}
|
401
|
-
end
|
402
|
-
|
403
431
|
# Get the source for an open file or create a new source if the file
|
404
432
|
# exists on disk. Sources created from disk are not added to the open
|
405
433
|
# workspace files, i.e., the version on disk remains the authoritative
|
@@ -409,7 +437,7 @@ module Solargraph
|
|
409
437
|
# @param filename [String]
|
410
438
|
# @return [Solargraph::Source]
|
411
439
|
def read filename
|
412
|
-
return
|
440
|
+
return @current if @current && @current.filename == filename
|
413
441
|
raise FileNotFoundError, "File not found: #{filename}" unless workspace.has_file?(filename)
|
414
442
|
workspace.source(filename)
|
415
443
|
end
|
@@ -71,8 +71,8 @@ module Solargraph
|
|
71
71
|
def generate_link
|
72
72
|
this_path = path || return_type.tag
|
73
73
|
return nil if this_path.nil? || this_path == 'undefined'
|
74
|
-
return this_path if comments.empty?
|
75
|
-
"[#{this_path.gsub('_', '\\\\_')}](solargraph:/document?query=#{URI.
|
74
|
+
# return this_path if comments.empty?
|
75
|
+
"[#{this_path.gsub('_', '\\\\_')}](solargraph:/document?query=#{URI.escape(this_path)})"
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
@@ -5,8 +5,20 @@ module Solargraph
|
|
5
5
|
def process
|
6
6
|
if node.children[0].nil?
|
7
7
|
if [:private, :public, :protected].include?(node.children[1])
|
8
|
-
|
9
|
-
|
8
|
+
if (node.children.length > 2)
|
9
|
+
node.children[2..-1].each do |child|
|
10
|
+
next unless child.is_a?(AST::Node) && (child.type == :sym || child.type == :str)
|
11
|
+
name = child.children[0].to_s
|
12
|
+
matches = pins.select{ |pin| [Pin::METHOD, Pin::ATTRIBUTE].include?(pin.kind) && pin.name == name && pin.namespace == region.namespace && pin.context.scope == region.scope }
|
13
|
+
matches.each do |pin|
|
14
|
+
# @todo Smelly instance variable access
|
15
|
+
pin.instance_variable_set(:@visibility, node.children[1])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
else
|
19
|
+
# @todo Smelly instance variable access
|
20
|
+
region.instance_variable_set(:@visibility, node.children[1])
|
21
|
+
end
|
10
22
|
elsif node.children[1] == :module_function
|
11
23
|
process_module_function
|
12
24
|
elsif [:attr_reader, :attr_writer, :attr_accessor].include?(node.children[1])
|
data/lib/solargraph/version.rb
CHANGED
@@ -12,7 +12,7 @@ module Solargraph
|
|
12
12
|
|
13
13
|
class << self
|
14
14
|
def cache_dir
|
15
|
-
@cache_dir ||= File.join(Dir.home, '.solargraph', 'cache')
|
15
|
+
@cache_dir ||= ENV["SOLARGRAPH_CACHE"] || File.join(Dir.home, '.solargraph', 'cache')
|
16
16
|
end
|
17
17
|
|
18
18
|
# Ensure installation of minimum documentation.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solargraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.30.
|
4
|
+
version: 0.30.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fred Snyder
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backport
|
@@ -227,6 +227,7 @@ files:
|
|
227
227
|
- lib/solargraph/diagnostics/base.rb
|
228
228
|
- lib/solargraph/diagnostics/require_not_found.rb
|
229
229
|
- lib/solargraph/diagnostics/rubocop.rb
|
230
|
+
- lib/solargraph/diagnostics/rubocop_helpers.rb
|
230
231
|
- lib/solargraph/diagnostics/severities.rb
|
231
232
|
- lib/solargraph/diagnostics/type_not_defined.rb
|
232
233
|
- lib/solargraph/diagnostics/update_errors.rb
|
@@ -236,6 +237,7 @@ files:
|
|
236
237
|
- lib/solargraph/language_server/host.rb
|
237
238
|
- lib/solargraph/language_server/host/cataloger.rb
|
238
239
|
- lib/solargraph/language_server/host/diagnoser.rb
|
240
|
+
- lib/solargraph/language_server/host/sources.rb
|
239
241
|
- lib/solargraph/language_server/message.rb
|
240
242
|
- lib/solargraph/language_server/message/base.rb
|
241
243
|
- lib/solargraph/language_server/message/cancel_request.rb
|