solargraph 0.51.2 → 0.54.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 +40 -0
- data/.github/workflows/rspec.yml +1 -3
- data/.github/workflows/typecheck.yml +34 -0
- data/.yardopts +2 -2
- data/CHANGELOG.md +127 -5
- data/README.md +13 -16
- data/SPONSORS.md +1 -7
- data/lib/solargraph/api_map/cache.rb +50 -20
- data/lib/solargraph/api_map/source_to_yard.rb +17 -10
- data/lib/solargraph/api_map/store.rb +60 -15
- data/lib/solargraph/api_map.rb +282 -123
- data/lib/solargraph/bench.rb +3 -2
- data/lib/solargraph/cache.rb +29 -5
- data/lib/solargraph/complex_type/type_methods.rb +122 -39
- data/lib/solargraph/complex_type/unique_type.rb +310 -76
- data/lib/solargraph/complex_type.rb +166 -44
- data/lib/solargraph/convention.rb +0 -1
- data/lib/solargraph/converters/dd.rb +5 -0
- data/lib/solargraph/converters/dl.rb +3 -0
- data/lib/solargraph/converters/dt.rb +3 -0
- data/lib/solargraph/diagnostics/rubocop.rb +8 -7
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
- data/lib/solargraph/diagnostics/type_check.rb +1 -0
- data/lib/solargraph/diagnostics.rb +2 -2
- data/lib/solargraph/doc_map.rb +187 -0
- data/lib/solargraph/gem_pins.rb +72 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
- data/lib/solargraph/language_server/host/dispatch.rb +22 -5
- data/lib/solargraph/language_server/host/message_worker.rb +49 -5
- data/lib/solargraph/language_server/host/sources.rb +8 -65
- data/lib/solargraph/language_server/host.rb +65 -84
- data/lib/solargraph/language_server/message/base.rb +19 -12
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
- data/lib/solargraph/language_server/message/initialize.rb +19 -2
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document.rb +0 -1
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +135 -0
- data/lib/solargraph/language_server/transport/adapter.rb +16 -1
- data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +207 -111
- data/lib/solargraph/location.rb +15 -1
- data/lib/solargraph/page.rb +6 -0
- data/lib/solargraph/parser/comment_ripper.rb +4 -0
- data/lib/solargraph/parser/node_methods.rb +47 -7
- data/lib/solargraph/parser/node_processor/base.rb +11 -1
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
- data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +62 -43
- data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +57 -0
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +7 -20
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +4 -4
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +8 -6
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
- data/lib/solargraph/parser/parser_gem.rb +12 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +8 -12
- data/lib/solargraph/pin/base.rb +78 -10
- data/lib/solargraph/pin/base_variable.rb +40 -7
- data/lib/solargraph/pin/block.rb +69 -46
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +23 -3
- data/lib/solargraph/pin/common.rb +6 -6
- data/lib/solargraph/pin/conversions.rb +36 -5
- data/lib/solargraph/pin/delegated_method.rb +6 -2
- data/lib/solargraph/pin/documenting.rb +25 -32
- data/lib/solargraph/pin/instance_variable.rb +6 -2
- data/lib/solargraph/pin/local_variable.rb +13 -1
- data/lib/solargraph/pin/method.rb +205 -32
- data/lib/solargraph/pin/namespace.rb +20 -7
- data/lib/solargraph/pin/parameter.rb +41 -36
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin/reference/override.rb +2 -2
- data/lib/solargraph/pin/reference.rb +8 -0
- data/lib/solargraph/pin/search.rb +3 -3
- data/lib/solargraph/pin/signature.rb +8 -14
- data/lib/solargraph/pin.rb +4 -2
- data/lib/solargraph/range.rb +4 -6
- data/lib/solargraph/rbs_map/conversions.rb +326 -76
- data/lib/solargraph/rbs_map/core_fills.rb +16 -33
- data/lib/solargraph/rbs_map/core_map.rb +3 -13
- data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
- data/lib/solargraph/rbs_map.rb +32 -13
- data/lib/solargraph/shell.rb +95 -72
- data/lib/solargraph/source/chain/array.rb +33 -0
- data/lib/solargraph/source/chain/block_symbol.rb +13 -0
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +152 -69
- data/lib/solargraph/source/chain/constant.rb +15 -1
- data/lib/solargraph/source/chain/if.rb +23 -0
- data/lib/solargraph/source/chain/link.rb +17 -2
- data/lib/solargraph/source/chain/or.rb +2 -2
- data/lib/solargraph/source/chain/z_super.rb +3 -3
- data/lib/solargraph/source/chain.rb +85 -26
- data/lib/solargraph/source/change.rb +3 -0
- data/lib/solargraph/source/cursor.rb +16 -2
- data/lib/solargraph/source/source_chainer.rb +8 -5
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +120 -148
- data/lib/solargraph/source_map/clip.rb +16 -27
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map/mapper.rb +15 -3
- data/lib/solargraph/source_map.rb +48 -24
- data/lib/solargraph/type_checker/checks.rb +10 -2
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +150 -39
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +9 -6
- data/lib/solargraph/workspace.rb +30 -3
- data/lib/solargraph/yard_map/cache.rb +6 -0
- data/lib/solargraph/yard_map/helpers.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +16 -3
- data/lib/solargraph/yard_map/mapper.rb +1 -1
- data/lib/solargraph/yard_map/to_method.rb +11 -4
- data/lib/solargraph/yard_map.rb +1 -292
- data/lib/solargraph/yard_tags.rb +20 -0
- data/lib/solargraph/yardoc.rb +52 -0
- data/lib/solargraph.rb +6 -4
- data/solargraph.gemspec +7 -6
- metadata +71 -82
- data/lib/solargraph/api_map/bundler_methods.rb +0 -22
- data/lib/solargraph/documentor.rb +0 -76
- data/lib/solargraph/language_server/host/cataloger.rb +0 -56
- data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
- data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
- data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -50
- data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
- data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
- data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
- data/lib/solargraph/parser/legacy.rb +0 -12
- data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -153
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
- data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
- data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
- data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
- data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
- data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
- data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
- data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
- data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
- data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
- data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
- data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
- data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
- data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
- data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
- data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
- data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
- data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
- data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
- data/lib/solargraph/parser/rubyvm.rb +0 -40
- data/lib/solargraph/rbs_map/core_signs.rb +0 -33
- data/lib/yard-solargraph.rb +0 -33
data/lib/solargraph/library.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
+
require 'observer'
|
4
5
|
|
5
6
|
module Solargraph
|
6
7
|
# A Library handles coordination between a Workspace and an ApiMap.
|
7
8
|
#
|
8
9
|
class Library
|
9
10
|
include Logging
|
11
|
+
include Observable
|
10
12
|
|
11
13
|
# @return [Solargraph::Workspace]
|
12
14
|
attr_reader :workspace
|
@@ -17,12 +19,19 @@ module Solargraph
|
|
17
19
|
# @return [Source, nil]
|
18
20
|
attr_reader :current
|
19
21
|
|
22
|
+
# @return [LanguageServer::Progress, nil]
|
23
|
+
attr_reader :cache_progress
|
24
|
+
|
20
25
|
# @param workspace [Solargraph::Workspace]
|
21
26
|
# @param name [String, nil]
|
22
27
|
def initialize workspace = Solargraph::Workspace.new, name = nil
|
23
28
|
@workspace = workspace
|
24
29
|
@name = name
|
25
|
-
@
|
30
|
+
# @type [Integer, nil]
|
31
|
+
@total = nil
|
32
|
+
# @type [Source, nil]
|
33
|
+
@current = nil
|
34
|
+
@sync_count = 0
|
26
35
|
end
|
27
36
|
|
28
37
|
def inspect
|
@@ -35,7 +44,7 @@ module Solargraph
|
|
35
44
|
#
|
36
45
|
# @return [Boolean]
|
37
46
|
def synchronized?
|
38
|
-
@
|
47
|
+
@sync_count < 2
|
39
48
|
end
|
40
49
|
|
41
50
|
# Attach a source to the library.
|
@@ -47,17 +56,15 @@ module Solargraph
|
|
47
56
|
# @param source [Source, nil]
|
48
57
|
# @return [void]
|
49
58
|
def attach source
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@external_requires = nil
|
55
|
-
@synchronized = false
|
56
|
-
end
|
57
|
-
@current = source
|
58
|
-
maybe_map @current
|
59
|
-
catalog_inlock
|
59
|
+
if @current && (!source || @current.filename != source.filename) && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
|
60
|
+
source_map_hash.delete @current.filename
|
61
|
+
source_map_external_require_hash.delete @current.filename
|
62
|
+
@external_requires = nil
|
60
63
|
end
|
64
|
+
changed = source && @current != source
|
65
|
+
@current = source
|
66
|
+
maybe_map @current
|
67
|
+
catalog if changed
|
61
68
|
end
|
62
69
|
|
63
70
|
# True if the specified file is currently attached.
|
@@ -95,15 +102,10 @@ module Solargraph
|
|
95
102
|
# @param text [String] The contents of the file
|
96
103
|
# @return [Boolean] True if the file was added to the workspace.
|
97
104
|
def create filename, text
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
source = Solargraph::Source.load_string(text, filename)
|
103
|
-
workspace.merge(source)
|
104
|
-
result = true
|
105
|
-
end
|
106
|
-
result
|
105
|
+
return false unless contain?(filename) || open?(filename)
|
106
|
+
source = Solargraph::Source.load_string(text, filename)
|
107
|
+
workspace.merge(source)
|
108
|
+
true
|
107
109
|
end
|
108
110
|
|
109
111
|
# Create file sources from files on disk. A file is ignored if it is
|
@@ -112,14 +114,11 @@ module Solargraph
|
|
112
114
|
# @param filenames [Array<String>]
|
113
115
|
# @return [Boolean] True if at least one file was added to the workspace.
|
114
116
|
def create_from_disk *filenames
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
result = workspace.merge(*sources)
|
121
|
-
sources.each { |source| maybe_map source }
|
122
|
-
end
|
117
|
+
sources = filenames
|
118
|
+
.reject { |filename| File.directory?(filename) || !File.exist?(filename) }
|
119
|
+
.map { |filename| Solargraph::Source.load_string(File.read(filename), filename) }
|
120
|
+
result = workspace.merge(*sources)
|
121
|
+
sources.each { |source| maybe_map source }
|
123
122
|
result
|
124
123
|
end
|
125
124
|
|
@@ -133,10 +132,7 @@ module Solargraph
|
|
133
132
|
result = false
|
134
133
|
filenames.each do |filename|
|
135
134
|
detach filename
|
136
|
-
|
137
|
-
result ||= workspace.remove(filename)
|
138
|
-
@synchronized = !result if synchronized?
|
139
|
-
end
|
135
|
+
result ||= workspace.remove(filename)
|
140
136
|
end
|
141
137
|
result
|
142
138
|
end
|
@@ -147,11 +143,10 @@ module Solargraph
|
|
147
143
|
# @param filename [String]
|
148
144
|
# @return [void]
|
149
145
|
def close filename
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
end
|
146
|
+
return unless @current&.filename == filename
|
147
|
+
|
148
|
+
@current = nil
|
149
|
+
catalog unless workspace.has_file?(filename)
|
155
150
|
end
|
156
151
|
|
157
152
|
# Get completion suggestions at the specified file and location.
|
@@ -159,12 +154,13 @@ module Solargraph
|
|
159
154
|
# @param filename [String] The file to analyze
|
160
155
|
# @param line [Integer] The zero-based line number
|
161
156
|
# @param column [Integer] The zero-based column number
|
162
|
-
# @return [SourceMap::Completion]
|
157
|
+
# @return [SourceMap::Completion, nil]
|
163
158
|
# @todo Take a Location instead of filename/line/column
|
164
159
|
def completions_at filename, line, column
|
160
|
+
sync_catalog
|
165
161
|
position = Position.new(line, column)
|
166
162
|
cursor = Source::Cursor.new(read(filename), position)
|
167
|
-
api_map.clip(cursor).complete
|
163
|
+
mutex.synchronize { api_map.clip(cursor).complete }
|
168
164
|
rescue FileNotFoundError => e
|
169
165
|
handle_file_not_found filename, e
|
170
166
|
end
|
@@ -175,9 +171,10 @@ module Solargraph
|
|
175
171
|
# @param filename [String] The file to analyze
|
176
172
|
# @param line [Integer] The zero-based line number
|
177
173
|
# @param column [Integer] The zero-based column number
|
178
|
-
# @return [Array<Solargraph::Pin::Base
|
174
|
+
# @return [Array<Solargraph::Pin::Base>, nil]
|
179
175
|
# @todo Take filename/position instead of filename/line/column
|
180
176
|
def definitions_at filename, line, column
|
177
|
+
sync_catalog
|
181
178
|
position = Position.new(line, column)
|
182
179
|
cursor = Source::Cursor.new(read(filename), position)
|
183
180
|
if cursor.comment?
|
@@ -187,13 +184,20 @@ module Solargraph
|
|
187
184
|
rgt = source.code[offset..-1].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
|
188
185
|
if lft && rgt
|
189
186
|
tag = (lft[1] + rgt[1]).sub(/:+$/, '')
|
190
|
-
clip = api_map.clip(cursor)
|
187
|
+
clip = mutex.synchronize { api_map.clip(cursor) }
|
191
188
|
clip.translate tag
|
192
189
|
else
|
193
190
|
[]
|
194
191
|
end
|
195
192
|
else
|
196
|
-
|
193
|
+
mutex.synchronize do
|
194
|
+
clip = api_map.clip(cursor)
|
195
|
+
if cursor.assign?
|
196
|
+
[Pin::ProxyType.new(name: cursor.word, return_type: clip.infer)]
|
197
|
+
else
|
198
|
+
clip.define.map { |pin| pin.realize(api_map) }
|
199
|
+
end
|
200
|
+
end
|
197
201
|
end
|
198
202
|
rescue FileNotFoundError => e
|
199
203
|
handle_file_not_found(filename, e)
|
@@ -205,12 +209,13 @@ module Solargraph
|
|
205
209
|
# @param filename [String] The file to analyze
|
206
210
|
# @param line [Integer] The zero-based line number
|
207
211
|
# @param column [Integer] The zero-based column number
|
208
|
-
# @return [Array<Solargraph::Pin::Base
|
212
|
+
# @return [Array<Solargraph::Pin::Base>, nil]
|
209
213
|
# @todo Take filename/position instead of filename/line/column
|
210
214
|
def type_definitions_at filename, line, column
|
215
|
+
sync_catalog
|
211
216
|
position = Position.new(line, column)
|
212
217
|
cursor = Source::Cursor.new(read(filename), position)
|
213
|
-
api_map.clip(cursor).types
|
218
|
+
mutex.synchronize { api_map.clip(cursor).types }
|
214
219
|
rescue FileNotFoundError => e
|
215
220
|
handle_file_not_found filename, e
|
216
221
|
end
|
@@ -224,9 +229,10 @@ module Solargraph
|
|
224
229
|
# @return [Array<Solargraph::Pin::Base>]
|
225
230
|
# @todo Take filename/position instead of filename/line/column
|
226
231
|
def signatures_at filename, line, column
|
232
|
+
sync_catalog
|
227
233
|
position = Position.new(line, column)
|
228
234
|
cursor = Source::Cursor.new(read(filename), position)
|
229
|
-
api_map.clip(cursor).signify
|
235
|
+
mutex.synchronize { api_map.clip(cursor).signify }
|
230
236
|
end
|
231
237
|
|
232
238
|
# @param filename [String]
|
@@ -237,8 +243,9 @@ module Solargraph
|
|
237
243
|
# @return [Array<Solargraph::Range>]
|
238
244
|
# @todo Take a Location instead of filename/line/column
|
239
245
|
def references_from filename, line, column, strip: false, only: false
|
240
|
-
|
241
|
-
|
246
|
+
sync_catalog
|
247
|
+
cursor = Source::Cursor.new(read(filename), [line, column])
|
248
|
+
clip = mutex.synchronize { api_map.clip(cursor) }
|
242
249
|
pin = clip.define.first
|
243
250
|
return [] unless pin
|
244
251
|
result = []
|
@@ -251,7 +258,19 @@ module Solargraph
|
|
251
258
|
found = source.references(pin.name)
|
252
259
|
found.select! do |loc|
|
253
260
|
referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
|
254
|
-
referenced
|
261
|
+
referenced&.path == pin.path
|
262
|
+
end
|
263
|
+
if pin.path == 'Class#new'
|
264
|
+
caller = cursor.chain.base.infer(api_map, clip.send(:block), clip.locals).first
|
265
|
+
if caller.defined?
|
266
|
+
found.select! do |loc|
|
267
|
+
clip = api_map.clip_at(loc.filename, loc.range.start)
|
268
|
+
other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:block), clip.locals).first
|
269
|
+
caller == other
|
270
|
+
end
|
271
|
+
else
|
272
|
+
found.clear
|
273
|
+
end
|
255
274
|
end
|
256
275
|
# HACK: for language clients that exclude special characters from the start of variable names
|
257
276
|
if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
|
@@ -271,7 +290,8 @@ module Solargraph
|
|
271
290
|
# @param location [Location]
|
272
291
|
# @return [Array<Solargraph::Pin::Base>]
|
273
292
|
def locate_pins location
|
274
|
-
|
293
|
+
sync_catalog
|
294
|
+
mutex.synchronize { api_map.locate_pins(location).map { |pin| pin.realize(api_map) } }
|
275
295
|
end
|
276
296
|
|
277
297
|
# Match a require reference to a file.
|
@@ -283,10 +303,16 @@ module Solargraph
|
|
283
303
|
return if map.nil?
|
284
304
|
pin = map.requires.select { |p| p.location.range.contain?(location.range.start) }.first
|
285
305
|
return nil if pin.nil?
|
306
|
+
# @param full [String]
|
307
|
+
return_if_match = proc do |full|
|
308
|
+
if source_map_hash.key?(full)
|
309
|
+
return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
|
310
|
+
end
|
311
|
+
end
|
286
312
|
workspace.require_paths.each do |path|
|
287
|
-
full =
|
288
|
-
|
289
|
-
|
313
|
+
full = File.join path, pin.name
|
314
|
+
return_if_match.(full)
|
315
|
+
return_if_match.(full << ".rb")
|
290
316
|
end
|
291
317
|
nil
|
292
318
|
rescue FileNotFoundError
|
@@ -296,21 +322,24 @@ module Solargraph
|
|
296
322
|
# Get an array of pins that match a path.
|
297
323
|
#
|
298
324
|
# @param path [String]
|
299
|
-
# @return [
|
325
|
+
# @return [Enumerable<Solargraph::Pin::Base>]
|
300
326
|
def get_path_pins path
|
301
|
-
|
327
|
+
sync_catalog
|
328
|
+
mutex.synchronize { api_map.get_path_suggestions(path) }
|
302
329
|
end
|
303
330
|
|
304
331
|
# @param query [String]
|
305
|
-
# @return [
|
332
|
+
# @return [Enumerable<YARD::CodeObjects::Base>]
|
306
333
|
def document query
|
307
|
-
|
334
|
+
sync_catalog
|
335
|
+
mutex.synchronize { api_map.document query }
|
308
336
|
end
|
309
337
|
|
310
338
|
# @param query [String]
|
311
339
|
# @return [Array<String>]
|
312
340
|
def search query
|
313
|
-
|
341
|
+
sync_catalog
|
342
|
+
mutex.synchronize { api_map.search query }
|
314
343
|
end
|
315
344
|
|
316
345
|
# Get an array of all symbols in the workspace that match the query.
|
@@ -318,7 +347,8 @@ module Solargraph
|
|
318
347
|
# @param query [String]
|
319
348
|
# @return [Array<Pin::Base>]
|
320
349
|
def query_symbols query
|
321
|
-
|
350
|
+
sync_catalog
|
351
|
+
mutex.synchronize { api_map.query_symbols query }
|
322
352
|
end
|
323
353
|
|
324
354
|
# Get an array of document symbols.
|
@@ -330,15 +360,18 @@ module Solargraph
|
|
330
360
|
# @param filename [String]
|
331
361
|
# @return [Array<Solargraph::Pin::Base>]
|
332
362
|
def document_symbols filename
|
333
|
-
|
363
|
+
sync_catalog
|
364
|
+
mutex.synchronize { api_map.document_symbols(filename) }
|
334
365
|
end
|
335
366
|
|
336
367
|
# @param path [String]
|
337
|
-
# @return [
|
368
|
+
# @return [Enumerable<Solargraph::Pin::Base>]
|
338
369
|
def path_pins path
|
339
|
-
|
370
|
+
sync_catalog
|
371
|
+
mutex.synchronize { api_map.get_path_suggestions(path) }
|
340
372
|
end
|
341
373
|
|
374
|
+
# @return [Array<SourceMap>]
|
342
375
|
def source_maps
|
343
376
|
source_map_hash.values
|
344
377
|
end
|
@@ -361,10 +394,10 @@ module Solargraph
|
|
361
394
|
# everything in the workspace should get diagnosed, or if there should
|
362
395
|
# be an option to do so.
|
363
396
|
#
|
397
|
+
sync_catalog
|
364
398
|
return [] unless open?(filename)
|
365
399
|
result = []
|
366
400
|
source = read(filename)
|
367
|
-
catalog
|
368
401
|
repargs = {}
|
369
402
|
workspace.config.reporters.each do |line|
|
370
403
|
if line == 'all!'
|
@@ -390,19 +423,10 @@ module Solargraph
|
|
390
423
|
#
|
391
424
|
# @return [void]
|
392
425
|
def catalog
|
393
|
-
|
394
|
-
catalog_inlock
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
private def catalog_inlock
|
399
|
-
return if synchronized?
|
400
|
-
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
401
|
-
api_map.catalog bench
|
402
|
-
@synchronized = true
|
403
|
-
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)" if logger.info?
|
426
|
+
@sync_count += 1
|
404
427
|
end
|
405
428
|
|
429
|
+
# @return [Bench]
|
406
430
|
def bench
|
407
431
|
Bench.new(
|
408
432
|
source_maps: source_map_hash.values,
|
@@ -437,16 +461,12 @@ module Solargraph
|
|
437
461
|
# @param source [Source]
|
438
462
|
# @return [Boolean] True if the source was merged into the workspace.
|
439
463
|
def merge source
|
440
|
-
|
441
|
-
|
442
|
-
mutex.synchronize do
|
443
|
-
result = workspace.merge(source)
|
444
|
-
maybe_map source
|
445
|
-
end
|
446
|
-
# catalog
|
464
|
+
result = workspace.merge(source)
|
465
|
+
maybe_map source
|
447
466
|
result
|
448
467
|
end
|
449
468
|
|
469
|
+
# @return [Hash{String => SourceMap}]
|
450
470
|
def source_map_hash
|
451
471
|
@source_map_hash ||= {}
|
452
472
|
end
|
@@ -455,52 +475,56 @@ module Solargraph
|
|
455
475
|
(workspace.filenames - source_map_hash.keys).empty?
|
456
476
|
end
|
457
477
|
|
478
|
+
# @return [SourceMap, Boolean]
|
458
479
|
def next_map
|
459
480
|
return false if mapped?
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
source_map_hash[src.filename]
|
468
|
-
else
|
469
|
-
false
|
470
|
-
end
|
481
|
+
src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
|
482
|
+
if src
|
483
|
+
Logging.logger.debug "Mapping #{src.filename}"
|
484
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
485
|
+
source_map_hash[src.filename]
|
486
|
+
else
|
487
|
+
false
|
471
488
|
end
|
472
489
|
end
|
473
490
|
|
491
|
+
# @return [self]
|
474
492
|
def map!
|
475
493
|
workspace.sources.each do |src|
|
476
494
|
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
477
|
-
find_external_requires
|
495
|
+
find_external_requires source_map_hash[src.filename]
|
478
496
|
end
|
479
497
|
self
|
480
498
|
end
|
481
499
|
|
500
|
+
# @return [Array<Solargraph::Pin::Base>]
|
482
501
|
def pins
|
483
502
|
@pins ||= []
|
484
503
|
end
|
485
504
|
|
505
|
+
# @return [Set<String>]
|
486
506
|
def external_requires
|
487
507
|
@external_requires ||= source_map_external_require_hash.values.flatten.to_set
|
488
508
|
end
|
489
509
|
|
490
510
|
private
|
491
511
|
|
512
|
+
# @return [Hash{String => Set<String>}]
|
492
513
|
def source_map_external_require_hash
|
493
514
|
@source_map_external_require_hash ||= {}
|
494
515
|
end
|
495
516
|
|
496
517
|
# @param source_map [SourceMap]
|
518
|
+
# @return [void]
|
497
519
|
def find_external_requires source_map
|
498
520
|
new_set = source_map.requires.map(&:name).to_set
|
499
521
|
# return if new_set == source_map_external_require_hash[source_map.filename]
|
522
|
+
_filenames = nil
|
523
|
+
filenames = ->{ _filenames ||= workspace.filenames.to_set }
|
500
524
|
source_map_external_require_hash[source_map.filename] = new_set.reject do |path|
|
501
525
|
workspace.require_paths.any? do |base|
|
502
|
-
full =
|
503
|
-
|
526
|
+
full = File.join(base, path)
|
527
|
+
filenames[].include?(full) or filenames[].include?(full << ".rb")
|
504
528
|
end
|
505
529
|
end
|
506
530
|
@external_requires = nil
|
@@ -530,6 +554,9 @@ module Solargraph
|
|
530
554
|
workspace.source(filename)
|
531
555
|
end
|
532
556
|
|
557
|
+
# @param filename [String]
|
558
|
+
# @param error [FileNotFoundError]
|
559
|
+
# @return [nil]
|
533
560
|
def handle_file_not_found filename, error
|
534
561
|
if workspace.source(filename)
|
535
562
|
Solargraph.logger.debug "#{filename} is not cataloged in the ApiMap"
|
@@ -539,28 +566,97 @@ module Solargraph
|
|
539
566
|
end
|
540
567
|
end
|
541
568
|
|
569
|
+
# @param source [Source, nil]
|
570
|
+
# @return [void]
|
542
571
|
def maybe_map source
|
543
572
|
return unless source
|
544
573
|
return unless @current == source || workspace.has_file?(source.filename)
|
545
574
|
if source_map_hash.key?(source.filename)
|
546
|
-
|
547
|
-
|
548
|
-
source.synchronized?
|
549
|
-
if source.synchronized?
|
550
|
-
new_map = Solargraph::SourceMap.map(source)
|
551
|
-
unless source_map_hash[source.filename].try_merge!(new_map)
|
552
|
-
source_map_hash[source.filename] = new_map
|
553
|
-
find_external_requires(source_map_hash[source.filename])
|
554
|
-
@synchronized = false
|
555
|
-
end
|
556
|
-
else
|
557
|
-
# @todo Smelly instance variable access
|
558
|
-
source_map_hash[source.filename].instance_variable_set(:@source, source)
|
559
|
-
end
|
575
|
+
new_map = Solargraph::SourceMap.map(source)
|
576
|
+
source_map_hash[source.filename] = new_map
|
560
577
|
else
|
561
578
|
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
562
|
-
|
563
|
-
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
# @return [Set<Gem::Specification>]
|
583
|
+
def cache_errors
|
584
|
+
@cache_errors ||= Set.new
|
585
|
+
end
|
586
|
+
|
587
|
+
# @return [void]
|
588
|
+
def cache_next_gemspec
|
589
|
+
return if @cache_progress
|
590
|
+
spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec) }
|
591
|
+
return end_cache_progress unless spec
|
592
|
+
|
593
|
+
pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
|
594
|
+
logger.info "Caching #{spec.name} #{spec.version}"
|
595
|
+
Thread.new do
|
596
|
+
cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
|
597
|
+
report_cache_progress spec.name, pending
|
598
|
+
Process.wait(cache_pid)
|
599
|
+
logger.info "Cached #{spec.name} #{spec.version}"
|
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
|
607
|
+
catalog
|
608
|
+
sync_catalog
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
# @param gem_name [String]
|
613
|
+
# @param pending [Integer]
|
614
|
+
# @return [void]
|
615
|
+
def report_cache_progress gem_name, pending
|
616
|
+
@total ||= pending
|
617
|
+
@total = pending if pending > @total
|
618
|
+
finished = @total - pending
|
619
|
+
pct = if @total.zero?
|
620
|
+
0
|
621
|
+
else
|
622
|
+
((finished.to_f / @total.to_f) * 100).to_i
|
623
|
+
end
|
624
|
+
message = "#{gem_name}#{pending > 0 ? " (+#{pending})" : ''}"
|
625
|
+
# "
|
626
|
+
if @cache_progress
|
627
|
+
@cache_progress.report(message, pct)
|
628
|
+
else
|
629
|
+
@cache_progress = LanguageServer::Progress.new('Caching gem')
|
630
|
+
# If we don't send both a begin and a report, the progress notification
|
631
|
+
# might get stuck in the status bar forever
|
632
|
+
@cache_progress.begin(message, pct)
|
633
|
+
changed
|
634
|
+
notify_observers @cache_progress
|
635
|
+
@cache_progress.report(message, pct)
|
636
|
+
end
|
637
|
+
changed
|
638
|
+
notify_observers @cache_progress
|
639
|
+
end
|
640
|
+
|
641
|
+
# @return [void]
|
642
|
+
def end_cache_progress
|
643
|
+
changed if @cache_progress&.finish('done')
|
644
|
+
notify_observers @cache_progress
|
645
|
+
@cache_progress = nil
|
646
|
+
@total = nil
|
647
|
+
end
|
648
|
+
|
649
|
+
def sync_catalog
|
650
|
+
return if @sync_count == 0
|
651
|
+
|
652
|
+
mutex.synchronize do
|
653
|
+
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
654
|
+
api_map.catalog bench
|
655
|
+
source_map_hash.values.each { |map| find_external_requires(map) }
|
656
|
+
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
657
|
+
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
658
|
+
cache_next_gemspec
|
659
|
+
@sync_count = 0
|
564
660
|
end
|
565
661
|
end
|
566
662
|
end
|
data/lib/solargraph/location.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Solargraph
|
4
|
-
# A section of text identified by its filename
|
4
|
+
# A pointer to a section of source text identified by its filename
|
5
|
+
# and Range.
|
5
6
|
#
|
6
7
|
class Location
|
7
8
|
# @return [String]
|
@@ -17,6 +18,11 @@ module Solargraph
|
|
17
18
|
@range = range
|
18
19
|
end
|
19
20
|
|
21
|
+
# @param location [self]
|
22
|
+
def contain? location
|
23
|
+
range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
|
24
|
+
end
|
25
|
+
|
20
26
|
# @return [Hash]
|
21
27
|
def to_hash
|
22
28
|
{
|
@@ -25,6 +31,14 @@ module Solargraph
|
|
25
31
|
}
|
26
32
|
end
|
27
33
|
|
34
|
+
# @param node [Parser::AST::Node, nil]
|
35
|
+
def self.from_node(node)
|
36
|
+
return nil if node.nil? || node.loc.nil?
|
37
|
+
range = Range.from_node(node)
|
38
|
+
self.new(node.loc.expression.source_buffer.name, range)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param other [BasicObject]
|
28
42
|
def == other
|
29
43
|
return false unless other.is_a?(Location)
|
30
44
|
filename == other.filename and range == other.range
|
data/lib/solargraph/page.rb
CHANGED
@@ -7,6 +7,12 @@ require 'cgi'
|
|
7
7
|
|
8
8
|
module Solargraph
|
9
9
|
class Page
|
10
|
+
# @todo This method directive is necessary because OpenStruct.new confuses
|
11
|
+
# the typechecker.
|
12
|
+
# @!method self.new(locals, render_method)
|
13
|
+
# @param locals[Hash]
|
14
|
+
# @param render_method [Proc]
|
15
|
+
# @return [Binder]
|
10
16
|
class Binder < OpenStruct
|
11
17
|
# @param locals [Hash]
|
12
18
|
# @param render_method [Proc]
|
@@ -3,6 +3,9 @@ require 'ripper'
|
|
3
3
|
module Solargraph
|
4
4
|
module Parser
|
5
5
|
class CommentRipper < Ripper::SexpBuilderPP
|
6
|
+
# @param src [String]
|
7
|
+
# @param filename [String]
|
8
|
+
# @param lineno [Integer]
|
6
9
|
def initialize src, filename = '(ripper)', lineno = 0
|
7
10
|
super
|
8
11
|
@buffer = src
|
@@ -42,6 +45,7 @@ module Solargraph
|
|
42
45
|
result
|
43
46
|
end
|
44
47
|
|
48
|
+
# @return [Hash{Integer => String}]
|
45
49
|
def parse
|
46
50
|
@comments = {}
|
47
51
|
super
|