solargraph 0.54.4 → 0.56.2
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/.github/workflows/plugins.yml +2 -0
- data/.github/workflows/typecheck.yml +3 -1
- data/.gitignore +2 -0
- data/CHANGELOG.md +62 -0
- data/README.md +13 -3
- data/lib/solargraph/api_map/index.rb +24 -16
- data/lib/solargraph/api_map/store.rb +48 -23
- data/lib/solargraph/api_map.rb +175 -77
- data/lib/solargraph/bench.rb +17 -1
- data/lib/solargraph/complex_type/type_methods.rb +6 -1
- data/lib/solargraph/complex_type/unique_type.rb +98 -9
- data/lib/solargraph/complex_type.rb +35 -6
- data/lib/solargraph/convention/base.rb +3 -3
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +60 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +89 -0
- data/lib/solargraph/convention/data_definition.rb +104 -0
- data/lib/solargraph/convention/gemspec.rb +2 -1
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +60 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
- data/lib/solargraph/convention/struct_definition.rb +141 -0
- data/lib/solargraph/convention.rb +5 -3
- data/lib/solargraph/doc_map.rb +277 -57
- data/lib/solargraph/gem_pins.rb +53 -37
- data/lib/solargraph/language_server/host/message_worker.rb +10 -7
- data/lib/solargraph/language_server/host.rb +12 -2
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/library.rb +45 -17
- data/lib/solargraph/location.rb +21 -0
- data/lib/solargraph/logging.rb +1 -0
- data/lib/solargraph/parser/comment_ripper.rb +12 -6
- data/lib/solargraph/parser/flow_sensitive_typing.rb +227 -0
- data/lib/solargraph/parser/node_methods.rb +14 -0
- data/lib/solargraph/parser/node_processor/base.rb +9 -4
- data/lib/solargraph/parser/node_processor.rb +21 -8
- data/lib/solargraph/parser/parser_gem/class_methods.rb +16 -14
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +10 -10
- data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +4 -1
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/parser.rb +1 -0
- data/lib/solargraph/pin/base.rb +316 -28
- data/lib/solargraph/pin/base_variable.rb +16 -9
- data/lib/solargraph/pin/block.rb +2 -0
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +74 -3
- data/lib/solargraph/pin/closure.rb +18 -1
- data/lib/solargraph/pin/common.rb +5 -0
- data/lib/solargraph/pin/delegated_method.rb +20 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +15 -6
- data/lib/solargraph/pin/method.rb +169 -43
- data/lib/solargraph/pin/namespace.rb +17 -9
- data/lib/solargraph/pin/parameter.rb +60 -11
- data/lib/solargraph/pin/proxy_type.rb +12 -6
- data/lib/solargraph/pin/reference/override.rb +10 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/signature.rb +42 -0
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +3 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/pin_cache.rb +185 -0
- data/lib/solargraph/position.rb +9 -0
- data/lib/solargraph/range.rb +9 -0
- data/lib/solargraph/rbs_map/conversions.rb +221 -67
- data/lib/solargraph/rbs_map/core_fills.rb +32 -16
- data/lib/solargraph/rbs_map/core_map.rb +34 -11
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +74 -17
- data/lib/solargraph/shell.rb +17 -18
- data/lib/solargraph/source/chain/array.rb +11 -7
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +53 -23
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/hash.rb +4 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +2 -0
- data/lib/solargraph/source/chain/literal.rb +22 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +78 -48
- data/lib/solargraph/source/source_chainer.rb +2 -2
- data/lib/solargraph/source_map/clip.rb +3 -1
- data/lib/solargraph/source_map/mapper.rb +9 -5
- data/lib/solargraph/source_map.rb +0 -17
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker.rb +35 -8
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/workspace/config.rb +1 -1
- data/lib/solargraph/workspace.rb +23 -5
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
- data/lib/solargraph/yard_map/mapper.rb +4 -3
- data/lib/solargraph/yard_map/to_method.rb +4 -2
- data/lib/solargraph/yardoc.rb +7 -8
- data/lib/solargraph.rb +32 -1
- data/rbs/fills/tuple.rbs +150 -0
- data/rbs_collection.yaml +19 -0
- data/solargraph.gemspec +2 -1
- metadata +37 -9
- data/lib/solargraph/cache.rb +0 -77
data/lib/solargraph/doc_map.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
4
|
+
require 'benchmark'
|
5
|
+
|
3
6
|
module Solargraph
|
4
7
|
# A collection of pins generated from required gems.
|
5
8
|
#
|
6
9
|
class DocMap
|
10
|
+
include Logging
|
11
|
+
|
7
12
|
# @return [Array<String>]
|
8
13
|
attr_reader :requires
|
14
|
+
alias required requires
|
9
15
|
|
10
16
|
# @return [Array<Gem::Specification>]
|
11
17
|
attr_reader :preferences
|
@@ -14,31 +20,121 @@ module Solargraph
|
|
14
20
|
attr_reader :pins
|
15
21
|
|
16
22
|
# @return [Array<Gem::Specification>]
|
17
|
-
|
23
|
+
def uncached_gemspecs
|
24
|
+
uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs)
|
25
|
+
.sort
|
26
|
+
.uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Array<Gem::Specification>]
|
30
|
+
attr_reader :uncached_yard_gemspecs
|
31
|
+
|
32
|
+
# @return [Array<Gem::Specification>]
|
33
|
+
attr_reader :uncached_rbs_collection_gemspecs
|
34
|
+
|
35
|
+
attr_reader :rbs_collection_path
|
36
|
+
|
37
|
+
attr_reader :rbs_collection_config_path
|
38
|
+
|
39
|
+
# @return [Workspace, nil]
|
40
|
+
attr_reader :workspace
|
41
|
+
|
42
|
+
# @return [Environ]
|
43
|
+
attr_reader :environ
|
18
44
|
|
19
45
|
# @param requires [Array<String>]
|
20
46
|
# @param preferences [Array<Gem::Specification>]
|
21
|
-
# @param
|
22
|
-
def initialize(requires, preferences,
|
47
|
+
# @param workspace [Workspace, nil]
|
48
|
+
def initialize(requires, preferences, workspace = nil)
|
23
49
|
@requires = requires.compact
|
24
50
|
@preferences = preferences.compact
|
25
|
-
@
|
26
|
-
|
51
|
+
@workspace = workspace
|
52
|
+
@rbs_collection_path = workspace&.rbs_collection_path
|
53
|
+
@rbs_collection_config_path = workspace&.rbs_collection_config_path
|
54
|
+
@environ = Convention.for_global(self)
|
55
|
+
load_serialized_gem_pins
|
56
|
+
pins.concat @environ.pins
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache_all!(out)
|
60
|
+
# if we log at debug level:
|
61
|
+
if logger.info?
|
62
|
+
gem_desc = uncached_gemspecs.map { |gemspec| "#{gemspec.name}:#{gemspec.version}" }.join(', ')
|
63
|
+
logger.info "Caching pins for gems: #{gem_desc}" unless uncached_gemspecs.empty?
|
64
|
+
end
|
65
|
+
logger.debug { "Caching for YARD: #{uncached_yard_gemspecs.map(&:name)}" }
|
66
|
+
logger.debug { "Caching for RBS collection: #{uncached_rbs_collection_gemspecs.map(&:name)}" }
|
67
|
+
load_serialized_gem_pins
|
68
|
+
uncached_gemspecs.each do |gemspec|
|
69
|
+
cache(gemspec, out: out)
|
70
|
+
end
|
71
|
+
load_serialized_gem_pins
|
72
|
+
@uncached_rbs_collection_gemspecs = []
|
73
|
+
@uncached_yard_gemspecs = []
|
74
|
+
end
|
75
|
+
|
76
|
+
def cache_yard_pins(gemspec, out)
|
77
|
+
pins = GemPins.build_yard_pins(gemspec)
|
78
|
+
PinCache.serialize_yard_gem(gemspec, pins)
|
79
|
+
logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def cache_rbs_collection_pins(gemspec, out)
|
83
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
84
|
+
pins = rbs_map.pins
|
85
|
+
rbs_version_cache_key = rbs_map.cache_key
|
86
|
+
# cache pins even if result is zero, so we don't retry building pins
|
87
|
+
pins ||= []
|
88
|
+
PinCache.serialize_rbs_collection_gem(gemspec, rbs_version_cache_key, pins)
|
89
|
+
logger.info { "Cached #{pins.length} RBS collection pins for gem #{gemspec.name} #{gemspec.version} with cache_key #{rbs_version_cache_key.inspect}" unless pins.empty? }
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param gemspec [Gem::Specification]
|
93
|
+
def cache(gemspec, rebuild: false, out: nil)
|
94
|
+
build_yard = uncached_yard_gemspecs.include?(gemspec) || rebuild
|
95
|
+
build_rbs_collection = uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
|
96
|
+
if build_yard || build_rbs_collection
|
97
|
+
type = []
|
98
|
+
type << 'YARD' if build_yard
|
99
|
+
type << 'RBS collection' if build_rbs_collection
|
100
|
+
out.puts("Caching #{type.join(' and ')} pins for gem #{gemspec.name}:#{gemspec.version}") if out
|
101
|
+
end
|
102
|
+
cache_yard_pins(gemspec, out) if build_yard
|
103
|
+
cache_rbs_collection_pins(gemspec, out) if build_rbs_collection
|
27
104
|
end
|
28
105
|
|
29
106
|
# @return [Array<Gem::Specification>]
|
30
107
|
def gemspecs
|
31
|
-
@gemspecs ||=
|
108
|
+
@gemspecs ||= required_gems_map.values.compact.flatten
|
32
109
|
end
|
33
110
|
|
34
111
|
# @return [Array<String>]
|
35
112
|
def unresolved_requires
|
36
|
-
@unresolved_requires ||=
|
113
|
+
@unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.all_yard_gems_in_memory
|
117
|
+
@yard_gems_in_memory ||= {}
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.all_rbs_collection_gems_in_memory
|
121
|
+
@rbs_collection_gems_in_memory ||= {}
|
122
|
+
end
|
123
|
+
|
124
|
+
def yard_pins_in_memory
|
125
|
+
self.class.all_yard_gems_in_memory
|
126
|
+
end
|
127
|
+
|
128
|
+
def rbs_collection_pins_in_memory
|
129
|
+
self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.all_combined_pins_in_memory
|
133
|
+
@combined_pins_in_memory ||= {}
|
37
134
|
end
|
38
135
|
|
39
|
-
|
40
|
-
|
41
|
-
@gems_in_memory ||= {}
|
136
|
+
def combined_pins_in_memory
|
137
|
+
self.class.all_combined_pins_in_memory
|
42
138
|
end
|
43
139
|
|
44
140
|
# @return [Set<Gem::Specification>]
|
@@ -49,23 +145,34 @@ module Solargraph
|
|
49
145
|
private
|
50
146
|
|
51
147
|
# @return [void]
|
52
|
-
def
|
148
|
+
def load_serialized_gem_pins
|
53
149
|
@pins = []
|
54
|
-
@
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
150
|
+
@uncached_yard_gemspecs = []
|
151
|
+
@uncached_rbs_collection_gemspecs = []
|
152
|
+
with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
|
153
|
+
paths = Hash[without_gemspecs].keys
|
154
|
+
gemspecs = Hash[with_gemspecs].values.flatten.compact + dependencies.to_a
|
155
|
+
|
156
|
+
paths.each do |path|
|
157
|
+
rbs_pins = deserialize_stdlib_rbs_map path
|
158
|
+
end
|
159
|
+
|
160
|
+
logger.debug { "DocMap#load_serialized_gem_pins: Combining pins..." }
|
161
|
+
time = Benchmark.measure do
|
162
|
+
gemspecs.each do |gemspec|
|
163
|
+
pins = deserialize_combined_pin_cache gemspec
|
164
|
+
@pins.concat pins if pins
|
60
165
|
end
|
61
166
|
end
|
62
|
-
|
63
|
-
@
|
167
|
+
logger.info { "DocMap#load_serialized_gem_pins: Loaded and processed serialized pins together in #{time.real} seconds" }
|
168
|
+
@uncached_yard_gemspecs.uniq!
|
169
|
+
@uncached_rbs_collection_gemspecs.uniq!
|
170
|
+
nil
|
64
171
|
end
|
65
172
|
|
66
|
-
# @return [Hash{String => Gem::Specification
|
67
|
-
def
|
68
|
-
@
|
173
|
+
# @return [Hash{String => Array<Gem::Specification>}]
|
174
|
+
def required_gems_map
|
175
|
+
@required_gems_map ||= requires.to_h { |path| [path, resolve_path_to_gemspecs(path)] }
|
69
176
|
end
|
70
177
|
|
71
178
|
# @return [Hash{String => Gem::Specification}]
|
@@ -73,32 +180,97 @@ module Solargraph
|
|
73
180
|
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
74
181
|
end
|
75
182
|
|
183
|
+
# @param gemspec [Gem::Specification]
|
184
|
+
# @return [Array<Pin::Base>]
|
185
|
+
def deserialize_yard_pin_cache gemspec
|
186
|
+
if yard_pins_in_memory.key?([gemspec.name, gemspec.version])
|
187
|
+
return yard_pins_in_memory[[gemspec.name, gemspec.version]]
|
188
|
+
end
|
189
|
+
|
190
|
+
cached = PinCache.deserialize_yard_gem(gemspec)
|
191
|
+
if cached
|
192
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
193
|
+
yard_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
194
|
+
cached
|
195
|
+
else
|
196
|
+
logger.debug "No YARD pin cache for #{gemspec.name}:#{gemspec.version}"
|
197
|
+
@uncached_yard_gemspecs.push gemspec
|
198
|
+
nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
76
202
|
# @param gemspec [Gem::Specification]
|
77
203
|
# @return [void]
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
204
|
+
def deserialize_combined_pin_cache(gemspec)
|
205
|
+
unless combined_pins_in_memory[[gemspec.name, gemspec.version]].nil?
|
206
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
207
|
+
end
|
208
|
+
|
209
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
210
|
+
rbs_version_cache_key = rbs_map.cache_key
|
211
|
+
|
212
|
+
cached = PinCache.deserialize_combined_gem(gemspec, rbs_version_cache_key)
|
213
|
+
if cached
|
214
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
215
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
216
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
217
|
+
end
|
218
|
+
|
219
|
+
rbs_collection_pins = deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
220
|
+
|
221
|
+
yard_pins = deserialize_yard_pin_cache gemspec
|
222
|
+
|
223
|
+
if !rbs_collection_pins.nil? && !yard_pins.nil?
|
224
|
+
logger.debug { "Combining pins for #{gemspec.name}:#{gemspec.version}" }
|
225
|
+
combined_pins = GemPins.combine(yard_pins, rbs_collection_pins)
|
226
|
+
PinCache.serialize_combined_gem(gemspec, rbs_version_cache_key, combined_pins)
|
227
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = combined_pins
|
228
|
+
logger.info { "Generated #{combined_pins_in_memory[[gemspec.name, gemspec.version]].length} combined pins for #{gemspec.name} #{gemspec.version}" }
|
229
|
+
return combined_pins
|
230
|
+
end
|
231
|
+
|
232
|
+
if !yard_pins.nil?
|
233
|
+
logger.debug { "Using only YARD pins for #{gemspec.name}:#{gemspec.version}" }
|
234
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = yard_pins
|
235
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
236
|
+
elsif !rbs_collection_pins.nil?
|
237
|
+
logger.debug { "Using only RBS collection pins for #{gemspec.name}:#{gemspec.version}" }
|
238
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = rbs_collection_pins
|
239
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
86
240
|
else
|
87
|
-
|
88
|
-
|
241
|
+
logger.debug { "Pins not yet cached for #{gemspec.name}:#{gemspec.version}" }
|
242
|
+
return nil
|
89
243
|
end
|
90
244
|
end
|
91
245
|
|
92
246
|
# @param path [String] require path that might be in the RBS stdlib collection
|
93
247
|
# @return [void]
|
94
|
-
def
|
248
|
+
def deserialize_stdlib_rbs_map path
|
95
249
|
map = RbsMap::StdlibMap.load(path)
|
96
250
|
if map.resolved?
|
97
|
-
|
251
|
+
logger.debug { "Loading stdlib pins for #{path}" }
|
98
252
|
@pins.concat map.pins
|
253
|
+
logger.debug { "Loaded #{map.pins.length} stdlib pins for #{path}" }
|
254
|
+
map.pins
|
99
255
|
else
|
100
256
|
# @todo Temporarily ignoring unresolved `require 'set'`
|
101
|
-
|
257
|
+
logger.debug { "Require path #{path} could not be resolved in RBS" } unless path == 'set'
|
258
|
+
nil
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# @return [Array<Pin::Base>, nil]
|
263
|
+
def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
264
|
+
return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
|
265
|
+
cached = PinCache.deserialize_rbs_collection_gem(gemspec, rbs_version_cache_key)
|
266
|
+
if cached
|
267
|
+
logger.info { "Loaded #{cached.length} pins from RBS collection cache for #{gemspec.name}:#{gemspec.version}" } unless cached.empty?
|
268
|
+
rbs_collection_pins_in_memory[[gemspec, rbs_version_cache_key]] = cached
|
269
|
+
cached
|
270
|
+
else
|
271
|
+
logger.debug "No RBS collection pin cache for #{gemspec.name} #{gemspec.version}"
|
272
|
+
@uncached_rbs_collection_gemspecs.push gemspec
|
273
|
+
nil
|
102
274
|
end
|
103
275
|
end
|
104
276
|
|
@@ -112,22 +284,11 @@ module Solargraph
|
|
112
284
|
true
|
113
285
|
end
|
114
286
|
|
115
|
-
# @param gemspec [Gem::Specification]
|
116
|
-
def update_from_collection gemspec, gempins
|
117
|
-
return gempins unless @rbs_path && File.directory?(@rbs_path)
|
118
|
-
return gempins if RbsMap.new(gemspec.name, gemspec.version).resolved?
|
119
|
-
|
120
|
-
rbs_map = RbsMap.new(gemspec.name, gemspec.version, directories: [@rbs_path])
|
121
|
-
return gempins unless rbs_map.resolved?
|
122
|
-
|
123
|
-
Solargraph.logger.info "Updating #{gemspec.name} #{gemspec.version} from collection"
|
124
|
-
GemPins.combine(gempins, rbs_map)
|
125
|
-
end
|
126
|
-
|
127
287
|
# @param path [String]
|
128
|
-
# @return [Gem::Specification
|
129
|
-
def
|
288
|
+
# @return [::Array<Gem::Specification>, nil]
|
289
|
+
def resolve_path_to_gemspecs path
|
130
290
|
return nil if path.empty?
|
291
|
+
return gemspecs_required_from_bundler if path == 'bundler/require'
|
131
292
|
|
132
293
|
gemspec = Gem::Specification.find_by_path(path)
|
133
294
|
if gemspec.nil?
|
@@ -141,17 +302,18 @@ module Solargraph
|
|
141
302
|
file = "lib/#{path}.rb"
|
142
303
|
gemspec = potential_gemspec if potential_gemspec.files.any? { |gemspec_file| file == gemspec_file }
|
143
304
|
rescue Gem::MissingSpecError
|
144
|
-
|
145
|
-
|
305
|
+
logger.debug { "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}" }
|
306
|
+
[]
|
146
307
|
end
|
147
308
|
end
|
148
|
-
|
309
|
+
return nil if gemspec.nil?
|
310
|
+
[gemspec_or_preference(gemspec)]
|
149
311
|
end
|
150
312
|
|
151
|
-
# @param gemspec [Gem::Specification
|
152
|
-
# @return [Gem::Specification
|
313
|
+
# @param gemspec [Gem::Specification]
|
314
|
+
# @return [Gem::Specification]
|
153
315
|
def gemspec_or_preference gemspec
|
154
|
-
return gemspec unless
|
316
|
+
return gemspec unless preference_map.key?(gemspec.name)
|
155
317
|
return gemspec if gemspec.version == preference_map[gemspec.name].version
|
156
318
|
|
157
319
|
change_gemspec_version gemspec, preference_map[by_path.name].version
|
@@ -170,12 +332,15 @@ module Solargraph
|
|
170
332
|
# @param gemspec [Gem::Specification]
|
171
333
|
# @return [Array<Gem::Specification>]
|
172
334
|
def fetch_dependencies gemspec
|
335
|
+
# @param spec [Gem::Dependency]
|
173
336
|
only_runtime_dependencies(gemspec).each_with_object(Set.new) do |spec, deps|
|
174
337
|
Solargraph.logger.info "Adding #{spec.name} dependency for #{gemspec.name}"
|
175
|
-
dep = Gem
|
338
|
+
dep = Gem.loaded_specs[spec.name]
|
339
|
+
# @todo is next line necessary?
|
340
|
+
dep ||= Gem::Specification.find_by_name(spec.name, spec.requirement)
|
176
341
|
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
177
342
|
rescue Gem::MissingSpecError
|
178
|
-
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.
|
343
|
+
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found in RubyGems."
|
179
344
|
end.to_a
|
180
345
|
end
|
181
346
|
|
@@ -184,5 +349,60 @@ module Solargraph
|
|
184
349
|
def only_runtime_dependencies gemspec
|
185
350
|
gemspec.dependencies - gemspec.development_dependencies
|
186
351
|
end
|
352
|
+
|
353
|
+
|
354
|
+
def inspect
|
355
|
+
self.class.inspect
|
356
|
+
end
|
357
|
+
|
358
|
+
def gemspecs_required_from_bundler
|
359
|
+
# @todo Handle projects with custom Bundler/Gemfile setups
|
360
|
+
return unless workspace.gemfile?
|
361
|
+
|
362
|
+
if workspace.gemfile? && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory)
|
363
|
+
# Find only the gems bundler is now using
|
364
|
+
Bundler.definition.locked_gems.specs.flat_map do |lazy_spec|
|
365
|
+
logger.info "Handling #{lazy_spec.name}:#{lazy_spec.version}"
|
366
|
+
[Gem::Specification.find_by_name(lazy_spec.name, lazy_spec.version)]
|
367
|
+
rescue Gem::MissingSpecError => e
|
368
|
+
logger.info("Could not find #{lazy_spec.name}:#{lazy_spec.version} with find_by_name, falling back to guess")
|
369
|
+
# can happen in local filesystem references
|
370
|
+
specs = resolve_path_to_gemspecs lazy_spec.name
|
371
|
+
logger.warn "Gem #{lazy_spec.name} #{lazy_spec.version} from bundle not found: #{e}" if specs.nil?
|
372
|
+
next specs
|
373
|
+
end.compact
|
374
|
+
else
|
375
|
+
logger.info 'Fetching gemspecs required from Bundler (bundler/require)'
|
376
|
+
gemspecs_required_from_external_bundle
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def gemspecs_required_from_external_bundle
|
381
|
+
logger.info 'Fetching gemspecs required from external bundle'
|
382
|
+
return [] unless workspace&.directory
|
383
|
+
|
384
|
+
Solargraph.with_clean_env do
|
385
|
+
cmd = [
|
386
|
+
'ruby', '-e',
|
387
|
+
"require 'bundler'; require 'json'; Dir.chdir('#{workspace&.directory}') { puts Bundler.definition.locked_gems.specs.map { |spec| [spec.name, spec.version] }.to_h.to_json }"
|
388
|
+
]
|
389
|
+
o, e, s = Open3.capture3(*cmd)
|
390
|
+
if s.success?
|
391
|
+
Solargraph.logger.debug "External bundle: #{o}"
|
392
|
+
hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
|
393
|
+
hash.flat_map do |name, version|
|
394
|
+
Gem::Specification.find_by_name(name, version)
|
395
|
+
rescue Gem::MissingSpecError => e
|
396
|
+
logger.info("Could not find #{name}:#{version} with find_by_name, falling back to guess")
|
397
|
+
# can happen in local filesystem references
|
398
|
+
specs = resolve_path_to_gemspecs name
|
399
|
+
logger.warn "Gem #{name} #{version} from bundle not found: #{e}" if specs.nil?
|
400
|
+
next specs
|
401
|
+
end.compact
|
402
|
+
else
|
403
|
+
Solargraph.logger.warn "Failed to load gems from bundle at #{workspace&.directory}: #{e}"
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
187
407
|
end
|
188
408
|
end
|
data/lib/solargraph/gem_pins.rb
CHANGED
@@ -7,59 +7,75 @@ module Solargraph
|
|
7
7
|
# documentation.
|
8
8
|
#
|
9
9
|
module GemPins
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
class << self
|
11
|
+
include Logging
|
12
|
+
end
|
13
|
+
|
14
14
|
# @param gemspec [Gem::Specification]
|
15
15
|
# @return [Array<Pin::Base>]
|
16
|
-
def self.
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def self.build_yard_pins(gemspec)
|
17
|
+
Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
|
18
|
+
yardoc = Yardoc.load!(gemspec)
|
19
|
+
YardMap::Mapper.new(yardoc, gemspec).map
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param pins [Array<Pin::Base>]
|
23
|
+
def self.combine_method_pins_by_path(pins)
|
24
|
+
# bad_pins = pins.select { |pin| pin.is_a?(Pin::Method) && pin.path == 'StringIO.open' && pin.source == :rbs }; raise "wtf: #{bad_pins}" if bad_pins.length > 1
|
25
|
+
method_pins, alias_pins = pins.partition { |pin| pin.class == Pin::Method }
|
26
|
+
by_path = method_pins.group_by(&:path)
|
27
|
+
by_path.transform_values! do |pins|
|
28
|
+
GemPins.combine_method_pins(*pins)
|
29
|
+
end
|
30
|
+
by_path.values + alias_pins
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.combine_method_pins(*pins)
|
34
|
+
out = pins.reduce(nil) do |memo, pin|
|
35
|
+
next pin if memo.nil?
|
36
|
+
if memo == pin && memo.source != :combined
|
37
|
+
# @todo we should track down situations where we are handled
|
38
|
+
# the same pin from the same source here and eliminate them -
|
39
|
+
# this is an efficiency workaround for now
|
40
|
+
next memo
|
41
|
+
end
|
42
|
+
memo.combine_with(pin)
|
43
|
+
end
|
44
|
+
logger.debug { "GemPins.combine_method_pins(pins.length=#{pins.length}, pins=#{pins}) => #{out.inspect}" }
|
45
|
+
out
|
20
46
|
end
|
21
47
|
|
22
48
|
# @param yard_pins [Array<Pin::Base>]
|
23
49
|
# @param rbs_map [RbsMap]
|
24
50
|
# @return [Array<Pin::Base>]
|
25
|
-
def self.combine(yard_pins,
|
51
|
+
def self.combine(yard_pins, rbs_pins)
|
26
52
|
in_yard = Set.new
|
27
|
-
|
28
|
-
|
29
|
-
|
53
|
+
rbs_api_map = Solargraph::ApiMap.new(pins: rbs_pins)
|
54
|
+
combined = yard_pins.map do |yard_pin|
|
55
|
+
in_yard.add yard_pin.path
|
56
|
+
rbs_pin = rbs_api_map.get_path_pins(yard_pin.path).filter { |pin| pin.is_a? Pin::Method }.first
|
57
|
+
next yard_pin unless rbs_pin && yard_pin.class == Pin::Method
|
30
58
|
|
31
|
-
|
32
|
-
|
59
|
+
unless rbs_pin
|
60
|
+
logger.debug { "GemPins.combine: No rbs pin for #{yard_pin.path} - using YARD's '#{yard_pin.inspect} (return_type=#{yard_pin.return_type}; signatures=#{yard_pin.signatures})" }
|
61
|
+
next yard_pin
|
62
|
+
end
|
33
63
|
|
34
|
-
|
35
|
-
yard.
|
36
|
-
|
37
|
-
closure: yard.closure,
|
38
|
-
name: yard.name,
|
39
|
-
comments: yard.comments,
|
40
|
-
scope: yard.scope,
|
41
|
-
parameters: rbs.parameters,
|
42
|
-
generics: rbs.generics,
|
43
|
-
node: yard.node,
|
44
|
-
signatures: yard.signatures,
|
45
|
-
return_type: best_return_type(rbs.return_type, yard.return_type)
|
46
|
-
)
|
64
|
+
out = combine_method_pins(rbs_pin, yard_pin)
|
65
|
+
logger.debug { "GemPins.combine: Combining yard.path=#{yard_pin.path} - rbs=#{rbs_pin.inspect} with yard=#{yard_pin.inspect} into #{out}" }
|
66
|
+
out
|
47
67
|
end
|
48
|
-
|
49
|
-
|
68
|
+
in_rbs_only = rbs_pins.select do |pin|
|
69
|
+
pin.path.nil? || !in_yard.include?(pin.path)
|
70
|
+
end
|
71
|
+
out = combined + in_rbs_only
|
72
|
+
logger.debug { "GemPins#combine: Returning #{out.length} combined pins" }
|
73
|
+
out
|
50
74
|
end
|
51
75
|
|
52
76
|
class << self
|
53
77
|
private
|
54
78
|
|
55
|
-
# @param gemspec [Gem::Specification]
|
56
|
-
# @return [Array<Pin::Base>]
|
57
|
-
def build_yard_pins(gemspec)
|
58
|
-
Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
|
59
|
-
yardoc = Yardoc.load!(gemspec)
|
60
|
-
YardMap::Mapper.new(yardoc, gemspec).map
|
61
|
-
end
|
62
|
-
|
63
79
|
# Select the first defined type.
|
64
80
|
#
|
65
81
|
# @param choices [Array<ComplexType>]
|
@@ -7,9 +7,16 @@ module Solargraph
|
|
7
7
|
#
|
8
8
|
class MessageWorker
|
9
9
|
UPDATE_METHODS = [
|
10
|
-
'textDocument/didOpen',
|
11
10
|
'textDocument/didChange',
|
12
|
-
'
|
11
|
+
'textDocument/didClose',
|
12
|
+
'textDocument/didOpen',
|
13
|
+
'textDocument/didSave',
|
14
|
+
'workspace/didChangeConfiguration',
|
15
|
+
'workspace/didChangeWatchedFiles',
|
16
|
+
'workspace/didCreateFiles',
|
17
|
+
'workspace/didChangeWorkspaceFolders',
|
18
|
+
'workspace/didDeleteFiles',
|
19
|
+
'workspace/didRenameFiles'
|
13
20
|
].freeze
|
14
21
|
|
15
22
|
# @param host [Host]
|
@@ -84,11 +91,7 @@ module Solargraph
|
|
84
91
|
idx = messages.find_index do |msg|
|
85
92
|
UPDATE_METHODS.include?(msg['method']) || version_dependent?(msg)
|
86
93
|
end
|
87
|
-
|
88
|
-
|
89
|
-
msg = messages[idx]
|
90
|
-
messages.delete_at idx
|
91
|
-
msg
|
94
|
+
idx ? messages.delete_at(idx) : messages.shift
|
92
95
|
end
|
93
96
|
|
94
97
|
# True if the message requires a previous update to have executed in
|
@@ -299,6 +299,10 @@ module Solargraph
|
|
299
299
|
end
|
300
300
|
end
|
301
301
|
|
302
|
+
def command_path
|
303
|
+
options['commandPath'] || 'solargraph'
|
304
|
+
end
|
305
|
+
|
302
306
|
# Prepare multiple folders.
|
303
307
|
#
|
304
308
|
# @param array [Array<Hash{String => String}>]
|
@@ -501,7 +505,8 @@ module Solargraph
|
|
501
505
|
parameters: pin.parameters,
|
502
506
|
return_type: ComplexType.try_parse(params['data']['path']),
|
503
507
|
comments: pin.comments,
|
504
|
-
closure: pin.closure
|
508
|
+
closure: pin.closure,
|
509
|
+
source: :solargraph
|
505
510
|
)
|
506
511
|
end)
|
507
512
|
end
|
@@ -597,7 +602,11 @@ module Solargraph
|
|
597
602
|
# @return [Array]
|
598
603
|
def document query
|
599
604
|
result = []
|
600
|
-
libraries.
|
605
|
+
if libraries.empty?
|
606
|
+
result.concat generic_library.document(query)
|
607
|
+
else
|
608
|
+
libraries.each { |lib| result.concat lib.document(query) }
|
609
|
+
end
|
601
610
|
result
|
602
611
|
end
|
603
612
|
|
@@ -749,6 +758,7 @@ module Solargraph
|
|
749
758
|
return change if source.code.length + 1 != change['text'].length
|
750
759
|
diffs = Diff::LCS.diff(source.code, change['text'])
|
751
760
|
return change if diffs.length.zero? || diffs.length > 1 || diffs.first.length > 1
|
761
|
+
# @sg-ignore push this upstream
|
752
762
|
# @type [Diff::LCS::Change]
|
753
763
|
diff = diffs.first.first
|
754
764
|
return change unless diff.adding? && ['.', ':', '(', ',', ' '].include?(diff.element)
|
@@ -83,6 +83,8 @@ module Solargraph
|
|
83
83
|
@fetched = true
|
84
84
|
begin
|
85
85
|
@available ||= begin
|
86
|
+
# @sg-ignore
|
87
|
+
# @type [Gem::Dependency, nil]
|
86
88
|
tuple = CheckGemVersion.fetcher.search_for_dependency(Gem::Dependency.new('solargraph')).flatten.first
|
87
89
|
if tuple.nil?
|
88
90
|
@error = 'An error occurred fetching the gem data'
|
@@ -6,12 +6,15 @@ module Solargraph
|
|
6
6
|
module Extended
|
7
7
|
class Document < Base
|
8
8
|
def process
|
9
|
-
|
9
|
+
api_map, pins = host.document(params['query'])
|
10
10
|
page = Solargraph::Page.new(host.options['viewsPath'])
|
11
|
-
content = page.render('document', layout: true, locals: {
|
11
|
+
content = page.render('document', layout: true, locals: { api_map: api_map, pins: pins })
|
12
12
|
set_result(
|
13
13
|
content: content
|
14
14
|
)
|
15
|
+
rescue StandardError => e
|
16
|
+
Solargraph.logger.warn "Error processing document: [#{e.class}] #{e.message}"
|
17
|
+
Solargraph.logger.debug e.backtrace.join("\n")
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -11,9 +11,9 @@ module Solargraph
|
|
11
11
|
#
|
12
12
|
class DocumentGems < Base
|
13
13
|
def process
|
14
|
-
cmd =
|
15
|
-
cmd
|
16
|
-
o, s = Open3.capture2(cmd)
|
14
|
+
cmd = [host.command_path, 'gems']
|
15
|
+
cmd.push '--rebuild' if params['rebuild']
|
16
|
+
o, s = Open3.capture2(*cmd)
|
17
17
|
if s != 0
|
18
18
|
host.show_message "An error occurred while building gem documentation.", LanguageServer::MessageTypes::ERROR
|
19
19
|
set_result({
|