solargraph 0.18.2 → 0.18.3
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 +33 -28
- data/lib/solargraph/api_map.rb +997 -1044
- data/lib/solargraph/api_map/source_to_yard.rb +4 -3
- data/lib/solargraph/diagnostics/rubocop.rb +4 -3
- data/lib/solargraph/language_server/host.rb +140 -70
- data/lib/solargraph/language_server/message/base.rb +1 -0
- data/lib/solargraph/language_server/message/client.rb +6 -2
- data/lib/solargraph/language_server/message/text_document/completion.rb +34 -39
- data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/did_close.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/did_save.rb +1 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/hover.rb +25 -30
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +8 -7
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +1 -1
- data/lib/solargraph/language_server/transport/socket.rb +15 -17
- data/lib/solargraph/library.rb +34 -16
- data/lib/solargraph/node_methods.rb +96 -96
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/pin/base.rb +2 -1
- data/lib/solargraph/pin/base_variable.rb +45 -5
- data/lib/solargraph/pin/block_parameter.rb +5 -2
- data/lib/solargraph/pin/method.rb +22 -0
- data/lib/solargraph/pin/namespace.rb +32 -2
- data/lib/solargraph/pin/reference.rb +21 -0
- data/lib/solargraph/pin/yard_object.rb +9 -0
- data/lib/solargraph/shell.rb +136 -136
- data/lib/solargraph/source.rb +134 -188
- data/lib/solargraph/source/change.rb +70 -0
- data/lib/solargraph/source/fragment.rb +120 -66
- data/lib/solargraph/source/position.rb +41 -0
- data/lib/solargraph/source/updater.rb +48 -0
- data/lib/solargraph/version.rb +3 -3
- data/lib/solargraph/workspace/config.rb +4 -9
- data/lib/solargraph/yard_map/core_docs.rb +0 -1
- metadata +5 -2
@@ -10,7 +10,7 @@ module Solargraph::LanguageServer::Message::TextDocument
|
|
10
10
|
filename = uri_to_file(params['textDocument']['uri'])
|
11
11
|
line = params['position']['line']
|
12
12
|
col = params['position']['character']
|
13
|
-
suggestions = host.
|
13
|
+
suggestions = host.definitions_at(filename, line, col)
|
14
14
|
locations = suggestions.map do |pin|
|
15
15
|
unless pin.location.nil?
|
16
16
|
parts = pin.location.split(':')
|
@@ -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.file_symbols params['textDocument']['uri']
|
6
6
|
info = pins.map do |pin|
|
7
7
|
parts = pin.location.split(':')
|
8
8
|
char = parts.pop.to_i
|
@@ -3,38 +3,33 @@ require 'uri'
|
|
3
3
|
module Solargraph::LanguageServer::Message::TextDocument
|
4
4
|
class Hover < Base
|
5
5
|
def process
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
this_path =
|
17
|
-
|
18
|
-
|
19
|
-
else
|
20
|
-
this_path = pin.path
|
21
|
-
end
|
22
|
-
if !this_path.nil? and this_path != last_path
|
23
|
-
parts.push link_documentation(this_path)
|
24
|
-
end
|
25
|
-
parts.push pin.documentation unless pin.documentation.nil? or pin.documentation.empty?
|
26
|
-
contents.push parts.join("\n\n") unless parts.empty?
|
27
|
-
last_path = this_path unless this_path.nil?
|
6
|
+
filename = uri_to_file(params['textDocument']['uri'])
|
7
|
+
line = params['position']['line']
|
8
|
+
col = params['position']['character']
|
9
|
+
contents = []
|
10
|
+
suggestions = host.definitions_at(filename, line, col)
|
11
|
+
last_path = nil
|
12
|
+
suggestions.each do |pin|
|
13
|
+
parts = []
|
14
|
+
this_path = nil
|
15
|
+
if pin.kind_of?(Solargraph::Pin::BaseVariable)
|
16
|
+
this_path = pin.return_type
|
17
|
+
else
|
18
|
+
this_path = pin.path
|
28
19
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
rescue Exception => e
|
36
|
-
set_error Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, e.message
|
20
|
+
if !this_path.nil? and this_path != last_path
|
21
|
+
parts.push link_documentation(this_path)
|
22
|
+
end
|
23
|
+
parts.push pin.documentation unless pin.documentation.nil? or pin.documentation.empty?
|
24
|
+
contents.push parts.join("\n\n") unless parts.empty?
|
25
|
+
last_path = this_path unless this_path.nil?
|
37
26
|
end
|
27
|
+
set_result(
|
28
|
+
contents: {
|
29
|
+
kind: 'markdown',
|
30
|
+
value: contents.join("\n\n")
|
31
|
+
}
|
32
|
+
)
|
38
33
|
end
|
39
34
|
|
40
35
|
private
|
@@ -5,7 +5,7 @@ module Solargraph
|
|
5
5
|
class OnTypeFormatting < Base
|
6
6
|
def process
|
7
7
|
# @todo Temporarily disabled
|
8
|
-
set_result
|
8
|
+
set_result nil
|
9
9
|
return
|
10
10
|
src = host.library.checkout(uri_to_file(params['textDocument']['uri']))
|
11
11
|
offset = src.get_offset(params['position']['line'], params['position']['character'])
|
@@ -9,20 +9,21 @@ module Solargraph::LanguageServer::Message::Workspace
|
|
9
9
|
include Solargraph::LanguageServer::UriHelpers
|
10
10
|
|
11
11
|
def process
|
12
|
+
# @param change [Hash]
|
12
13
|
params['changes'].each do |change|
|
13
14
|
if change['type'] == CREATED
|
14
|
-
|
15
|
-
#
|
15
|
+
# It's only necessary to create the file from if the file isn't open
|
16
|
+
# in the client
|
17
|
+
host.create change['uri'] unless host.open?(change['uri'])
|
16
18
|
elsif change['type'] == CHANGED
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
20
|
-
# host.api_map.refresh
|
21
|
-
STDERR.puts "TODO: Workspace changed"
|
19
|
+
# It's only necessary to update from here if the file isn't open in
|
20
|
+
# the client
|
21
|
+
host.create change['uri'] unless host.open?(change['uri'])
|
22
22
|
elsif change['type'] == DELETED
|
23
23
|
host.delete change['uri']
|
24
24
|
else
|
25
25
|
# @todo Handle error
|
26
|
+
set_error Solargraph::LanguageServer::ErrorCodes::INVALID_PARAMS, "Unknown change type ##{change['type']} for #{uri_to_file(change['uri'])}"
|
26
27
|
end
|
27
28
|
end
|
28
29
|
end
|
@@ -2,7 +2,7 @@ class Solargraph::LanguageServer::Message::Workspace::WorkspaceSymbol < Solargra
|
|
2
2
|
include Solargraph::LanguageServer::UriHelpers
|
3
3
|
|
4
4
|
def process
|
5
|
-
pins = host.
|
5
|
+
pins = host.query_symbols(params['query'])
|
6
6
|
info = pins.map do |pin|
|
7
7
|
parts = pin.location.split(':')
|
8
8
|
char = parts.pop.to_i
|
@@ -11,30 +11,19 @@ module Solargraph
|
|
11
11
|
@content_length = 0
|
12
12
|
@buffer = ''
|
13
13
|
@host = Solargraph::LanguageServer::Host.new
|
14
|
-
|
15
|
-
tmp = @host.flush
|
16
|
-
send_data tmp unless tmp.empty?
|
17
|
-
EventMachine.stop if @host.stopped?
|
18
|
-
end
|
19
|
-
@message_semaphore = Mutex.new
|
20
|
-
@message_stack = 0
|
14
|
+
start_timers
|
21
15
|
end
|
22
|
-
|
16
|
+
|
23
17
|
def process request
|
24
18
|
Thread.new do
|
25
|
-
@message_semaphore.synchronize do
|
26
|
-
@message_stack += 1
|
27
|
-
end
|
28
19
|
message = @host.start(request)
|
29
20
|
message.send
|
30
21
|
tmp = @host.flush
|
31
22
|
send_data tmp unless tmp.empty?
|
32
|
-
|
33
|
-
@message_stack -= 1
|
34
|
-
end
|
23
|
+
GC.start unless request['method'] == 'textDocument/didChange'
|
35
24
|
end
|
36
25
|
end
|
37
|
-
|
26
|
+
|
38
27
|
# @param data [String]
|
39
28
|
def receive_data data
|
40
29
|
data.each_char do |char|
|
@@ -55,9 +44,8 @@ module Solargraph
|
|
55
44
|
if @buffer.bytesize == @content_length
|
56
45
|
begin
|
57
46
|
process JSON.parse(@buffer)
|
58
|
-
rescue
|
47
|
+
rescue JSON::ParserError => e
|
59
48
|
STDERR.puts "Failed to parse request: #{e.message}"
|
60
|
-
STDERR.puts e.backtrace.inspect
|
61
49
|
STDERR.puts "Buffer: #{@buffer}"
|
62
50
|
ensure
|
63
51
|
@buffer.clear
|
@@ -68,6 +56,16 @@ module Solargraph
|
|
68
56
|
end
|
69
57
|
end
|
70
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def start_timers
|
63
|
+
EventMachine.add_periodic_timer 0.1 do
|
64
|
+
tmp = @host.flush
|
65
|
+
send_data tmp unless tmp.empty?
|
66
|
+
EventMachine.stop if @host.stopped?
|
67
|
+
end
|
68
|
+
end
|
71
69
|
end
|
72
70
|
end
|
73
71
|
end
|
data/lib/solargraph/library.rb
CHANGED
@@ -2,7 +2,6 @@ module Solargraph
|
|
2
2
|
# A library handles coordination between a Workspace and an ApiMap.
|
3
3
|
#
|
4
4
|
class Library
|
5
|
-
class FileNotFoundError < Exception; end
|
6
5
|
|
7
6
|
# @param workspace [Solargraph::Workspace]
|
8
7
|
def initialize workspace = Solargraph::Workspace.new(nil)
|
@@ -24,6 +23,14 @@ module Solargraph
|
|
24
23
|
api_map.refresh
|
25
24
|
end
|
26
25
|
|
26
|
+
# True if the specified file is currently open in the workspace.
|
27
|
+
#
|
28
|
+
# @param filename [String]
|
29
|
+
# @return [Boolean]
|
30
|
+
def open? filename
|
31
|
+
source_hash.has_key? filename
|
32
|
+
end
|
33
|
+
|
27
34
|
# Create a file source to be added to the workspace. The source is ignored
|
28
35
|
# if the workspace is not configured to include the file.
|
29
36
|
#
|
@@ -31,16 +38,11 @@ module Solargraph
|
|
31
38
|
# @param text [String] The contents of the file
|
32
39
|
# @return [Boolean] True if the file was added to the workspace.
|
33
40
|
def create filename, text
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
api_map.refresh
|
40
|
-
result = true
|
41
|
-
end
|
42
|
-
end
|
43
|
-
result
|
41
|
+
return false unless workspace.would_merge?(filename)
|
42
|
+
source = Solargraph::Source.load_string(text, filename)
|
43
|
+
workspace.merge(source)
|
44
|
+
api_map.refresh
|
45
|
+
true
|
44
46
|
end
|
45
47
|
|
46
48
|
# Delete a file from the library. Deleting a file will make it unavailable
|
@@ -62,6 +64,17 @@ module Solargraph
|
|
62
64
|
# @param filename [String]
|
63
65
|
def close filename
|
64
66
|
source_hash.delete filename
|
67
|
+
if workspace.has_file?(filename)
|
68
|
+
source = Solargraph::Source.load(filename)
|
69
|
+
workspace.merge source
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def overwrite filename, version
|
74
|
+
source = source_hash[filename]
|
75
|
+
return if source.nil?
|
76
|
+
STDERR.puts "Save out of sync for #{filename}" if source.version > version
|
77
|
+
open filename, File.read(filename), version
|
65
78
|
end
|
66
79
|
|
67
80
|
# Get completion suggestions at the specified file and location.
|
@@ -71,9 +84,8 @@ module Solargraph
|
|
71
84
|
# @param column [Integer] The zero-based column number
|
72
85
|
# @return [ApiMap::Completion]
|
73
86
|
def completions_at filename, line, column
|
74
|
-
# @type [Solargraph::Source]
|
75
|
-
source = nil
|
76
87
|
source = read(filename)
|
88
|
+
api_map.virtualize source
|
77
89
|
fragment = source.fragment_at(line, column)
|
78
90
|
api_map.complete(fragment)
|
79
91
|
end
|
@@ -87,9 +99,9 @@ module Solargraph
|
|
87
99
|
# @return [Array<Solargraph::Pin::Base>]
|
88
100
|
def definitions_at filename, line, column
|
89
101
|
source = read(filename)
|
102
|
+
api_map.virtualize source
|
90
103
|
fragment = source.fragment_at(line, column)
|
91
|
-
|
92
|
-
result
|
104
|
+
api_map.define(fragment)
|
93
105
|
end
|
94
106
|
|
95
107
|
# Get signature suggestions for the method at the specified file and
|
@@ -101,6 +113,7 @@ module Solargraph
|
|
101
113
|
# @return [Array<Solargraph::Pin::Base>]
|
102
114
|
def signatures_at filename, line, column
|
103
115
|
source = read(filename)
|
116
|
+
api_map.virtualize source
|
104
117
|
fragment = source.fragment_at(line, column)
|
105
118
|
api_map.signify(fragment)
|
106
119
|
end
|
@@ -163,6 +176,11 @@ module Solargraph
|
|
163
176
|
api_map.get_path_suggestions(path)
|
164
177
|
end
|
165
178
|
|
179
|
+
def synchronize updater
|
180
|
+
source = read(updater.filename)
|
181
|
+
source.synchronize updater
|
182
|
+
end
|
183
|
+
|
166
184
|
# Get the current text of a file in the library.
|
167
185
|
#
|
168
186
|
# @param filename [String]
|
@@ -202,7 +220,7 @@ module Solargraph
|
|
202
220
|
def read filename
|
203
221
|
source = source_hash[filename]
|
204
222
|
raise FileNotFoundError, "Source not found for #{filename}" if source.nil?
|
205
|
-
api_map.virtualize source
|
223
|
+
# api_map.virtualize source
|
206
224
|
source
|
207
225
|
end
|
208
226
|
end
|
@@ -1,96 +1,96 @@
|
|
1
|
-
module Solargraph
|
2
|
-
module NodeMethods
|
3
|
-
# @return [String]
|
4
|
-
def unpack_name(node)
|
5
|
-
pack_name(node).join("::")
|
6
|
-
end
|
7
|
-
|
8
|
-
# @return [Array<String>]
|
9
|
-
def pack_name(node)
|
10
|
-
parts = []
|
11
|
-
if node.kind_of?(AST::Node)
|
12
|
-
node.children.each { |n|
|
13
|
-
if n.kind_of?(AST::Node)
|
14
|
-
if n.type == :cbase
|
15
|
-
parts = pack_name(n)
|
16
|
-
else
|
17
|
-
parts += pack_name(n)
|
18
|
-
end
|
19
|
-
else
|
20
|
-
parts.push n unless n.nil?
|
21
|
-
end
|
22
|
-
}
|
23
|
-
end
|
24
|
-
parts
|
25
|
-
end
|
26
|
-
|
27
|
-
# @return [String]
|
28
|
-
def const_from node
|
29
|
-
if node.kind_of?(AST::Node) and node.type == :const
|
30
|
-
result = ''
|
31
|
-
unless node.children[0].nil?
|
32
|
-
result = const_from(node.children[0])
|
33
|
-
end
|
34
|
-
if result == ''
|
35
|
-
result = node.children[1].to_s
|
36
|
-
else
|
37
|
-
result = result + '::' + node.children[1].to_s
|
38
|
-
end
|
39
|
-
result
|
40
|
-
else
|
41
|
-
nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# @return [String]
|
46
|
-
def infer_literal_node_type node
|
47
|
-
return nil unless node.kind_of?(AST::Node)
|
48
|
-
if node.type == :str or node.type == :dstr
|
49
|
-
return 'String'
|
50
|
-
elsif node.type == :array
|
51
|
-
return 'Array'
|
52
|
-
elsif node.type == :hash
|
53
|
-
return 'Hash'
|
54
|
-
elsif node.type == :int
|
55
|
-
return 'Integer'
|
56
|
-
elsif node.type == :float
|
57
|
-
return 'Float'
|
58
|
-
elsif node.type == :sym
|
59
|
-
return 'Symbol'
|
60
|
-
end
|
61
|
-
nil
|
62
|
-
end
|
63
|
-
|
64
|
-
# Get a call signature from a node.
|
65
|
-
# The result should be a string in the form of a method path, e.g.,
|
66
|
-
# String.new or variable.method.
|
67
|
-
#
|
68
|
-
# @return [String]
|
69
|
-
def resolve_node_signature node
|
70
|
-
drill_signature node, ''
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def drill_signature node, signature
|
76
|
-
return signature unless node.kind_of?(AST::Node)
|
77
|
-
if node.type == :const or node.type == :cbase
|
78
|
-
unless node.children[0].nil?
|
79
|
-
signature += drill_signature(node.children[0], signature)
|
80
|
-
end
|
81
|
-
signature += '::' unless signature.empty?
|
82
|
-
signature += node.children[1].to_s
|
83
|
-
elsif node.type == :lvar or node.type == :ivar or node.type == :cvar
|
84
|
-
signature += '.' unless signature.empty?
|
85
|
-
signature += node.children[0].to_s
|
86
|
-
elsif node.type == :send
|
87
|
-
unless node.children[0].nil?
|
88
|
-
signature += drill_signature(node.children[0], signature)
|
89
|
-
end
|
90
|
-
signature += '.' unless signature.empty?
|
91
|
-
signature += node.children[1].to_s
|
92
|
-
end
|
93
|
-
signature
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
1
|
+
module Solargraph
|
2
|
+
module NodeMethods
|
3
|
+
# @return [String]
|
4
|
+
def unpack_name(node)
|
5
|
+
pack_name(node).join("::")
|
6
|
+
end
|
7
|
+
|
8
|
+
# @return [Array<String>]
|
9
|
+
def pack_name(node)
|
10
|
+
parts = []
|
11
|
+
if node.kind_of?(AST::Node)
|
12
|
+
node.children.each { |n|
|
13
|
+
if n.kind_of?(AST::Node)
|
14
|
+
if n.type == :cbase
|
15
|
+
parts = pack_name(n)
|
16
|
+
else
|
17
|
+
parts += pack_name(n)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
parts.push n unless n.nil?
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
24
|
+
parts
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String]
|
28
|
+
def const_from node
|
29
|
+
if node.kind_of?(AST::Node) and node.type == :const
|
30
|
+
result = ''
|
31
|
+
unless node.children[0].nil?
|
32
|
+
result = const_from(node.children[0])
|
33
|
+
end
|
34
|
+
if result == ''
|
35
|
+
result = node.children[1].to_s
|
36
|
+
else
|
37
|
+
result = result + '::' + node.children[1].to_s
|
38
|
+
end
|
39
|
+
result
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [String]
|
46
|
+
def infer_literal_node_type node
|
47
|
+
return nil unless node.kind_of?(AST::Node)
|
48
|
+
if node.type == :str or node.type == :dstr
|
49
|
+
return 'String'
|
50
|
+
elsif node.type == :array
|
51
|
+
return 'Array'
|
52
|
+
elsif node.type == :hash
|
53
|
+
return 'Hash'
|
54
|
+
elsif node.type == :int
|
55
|
+
return 'Integer'
|
56
|
+
elsif node.type == :float
|
57
|
+
return 'Float'
|
58
|
+
elsif node.type == :sym
|
59
|
+
return 'Symbol'
|
60
|
+
end
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get a call signature from a node.
|
65
|
+
# The result should be a string in the form of a method path, e.g.,
|
66
|
+
# String.new or variable.method.
|
67
|
+
#
|
68
|
+
# @return [String]
|
69
|
+
def resolve_node_signature node
|
70
|
+
drill_signature node, ''
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def drill_signature node, signature
|
76
|
+
return signature unless node.kind_of?(AST::Node)
|
77
|
+
if node.type == :const or node.type == :cbase
|
78
|
+
unless node.children[0].nil?
|
79
|
+
signature += drill_signature(node.children[0], signature)
|
80
|
+
end
|
81
|
+
signature += '::' unless signature.empty?
|
82
|
+
signature += node.children[1].to_s
|
83
|
+
elsif node.type == :lvar or node.type == :ivar or node.type == :cvar
|
84
|
+
signature += '.' unless signature.empty?
|
85
|
+
signature += node.children[0].to_s
|
86
|
+
elsif node.type == :send
|
87
|
+
unless node.children[0].nil?
|
88
|
+
signature += drill_signature(node.children[0], signature)
|
89
|
+
end
|
90
|
+
signature += '.' unless signature.empty?
|
91
|
+
signature += node.children[1].to_s
|
92
|
+
end
|
93
|
+
signature
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|