solargraph 0.24.1 → 0.25.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/api_map.rb +93 -46
- data/lib/solargraph/api_map/cache.rb +51 -0
- data/lib/solargraph/api_map/probe.rb +23 -12
- data/lib/solargraph/api_map/source_to_yard.rb +2 -2
- data/lib/solargraph/api_map/store.rb +20 -9
- data/lib/solargraph/complex_type.rb +10 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +1 -1
- data/lib/solargraph/diagnostics/rubocop.rb +35 -27
- data/lib/solargraph/diagnostics/type_not_defined.rb +10 -13
- data/lib/solargraph/language_server/host.rb +11 -11
- data/lib/solargraph/language_server/message.rb +0 -1
- data/lib/solargraph/language_server/message/base.rb +24 -4
- data/lib/solargraph/language_server/message/text_document/completion.rb +9 -16
- data/lib/solargraph/language_server/message/text_document/did_change.rb +0 -2
- data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -10
- data/lib/solargraph/language_server/transport/socket.rb +0 -1
- data/lib/solargraph/language_server/transport/stdio.rb +0 -1
- data/lib/solargraph/pin.rb +1 -1
- data/lib/solargraph/pin/attribute.rb +4 -7
- data/lib/solargraph/pin/base.rb +113 -8
- data/lib/solargraph/pin/base_variable.rb +17 -25
- data/lib/solargraph/pin/block.rb +2 -2
- data/lib/solargraph/pin/block_parameter.rb +8 -10
- data/lib/solargraph/pin/constant.rb +2 -2
- data/lib/solargraph/pin/conversions.rb +8 -0
- data/lib/solargraph/pin/documenting.rb +2 -2
- data/lib/solargraph/pin/duck_method.rb +0 -1
- data/lib/solargraph/pin/local_variable.rb +8 -2
- data/lib/solargraph/pin/method.rb +26 -16
- data/lib/solargraph/pin/method_parameter.rb +15 -8
- data/lib/solargraph/pin/namespace.rb +2 -2
- data/lib/solargraph/pin/reference.rb +7 -0
- data/lib/solargraph/pin/yard_pin.rb +10 -0
- data/lib/solargraph/pin/yard_pin/constant.rb +14 -0
- data/lib/solargraph/pin/yard_pin/method.rb +35 -0
- data/lib/solargraph/pin/yard_pin/namespace.rb +27 -0
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +18 -0
- data/lib/solargraph/source.rb +59 -15
- data/lib/solargraph/source/mapper.rb +46 -99
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +11 -2
- data/lib/solargraph/workspace/config.rb +47 -1
- data/lib/solargraph/yard_map.rb +103 -278
- data/lib/solargraph/yard_map/cache.rb +13 -38
- metadata +7 -3
- data/lib/solargraph/pin/yard_object.rb +0 -119
@@ -24,7 +24,7 @@ module Solargraph
|
|
24
24
|
else
|
25
25
|
code_object_map[pin.path] ||= YARD::CodeObjects::ModuleObject.new(root_code_object, pin.path)
|
26
26
|
end
|
27
|
-
code_object_map[pin.path].docstring = pin.docstring
|
27
|
+
code_object_map[pin.path].docstring = pin.docstring
|
28
28
|
code_object_map[pin.path].files.push pin.location.filename
|
29
29
|
end
|
30
30
|
s.namespace_pins.each do |pin|
|
@@ -34,7 +34,7 @@ module Solargraph
|
|
34
34
|
end
|
35
35
|
s.method_pins.each do |pin|
|
36
36
|
code_object_map[pin.path] ||= YARD::CodeObjects::MethodObject.new(code_object_at(pin.namespace), pin.name, pin.scope)
|
37
|
-
code_object_map[pin.path].docstring = pin.docstring
|
37
|
+
code_object_map[pin.path].docstring = pin.docstring
|
38
38
|
code_object_map[pin.path].visibility = pin.visibility || :public
|
39
39
|
code_object_map[pin.path].files.push pin.location.filename
|
40
40
|
code_object_map[pin.path].parameters = pin.parameters.map do |p|
|
@@ -4,8 +4,9 @@ module Solargraph
|
|
4
4
|
class ApiMap
|
5
5
|
class Store
|
6
6
|
# @param sources [Array<Solargraph::Source>]
|
7
|
-
def initialize sources
|
8
|
-
|
7
|
+
def initialize sources, yard_pins
|
8
|
+
inner_update *sources
|
9
|
+
pins.concat yard_pins
|
9
10
|
index
|
10
11
|
end
|
11
12
|
|
@@ -16,19 +17,20 @@ module Solargraph
|
|
16
17
|
|
17
18
|
def remove *sources
|
18
19
|
sources.each do |source|
|
19
|
-
pins.delete_if { |pin| pin.filename == source.filename }
|
20
|
+
pins.delete_if { |pin| !pin.yard_pin? and pin.filename == source.filename }
|
20
21
|
symbols.delete_if { |pin| pin.filename == source.filename }
|
21
22
|
end
|
22
23
|
index
|
23
24
|
end
|
24
25
|
|
25
26
|
def update *sources
|
26
|
-
sources
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
inner_update *sources
|
28
|
+
index
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_yard yard_pins
|
32
|
+
pins.delete_if(&:yard_pin?)
|
33
|
+
pins.concat yard_pins
|
32
34
|
index
|
33
35
|
end
|
34
36
|
|
@@ -154,6 +156,15 @@ module Solargraph
|
|
154
156
|
namespaces.add pin.path if pin.kind == Pin::NAMESPACE and !pin.path.empty?
|
155
157
|
end
|
156
158
|
end
|
159
|
+
|
160
|
+
def inner_update *sources
|
161
|
+
sources.each do |source|
|
162
|
+
pins.delete_if { |pin| !pin.yard_pin? and pin.filename == source.filename }
|
163
|
+
symbols.delete_if { |pin| pin.filename == source.filename }
|
164
|
+
pins.concat source.pins
|
165
|
+
symbols.concat source.symbols
|
166
|
+
end
|
167
|
+
end
|
157
168
|
end
|
158
169
|
end
|
159
170
|
end
|
@@ -50,6 +50,11 @@ module Solargraph
|
|
50
50
|
@scope ||= ((name == 'Class' or name == 'Module') and !subtypes.empty?) ? :class : :instance
|
51
51
|
end
|
52
52
|
|
53
|
+
def == other
|
54
|
+
return false unless self.class == other.class
|
55
|
+
tag == other.tag
|
56
|
+
end
|
57
|
+
|
53
58
|
class << self
|
54
59
|
# @param *strings [Array<String>] The type definitions to parse
|
55
60
|
# @return [Array<ComplexType>]
|
@@ -57,6 +62,7 @@ module Solargraph
|
|
57
62
|
types = []
|
58
63
|
strings.each do |type_string|
|
59
64
|
point_stack = 0
|
65
|
+
curly_stack = 0
|
60
66
|
base = ''
|
61
67
|
subtype_string = ''
|
62
68
|
type_string.each_char do |char|
|
@@ -65,7 +71,10 @@ module Solargraph
|
|
65
71
|
next if point_stack == 1
|
66
72
|
elsif char == '>'
|
67
73
|
point_stack -= 1
|
68
|
-
raise
|
74
|
+
raise "Invalid close in type #{type_string}" if point_stack < 0
|
75
|
+
elsif char == '{'
|
76
|
+
# @todo Temporarily short-circuiting types with {}
|
77
|
+
break
|
69
78
|
elsif char == ',' and point_stack == 0
|
70
79
|
types.push ComplexType.new base.strip, subtype_string.strip
|
71
80
|
base = ''
|
@@ -10,7 +10,7 @@ module Solargraph
|
|
10
10
|
source.requires.each do |ref|
|
11
11
|
refs[ref.name] = ref
|
12
12
|
end
|
13
|
-
api_map.
|
13
|
+
api_map.unresolved_requires.each do |r|
|
14
14
|
next unless refs.has_key?(r)
|
15
15
|
result.push(
|
16
16
|
range: refs[r].location.range.to_hash,
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'rubocop'
|
2
|
+
require 'stringio'
|
3
3
|
|
4
4
|
module Solargraph
|
5
5
|
module Diagnostics
|
@@ -15,43 +15,51 @@ module Solargraph
|
|
15
15
|
'fatal' => Severities::ERROR
|
16
16
|
}
|
17
17
|
|
18
|
-
# The rubocop command
|
19
|
-
#
|
20
|
-
# @return [String]
|
21
|
-
attr_reader :command
|
22
|
-
|
23
|
-
def initialize(command = 'rubocop')
|
24
|
-
@command = command
|
25
|
-
end
|
26
|
-
|
27
18
|
# @param source [Solargraph::Source]
|
28
19
|
# @param api_map [Solargraph::ApiMap]
|
29
20
|
# @return [Array<Hash>]
|
30
21
|
def diagnose source, api_map
|
31
22
|
begin
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
unless api_map.workspace.nil? or api_map.workspace.directory.nil?
|
37
|
-
rc = File.join(api_map.workspace.directory, '.rubocop.yml')
|
38
|
-
cmd += " -c #{Shellwords.escape(fix_drive_letter(rc))}" if File.file?(rc)
|
39
|
-
end
|
40
|
-
cmd += " -s #{Shellwords.escape(fix_drive_letter(filename))}"
|
41
|
-
o, e, s = Open3.capture3(cmd, stdin_data: text)
|
42
|
-
STDERR.puts e unless e.empty?
|
43
|
-
raise DiagnosticsError, "Command '#{command}' is not available (gem exception)" if e.include?('Gem::Exception')
|
44
|
-
raise DiagnosticsError, "RuboCop returned empty data" if o.empty?
|
45
|
-
make_array JSON.parse(o)
|
23
|
+
options, paths = generate_options(api_map.workspace, source.filename, source.code)
|
24
|
+
runner = RuboCop::Runner.new(options, RuboCop::ConfigStore.new)
|
25
|
+
result = redirect_stdout{ runner.run(paths) }
|
26
|
+
make_array JSON.parse(result)
|
46
27
|
rescue JSON::ParserError
|
47
28
|
raise DiagnosticsError, 'RuboCop returned invalid data'
|
48
|
-
rescue Errno::ENOENT
|
49
|
-
raise DiagnosticsError, "Command '#{command}' is not available"
|
50
29
|
end
|
51
30
|
end
|
52
31
|
|
53
32
|
private
|
54
33
|
|
34
|
+
# @param workspace [Solargraph::Workspace]
|
35
|
+
# @param filename [String]
|
36
|
+
# @param code [String]
|
37
|
+
# @return [Array]
|
38
|
+
def generate_options workspace, filename, code
|
39
|
+
args = ['-f', 'j']
|
40
|
+
unless workspace.nil? or workspace.directory.nil?
|
41
|
+
rc = File.join(workspace.directory, '.rubocop.yml')
|
42
|
+
args.push('-c', fix_drive_letter(rc)) if File.file?(rc)
|
43
|
+
end
|
44
|
+
args.push filename
|
45
|
+
options, paths = RuboCop::Options.new.parse(args)
|
46
|
+
options[:stdin] = code
|
47
|
+
[options, paths]
|
48
|
+
end
|
49
|
+
|
50
|
+
# @todo This is a smelly way to redirect output, but the RuboCop specs do the
|
51
|
+
# same thing.
|
52
|
+
# @return [String]
|
53
|
+
def redirect_stdout
|
54
|
+
redir = StringIO.new
|
55
|
+
$stdout = redir
|
56
|
+
yield if block_given?
|
57
|
+
$stdout = STDOUT
|
58
|
+
redir.string
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param resp [Hash]
|
62
|
+
# @return [Array<Hash>]
|
55
63
|
def make_array resp
|
56
64
|
diagnostics = []
|
57
65
|
resp['files'].each do |file|
|
@@ -47,16 +47,14 @@ module Solargraph
|
|
47
47
|
|
48
48
|
def check_param_tags pin, api_map, source
|
49
49
|
result = []
|
50
|
-
|
51
|
-
pin.
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
)
|
59
|
-
end
|
50
|
+
pin.docstring.tags(:param).each do |par|
|
51
|
+
next if pin.parameter_names.include?(par.name)
|
52
|
+
result.push(
|
53
|
+
range: extract_first_line(pin, source),
|
54
|
+
severity: Diagnostics::Severities::WARNING,
|
55
|
+
source: 'Solargraph',
|
56
|
+
message: "Method `#{pin.name}` has mistagged param `#{par.name}`."
|
57
|
+
)
|
60
58
|
end
|
61
59
|
result
|
62
60
|
end
|
@@ -76,14 +74,14 @@ module Solargraph
|
|
76
74
|
|
77
75
|
def defined_return_type? pin, api_map
|
78
76
|
return true unless pin.return_type.nil?
|
79
|
-
matches = api_map.
|
77
|
+
matches = api_map.get_method_stack(pin.namespace, pin.name, scope: pin.scope)
|
80
78
|
matches.shift
|
81
79
|
matches.any?{|m| !m.return_type.nil?}
|
82
80
|
end
|
83
81
|
|
84
82
|
def defined_param_type? pin, param, api_map
|
85
83
|
return true if param_in_docstring?(param, pin.docstring)
|
86
|
-
matches = api_map.
|
84
|
+
matches = api_map.get_method_stack(pin.namespace, pin.name, scope: pin.scope)
|
87
85
|
matches.shift
|
88
86
|
matches.each do |m|
|
89
87
|
next unless pin.parameter_names == m.parameter_names
|
@@ -93,7 +91,6 @@ module Solargraph
|
|
93
91
|
end
|
94
92
|
|
95
93
|
def param_in_docstring? param, docstring
|
96
|
-
return false if docstring.nil?
|
97
94
|
tags = docstring.tags(:param)
|
98
95
|
tags.any?{|t| t.name == param}
|
99
96
|
end
|
@@ -492,17 +492,17 @@ module Solargraph
|
|
492
492
|
@diagnostics_queue.push change['textDocument']['uri']
|
493
493
|
changed = true
|
494
494
|
next true
|
495
|
-
elsif change['textDocument']['version'] == source.version + 1 #and change['contentChanges'].length == 0
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
495
|
+
# elsif change['textDocument']['version'] == source.version + 1 #and change['contentChanges'].length == 0
|
496
|
+
# # HACK: This condition fixes the fact that formatting
|
497
|
+
# # increments the version by one regardless of the number
|
498
|
+
# # of changes
|
499
|
+
# STDERR.puts "Warning: change applied to #{uri_to_file(change['textDocument']['uri'])} is possibly out of sync"
|
500
|
+
# pending[change['textDocument']['uri']] -= 1
|
501
|
+
# updater = generate_updater(change)
|
502
|
+
# library.synchronize updater, pending[change['textDocument']['uri']] == 0
|
503
|
+
# @diagnostics_queue.push change['textDocument']['uri']
|
504
|
+
# changed = true
|
505
|
+
# next true
|
506
506
|
elsif change['textDocument']['version'] <= source.version
|
507
507
|
# @todo Is deleting outdated changes correct behavior?
|
508
508
|
STDERR.puts "Warning: outdated change to #{change['textDocument']['uri']} was ignored"
|
@@ -4,13 +4,27 @@ module Solargraph
|
|
4
4
|
class Base
|
5
5
|
# @return [Solargraph::LanguageServer::Host]
|
6
6
|
attr_reader :host
|
7
|
+
|
8
|
+
# @return [Integer]
|
7
9
|
attr_reader :id
|
10
|
+
|
11
|
+
# @return [Hash]
|
8
12
|
attr_reader :request
|
13
|
+
|
14
|
+
# @return [String]
|
9
15
|
attr_reader :method
|
16
|
+
|
17
|
+
# @return [Hash]
|
10
18
|
attr_reader :params
|
19
|
+
|
20
|
+
# @return [Hash, Array, nil]
|
11
21
|
attr_reader :result
|
22
|
+
|
23
|
+
# @return [Hash, nil]
|
12
24
|
attr_reader :error
|
13
25
|
|
26
|
+
# @param host [Solargraph::LanguageServer::Host]
|
27
|
+
# @param request [Hash]
|
14
28
|
def initialize host, request
|
15
29
|
@host = host
|
16
30
|
@id = request['id'].freeze
|
@@ -20,16 +34,21 @@ module Solargraph
|
|
20
34
|
post_initialize
|
21
35
|
end
|
22
36
|
|
23
|
-
|
24
|
-
end
|
37
|
+
# @return [void]
|
38
|
+
def post_initialize; end
|
25
39
|
|
26
|
-
|
27
|
-
end
|
40
|
+
# @return [void]
|
41
|
+
def process; end
|
28
42
|
|
43
|
+
# @param data [Hash, Array, nil]
|
44
|
+
# @return [void]
|
29
45
|
def set_result data
|
30
46
|
@result = data
|
31
47
|
end
|
32
48
|
|
49
|
+
# @param code [Integer] See Solargraph::LanguageServer::ErrorCodes
|
50
|
+
# @param message [String]
|
51
|
+
# @return [void]
|
33
52
|
def set_error code, message
|
34
53
|
@error = {
|
35
54
|
code: code,
|
@@ -37,6 +56,7 @@ module Solargraph
|
|
37
56
|
}
|
38
57
|
end
|
39
58
|
|
59
|
+
# @return [void]
|
40
60
|
def send_response
|
41
61
|
unless id.nil? or host.cancel?(id)
|
42
62
|
response = {
|
@@ -6,25 +6,16 @@ module Solargraph
|
|
6
6
|
module TextDocument
|
7
7
|
class Completion < Base
|
8
8
|
def process
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
if Time.now - start > 1
|
14
|
-
# set_error Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, 'Completion request timed out'
|
15
|
-
set_result empty_result
|
16
|
-
processed = true
|
17
|
-
end
|
18
|
-
else
|
19
|
-
inner_process
|
20
|
-
processed = true
|
21
|
-
end
|
22
|
-
sleep 0.1 unless processed
|
9
|
+
if host.changing?(params['textDocument']['uri'])
|
10
|
+
set_result empty_result(true)
|
11
|
+
else
|
12
|
+
inner_process
|
23
13
|
end
|
24
14
|
end
|
25
15
|
|
26
16
|
private
|
27
17
|
|
18
|
+
# @return [void]
|
28
19
|
def inner_process
|
29
20
|
filename = uri_to_file(params['textDocument']['uri'])
|
30
21
|
line = params['position']['line']
|
@@ -56,9 +47,11 @@ module Solargraph
|
|
56
47
|
end
|
57
48
|
end
|
58
49
|
|
59
|
-
|
50
|
+
# @param incomplete [Boolean]
|
51
|
+
# @return [Hash]
|
52
|
+
def empty_result incomplete = false
|
60
53
|
{
|
61
|
-
isIncomplete:
|
54
|
+
isIncomplete: incomplete,
|
62
55
|
items: []
|
63
56
|
}
|
64
57
|
end
|
data/lib/solargraph/pin.rb
CHANGED
@@ -13,7 +13,6 @@ module Solargraph
|
|
13
13
|
autoload :Constant, 'solargraph/pin/constant'
|
14
14
|
autoload :Symbol, 'solargraph/pin/symbol'
|
15
15
|
autoload :Namespace, 'solargraph/pin/namespace'
|
16
|
-
autoload :YardObject, 'solargraph/pin/yard_object'
|
17
16
|
autoload :Keyword, 'solargraph/pin/keyword'
|
18
17
|
autoload :MethodParameter, 'solargraph/pin/method_parameter'
|
19
18
|
autoload :BlockParameter, 'solargraph/pin/block_parameter'
|
@@ -23,6 +22,7 @@ module Solargraph
|
|
23
22
|
autoload :Localized, 'solargraph/pin/localized'
|
24
23
|
autoload :ProxyMethod, 'solargraph/pin/proxy_method'
|
25
24
|
autoload :DuckMethod, 'solargraph/pin/duck_method'
|
25
|
+
autoload :YardPin, 'solargraph/pin/yard_pin'
|
26
26
|
|
27
27
|
ATTRIBUTE = 1
|
28
28
|
CLASS_VARIABLE = 2
|