solargraph 0.40.0 → 0.41.0
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/.travis.yml +2 -1
- data/CHANGELOG.md +33 -0
- data/README.md +15 -0
- data/SPONSORS.md +1 -0
- data/lib/.rubocop.yml +1 -1
- data/lib/solargraph.rb +8 -7
- data/lib/solargraph/api_map.rb +52 -75
- data/lib/solargraph/api_map/store.rb +5 -0
- data/lib/solargraph/bench.rb +16 -19
- data/lib/solargraph/compat.rb +15 -1
- data/lib/solargraph/diagnostics/rubocop.rb +10 -2
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +19 -20
- data/lib/solargraph/language_server/host.rb +74 -1
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +1 -0
- data/lib/solargraph/language_server/message/extended/environment.rb +3 -3
- data/lib/solargraph/language_server/message/initialize.rb +30 -35
- data/lib/solargraph/language_server/message/text_document/formatting.rb +69 -21
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/library.rb +94 -24
- data/lib/solargraph/parser/legacy/node_methods.rb +9 -0
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -1
- data/lib/solargraph/parser/rubyvm/node_methods.rb +18 -1
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +11 -12
- data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +1 -6
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +1 -1
- data/lib/solargraph/source.rb +1 -1
- data/lib/solargraph/source/chain/head.rb +0 -16
- data/lib/solargraph/source/source_chainer.rb +1 -0
- data/lib/solargraph/source_map/mapper.rb +0 -5
- data/lib/solargraph/type_checker.rb +49 -39
- data/lib/solargraph/type_checker/checks.rb +9 -5
- data/lib/solargraph/type_checker/rules.rb +5 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +19 -3
- data/lib/solargraph/yard_map/core_fills.rb +1 -0
- data/solargraph.gemspec +1 -1
- metadata +4 -4
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'observer'
|
|
4
4
|
require 'set'
|
|
5
|
+
require 'securerandom'
|
|
5
6
|
|
|
6
7
|
module Solargraph
|
|
7
8
|
module LanguageServer
|
|
@@ -192,7 +193,7 @@ module Solargraph
|
|
|
192
193
|
def diagnose uri
|
|
193
194
|
if sources.include?(uri)
|
|
194
195
|
library = library_for(uri)
|
|
195
|
-
if library.synchronized?
|
|
196
|
+
if library.mapped? && library.synchronized?
|
|
196
197
|
logger.info "Diagnosing #{uri}"
|
|
197
198
|
begin
|
|
198
199
|
results = library.diagnose uri_to_file(uri)
|
|
@@ -277,6 +278,7 @@ module Solargraph
|
|
|
277
278
|
begin
|
|
278
279
|
lib = Solargraph::Library.load(path, name)
|
|
279
280
|
libraries.push lib
|
|
281
|
+
async_library_map lib
|
|
280
282
|
rescue WorkspaceTooLargeError => e
|
|
281
283
|
send_notification 'window/showMessage', {
|
|
282
284
|
'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
|
|
@@ -494,6 +496,11 @@ module Solargraph
|
|
|
494
496
|
library.read_text(filename)
|
|
495
497
|
end
|
|
496
498
|
|
|
499
|
+
def formatter_config uri
|
|
500
|
+
library = library_for(uri)
|
|
501
|
+
library.workspace.config.formatter
|
|
502
|
+
end
|
|
503
|
+
|
|
497
504
|
# @param uri [String]
|
|
498
505
|
# @param line [Integer]
|
|
499
506
|
# @param column [Integer]
|
|
@@ -626,6 +633,7 @@ module Solargraph
|
|
|
626
633
|
|
|
627
634
|
# @return [void]
|
|
628
635
|
def catalog
|
|
636
|
+
return unless libraries.all?(&:mapped?)
|
|
629
637
|
libraries.each(&:catalog)
|
|
630
638
|
end
|
|
631
639
|
|
|
@@ -736,6 +744,71 @@ module Solargraph
|
|
|
736
744
|
def prepare_rename?
|
|
737
745
|
client_capabilities['rename'] && client_capabilities['rename']['prepareSupport']
|
|
738
746
|
end
|
|
747
|
+
|
|
748
|
+
def client_supports_progress?
|
|
749
|
+
client_capabilities['window'] && client_capabilities['window']['workDoneProgress']
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
# @param library [Library]
|
|
753
|
+
# @return [void]
|
|
754
|
+
def async_library_map library
|
|
755
|
+
return if library.mapped?
|
|
756
|
+
Thread.new do
|
|
757
|
+
if client_supports_progress?
|
|
758
|
+
uuid = SecureRandom.uuid
|
|
759
|
+
send_request 'window/workDoneProgress/create', {
|
|
760
|
+
token: uuid
|
|
761
|
+
} do |response|
|
|
762
|
+
do_async_library_map library, response.nil? ? uuid : nil
|
|
763
|
+
end
|
|
764
|
+
else
|
|
765
|
+
do_async_library_map library
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
def do_async_library_map library, uuid = nil
|
|
771
|
+
total = library.workspace.sources.length
|
|
772
|
+
if uuid
|
|
773
|
+
send_notification '$/progress', {
|
|
774
|
+
token: uuid,
|
|
775
|
+
value: {
|
|
776
|
+
kind: 'begin',
|
|
777
|
+
title: "Mapping workspace",
|
|
778
|
+
message: "0/#{total} files",
|
|
779
|
+
cancellable: false,
|
|
780
|
+
percentage: 0
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
end
|
|
784
|
+
pct = 0
|
|
785
|
+
mod = 10
|
|
786
|
+
while library.next_map
|
|
787
|
+
next unless uuid
|
|
788
|
+
cur = ((library.source_map_hash.keys.length.to_f / total.to_f) * 100).to_i
|
|
789
|
+
if cur > pct && cur % mod == 0
|
|
790
|
+
pct = cur
|
|
791
|
+
send_notification '$/progress', {
|
|
792
|
+
token: uuid,
|
|
793
|
+
value: {
|
|
794
|
+
kind: 'report',
|
|
795
|
+
cancellable: false,
|
|
796
|
+
message: "#{library.source_map_hash.keys.length}/#{total} files",
|
|
797
|
+
percentage: pct
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
if uuid
|
|
803
|
+
send_notification '$/progress', {
|
|
804
|
+
token: uuid,
|
|
805
|
+
value: {
|
|
806
|
+
kind: 'end',
|
|
807
|
+
message: 'Mapping complete'
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
end
|
|
811
|
+
end
|
|
739
812
|
end
|
|
740
813
|
end
|
|
741
814
|
end
|
|
@@ -21,6 +21,7 @@ module Solargraph
|
|
|
21
21
|
docs = pins
|
|
22
22
|
.reject { |pin| pin.documentation.empty? && pin.return_type.undefined? }
|
|
23
23
|
result = params
|
|
24
|
+
.transform_keys(&:to_sym)
|
|
24
25
|
.merge(pins.first.resolve_completion_item)
|
|
25
26
|
.merge(documentation: markup_content(join_docs(docs)))
|
|
26
27
|
result[:detail] = pins.first.detail
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Make sure the environment page can report RuboCop's version
|
|
4
|
-
require 'rubocop'
|
|
5
|
-
|
|
6
3
|
module Solargraph
|
|
7
4
|
module LanguageServer
|
|
8
5
|
module Message
|
|
@@ -12,6 +9,9 @@ module Solargraph
|
|
|
12
9
|
#
|
|
13
10
|
class Environment < Base
|
|
14
11
|
def process
|
|
12
|
+
# Make sure the environment page can report RuboCop's version
|
|
13
|
+
require 'rubocop'
|
|
14
|
+
|
|
15
15
|
page = Solargraph::Page.new(host.options['viewsPath'])
|
|
16
16
|
content = page.render('environment', layout: true, locals: { config: host.options, folders: host.folders })
|
|
17
17
|
set_result(
|
|
@@ -1,49 +1,44 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'benchmark'
|
|
4
|
-
|
|
5
3
|
module Solargraph
|
|
6
4
|
module LanguageServer
|
|
7
5
|
module Message
|
|
8
6
|
class Initialize < Base
|
|
9
7
|
def process
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
changeNotifications: true
|
|
27
|
-
}
|
|
8
|
+
host.configure params['initializationOptions']
|
|
9
|
+
host.client_capabilities = params['capabilities']
|
|
10
|
+
if support_workspace_folders?
|
|
11
|
+
host.prepare_folders params['workspaceFolders']
|
|
12
|
+
elsif params['rootUri']
|
|
13
|
+
host.prepare UriHelpers.uri_to_file(params['rootUri'])
|
|
14
|
+
else
|
|
15
|
+
host.prepare params['rootPath']
|
|
16
|
+
end
|
|
17
|
+
result = {
|
|
18
|
+
capabilities: {
|
|
19
|
+
textDocumentSync: 2, # @todo What should this be?
|
|
20
|
+
workspace: {
|
|
21
|
+
workspaceFolders: {
|
|
22
|
+
supported: true,
|
|
23
|
+
changeNotifications: true
|
|
28
24
|
}
|
|
29
25
|
}
|
|
30
26
|
}
|
|
31
|
-
result[:capabilities].merge! static_completion unless dynamic_registration_for?('textDocument', 'completion')
|
|
32
|
-
result[:capabilities].merge! static_signature_help unless dynamic_registration_for?('textDocument', 'signatureHelp')
|
|
33
|
-
# result[:capabilities].merge! static_on_type_formatting unless dynamic_registration_for?('textDocument', 'onTypeFormatting')
|
|
34
|
-
result[:capabilities].merge! static_hover unless dynamic_registration_for?('textDocument', 'hover')
|
|
35
|
-
result[:capabilities].merge! static_document_formatting unless dynamic_registration_for?('textDocument', 'formatting')
|
|
36
|
-
result[:capabilities].merge! static_document_symbols unless dynamic_registration_for?('textDocument', 'documentSymbol')
|
|
37
|
-
result[:capabilities].merge! static_definitions unless dynamic_registration_for?('textDocument', 'definition')
|
|
38
|
-
result[:capabilities].merge! static_rename unless dynamic_registration_for?('textDocument', 'rename')
|
|
39
|
-
result[:capabilities].merge! static_references unless dynamic_registration_for?('textDocument', 'references')
|
|
40
|
-
result[:capabilities].merge! static_workspace_symbols unless dynamic_registration_for?('workspace', 'symbol')
|
|
41
|
-
result[:capabilities].merge! static_folding_range unless dynamic_registration_for?('textDocument', 'foldingRange')
|
|
42
|
-
# @todo Temporarily disabled
|
|
43
|
-
# result[:capabilities].merge! static_code_action unless dynamic_registration_for?('textDocument', 'codeAction')
|
|
44
|
-
set_result result
|
|
45
27
|
}
|
|
46
|
-
|
|
28
|
+
result[:capabilities].merge! static_completion unless dynamic_registration_for?('textDocument', 'completion')
|
|
29
|
+
result[:capabilities].merge! static_signature_help unless dynamic_registration_for?('textDocument', 'signatureHelp')
|
|
30
|
+
# result[:capabilities].merge! static_on_type_formatting unless dynamic_registration_for?('textDocument', 'onTypeFormatting')
|
|
31
|
+
result[:capabilities].merge! static_hover unless dynamic_registration_for?('textDocument', 'hover')
|
|
32
|
+
result[:capabilities].merge! static_document_formatting unless dynamic_registration_for?('textDocument', 'formatting')
|
|
33
|
+
result[:capabilities].merge! static_document_symbols unless dynamic_registration_for?('textDocument', 'documentSymbol')
|
|
34
|
+
result[:capabilities].merge! static_definitions unless dynamic_registration_for?('textDocument', 'definition')
|
|
35
|
+
result[:capabilities].merge! static_rename unless dynamic_registration_for?('textDocument', 'rename')
|
|
36
|
+
result[:capabilities].merge! static_references unless dynamic_registration_for?('textDocument', 'references')
|
|
37
|
+
result[:capabilities].merge! static_workspace_symbols unless dynamic_registration_for?('workspace', 'symbol')
|
|
38
|
+
result[:capabilities].merge! static_folding_range unless dynamic_registration_for?('textDocument', 'foldingRange')
|
|
39
|
+
# @todo Temporarily disabled
|
|
40
|
+
# result[:capabilities].merge! static_code_action unless dynamic_registration_for?('textDocument', 'codeAction')
|
|
41
|
+
set_result result
|
|
47
42
|
end
|
|
48
43
|
|
|
49
44
|
private
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'rubocop'
|
|
4
3
|
require 'securerandom'
|
|
4
|
+
require 'tmpdir'
|
|
5
5
|
|
|
6
6
|
module Solargraph
|
|
7
7
|
module LanguageServer
|
|
@@ -11,31 +11,79 @@ module Solargraph
|
|
|
11
11
|
include Solargraph::Diagnostics::RubocopHelpers
|
|
12
12
|
|
|
13
13
|
def process
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
args.unshift('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
|
|
25
|
-
options, paths = RuboCop::Options.new.parse(args)
|
|
26
|
-
store = RuboCop::ConfigStore.new
|
|
27
|
-
redirect_stdout { RuboCop::Runner.new(options, store).run(paths) }
|
|
28
|
-
result = File.read(tempfile)
|
|
29
|
-
format original, result
|
|
30
|
-
rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
|
|
31
|
-
set_error(Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}")
|
|
32
|
-
ensure
|
|
33
|
-
File.unlink tempfile
|
|
14
|
+
file_uri = params['textDocument']['uri']
|
|
15
|
+
config = config_for(file_uri)
|
|
16
|
+
original = host.read_text(file_uri)
|
|
17
|
+
args = cli_args(file_uri, config)
|
|
18
|
+
|
|
19
|
+
require_rubocop(config['version'])
|
|
20
|
+
options, paths = RuboCop::Options.new.parse(args)
|
|
21
|
+
options[:stdin] = original
|
|
22
|
+
corrections = redirect_stdout do
|
|
23
|
+
RuboCop::Runner.new(options, RuboCop::ConfigStore.new).run(paths)
|
|
34
24
|
end
|
|
25
|
+
result = options[:stdin]
|
|
26
|
+
|
|
27
|
+
log_corrections(corrections)
|
|
28
|
+
|
|
29
|
+
format original, result
|
|
30
|
+
rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
|
|
31
|
+
set_error(Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}")
|
|
35
32
|
end
|
|
36
33
|
|
|
37
34
|
private
|
|
38
35
|
|
|
36
|
+
def log_corrections(corrections)
|
|
37
|
+
corrections = corrections&.strip
|
|
38
|
+
return if corrections&.empty?
|
|
39
|
+
|
|
40
|
+
Solargraph.logger.info('Formatting result:')
|
|
41
|
+
corrections.each_line do |line|
|
|
42
|
+
next if line.strip.empty?
|
|
43
|
+
Solargraph.logger.info(line.strip)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def config_for(file_uri)
|
|
48
|
+
conf = host.formatter_config(file_uri)
|
|
49
|
+
return {} unless conf.is_a?(Hash)
|
|
50
|
+
|
|
51
|
+
conf['rubocop'] || {}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def cli_args file_uri, config
|
|
55
|
+
file = UriHelpers.uri_to_file(file_uri)
|
|
56
|
+
args = [
|
|
57
|
+
config['cops'] == 'all' ? '--auto-correct-all' : '--auto-correct',
|
|
58
|
+
'--cache', 'false',
|
|
59
|
+
'--format', formatter_class(config).name,
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
['except', 'only'].each do |arg|
|
|
63
|
+
cops = cop_list(config[arg])
|
|
64
|
+
args += ["--#{arg}", cops] if cops
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
args += config['extra_args'] if config['extra_args']
|
|
68
|
+
args + [file]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def formatter_class(config)
|
|
72
|
+
if self.class.const_defined?('BlankRubocopFormatter')
|
|
73
|
+
BlankRubocopFormatter
|
|
74
|
+
else
|
|
75
|
+
require_rubocop(config['version'])
|
|
76
|
+
klass = Class.new(::RuboCop::Formatter::BaseFormatter)
|
|
77
|
+
self.class.const_set 'BlankRubocopFormatter', klass
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def cop_list(value)
|
|
82
|
+
value = value.join(',') if value.respond_to?(:join)
|
|
83
|
+
return nil if value == '' || !value.is_a?(String)
|
|
84
|
+
value
|
|
85
|
+
end
|
|
86
|
+
|
|
39
87
|
# @param original [String]
|
|
40
88
|
# @param result [String]
|
|
41
89
|
# @return [void]
|
|
@@ -17,7 +17,7 @@ module Solargraph
|
|
|
17
17
|
if !this_link.nil? && this_link != last_link
|
|
18
18
|
parts.push this_link
|
|
19
19
|
end
|
|
20
|
-
parts.push pin.detail.gsub(':', '\\:') unless pin.is_a?(Pin::Namespace) || pin.detail.nil?
|
|
20
|
+
parts.push "`" + pin.detail.gsub(':', '\\:') + "`" unless pin.is_a?(Pin::Namespace) || pin.detail.nil?
|
|
21
21
|
parts.push pin.documentation unless pin.documentation.nil? || pin.documentation.empty?
|
|
22
22
|
unless parts.empty?
|
|
23
23
|
data = parts.join("\n\n")
|
data/lib/solargraph/library.rb
CHANGED
|
@@ -20,9 +20,7 @@ module Solargraph
|
|
|
20
20
|
def initialize workspace = Solargraph::Workspace.new, name = nil
|
|
21
21
|
@workspace = workspace
|
|
22
22
|
@name = name
|
|
23
|
-
|
|
24
|
-
@synchronized = true
|
|
25
|
-
@catalog_mutex = Mutex.new
|
|
23
|
+
@synchronized = false
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
def inspect
|
|
@@ -48,9 +46,13 @@ module Solargraph
|
|
|
48
46
|
# @return [void]
|
|
49
47
|
def attach source
|
|
50
48
|
mutex.synchronize do
|
|
51
|
-
@
|
|
49
|
+
if @current && @current.filename != source.filename && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
|
|
50
|
+
source_map_hash.delete @current.filename
|
|
51
|
+
@synchronized = false
|
|
52
|
+
end
|
|
52
53
|
@current = source
|
|
53
|
-
|
|
54
|
+
maybe_map @current
|
|
55
|
+
api_map.catalog bench unless synchronized?
|
|
54
56
|
end
|
|
55
57
|
end
|
|
56
58
|
|
|
@@ -110,9 +112,9 @@ module Solargraph
|
|
|
110
112
|
mutex.synchronize do
|
|
111
113
|
next if File.directory?(filename) || !File.exist?(filename)
|
|
112
114
|
next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
|
|
113
|
-
@synchronized = false
|
|
114
115
|
source = Solargraph::Source.load_string(File.read(filename), filename)
|
|
115
116
|
workspace.merge(source)
|
|
117
|
+
maybe_map source
|
|
116
118
|
result = true
|
|
117
119
|
end
|
|
118
120
|
result
|
|
@@ -158,6 +160,8 @@ module Solargraph
|
|
|
158
160
|
position = Position.new(line, column)
|
|
159
161
|
cursor = Source::Cursor.new(read(filename), position)
|
|
160
162
|
api_map.clip(cursor).complete
|
|
163
|
+
rescue FileNotFoundError => e
|
|
164
|
+
handle_file_not_found filename, e
|
|
161
165
|
end
|
|
162
166
|
|
|
163
167
|
# Get definition suggestions for the expression at the specified file and
|
|
@@ -186,6 +190,8 @@ module Solargraph
|
|
|
186
190
|
else
|
|
187
191
|
api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
|
|
188
192
|
end
|
|
193
|
+
rescue FileNotFoundError => e
|
|
194
|
+
handle_file_not_found(filename, e)
|
|
189
195
|
end
|
|
190
196
|
|
|
191
197
|
# Get signature suggestions for the method at the specified file and
|
|
@@ -209,7 +215,6 @@ module Solargraph
|
|
|
209
215
|
# @return [Array<Solargraph::Range>]
|
|
210
216
|
# @todo Take a Location instead of filename/line/column
|
|
211
217
|
def references_from filename, line, column, strip: false
|
|
212
|
-
# checkout filename
|
|
213
218
|
cursor = api_map.cursor_at(filename, Position.new(line, column))
|
|
214
219
|
clip = api_map.clip(cursor)
|
|
215
220
|
pins = clip.define
|
|
@@ -222,7 +227,7 @@ module Solargraph
|
|
|
222
227
|
referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
|
|
223
228
|
# HACK: The additional location comparison is necessary because
|
|
224
229
|
# Clip#define can return proxies for parameter pins
|
|
225
|
-
referenced.any?{|r| r == pin || r.location == pin.location}
|
|
230
|
+
referenced.any? { |r| r == pin || r.location == pin.location }
|
|
226
231
|
end
|
|
227
232
|
# HACK: for language clients that exclude special characters from the start of variable names
|
|
228
233
|
if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
|
|
@@ -261,14 +266,12 @@ module Solargraph
|
|
|
261
266
|
# @param query [String]
|
|
262
267
|
# @return [Array<YARD::CodeObjects::Base>]
|
|
263
268
|
def document query
|
|
264
|
-
catalog
|
|
265
269
|
api_map.document query
|
|
266
270
|
end
|
|
267
271
|
|
|
268
272
|
# @param query [String]
|
|
269
273
|
# @return [Array<String>]
|
|
270
274
|
def search query
|
|
271
|
-
catalog
|
|
272
275
|
api_map.search query
|
|
273
276
|
end
|
|
274
277
|
|
|
@@ -277,7 +280,6 @@ module Solargraph
|
|
|
277
280
|
# @param query [String]
|
|
278
281
|
# @return [Array<Pin::Base>]
|
|
279
282
|
def query_symbols query
|
|
280
|
-
catalog
|
|
281
283
|
api_map.query_symbols query
|
|
282
284
|
end
|
|
283
285
|
|
|
@@ -290,17 +292,19 @@ module Solargraph
|
|
|
290
292
|
# @param filename [String]
|
|
291
293
|
# @return [Array<Solargraph::Pin::Base>]
|
|
292
294
|
def document_symbols filename
|
|
293
|
-
# checkout filename
|
|
294
295
|
api_map.document_symbols(filename)
|
|
295
296
|
end
|
|
296
297
|
|
|
297
298
|
# @param path [String]
|
|
298
299
|
# @return [Array<Solargraph::Pin::Base>]
|
|
299
300
|
def path_pins path
|
|
300
|
-
catalog
|
|
301
301
|
api_map.get_path_suggestions(path)
|
|
302
302
|
end
|
|
303
303
|
|
|
304
|
+
def source_maps
|
|
305
|
+
source_map_hash.values
|
|
306
|
+
end
|
|
307
|
+
|
|
304
308
|
# Get the current text of a file in the library.
|
|
305
309
|
#
|
|
306
310
|
# @param filename [String]
|
|
@@ -320,7 +324,6 @@ module Solargraph
|
|
|
320
324
|
# be an option to do so.
|
|
321
325
|
#
|
|
322
326
|
return [] unless open?(filename)
|
|
323
|
-
catalog
|
|
324
327
|
result = []
|
|
325
328
|
source = read(filename)
|
|
326
329
|
repargs = {}
|
|
@@ -348,7 +351,7 @@ module Solargraph
|
|
|
348
351
|
#
|
|
349
352
|
# @return [void]
|
|
350
353
|
def catalog
|
|
351
|
-
|
|
354
|
+
mutex.synchronize do
|
|
352
355
|
break if synchronized?
|
|
353
356
|
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
|
354
357
|
api_map.catalog bench
|
|
@@ -357,6 +360,16 @@ module Solargraph
|
|
|
357
360
|
end
|
|
358
361
|
end
|
|
359
362
|
|
|
363
|
+
def bench
|
|
364
|
+
source_maps = @current ? [@current] : []
|
|
365
|
+
source_maps.concat source_map_hash.values
|
|
366
|
+
Bench.new(
|
|
367
|
+
source_maps: source_maps,
|
|
368
|
+
load_paths: workspace.require_paths,
|
|
369
|
+
gemnames: workspace.gemnames
|
|
370
|
+
)
|
|
371
|
+
end
|
|
372
|
+
|
|
360
373
|
# Get an array of foldable ranges for the specified file.
|
|
361
374
|
#
|
|
362
375
|
# @deprecated The library should not need to handle folding ranges. The
|
|
@@ -383,14 +396,49 @@ module Solargraph
|
|
|
383
396
|
# @param source [Source]
|
|
384
397
|
# @return [Boolean] True if the source was merged into the workspace.
|
|
385
398
|
def merge source
|
|
399
|
+
Logging.logger.debug "Merging source: #{source.filename}"
|
|
386
400
|
result = false
|
|
387
401
|
mutex.synchronize do
|
|
388
402
|
result = workspace.merge(source)
|
|
389
|
-
|
|
403
|
+
maybe_map source
|
|
390
404
|
end
|
|
405
|
+
# catalog
|
|
391
406
|
result
|
|
392
407
|
end
|
|
393
408
|
|
|
409
|
+
def source_map_hash
|
|
410
|
+
@source_map_hash ||= {}
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def mapped?
|
|
414
|
+
(workspace.filenames - source_map_hash.keys).empty?
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def next_map
|
|
418
|
+
return false if mapped?
|
|
419
|
+
mutex.synchronize do
|
|
420
|
+
@synchronized = false
|
|
421
|
+
src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
|
|
422
|
+
if src
|
|
423
|
+
Logging.logger.debug "Mapping #{src.filename}"
|
|
424
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
|
425
|
+
else
|
|
426
|
+
false
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def map!
|
|
432
|
+
workspace.sources.each do |src|
|
|
433
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
|
434
|
+
end
|
|
435
|
+
self
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def pins
|
|
439
|
+
@pins ||= []
|
|
440
|
+
end
|
|
441
|
+
|
|
394
442
|
private
|
|
395
443
|
|
|
396
444
|
# @return [Mutex]
|
|
@@ -403,14 +451,6 @@ module Solargraph
|
|
|
403
451
|
@api_map ||= Solargraph::ApiMap.new
|
|
404
452
|
end
|
|
405
453
|
|
|
406
|
-
# @return [Bench]
|
|
407
|
-
def bench
|
|
408
|
-
Bench.new(
|
|
409
|
-
workspace: workspace,
|
|
410
|
-
opened: @current ? [@current] : []
|
|
411
|
-
)
|
|
412
|
-
end
|
|
413
|
-
|
|
414
454
|
# Get the source for an open file or create a new source if the file
|
|
415
455
|
# exists on disk. Sources created from disk are not added to the open
|
|
416
456
|
# workspace files, i.e., the version on disk remains the authoritative
|
|
@@ -424,5 +464,35 @@ module Solargraph
|
|
|
424
464
|
raise FileNotFoundError, "File not found: #{filename}" unless workspace.has_file?(filename)
|
|
425
465
|
workspace.source(filename)
|
|
426
466
|
end
|
|
467
|
+
|
|
468
|
+
def handle_file_not_found filename, error
|
|
469
|
+
if workspace.source(filename)
|
|
470
|
+
Solargraph.logger.debug "#{filename} is not cataloged in the ApiMap"
|
|
471
|
+
nil
|
|
472
|
+
else
|
|
473
|
+
raise error
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def maybe_map source
|
|
478
|
+
if source_map_hash.key?(source.filename)
|
|
479
|
+
return if source_map_hash[source.filename].code == source.code &&
|
|
480
|
+
source_map_hash[source.filename].source.synchronized? &&
|
|
481
|
+
source.synchronized?
|
|
482
|
+
if source.synchronized?
|
|
483
|
+
new_map = Solargraph::SourceMap.map(source)
|
|
484
|
+
unless source_map_hash[source.filename].try_merge!(new_map)
|
|
485
|
+
source_map_hash[source.filename] = new_map
|
|
486
|
+
@synchronized = false
|
|
487
|
+
end
|
|
488
|
+
else
|
|
489
|
+
# @todo Smelly instance variable access
|
|
490
|
+
source_map_hash[source.filename].instance_variable_set(:@source, source)
|
|
491
|
+
end
|
|
492
|
+
else
|
|
493
|
+
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
|
494
|
+
@synchronized = false
|
|
495
|
+
end
|
|
496
|
+
end
|
|
427
497
|
end
|
|
428
498
|
end
|