solargraph 0.18.2 → 0.18.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/solargraph.rb +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
|