solargraph 0.55.3 → 0.56.1
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 +26 -1
- data/README.md +13 -3
- data/lib/solargraph/api_map/index.rb +23 -15
- data/lib/solargraph/api_map/store.rb +8 -4
- data/lib/solargraph/api_map.rb +150 -57
- data/lib/solargraph/complex_type/type_methods.rb +6 -1
- data/lib/solargraph/complex_type/unique_type.rb +10 -2
- data/lib/solargraph/convention/base.rb +3 -3
- data/lib/solargraph/convention.rb +3 -3
- data/lib/solargraph/doc_map.rb +209 -49
- data/lib/solargraph/gem_pins.rb +53 -37
- data/lib/solargraph/language_server/host.rb +11 -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 +43 -16
- data/lib/solargraph/location.rb +13 -0
- data/lib/solargraph/logging.rb +1 -0
- data/lib/solargraph/parser/comment_ripper.rb +1 -0
- data/lib/solargraph/parser/flow_sensitive_typing.rb +2 -1
- data/lib/solargraph/parser/node_processor.rb +3 -1
- data/lib/solargraph/parser/parser_gem/class_methods.rb +5 -8
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- 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 +4 -3
- 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/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/namespace_node.rb +6 -4
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -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 +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +1 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/pin/base.rb +295 -28
- data/lib/solargraph/pin/base_variable.rb +9 -8
- 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 +2 -0
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +8 -5
- data/lib/solargraph/pin/method.rb +147 -25
- data/lib/solargraph/pin/namespace.rb +7 -2
- data/lib/solargraph/pin/parameter.rb +47 -6
- data/lib/solargraph/pin/proxy_type.rb +3 -3
- 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.rb +1 -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 +183 -56
- data/lib/solargraph/rbs_map/core_fills.rb +24 -15
- 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 +7 -4
- 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 +8 -7
- data/lib/solargraph/source/chain/hash.rb +1 -1
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/literal.rb +2 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +2 -2
- data/lib/solargraph/source_map/mapper.rb +9 -5
- data/lib/solargraph/source_map.rb +0 -17
- 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.rb +23 -5
- data/lib/solargraph/yard_map/mapper/to_constant.rb +4 -2
- data/lib/solargraph/yard_map/mapper/to_method.rb +14 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +4 -2
- 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 +18 -1
- data/rbs/fills/tuple.rbs +150 -0
- data/rbs_collection.yaml +19 -0
- data/solargraph.gemspec +2 -1
- metadata +22 -9
- data/lib/solargraph/cache.rb +0 -77
data/lib/solargraph/doc_map.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
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
|
#
|
@@ -8,6 +11,7 @@ module Solargraph
|
|
8
11
|
|
9
12
|
# @return [Array<String>]
|
10
13
|
attr_reader :requires
|
14
|
+
alias required requires
|
11
15
|
|
12
16
|
# @return [Array<Gem::Specification>]
|
13
17
|
attr_reader :preferences
|
@@ -16,11 +20,28 @@ module Solargraph
|
|
16
20
|
attr_reader :pins
|
17
21
|
|
18
22
|
# @return [Array<Gem::Specification>]
|
19
|
-
|
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
|
20
38
|
|
21
39
|
# @return [Workspace, nil]
|
22
40
|
attr_reader :workspace
|
23
41
|
|
42
|
+
# @return [Environ]
|
43
|
+
attr_reader :environ
|
44
|
+
|
24
45
|
# @param requires [Array<String>]
|
25
46
|
# @param preferences [Array<Gem::Specification>]
|
26
47
|
# @param workspace [Workspace, nil]
|
@@ -28,7 +49,58 @@ module Solargraph
|
|
28
49
|
@requires = requires.compact
|
29
50
|
@preferences = preferences.compact
|
30
51
|
@workspace = workspace
|
31
|
-
|
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
|
32
104
|
end
|
33
105
|
|
34
106
|
# @return [Array<Gem::Specification>]
|
@@ -41,9 +113,28 @@ module Solargraph
|
|
41
113
|
@unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
|
42
114
|
end
|
43
115
|
|
44
|
-
|
45
|
-
|
46
|
-
|
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 ||= {}
|
134
|
+
end
|
135
|
+
|
136
|
+
def combined_pins_in_memory
|
137
|
+
self.class.all_combined_pins_in_memory
|
47
138
|
end
|
48
139
|
|
49
140
|
# @return [Set<Gem::Specification>]
|
@@ -54,20 +145,29 @@ module Solargraph
|
|
54
145
|
private
|
55
146
|
|
56
147
|
# @return [void]
|
57
|
-
def
|
148
|
+
def load_serialized_gem_pins
|
58
149
|
@pins = []
|
59
|
-
@
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
67
165
|
end
|
68
166
|
end
|
69
|
-
|
70
|
-
@
|
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
|
71
171
|
end
|
72
172
|
|
73
173
|
# @return [Hash{String => Array<Gem::Specification>}]
|
@@ -80,32 +180,97 @@ module Solargraph
|
|
80
180
|
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
81
181
|
end
|
82
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
|
+
|
83
202
|
# @param gemspec [Gem::Specification]
|
84
203
|
# @return [void]
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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]]
|
93
240
|
else
|
94
|
-
|
95
|
-
|
241
|
+
logger.debug { "Pins not yet cached for #{gemspec.name}:#{gemspec.version}" }
|
242
|
+
return nil
|
96
243
|
end
|
97
244
|
end
|
98
245
|
|
99
246
|
# @param path [String] require path that might be in the RBS stdlib collection
|
100
247
|
# @return [void]
|
101
|
-
def
|
248
|
+
def deserialize_stdlib_rbs_map path
|
102
249
|
map = RbsMap::StdlibMap.load(path)
|
103
250
|
if map.resolved?
|
104
|
-
|
251
|
+
logger.debug { "Loading stdlib pins for #{path}" }
|
105
252
|
@pins.concat map.pins
|
253
|
+
logger.debug { "Loaded #{map.pins.length} stdlib pins for #{path}" }
|
254
|
+
map.pins
|
106
255
|
else
|
107
256
|
# @todo Temporarily ignoring unresolved `require 'set'`
|
108
|
-
|
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
|
109
274
|
end
|
110
275
|
end
|
111
276
|
|
@@ -119,18 +284,6 @@ module Solargraph
|
|
119
284
|
true
|
120
285
|
end
|
121
286
|
|
122
|
-
# @param gemspec [Gem::Specification]
|
123
|
-
def update_from_collection gemspec, gempins
|
124
|
-
return gempins unless workspace&.rbs_collection_path && File.directory?(workspace&.rbs_collection_path)
|
125
|
-
return gempins if RbsMap.new(gemspec.name, gemspec.version).resolved?
|
126
|
-
|
127
|
-
rbs_map = RbsMap.new(gemspec.name, gemspec.version, directories: [workspace&.rbs_collection_path])
|
128
|
-
return gempins unless rbs_map.resolved?
|
129
|
-
|
130
|
-
Solargraph.logger.info "Updating #{gemspec.name} #{gemspec.version} from collection"
|
131
|
-
GemPins.combine(gempins, rbs_map)
|
132
|
-
end
|
133
|
-
|
134
287
|
# @param path [String]
|
135
288
|
# @return [::Array<Gem::Specification>, nil]
|
136
289
|
def resolve_path_to_gemspecs path
|
@@ -149,7 +302,7 @@ module Solargraph
|
|
149
302
|
file = "lib/#{path}.rb"
|
150
303
|
gemspec = potential_gemspec if potential_gemspec.files.any? { |gemspec_file| file == gemspec_file }
|
151
304
|
rescue Gem::MissingSpecError
|
152
|
-
|
305
|
+
logger.debug { "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}" }
|
153
306
|
[]
|
154
307
|
end
|
155
308
|
end
|
@@ -187,7 +340,7 @@ module Solargraph
|
|
187
340
|
dep ||= Gem::Specification.find_by_name(spec.name, spec.requirement)
|
188
341
|
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
189
342
|
rescue Gem::MissingSpecError
|
190
|
-
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found."
|
343
|
+
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found in RubyGems."
|
191
344
|
end.to_a
|
192
345
|
end
|
193
346
|
|
@@ -197,8 +350,16 @@ module Solargraph
|
|
197
350
|
gemspec.dependencies - gemspec.development_dependencies
|
198
351
|
end
|
199
352
|
|
353
|
+
|
354
|
+
def inspect
|
355
|
+
self.class.inspect
|
356
|
+
end
|
357
|
+
|
200
358
|
def gemspecs_required_from_bundler
|
201
|
-
|
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)
|
202
363
|
# Find only the gems bundler is now using
|
203
364
|
Bundler.definition.locked_gems.specs.flat_map do |lazy_spec|
|
204
365
|
logger.info "Handling #{lazy_spec.name}:#{lazy_spec.version}"
|
@@ -207,7 +368,7 @@ module Solargraph
|
|
207
368
|
logger.info("Could not find #{lazy_spec.name}:#{lazy_spec.version} with find_by_name, falling back to guess")
|
208
369
|
# can happen in local filesystem references
|
209
370
|
specs = resolve_path_to_gemspecs lazy_spec.name
|
210
|
-
logger.
|
371
|
+
logger.warn "Gem #{lazy_spec.name} #{lazy_spec.version} from bundle not found: #{e}" if specs.nil?
|
211
372
|
next specs
|
212
373
|
end.compact
|
213
374
|
else
|
@@ -229,18 +390,17 @@ module Solargraph
|
|
229
390
|
if s.success?
|
230
391
|
Solargraph.logger.debug "External bundle: #{o}"
|
231
392
|
hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
|
232
|
-
hash.
|
393
|
+
hash.flat_map do |name, version|
|
233
394
|
Gem::Specification.find_by_name(name, version)
|
234
395
|
rescue Gem::MissingSpecError => e
|
235
396
|
logger.info("Could not find #{name}:#{version} with find_by_name, falling back to guess")
|
236
397
|
# can happen in local filesystem references
|
237
398
|
specs = resolve_path_to_gemspecs name
|
238
|
-
logger.
|
399
|
+
logger.warn "Gem #{name} #{version} from bundle not found: #{e}" if specs.nil?
|
239
400
|
next specs
|
240
401
|
end.compact
|
241
402
|
else
|
242
|
-
Solargraph.logger.warn e
|
243
|
-
raise BundleNotFoundError, "Failed to load gems from bundle at #{workspace&.directory}"
|
403
|
+
Solargraph.logger.warn "Failed to load gems from bundle at #{workspace&.directory}: #{e}"
|
244
404
|
end
|
245
405
|
end
|
246
406
|
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>]
|
@@ -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
|
|
@@ -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({
|
data/lib/solargraph/library.rb
CHANGED
@@ -327,9 +327,10 @@ module Solargraph
|
|
327
327
|
|
328
328
|
# @param query [String]
|
329
329
|
# @return [Enumerable<YARD::CodeObjects::Base>]
|
330
|
+
# @return [Array(ApiMap, Enumerable<Pin::Base>)]
|
330
331
|
def document query
|
331
332
|
sync_catalog
|
332
|
-
mutex.synchronize { api_map.
|
333
|
+
mutex.synchronize { [api_map, api_map.get_path_pins(query)] }
|
333
334
|
end
|
334
335
|
|
335
336
|
# @param query [String]
|
@@ -587,28 +588,53 @@ module Solargraph
|
|
587
588
|
# @return [void]
|
588
589
|
def cache_next_gemspec
|
589
590
|
return if @cache_progress
|
590
|
-
|
591
|
+
|
592
|
+
spec = cacheable_specs.first
|
591
593
|
return end_cache_progress unless spec
|
592
594
|
|
593
595
|
pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
rescue Errno::EINVAL => _e
|
601
|
-
logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
|
602
|
-
rescue StandardError => e
|
603
|
-
cache_errors.add spec
|
604
|
-
Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
|
605
|
-
ensure
|
606
|
-
end_cache_progress
|
596
|
+
|
597
|
+
if Yardoc.processing?(spec)
|
598
|
+
logger.info "Enqueuing cache of #{spec.name} #{spec.version} (already being processed)"
|
599
|
+
queued_gemspec_cache.push(spec)
|
600
|
+
return if pending - queued_gemspec_cache.length < 1
|
601
|
+
|
607
602
|
catalog
|
608
603
|
sync_catalog
|
604
|
+
else
|
605
|
+
logger.info "Caching #{spec.name} #{spec.version}"
|
606
|
+
Thread.new do
|
607
|
+
cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
|
608
|
+
report_cache_progress spec.name, pending
|
609
|
+
Process.wait(cache_pid)
|
610
|
+
logger.info "Cached #{spec.name} #{spec.version}"
|
611
|
+
rescue Errno::EINVAL => _e
|
612
|
+
logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
|
613
|
+
rescue StandardError => e
|
614
|
+
cache_errors.add spec
|
615
|
+
Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
|
616
|
+
ensure
|
617
|
+
end_cache_progress
|
618
|
+
catalog
|
619
|
+
sync_catalog
|
620
|
+
end
|
609
621
|
end
|
610
622
|
end
|
611
623
|
|
624
|
+
def cacheable_specs
|
625
|
+
cacheable = api_map.uncached_yard_gemspecs +
|
626
|
+
api_map.uncached_rbs_collection_gemspecs -
|
627
|
+
queued_gemspec_cache -
|
628
|
+
cache_errors.to_a
|
629
|
+
return cacheable unless cacheable.empty?
|
630
|
+
|
631
|
+
queued_gemspec_cache
|
632
|
+
end
|
633
|
+
|
634
|
+
def queued_gemspec_cache
|
635
|
+
@queued_gemspec_cache ||= []
|
636
|
+
end
|
637
|
+
|
612
638
|
# @param gem_name [String]
|
613
639
|
# @param pending [Integer]
|
614
640
|
# @return [void]
|
@@ -654,7 +680,8 @@ module Solargraph
|
|
654
680
|
api_map.catalog bench
|
655
681
|
source_map_hash.values.each { |map| find_external_requires(map) }
|
656
682
|
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
657
|
-
logger.info "#{api_map.
|
683
|
+
logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
|
684
|
+
logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
|
658
685
|
cache_next_gemspec
|
659
686
|
@sync_count = 0
|
660
687
|
end
|
data/lib/solargraph/location.rb
CHANGED
@@ -25,6 +25,19 @@ module Solargraph
|
|
25
25
|
[filename, range]
|
26
26
|
end
|
27
27
|
|
28
|
+
def <=>(other)
|
29
|
+
return nil unless other.is_a?(Location)
|
30
|
+
if filename == other.filename
|
31
|
+
range <=> other.range
|
32
|
+
else
|
33
|
+
filename <=> other.filename
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def rbs?
|
38
|
+
filename.end_with?('.rbs')
|
39
|
+
end
|
40
|
+
|
28
41
|
# @param location [self]
|
29
42
|
def contain? location
|
30
43
|
range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
|