solargraph 0.26.1 → 0.27.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/lib/solargraph.rb +5 -2
- data/lib/solargraph/api_map.rb +236 -234
- data/lib/solargraph/api_map/store.rb +18 -53
- data/lib/solargraph/bundle.rb +22 -0
- data/lib/solargraph/complex_type.rb +9 -5
- data/lib/solargraph/complex_type/type_methods.rb +113 -0
- data/lib/solargraph/complex_type/unique_type.rb +35 -0
- data/lib/solargraph/core_fills.rb +1 -0
- data/lib/solargraph/diagnostics.rb +6 -4
- data/lib/solargraph/diagnostics/base.rb +3 -0
- data/lib/solargraph/diagnostics/require_not_found.rb +2 -1
- data/lib/solargraph/diagnostics/rubocop.rb +21 -6
- data/lib/solargraph/diagnostics/type_not_defined.rb +4 -3
- data/lib/solargraph/diagnostics/update_errors.rb +18 -0
- data/lib/solargraph/language_server/host.rb +90 -222
- data/lib/solargraph/language_server/host/cataloger.rb +68 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +85 -0
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +35 -24
- data/lib/solargraph/language_server/message/text_document/completion.rb +6 -8
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +0 -1
- data/lib/solargraph/language_server/transport/socket.rb +4 -6
- data/lib/solargraph/language_server/transport/stdio.rb +4 -6
- data/lib/solargraph/library.rb +152 -99
- data/lib/solargraph/live_map.rb +1 -1
- data/lib/solargraph/location.rb +28 -0
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin/attribute.rb +26 -12
- data/lib/solargraph/pin/base.rb +15 -35
- data/lib/solargraph/pin/base_variable.rb +7 -15
- data/lib/solargraph/pin/block.rb +5 -9
- data/lib/solargraph/pin/block_parameter.rb +9 -7
- data/lib/solargraph/pin/conversions.rb +5 -5
- data/lib/solargraph/pin/duck_method.rb +1 -1
- data/lib/solargraph/pin/instance_variable.rb +0 -4
- data/lib/solargraph/pin/keyword.rb +4 -0
- data/lib/solargraph/pin/localized.rb +5 -3
- data/lib/solargraph/pin/method.rb +11 -0
- data/lib/solargraph/pin/namespace.rb +7 -3
- data/lib/solargraph/pin/proxy_type.rb +3 -7
- data/lib/solargraph/pin/reference.rb +2 -2
- data/lib/solargraph/pin/symbol.rb +1 -1
- data/lib/solargraph/pin/yard_pin/method.rb +2 -2
- data/lib/solargraph/pin/yard_pin/namespace.rb +16 -7
- data/lib/solargraph/position.rb +103 -0
- data/lib/solargraph/range.rb +70 -0
- data/lib/solargraph/source.rb +159 -328
- data/lib/solargraph/source/chain.rb +38 -55
- data/lib/solargraph/source/chain/call.rb +47 -29
- data/lib/solargraph/source/chain/class_variable.rb +2 -2
- data/lib/solargraph/source/chain/constant.rb +3 -3
- data/lib/solargraph/source/chain/definition.rb +7 -3
- data/lib/solargraph/source/chain/global_variable.rb +1 -1
- data/lib/solargraph/source/chain/head.rb +22 -9
- data/lib/solargraph/source/chain/instance_variable.rb +2 -2
- data/lib/solargraph/source/chain/link.rb +4 -4
- data/lib/solargraph/source/chain/literal.rb +1 -1
- data/lib/solargraph/source/chain/variable.rb +2 -2
- data/lib/solargraph/source/change.rb +0 -6
- data/lib/solargraph/source/cursor.rb +161 -0
- data/lib/solargraph/source/encoding_fixes.rb +1 -1
- data/lib/solargraph/source/node_chainer.rb +28 -21
- data/lib/solargraph/source/node_methods.rb +1 -1
- data/lib/solargraph/source/source_chainer.rb +217 -0
- data/lib/solargraph/source_map.rb +138 -0
- data/lib/solargraph/source_map/clip.rb +123 -0
- data/lib/solargraph/{source → source_map}/completion.rb +3 -3
- data/lib/solargraph/{source → source_map}/mapper.rb +143 -41
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +13 -20
- data/lib/solargraph/yard_map.rb +77 -48
- metadata +17 -11
- data/lib/solargraph/basic_type.rb +0 -33
- data/lib/solargraph/basic_type_methods.rb +0 -111
- data/lib/solargraph/source/call_chainer.rb +0 -273
- data/lib/solargraph/source/fragment.rb +0 -342
- data/lib/solargraph/source/location.rb +0 -23
- data/lib/solargraph/source/position.rb +0 -95
- data/lib/solargraph/source/range.rb +0 -64
@@ -0,0 +1,68 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module LanguageServer
|
3
|
+
class Host
|
4
|
+
class Cataloger
|
5
|
+
def initialize host
|
6
|
+
@host = host
|
7
|
+
@mutex = Mutex.new
|
8
|
+
@stopped = true
|
9
|
+
@pings = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Notify the Cataloger that changes are pending.
|
13
|
+
#
|
14
|
+
# @return [void]
|
15
|
+
def ping
|
16
|
+
mutex.synchronize { pings.push nil }
|
17
|
+
end
|
18
|
+
|
19
|
+
def synchronizing?
|
20
|
+
!pings.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Stop the catalog thread.
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
def stop
|
27
|
+
@stopped = true
|
28
|
+
end
|
29
|
+
|
30
|
+
# True if the cataloger is stopped.
|
31
|
+
#
|
32
|
+
# @return [Boolean]
|
33
|
+
def stopped?
|
34
|
+
@stopped
|
35
|
+
end
|
36
|
+
|
37
|
+
# Start the catalog thread.
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
def start
|
41
|
+
return unless stopped?
|
42
|
+
@stopped = false
|
43
|
+
Thread.new do
|
44
|
+
until stopped?
|
45
|
+
sleep 0.1
|
46
|
+
next if pings.empty?
|
47
|
+
mutex.synchronize do
|
48
|
+
host.catalog
|
49
|
+
pings.clear
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# @return [Host]
|
58
|
+
attr_reader :host
|
59
|
+
|
60
|
+
# @return [Mutex]
|
61
|
+
attr_reader :mutex
|
62
|
+
|
63
|
+
# @return [Array]
|
64
|
+
attr_reader :pings
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module LanguageServer
|
3
|
+
class Host
|
4
|
+
class Diagnoser
|
5
|
+
def initialize host
|
6
|
+
@host = host
|
7
|
+
@mutex = Mutex.new
|
8
|
+
@queue = []
|
9
|
+
@stopped = true
|
10
|
+
end
|
11
|
+
|
12
|
+
# Schedule a file to be diagnosed.
|
13
|
+
#
|
14
|
+
# @param uri [String]
|
15
|
+
# @return [void]
|
16
|
+
def schedule uri
|
17
|
+
mutex.synchronize { queue.push uri }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Stop the diagnosis thread.
|
21
|
+
#
|
22
|
+
# @return [void]
|
23
|
+
def stop
|
24
|
+
@stopped = true
|
25
|
+
end
|
26
|
+
|
27
|
+
# True is the diagnoser is stopped.
|
28
|
+
#
|
29
|
+
# @return [Boolean]
|
30
|
+
def stopped?
|
31
|
+
@stopped
|
32
|
+
end
|
33
|
+
|
34
|
+
# Start the diagnosis thread.
|
35
|
+
#
|
36
|
+
# @return [self]
|
37
|
+
def start
|
38
|
+
return unless @stopped
|
39
|
+
@stopped = false
|
40
|
+
Thread.new do
|
41
|
+
until stopped?
|
42
|
+
sleep 0.1
|
43
|
+
next if queue.empty? || host.synchronizing?
|
44
|
+
if !host.options['diagnostics']
|
45
|
+
mutex.synchronize { queue.clear }
|
46
|
+
next
|
47
|
+
end
|
48
|
+
begin
|
49
|
+
current = nil
|
50
|
+
mutex.synchronize { current = queue.shift }
|
51
|
+
next if queue.include?(current)
|
52
|
+
results = []
|
53
|
+
results.concat host.diagnose(current) if host.open?(current)
|
54
|
+
host.send_notification "textDocument/publishDiagnostics", {
|
55
|
+
uri: current,
|
56
|
+
diagnostics: results
|
57
|
+
}
|
58
|
+
sleep 0.5
|
59
|
+
rescue DiagnosticsError => e
|
60
|
+
STDERR.puts "Error in diagnostics: #{e.message}"
|
61
|
+
options['diagnostics'] = false
|
62
|
+
host.send_notification 'window/showMessage', {
|
63
|
+
type: LanguageServer::MessageTypes::ERROR,
|
64
|
+
message: "Error in diagnostics: #{e.message}"
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# @return [Host]
|
75
|
+
attr_reader :host
|
76
|
+
|
77
|
+
# @return [Mutex]
|
78
|
+
attr_reader :mutex
|
79
|
+
|
80
|
+
# @return [Array]
|
81
|
+
attr_reader :queue
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
2
|
|
3
3
|
module Solargraph
|
4
4
|
module LanguageServer
|
@@ -10,30 +10,41 @@ module Solargraph
|
|
10
10
|
#
|
11
11
|
class CheckGemVersion < Base
|
12
12
|
def process
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
13
|
+
begin
|
14
|
+
fetcher = Gem::SpecFetcher.new
|
15
|
+
tuple = fetcher.search_for_dependency(Gem::Dependency.new('solargraph')).flatten.first
|
16
|
+
if tuple.nil?
|
17
|
+
msg = "An error occurred checking the Solargraph gem version."
|
18
|
+
STDERR.puts msg
|
19
|
+
host.show_message(msg, MessageTypes::ERROR) if params['verbose']
|
20
|
+
else
|
21
|
+
available = Gem::Version.new(tuple.version)
|
22
|
+
current = Gem::Version.new(Solargraph::VERSION)
|
23
|
+
if available > current
|
24
|
+
host.show_message_request "Solagraph gem version #{available} is available.",
|
25
|
+
LanguageServer::MessageTypes::INFO,
|
26
|
+
['Update now'] do |result|
|
27
|
+
break unless result == 'Update now'
|
28
|
+
o, s = Open3.capture2("gem update solargraph")
|
29
|
+
if s == 0
|
30
|
+
host.show_message 'Successfully updated the Solargraph gem.', LanguageServer::MessageTypes::INFO
|
31
|
+
else
|
32
|
+
host.show_message 'An error occurred while updating the gem.', LanguageServer::MessageTypes::ERROR
|
33
|
+
end
|
34
|
+
end
|
35
|
+
elsif params['verbose']
|
36
|
+
host.show_message "The Solargraph gem is up to date (version #{Solargraph::VERSION})."
|
37
|
+
end
|
38
|
+
set_result({
|
39
|
+
installed: current,
|
40
|
+
available: available
|
41
|
+
})
|
42
|
+
end
|
43
|
+
rescue Errno::EADDRNOTAVAIL => e
|
44
|
+
msg = "Unable to connect to gem source: #{e.message}"
|
45
|
+
STDERR.puts msg
|
46
|
+
host.show_message(msg, MessageTypes::ERROR) if params['verbose']
|
32
47
|
end
|
33
|
-
set_result({
|
34
|
-
installed: current,
|
35
|
-
available: available
|
36
|
-
})
|
37
48
|
end
|
38
49
|
end
|
39
50
|
end
|
@@ -6,11 +6,7 @@ module Solargraph
|
|
6
6
|
module TextDocument
|
7
7
|
class Completion < Base
|
8
8
|
def process
|
9
|
-
|
10
|
-
set_result empty_result(true)
|
11
|
-
else
|
12
|
-
inner_process
|
13
|
-
end
|
9
|
+
inner_process
|
14
10
|
end
|
15
11
|
|
16
12
|
private
|
@@ -26,16 +22,18 @@ module Solargraph
|
|
26
22
|
return set_result(empty_result) if host.cancel?(id)
|
27
23
|
end
|
28
24
|
items = []
|
29
|
-
|
25
|
+
last_context = nil
|
26
|
+
idx = -1
|
30
27
|
completion.pins.each do |pin|
|
28
|
+
idx += 1 if last_context != pin.context
|
31
29
|
items.push pin.completion_item.merge({
|
32
30
|
textEdit: {
|
33
31
|
range: completion.range.to_hash,
|
34
32
|
newText: pin.name.sub(/=$/, ' = ')
|
35
33
|
},
|
36
|
-
sortText: "#{
|
34
|
+
sortText: "#{idx.to_s.rjust(4, '0')}#{pin.name}"
|
37
35
|
})
|
38
|
-
|
36
|
+
last_context = pin.context
|
39
37
|
end
|
40
38
|
set_result(
|
41
39
|
isIncomplete: false,
|
@@ -2,7 +2,7 @@ class Solargraph::LanguageServer::Message::TextDocument::DocumentSymbol < Solarg
|
|
2
2
|
include Solargraph::LanguageServer::UriHelpers
|
3
3
|
|
4
4
|
def process
|
5
|
-
pins = host.
|
5
|
+
pins = host.document_symbols params['textDocument']['uri']
|
6
6
|
info = pins.map do |pin|
|
7
7
|
result = {
|
8
8
|
name: pin.name,
|
@@ -22,7 +22,6 @@ module Solargraph::LanguageServer::Message::Workspace
|
|
22
22
|
elsif change['type'] == DELETED
|
23
23
|
host.delete change['uri']
|
24
24
|
else
|
25
|
-
# @todo Handle error
|
26
25
|
set_error Solargraph::LanguageServer::ErrorCodes::INVALID_PARAMS, "Unknown change type ##{change['type']} for #{uri_to_file(change['uri'])}"
|
27
26
|
end
|
28
27
|
end
|
@@ -16,12 +16,10 @@ module Solargraph
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def process request
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
send_data tmp unless tmp.empty?
|
24
|
-
end
|
19
|
+
message = @host.start(request)
|
20
|
+
message.send_response
|
21
|
+
tmp = @host.flush
|
22
|
+
send_data tmp unless tmp.empty?
|
25
23
|
end
|
26
24
|
|
27
25
|
# @param data [String]
|
@@ -44,12 +44,10 @@ module Solargraph
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def process request
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
send_data tmp unless tmp.empty?
|
52
|
-
end
|
47
|
+
message = @host.start(request)
|
48
|
+
message.send_response
|
49
|
+
tmp = @host.flush
|
50
|
+
send_data tmp unless tmp.empty?
|
53
51
|
end
|
54
52
|
|
55
53
|
def start_timers
|
data/lib/solargraph/library.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Solargraph
|
2
4
|
# A library handles coordination between a Workspace and an ApiMap.
|
3
5
|
#
|
4
6
|
class Library
|
5
7
|
# @param workspace [Solargraph::Workspace]
|
6
8
|
def initialize workspace = Solargraph::Workspace.new(nil)
|
9
|
+
@mutex = Mutex.new
|
7
10
|
@workspace = workspace
|
8
|
-
api_map
|
11
|
+
api_map.catalog bundle
|
12
|
+
@synchronized = true
|
13
|
+
end
|
14
|
+
|
15
|
+
# True if the ApiMap is up to date with the library's workspace and open
|
16
|
+
# files.
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
19
|
+
def synchronized?
|
20
|
+
@synchronized
|
9
21
|
end
|
10
22
|
|
11
23
|
# Open a file in the library. Opening a file will make it available for
|
@@ -14,20 +26,22 @@ module Solargraph
|
|
14
26
|
# @param filename [String]
|
15
27
|
# @param text [String]
|
16
28
|
# @param version [Integer]
|
29
|
+
# @return [void]
|
17
30
|
def open filename, text, version
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
31
|
+
mutex.synchronize do
|
32
|
+
source = Solargraph::Source.load_string(text, filename, version)
|
33
|
+
workspace.merge source
|
34
|
+
open_file_hash[filename] = source
|
35
|
+
catalog #unless api_map.try_merge!(source)
|
36
|
+
end
|
23
37
|
end
|
24
38
|
|
25
|
-
# True if the specified file is currently open
|
39
|
+
# True if the specified file is currently open.
|
26
40
|
#
|
27
41
|
# @param filename [String]
|
28
42
|
# @return [Boolean]
|
29
43
|
def open? filename
|
30
|
-
|
44
|
+
open_file_hash.has_key? filename
|
31
45
|
end
|
32
46
|
|
33
47
|
# True if the specified file is included in the workspace (but not
|
@@ -39,18 +53,22 @@ module Solargraph
|
|
39
53
|
workspace.has_file?(filename)
|
40
54
|
end
|
41
55
|
|
42
|
-
# Create a
|
43
|
-
#
|
56
|
+
# Create a source to be added to the workspace. The file is ignored if the
|
57
|
+
# workspace is not configured to include the file.
|
44
58
|
#
|
45
59
|
# @param filename [String]
|
46
60
|
# @param text [String] The contents of the file
|
47
61
|
# @return [Boolean] True if the file was added to the workspace.
|
48
62
|
def create filename, text
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
result = false
|
64
|
+
mutex.synchronize do
|
65
|
+
next unless workspace.would_merge?(filename)
|
66
|
+
source = Solargraph::Source.load_string(text, filename)
|
67
|
+
workspace.merge(source)
|
68
|
+
catalog #unless api_map.try_merge!(source)
|
69
|
+
result = true
|
70
|
+
end
|
71
|
+
result
|
54
72
|
end
|
55
73
|
|
56
74
|
# Create a file source from a file on disk. The file is ignored if the
|
@@ -59,12 +77,16 @@ module Solargraph
|
|
59
77
|
# @param filename [String]
|
60
78
|
# @return [Boolean] True if the file was added to the workspace.
|
61
79
|
def create_from_disk filename
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
80
|
+
result = false
|
81
|
+
mutex.synchronize do
|
82
|
+
next if File.directory?(filename) or !File.exist?(filename)
|
83
|
+
next unless workspace.would_merge?(filename)
|
84
|
+
source = Solargraph::Source.load_string(File.read(filename), filename)
|
85
|
+
workspace.merge(source)
|
86
|
+
catalog #unless api_map.try_merge!(source)
|
87
|
+
result = true
|
88
|
+
end
|
89
|
+
result
|
68
90
|
end
|
69
91
|
|
70
92
|
# Delete a file from the library. Deleting a file will make it unavailable
|
@@ -72,35 +94,40 @@ module Solargraph
|
|
72
94
|
# workspace configuration determines that it should still exist.
|
73
95
|
#
|
74
96
|
# @param filename [String]
|
97
|
+
# @return [void]
|
75
98
|
def delete filename
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
99
|
+
mutex.synchronize do
|
100
|
+
open_file_hash.delete filename
|
101
|
+
workspace.remove filename
|
102
|
+
catalog
|
103
|
+
end
|
81
104
|
end
|
82
105
|
|
83
106
|
# Close a file in the library. Closing a file will make it unavailable for
|
84
107
|
# checkout although it may still exist in the workspace.
|
85
108
|
#
|
86
109
|
# @param filename [String]
|
110
|
+
# @return [void]
|
87
111
|
def close filename
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
workspace.merge source
|
112
|
+
mutex.synchronize do
|
113
|
+
open_file_hash.delete filename
|
114
|
+
catalog
|
92
115
|
end
|
93
116
|
end
|
94
117
|
|
95
118
|
# @param filename [String]
|
96
119
|
# @param version [Integer]
|
120
|
+
# @return [void]
|
97
121
|
def overwrite filename, version
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
122
|
+
mutex.synchronize do
|
123
|
+
source = source_hash[filename]
|
124
|
+
return if source.nil?
|
125
|
+
if source.version > version
|
126
|
+
STDERR.puts "Save out of sync for #{filename} (current #{source.version}, overwrite #{version})" if source.version > version
|
127
|
+
else
|
128
|
+
open filename, File.read(filename), version
|
129
|
+
end
|
130
|
+
catalog
|
104
131
|
end
|
105
132
|
end
|
106
133
|
|
@@ -109,12 +136,12 @@ module Solargraph
|
|
109
136
|
# @param filename [String] The file to analyze
|
110
137
|
# @param line [Integer] The zero-based line number
|
111
138
|
# @param column [Integer] The zero-based column number
|
112
|
-
# @return [
|
139
|
+
# @return [SourceMap::Completion]
|
140
|
+
# @todo Take a Location instead of filename/line/column
|
113
141
|
def completions_at filename, line, column
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
fragment.complete(api_map)
|
142
|
+
position = Position.new(line, column)
|
143
|
+
cursor = Source::Cursor.new(checkout(filename), position)
|
144
|
+
api_map.clip(cursor).complete
|
118
145
|
end
|
119
146
|
|
120
147
|
# Get definition suggestions for the expression at the specified file and
|
@@ -124,11 +151,11 @@ module Solargraph
|
|
124
151
|
# @param line [Integer] The zero-based line number
|
125
152
|
# @param column [Integer] The zero-based column number
|
126
153
|
# @return [Array<Solargraph::Pin::Base>]
|
154
|
+
# @todo Take filename/position instead of filename/line/column
|
127
155
|
def definitions_at filename, line, column
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
fragment.define(api_map)
|
156
|
+
position = Position.new(line, column)
|
157
|
+
cursor = Source::Cursor.new(checkout(filename), position)
|
158
|
+
api_map.clip(cursor).define
|
132
159
|
end
|
133
160
|
|
134
161
|
# Get signature suggestions for the method at the specified file and
|
@@ -138,37 +165,33 @@ module Solargraph
|
|
138
165
|
# @param line [Integer] The zero-based line number
|
139
166
|
# @param column [Integer] The zero-based column number
|
140
167
|
# @return [Array<Solargraph::Pin::Base>]
|
168
|
+
# @todo Take filename/position instead of filename/line/column
|
141
169
|
def signatures_at filename, line, column
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
fragment.signify(api_map)
|
170
|
+
position = Position.new(line, column)
|
171
|
+
cursor = Source::Cursor.new(checkout(filename), position)
|
172
|
+
api_map.clip(cursor).signify
|
146
173
|
end
|
147
174
|
|
148
175
|
# @param filename [String]
|
149
176
|
# @param line [Integer]
|
150
177
|
# @param column [Integer]
|
151
|
-
# @return [Array<Solargraph::
|
178
|
+
# @return [Array<Solargraph::Range>]
|
179
|
+
# @todo Take a Location instead of filename/line/column
|
152
180
|
def references_from filename, line, column
|
153
|
-
|
154
|
-
|
155
|
-
fragment = source.fragment_at(line, column)
|
156
|
-
pins = fragment.define(api_map)
|
181
|
+
clip = api_map.clip_at(filename, Position.new(line, column))
|
182
|
+
pins = clip.define
|
157
183
|
return [] if pins.empty?
|
158
184
|
result = []
|
159
|
-
# @param pin [Solargraph::Pin::Base]
|
160
185
|
pins.uniq.each do |pin|
|
161
|
-
|
162
|
-
mn_loc = get_symbol_name_location(pin)
|
163
|
-
result.push mn_loc unless mn_loc.nil?
|
164
|
-
end
|
165
|
-
(workspace.sources + source_hash.values).uniq(&:filename).each do |source|
|
186
|
+
(workspace.sources + open_file_hash.values).uniq.each do |source|
|
166
187
|
found = source.references(pin.name)
|
167
188
|
found.select do |loc|
|
168
189
|
referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
|
169
190
|
referenced.any?{|r| r.path == pin.path}
|
170
191
|
end
|
171
|
-
result.concat
|
192
|
+
result.concat(found.sort{ |a, b|
|
193
|
+
a.range.start.line <=> b.range.start.line
|
194
|
+
})
|
172
195
|
end
|
173
196
|
end
|
174
197
|
result
|
@@ -176,6 +199,7 @@ module Solargraph
|
|
176
199
|
|
177
200
|
# Get the pin at the specified location or nil if the pin does not exist.
|
178
201
|
#
|
202
|
+
# @param location [Location]
|
179
203
|
# @return [Solargraph::Pin::Base]
|
180
204
|
def locate_pin location
|
181
205
|
api_map.locate_pin location
|
@@ -200,16 +224,7 @@ module Solargraph
|
|
200
224
|
# @param filename [String]
|
201
225
|
# @return [Source]
|
202
226
|
def checkout filename
|
203
|
-
|
204
|
-
api_map.virtualize nil
|
205
|
-
nil
|
206
|
-
else
|
207
|
-
read filename
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def refresh force = false
|
212
|
-
api_map.refresh force
|
227
|
+
read filename
|
213
228
|
end
|
214
229
|
|
215
230
|
# @param query [String]
|
@@ -232,10 +247,17 @@ module Solargraph
|
|
232
247
|
api_map.query_symbols query
|
233
248
|
end
|
234
249
|
|
250
|
+
# Get an array of document symbols.
|
251
|
+
#
|
252
|
+
# Document symbols are composed of namespace, method, and constant pins.
|
253
|
+
# The results of this query are appropriate for building the response to a
|
254
|
+
# textDocument/documentSymbol message in the language server protocol.
|
255
|
+
#
|
235
256
|
# @param filename [String]
|
236
257
|
# @return [Array<Solargraph::Pin::Base>]
|
237
|
-
def
|
238
|
-
|
258
|
+
def document_symbols filename
|
259
|
+
return [] unless open_file_hash.has_key?(filename)
|
260
|
+
api_map.document_symbols(filename)
|
239
261
|
end
|
240
262
|
|
241
263
|
# @param path [String]
|
@@ -244,10 +266,26 @@ module Solargraph
|
|
244
266
|
api_map.get_path_suggestions(path)
|
245
267
|
end
|
246
268
|
|
269
|
+
# Update a source in the library from the provided updater.
|
270
|
+
#
|
271
|
+
# @note This method will not update the library's ApiMap. See
|
272
|
+
# Library#ynchronized? and Library#catalog for more information.
|
273
|
+
#
|
274
|
+
#
|
275
|
+
# @raise [FileNotFoundError] if the updater's file is not available.
|
247
276
|
# @param updater [Solargraph::Source::Updater]
|
248
|
-
|
249
|
-
|
250
|
-
|
277
|
+
# @return [void]
|
278
|
+
def update updater
|
279
|
+
mutex.synchronize do
|
280
|
+
if workspace.has_file?(updater.filename)
|
281
|
+
workspace.synchronize!(updater)
|
282
|
+
open_file_hash[updater.filename] = workspace.source(updater.filename) if open?(updater.filename)
|
283
|
+
else
|
284
|
+
raise FileNotFoundError, "Unable to update #{updater.filename}" unless open?(updater.filename)
|
285
|
+
open_file_hash[updater.filename] = open_file_hash[updater.filename].synchronize(updater)
|
286
|
+
end
|
287
|
+
@synchronized = false
|
288
|
+
end
|
251
289
|
end
|
252
290
|
|
253
291
|
# Get the current text of a file in the library.
|
@@ -278,6 +316,14 @@ module Solargraph
|
|
278
316
|
result
|
279
317
|
end
|
280
318
|
|
319
|
+
# Update the ApiMap from the library's workspace and open files.
|
320
|
+
#
|
321
|
+
# @return [void]
|
322
|
+
def catalog
|
323
|
+
api_map.catalog bundle
|
324
|
+
@synchronized = true
|
325
|
+
end
|
326
|
+
|
281
327
|
# Create a library from a directory.
|
282
328
|
#
|
283
329
|
# @param directory [String] The path to be used for the workspace
|
@@ -288,14 +334,27 @@ module Solargraph
|
|
288
334
|
|
289
335
|
private
|
290
336
|
|
291
|
-
# @return [
|
292
|
-
|
293
|
-
@source_hash ||= {}
|
294
|
-
end
|
337
|
+
# @return [Mutex]
|
338
|
+
attr_reader :mutex
|
295
339
|
|
296
|
-
# @return [
|
340
|
+
# @return [ApiMap]
|
297
341
|
def api_map
|
298
|
-
@api_map ||= Solargraph::ApiMap.new
|
342
|
+
@api_map ||= Solargraph::ApiMap.new
|
343
|
+
end
|
344
|
+
|
345
|
+
# @return [YardMap]
|
346
|
+
def yard_map
|
347
|
+
@yard_map ||= Solargraph::YardMap.new
|
348
|
+
end
|
349
|
+
|
350
|
+
# @return [Bundle]
|
351
|
+
def bundle
|
352
|
+
Bundle.new(
|
353
|
+
sources: (workspace.sources + open_file_hash.values).uniq(&:filename),
|
354
|
+
required: workspace.config.required,
|
355
|
+
load_paths: workspace.require_paths,
|
356
|
+
yard_map: yard_map
|
357
|
+
)
|
299
358
|
end
|
300
359
|
|
301
360
|
# @return [Solargraph::Workspace]
|
@@ -303,6 +362,14 @@ module Solargraph
|
|
303
362
|
@workspace
|
304
363
|
end
|
305
364
|
|
365
|
+
# A collection of files that are currently open in the library. Open
|
366
|
+
# files do not need to be in the workspace.
|
367
|
+
#
|
368
|
+
# @return [Hash{String => Source}]
|
369
|
+
def open_file_hash
|
370
|
+
@open_file_hash ||= {}
|
371
|
+
end
|
372
|
+
|
306
373
|
# Get the source for an open file or create a new source if the file
|
307
374
|
# exists on disk. Sources created from disk are not added to the open
|
308
375
|
# workspace files, i.e., the version on disk remains the authoritative
|
@@ -312,23 +379,9 @@ module Solargraph
|
|
312
379
|
# @param filename [String]
|
313
380
|
# @return [Solargraph::Source]
|
314
381
|
def read filename
|
315
|
-
return
|
316
|
-
|
317
|
-
|
318
|
-
Solargraph::Source.load(filename)
|
319
|
-
end
|
320
|
-
|
321
|
-
def get_symbol_name_location pin
|
322
|
-
decsrc = read(pin.location.filename)
|
323
|
-
offset = Solargraph::Source::Position.to_offset(decsrc.code, pin.location.range.start)
|
324
|
-
soff = decsrc.code.index(pin.name, offset)
|
325
|
-
eoff = soff + pin.name.length
|
326
|
-
Solargraph::Source::Location.new(
|
327
|
-
pin.location.filename, Solargraph::Source::Range.new(
|
328
|
-
Solargraph::Source::Position.from_offset(decsrc.code, soff),
|
329
|
-
Solargraph::Source::Position.from_offset(decsrc.code, eoff)
|
330
|
-
)
|
331
|
-
)
|
382
|
+
return open_file_hash[filename] if open_file_hash.has_key?(filename)
|
383
|
+
raise FileNotFoundError, "File not found: #{filename}" unless workspace.has_file?(filename)
|
384
|
+
workspace.source(filename)
|
332
385
|
end
|
333
386
|
end
|
334
387
|
end
|