solargraph 0.58.1 → 0.58.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/.gitignore +1 -0
- data/CHANGELOG.md +7 -1
- data/lib/solargraph/api_map/cache.rb +110 -110
- data/lib/solargraph/api_map/constants.rb +279 -279
- data/lib/solargraph/api_map/index.rb +193 -193
- data/lib/solargraph/api_map/source_to_yard.rb +97 -97
- data/lib/solargraph/api_map/store.rb +384 -384
- data/lib/solargraph/api_map.rb +945 -945
- data/lib/solargraph/complex_type/type_methods.rb +228 -228
- data/lib/solargraph/complex_type/unique_type.rb +482 -482
- data/lib/solargraph/complex_type.rb +444 -444
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -91
- data/lib/solargraph/convention/data_definition.rb +105 -105
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -61
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -102
- data/lib/solargraph/convention/struct_definition.rb +164 -164
- data/lib/solargraph/diagnostics/require_not_found.rb +53 -53
- data/lib/solargraph/diagnostics/rubocop.rb +118 -118
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +68 -68
- data/lib/solargraph/diagnostics/type_check.rb +55 -55
- data/lib/solargraph/doc_map.rb +439 -439
- data/lib/solargraph/equality.rb +34 -34
- data/lib/solargraph/gem_pins.rb +98 -98
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
- data/lib/solargraph/language_server/host/dispatch.rb +130 -130
- data/lib/solargraph/language_server/host/message_worker.rb +112 -112
- data/lib/solargraph/language_server/host/sources.rb +99 -99
- data/lib/solargraph/language_server/host.rb +878 -878
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +114 -114
- data/lib/solargraph/language_server/message/extended/document.rb +23 -23
- data/lib/solargraph/language_server/message/text_document/completion.rb +56 -56
- data/lib/solargraph/language_server/message/text_document/definition.rb +40 -40
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +26 -26
- data/lib/solargraph/language_server/message/text_document/formatting.rb +148 -148
- data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -24
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -25
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -23
- data/lib/solargraph/library.rb +683 -683
- data/lib/solargraph/location.rb +82 -82
- data/lib/solargraph/logging.rb +37 -37
- data/lib/solargraph/parser/comment_ripper.rb +69 -69
- data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -255
- data/lib/solargraph/parser/node_processor/base.rb +92 -92
- data/lib/solargraph/parser/node_processor.rb +62 -62
- data/lib/solargraph/parser/parser_gem/class_methods.rb +149 -149
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +166 -166
- data/lib/solargraph/parser/parser_gem/node_methods.rb +486 -486
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +59 -59
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +15 -15
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +53 -53
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -23
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +40 -40
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +29 -29
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +59 -59
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +38 -38
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +52 -52
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +291 -291
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -29
- data/lib/solargraph/parser/parser_gem/node_processors.rb +70 -70
- data/lib/solargraph/parser/region.rb +69 -69
- data/lib/solargraph/parser/snippet.rb +17 -17
- data/lib/solargraph/pin/base.rb +729 -729
- data/lib/solargraph/pin/base_variable.rb +126 -126
- data/lib/solargraph/pin/block.rb +104 -104
- data/lib/solargraph/pin/breakable.rb +9 -9
- data/lib/solargraph/pin/callable.rb +231 -231
- data/lib/solargraph/pin/closure.rb +72 -72
- data/lib/solargraph/pin/common.rb +79 -79
- data/lib/solargraph/pin/conversions.rb +123 -123
- data/lib/solargraph/pin/delegated_method.rb +120 -120
- data/lib/solargraph/pin/documenting.rb +114 -114
- data/lib/solargraph/pin/instance_variable.rb +34 -34
- data/lib/solargraph/pin/keyword.rb +20 -20
- data/lib/solargraph/pin/local_variable.rb +75 -75
- data/lib/solargraph/pin/method.rb +672 -672
- data/lib/solargraph/pin/method_alias.rb +34 -34
- data/lib/solargraph/pin/namespace.rb +115 -115
- data/lib/solargraph/pin/parameter.rb +275 -275
- data/lib/solargraph/pin/proxy_type.rb +39 -39
- data/lib/solargraph/pin/reference/override.rb +47 -47
- data/lib/solargraph/pin/reference/superclass.rb +15 -15
- data/lib/solargraph/pin/reference.rb +39 -39
- data/lib/solargraph/pin/search.rb +61 -61
- data/lib/solargraph/pin/signature.rb +61 -61
- data/lib/solargraph/pin/symbol.rb +53 -53
- data/lib/solargraph/pin/until.rb +18 -18
- data/lib/solargraph/pin/while.rb +18 -18
- data/lib/solargraph/pin.rb +44 -44
- data/lib/solargraph/pin_cache.rb +245 -245
- data/lib/solargraph/position.rb +132 -119
- data/lib/solargraph/range.rb +112 -112
- data/lib/solargraph/rbs_map/conversions.rb +823 -823
- data/lib/solargraph/rbs_map/core_map.rb +58 -58
- data/lib/solargraph/rbs_map/stdlib_map.rb +43 -43
- data/lib/solargraph/rbs_map.rb +163 -163
- data/lib/solargraph/shell.rb +352 -352
- data/lib/solargraph/source/chain/call.rb +337 -337
- data/lib/solargraph/source/chain/constant.rb +26 -26
- data/lib/solargraph/source/chain/hash.rb +34 -34
- data/lib/solargraph/source/chain/if.rb +28 -28
- data/lib/solargraph/source/chain/instance_variable.rb +13 -13
- data/lib/solargraph/source/chain/literal.rb +48 -48
- data/lib/solargraph/source/chain/or.rb +23 -23
- data/lib/solargraph/source/chain.rb +291 -291
- data/lib/solargraph/source/change.rb +82 -82
- data/lib/solargraph/source/cursor.rb +166 -166
- data/lib/solargraph/source/source_chainer.rb +194 -194
- data/lib/solargraph/source/updater.rb +55 -55
- data/lib/solargraph/source.rb +498 -498
- data/lib/solargraph/source_map/clip.rb +226 -226
- data/lib/solargraph/source_map/data.rb +34 -34
- data/lib/solargraph/source_map/mapper.rb +259 -259
- data/lib/solargraph/source_map.rb +212 -212
- data/lib/solargraph/type_checker/checks.rb +124 -124
- data/lib/solargraph/type_checker/param_def.rb +37 -37
- data/lib/solargraph/type_checker/problem.rb +32 -32
- data/lib/solargraph/type_checker/rules.rb +84 -84
- data/lib/solargraph/type_checker.rb +814 -814
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +255 -255
- data/lib/solargraph/workspace/require_paths.rb +97 -97
- data/lib/solargraph/workspace.rb +220 -220
- data/lib/solargraph/yard_map/helpers.rb +44 -44
- data/lib/solargraph/yard_map/mapper/to_method.rb +130 -130
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +31 -31
- data/lib/solargraph/yard_map/mapper.rb +79 -79
- data/lib/solargraph/yard_map/to_method.rb +89 -89
- data/lib/solargraph/yardoc.rb +87 -87
- data/lib/solargraph.rb +105 -105
- data/rbs_collection.yaml +1 -1
- metadata +12 -12
- /data/{sig → rbs}/shims/ast/0/node.rbs +0 -0
- /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
data/lib/solargraph/shell.rb
CHANGED
|
@@ -1,352 +1,352 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'benchmark'
|
|
4
|
-
require 'thor'
|
|
5
|
-
require 'yard'
|
|
6
|
-
|
|
7
|
-
module Solargraph
|
|
8
|
-
class Shell < Thor
|
|
9
|
-
include Solargraph::ServerMethods
|
|
10
|
-
|
|
11
|
-
# Tell Thor to ensure the process exits with status 1 if any error happens.
|
|
12
|
-
def self.exit_on_failure?
|
|
13
|
-
true
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
map %w[--version -v] => :version
|
|
17
|
-
|
|
18
|
-
desc "--version, -v", "Print the version"
|
|
19
|
-
# @return [void]
|
|
20
|
-
def version
|
|
21
|
-
puts Solargraph::VERSION
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
desc 'socket', 'Run a Solargraph socket server'
|
|
25
|
-
option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
|
|
26
|
-
option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
|
|
27
|
-
# @return [void]
|
|
28
|
-
def socket
|
|
29
|
-
require 'backport'
|
|
30
|
-
port = options[:port]
|
|
31
|
-
port = available_port if port.zero?
|
|
32
|
-
Backport.run do
|
|
33
|
-
Signal.trap("INT") do
|
|
34
|
-
Backport.stop
|
|
35
|
-
end
|
|
36
|
-
Signal.trap("TERM") do
|
|
37
|
-
Backport.stop
|
|
38
|
-
end
|
|
39
|
-
# @sg-ignore Wrong argument type for Backport.prepare_tcp_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
|
|
40
|
-
Backport.prepare_tcp_server host: options[:host], port: port, adapter: Solargraph::LanguageServer::Transport::Adapter
|
|
41
|
-
STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
desc 'stdio', 'Run a Solargraph stdio server'
|
|
46
|
-
# @return [void]
|
|
47
|
-
def stdio
|
|
48
|
-
require 'backport'
|
|
49
|
-
Backport.run do
|
|
50
|
-
Signal.trap("INT") do
|
|
51
|
-
Backport.stop
|
|
52
|
-
end
|
|
53
|
-
Signal.trap("TERM") do
|
|
54
|
-
Backport.stop
|
|
55
|
-
end
|
|
56
|
-
# @sg-ignore Wrong argument type for Backport.prepare_stdio_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
|
|
57
|
-
Backport.prepare_stdio_server adapter: Solargraph::LanguageServer::Transport::Adapter
|
|
58
|
-
STDERR.puts "Solargraph is listening on stdio PID=#{Process.pid}"
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
|
|
63
|
-
option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
|
|
64
|
-
# @param directory [String]
|
|
65
|
-
# @return [void]
|
|
66
|
-
def config(directory = '.')
|
|
67
|
-
matches = []
|
|
68
|
-
if options[:extensions]
|
|
69
|
-
Gem::Specification.each do |g|
|
|
70
|
-
if g.name.match(/^solargraph\-[A-Za-z0-9_\-]*?\-ext/)
|
|
71
|
-
require g.name
|
|
72
|
-
matches.push g.name
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
conf = Solargraph::Workspace::Config.new.raw_data
|
|
77
|
-
unless matches.empty?
|
|
78
|
-
matches.each do |m|
|
|
79
|
-
conf['extensions'].push m
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
# @param file [File]
|
|
83
|
-
File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
|
|
84
|
-
file.puts conf.to_yaml
|
|
85
|
-
end
|
|
86
|
-
STDOUT.puts "Configuration file initialized."
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
desc 'clear', 'Delete all cached documentation'
|
|
90
|
-
long_desc %(
|
|
91
|
-
This command will delete all core and gem documentation from the cache.
|
|
92
|
-
)
|
|
93
|
-
# @return [void]
|
|
94
|
-
def clear
|
|
95
|
-
puts "Deleting all cached documentation (gems, core and stdlib)"
|
|
96
|
-
Solargraph::PinCache.clear
|
|
97
|
-
end
|
|
98
|
-
map 'clear-cache' => :clear
|
|
99
|
-
map 'clear-cores' => :clear
|
|
100
|
-
|
|
101
|
-
desc 'cache', 'Cache a gem', hide: true
|
|
102
|
-
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
103
|
-
# @return [void]
|
|
104
|
-
# @param gem [String]
|
|
105
|
-
# @param version [String, nil]
|
|
106
|
-
def cache gem, version = nil
|
|
107
|
-
api_map = Solargraph::ApiMap.load(Dir.pwd)
|
|
108
|
-
spec = Gem::Specification.find_by_name(gem, version)
|
|
109
|
-
api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
|
|
113
|
-
long_desc %(
|
|
114
|
-
Specify one or more gem names to clear. 'core' or 'stdlib' may
|
|
115
|
-
also be specified to clear cached system documentation.
|
|
116
|
-
Documentation will be regenerated as needed.
|
|
117
|
-
)
|
|
118
|
-
# @param gems [Array<String>]
|
|
119
|
-
# @return [void]
|
|
120
|
-
def uncache *gems
|
|
121
|
-
raise ArgumentError, 'No gems specified.' if gems.empty?
|
|
122
|
-
gems.each do |gem|
|
|
123
|
-
if gem == 'core'
|
|
124
|
-
PinCache.uncache_core
|
|
125
|
-
next
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
if gem == 'stdlib'
|
|
129
|
-
PinCache.uncache_stdlib
|
|
130
|
-
next
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
spec = Gem::Specification.find_by_name(gem)
|
|
134
|
-
PinCache.uncache_gem(spec, out: $stdout)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
|
|
139
|
-
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
140
|
-
# @param names [Array<String>]
|
|
141
|
-
# @return [void]
|
|
142
|
-
def gems *names
|
|
143
|
-
api_map = ApiMap.load('.')
|
|
144
|
-
if names.empty?
|
|
145
|
-
Gem::Specification.to_a.each { |spec| do_cache spec, api_map }
|
|
146
|
-
STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
|
|
147
|
-
else
|
|
148
|
-
names.each do |name|
|
|
149
|
-
spec = Gem::Specification.find_by_name(*name.split('='))
|
|
150
|
-
do_cache spec, api_map
|
|
151
|
-
rescue Gem::MissingSpecError
|
|
152
|
-
warn "Gem '#{name}' not found"
|
|
153
|
-
end
|
|
154
|
-
STDERR.puts "Documentation cached for #{names.count} gems."
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
desc 'reporters', 'Get a list of diagnostics reporters'
|
|
159
|
-
# @return [void]
|
|
160
|
-
def reporters
|
|
161
|
-
puts Solargraph::Diagnostics.reporters
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
desc 'typecheck [FILE(s)]', 'Run the type checker'
|
|
165
|
-
long_desc %(
|
|
166
|
-
Perform type checking on one or more files in a workspace. Check the
|
|
167
|
-
entire workspace if no files are specified.
|
|
168
|
-
|
|
169
|
-
Type checking levels are normal, typed, strict, and strong.
|
|
170
|
-
)
|
|
171
|
-
option :level, type: :string, aliases: [:mode, :m, :l], desc: 'Type checking level', default: 'normal'
|
|
172
|
-
option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
|
|
173
|
-
# @return [void]
|
|
174
|
-
def typecheck *files
|
|
175
|
-
directory = File.realpath(options[:directory])
|
|
176
|
-
workspace = Solargraph::Workspace.new(directory)
|
|
177
|
-
level = options[:level].to_sym
|
|
178
|
-
rules = workspace.rules(level)
|
|
179
|
-
api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
|
|
180
|
-
probcount = 0
|
|
181
|
-
if files.empty?
|
|
182
|
-
files = api_map.source_maps.map(&:filename)
|
|
183
|
-
else
|
|
184
|
-
files.map! { |file| File.realpath(file) }
|
|
185
|
-
end
|
|
186
|
-
filecount = 0
|
|
187
|
-
|
|
188
|
-
time = Benchmark.measure {
|
|
189
|
-
files.each do |file|
|
|
190
|
-
checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym, workspace: workspace)
|
|
191
|
-
problems = checker.problems
|
|
192
|
-
next if problems.empty?
|
|
193
|
-
problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
|
|
194
|
-
puts problems.map { |prob| "#{prob.location.filename}:#{prob.location.range.start.line + 1} - #{prob.message}" }.join("\n")
|
|
195
|
-
filecount += 1
|
|
196
|
-
probcount += problems.length
|
|
197
|
-
end
|
|
198
|
-
# "
|
|
199
|
-
}
|
|
200
|
-
puts "Typecheck finished in #{time.real} seconds."
|
|
201
|
-
puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
|
|
202
|
-
# "
|
|
203
|
-
exit 1 if probcount > 0
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
desc 'scan', 'Test the workspace for problems'
|
|
207
|
-
long_desc %(
|
|
208
|
-
A scan loads the entire workspace to make sure that the ASTs and
|
|
209
|
-
maps do not raise errors during analysis. It does not perform any type
|
|
210
|
-
checking or validation; it only confirms that the analysis itself is
|
|
211
|
-
error-free.
|
|
212
|
-
)
|
|
213
|
-
option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
|
|
214
|
-
option :verbose, type: :boolean, aliases: :v, desc: 'Verbose output', default: false
|
|
215
|
-
# @return [void]
|
|
216
|
-
def scan
|
|
217
|
-
directory = File.realpath(options[:directory])
|
|
218
|
-
# @type [Solargraph::ApiMap, nil]
|
|
219
|
-
api_map = nil
|
|
220
|
-
time = Benchmark.measure {
|
|
221
|
-
api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
|
|
222
|
-
api_map.pins.each do |pin|
|
|
223
|
-
begin
|
|
224
|
-
puts pin_description(pin) if options[:verbose]
|
|
225
|
-
pin.typify api_map
|
|
226
|
-
pin.probe api_map
|
|
227
|
-
rescue StandardError => e
|
|
228
|
-
STDERR.puts "Error testing #{pin_description(pin)} #{pin.location ? "at #{pin.location.filename}:#{pin.location.range.start.line + 1}" : ''}"
|
|
229
|
-
STDERR.puts "[#{e.class}]: #{e.message}"
|
|
230
|
-
STDERR.puts e.backtrace.join("\n")
|
|
231
|
-
exit 1
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
}
|
|
235
|
-
puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
desc 'list', 'List the files in the workspace and the total count'
|
|
239
|
-
option :count, type: :boolean, aliases: :c, desc: 'Display the file count only', default: false
|
|
240
|
-
option :directory, type: :string, aliases: :d, desc: 'The directory to read', default: '.'
|
|
241
|
-
# @return [void]
|
|
242
|
-
def list
|
|
243
|
-
workspace = Solargraph::Workspace.new(options[:directory])
|
|
244
|
-
puts workspace.filenames unless options[:count]
|
|
245
|
-
puts "#{workspace.filenames.length} files total."
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
desc 'pin [PATH]', 'Describe a pin', hide: true
|
|
249
|
-
option :rbs, type: :boolean, desc: 'Output the pin as RBS', default: false
|
|
250
|
-
option :typify, type: :boolean, desc: 'Output the calculated return type of the pin from annotations', default: false
|
|
251
|
-
option :references, type: :boolean, desc: 'Show references', default: false
|
|
252
|
-
option :probe, type: :boolean, desc: 'Output the calculated return type of the pin from annotations and inference', default: false
|
|
253
|
-
option :stack, type: :boolean, desc: 'Show entire stack of a method pin by including definitions in superclasses', default: false
|
|
254
|
-
# @param path [String] The path to the method pin, e.g. 'Class#method' or 'Class.method'
|
|
255
|
-
# @return [void]
|
|
256
|
-
def pin path
|
|
257
|
-
api_map = Solargraph::ApiMap.load_with_cache('.', $stderr)
|
|
258
|
-
is_method = path.include?('#') || path.include?('.')
|
|
259
|
-
if is_method && options[:stack]
|
|
260
|
-
scope, ns, meth = if path.include? '#'
|
|
261
|
-
[:instance, *path.split('#', 2)]
|
|
262
|
-
else
|
|
263
|
-
[:class, *path.split('.', 2)]
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
# @sg-ignore Wrong argument type for
|
|
267
|
-
# Solargraph::ApiMap#get_method_stack: rooted_tag
|
|
268
|
-
# expected String, received Array<String>
|
|
269
|
-
pins = api_map.get_method_stack(ns, meth, scope: scope)
|
|
270
|
-
else
|
|
271
|
-
pins = api_map.get_path_pins path
|
|
272
|
-
end
|
|
273
|
-
# @type [Hash{Symbol => Pin::Base}]
|
|
274
|
-
references = {}
|
|
275
|
-
pin = pins.first
|
|
276
|
-
case pin
|
|
277
|
-
when nil
|
|
278
|
-
$stderr.puts "Pin not found for path '#{path}'"
|
|
279
|
-
exit 1
|
|
280
|
-
when Pin::Namespace
|
|
281
|
-
if options[:references]
|
|
282
|
-
superclass_tag = api_map.qualify_superclass(pin.return_type.tag)
|
|
283
|
-
superclass_pin = api_map.get_path_pins(superclass_tag).first if superclass_tag
|
|
284
|
-
references[:superclass] = superclass_pin if superclass_pin
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
pins.each do |pin|
|
|
289
|
-
if options[:typify] || options[:probe]
|
|
290
|
-
type = ComplexType::UNDEFINED
|
|
291
|
-
type = pin.typify(api_map) if options[:typify]
|
|
292
|
-
type = pin.probe(api_map) if options[:probe] && type.undefined?
|
|
293
|
-
print_type(type)
|
|
294
|
-
next
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
print_pin(pin)
|
|
298
|
-
end
|
|
299
|
-
references.each do |key, refpin|
|
|
300
|
-
puts "\n# #{key.to_s.capitalize}:\n\n"
|
|
301
|
-
print_pin(refpin)
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
private
|
|
306
|
-
|
|
307
|
-
# @param pin [Solargraph::Pin::Base]
|
|
308
|
-
# @return [String]
|
|
309
|
-
def pin_description pin
|
|
310
|
-
desc = if pin.path.nil? || pin.path.empty?
|
|
311
|
-
if pin.closure
|
|
312
|
-
"#{pin.closure.path} | #{pin.name}"
|
|
313
|
-
else
|
|
314
|
-
"#{pin.context.namespace} | #{pin.name}"
|
|
315
|
-
end
|
|
316
|
-
else
|
|
317
|
-
pin.path
|
|
318
|
-
end
|
|
319
|
-
desc += " (#{pin.location.filename} #{pin.location.range.start.line})" if pin.location
|
|
320
|
-
desc
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
# @param gemspec [Gem::Specification]
|
|
324
|
-
# @param api_map [ApiMap]
|
|
325
|
-
# @return [void]
|
|
326
|
-
def do_cache gemspec, api_map
|
|
327
|
-
# @todo if the rebuild: option is passed as a positional arg,
|
|
328
|
-
# typecheck doesn't complain on the below line
|
|
329
|
-
api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
# @param type [ComplexType]
|
|
333
|
-
# @return [void]
|
|
334
|
-
def print_type(type)
|
|
335
|
-
if options[:rbs]
|
|
336
|
-
puts type.to_rbs
|
|
337
|
-
else
|
|
338
|
-
puts type.rooted_tag
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
# @param pin [Solargraph::Pin::Base]
|
|
343
|
-
# @return [void]
|
|
344
|
-
def print_pin(pin)
|
|
345
|
-
if options[:rbs]
|
|
346
|
-
puts pin.to_rbs
|
|
347
|
-
else
|
|
348
|
-
puts pin.inspect
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
require 'thor'
|
|
5
|
+
require 'yard'
|
|
6
|
+
|
|
7
|
+
module Solargraph
|
|
8
|
+
class Shell < Thor
|
|
9
|
+
include Solargraph::ServerMethods
|
|
10
|
+
|
|
11
|
+
# Tell Thor to ensure the process exits with status 1 if any error happens.
|
|
12
|
+
def self.exit_on_failure?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
map %w[--version -v] => :version
|
|
17
|
+
|
|
18
|
+
desc "--version, -v", "Print the version"
|
|
19
|
+
# @return [void]
|
|
20
|
+
def version
|
|
21
|
+
puts Solargraph::VERSION
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc 'socket', 'Run a Solargraph socket server'
|
|
25
|
+
option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
|
|
26
|
+
option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
|
|
27
|
+
# @return [void]
|
|
28
|
+
def socket
|
|
29
|
+
require 'backport'
|
|
30
|
+
port = options[:port]
|
|
31
|
+
port = available_port if port.zero?
|
|
32
|
+
Backport.run do
|
|
33
|
+
Signal.trap("INT") do
|
|
34
|
+
Backport.stop
|
|
35
|
+
end
|
|
36
|
+
Signal.trap("TERM") do
|
|
37
|
+
Backport.stop
|
|
38
|
+
end
|
|
39
|
+
# @sg-ignore Wrong argument type for Backport.prepare_tcp_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
|
|
40
|
+
Backport.prepare_tcp_server host: options[:host], port: port, adapter: Solargraph::LanguageServer::Transport::Adapter
|
|
41
|
+
STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc 'stdio', 'Run a Solargraph stdio server'
|
|
46
|
+
# @return [void]
|
|
47
|
+
def stdio
|
|
48
|
+
require 'backport'
|
|
49
|
+
Backport.run do
|
|
50
|
+
Signal.trap("INT") do
|
|
51
|
+
Backport.stop
|
|
52
|
+
end
|
|
53
|
+
Signal.trap("TERM") do
|
|
54
|
+
Backport.stop
|
|
55
|
+
end
|
|
56
|
+
# @sg-ignore Wrong argument type for Backport.prepare_stdio_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
|
|
57
|
+
Backport.prepare_stdio_server adapter: Solargraph::LanguageServer::Transport::Adapter
|
|
58
|
+
STDERR.puts "Solargraph is listening on stdio PID=#{Process.pid}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
|
|
63
|
+
option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
|
|
64
|
+
# @param directory [String]
|
|
65
|
+
# @return [void]
|
|
66
|
+
def config(directory = '.')
|
|
67
|
+
matches = []
|
|
68
|
+
if options[:extensions]
|
|
69
|
+
Gem::Specification.each do |g|
|
|
70
|
+
if g.name.match(/^solargraph\-[A-Za-z0-9_\-]*?\-ext/)
|
|
71
|
+
require g.name
|
|
72
|
+
matches.push g.name
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
conf = Solargraph::Workspace::Config.new.raw_data
|
|
77
|
+
unless matches.empty?
|
|
78
|
+
matches.each do |m|
|
|
79
|
+
conf['extensions'].push m
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
# @param file [File]
|
|
83
|
+
File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
|
|
84
|
+
file.puts conf.to_yaml
|
|
85
|
+
end
|
|
86
|
+
STDOUT.puts "Configuration file initialized."
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
desc 'clear', 'Delete all cached documentation'
|
|
90
|
+
long_desc %(
|
|
91
|
+
This command will delete all core and gem documentation from the cache.
|
|
92
|
+
)
|
|
93
|
+
# @return [void]
|
|
94
|
+
def clear
|
|
95
|
+
puts "Deleting all cached documentation (gems, core and stdlib)"
|
|
96
|
+
Solargraph::PinCache.clear
|
|
97
|
+
end
|
|
98
|
+
map 'clear-cache' => :clear
|
|
99
|
+
map 'clear-cores' => :clear
|
|
100
|
+
|
|
101
|
+
desc 'cache', 'Cache a gem', hide: true
|
|
102
|
+
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
103
|
+
# @return [void]
|
|
104
|
+
# @param gem [String]
|
|
105
|
+
# @param version [String, nil]
|
|
106
|
+
def cache gem, version = nil
|
|
107
|
+
api_map = Solargraph::ApiMap.load(Dir.pwd)
|
|
108
|
+
spec = Gem::Specification.find_by_name(gem, version)
|
|
109
|
+
api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
|
|
113
|
+
long_desc %(
|
|
114
|
+
Specify one or more gem names to clear. 'core' or 'stdlib' may
|
|
115
|
+
also be specified to clear cached system documentation.
|
|
116
|
+
Documentation will be regenerated as needed.
|
|
117
|
+
)
|
|
118
|
+
# @param gems [Array<String>]
|
|
119
|
+
# @return [void]
|
|
120
|
+
def uncache *gems
|
|
121
|
+
raise ArgumentError, 'No gems specified.' if gems.empty?
|
|
122
|
+
gems.each do |gem|
|
|
123
|
+
if gem == 'core'
|
|
124
|
+
PinCache.uncache_core
|
|
125
|
+
next
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if gem == 'stdlib'
|
|
129
|
+
PinCache.uncache_stdlib
|
|
130
|
+
next
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
spec = Gem::Specification.find_by_name(gem)
|
|
134
|
+
PinCache.uncache_gem(spec, out: $stdout)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
|
|
139
|
+
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
140
|
+
# @param names [Array<String>]
|
|
141
|
+
# @return [void]
|
|
142
|
+
def gems *names
|
|
143
|
+
api_map = ApiMap.load('.')
|
|
144
|
+
if names.empty?
|
|
145
|
+
Gem::Specification.to_a.each { |spec| do_cache spec, api_map }
|
|
146
|
+
STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
|
|
147
|
+
else
|
|
148
|
+
names.each do |name|
|
|
149
|
+
spec = Gem::Specification.find_by_name(*name.split('='))
|
|
150
|
+
do_cache spec, api_map
|
|
151
|
+
rescue Gem::MissingSpecError
|
|
152
|
+
warn "Gem '#{name}' not found"
|
|
153
|
+
end
|
|
154
|
+
STDERR.puts "Documentation cached for #{names.count} gems."
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
desc 'reporters', 'Get a list of diagnostics reporters'
|
|
159
|
+
# @return [void]
|
|
160
|
+
def reporters
|
|
161
|
+
puts Solargraph::Diagnostics.reporters
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
desc 'typecheck [FILE(s)]', 'Run the type checker'
|
|
165
|
+
long_desc %(
|
|
166
|
+
Perform type checking on one or more files in a workspace. Check the
|
|
167
|
+
entire workspace if no files are specified.
|
|
168
|
+
|
|
169
|
+
Type checking levels are normal, typed, strict, and strong.
|
|
170
|
+
)
|
|
171
|
+
option :level, type: :string, aliases: [:mode, :m, :l], desc: 'Type checking level', default: 'normal'
|
|
172
|
+
option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
|
|
173
|
+
# @return [void]
|
|
174
|
+
def typecheck *files
|
|
175
|
+
directory = File.realpath(options[:directory])
|
|
176
|
+
workspace = Solargraph::Workspace.new(directory)
|
|
177
|
+
level = options[:level].to_sym
|
|
178
|
+
rules = workspace.rules(level)
|
|
179
|
+
api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
|
|
180
|
+
probcount = 0
|
|
181
|
+
if files.empty?
|
|
182
|
+
files = api_map.source_maps.map(&:filename)
|
|
183
|
+
else
|
|
184
|
+
files.map! { |file| File.realpath(file) }
|
|
185
|
+
end
|
|
186
|
+
filecount = 0
|
|
187
|
+
|
|
188
|
+
time = Benchmark.measure {
|
|
189
|
+
files.each do |file|
|
|
190
|
+
checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym, workspace: workspace)
|
|
191
|
+
problems = checker.problems
|
|
192
|
+
next if problems.empty?
|
|
193
|
+
problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
|
|
194
|
+
puts problems.map { |prob| "#{prob.location.filename}:#{prob.location.range.start.line + 1} - #{prob.message}" }.join("\n")
|
|
195
|
+
filecount += 1
|
|
196
|
+
probcount += problems.length
|
|
197
|
+
end
|
|
198
|
+
# "
|
|
199
|
+
}
|
|
200
|
+
puts "Typecheck finished in #{time.real} seconds."
|
|
201
|
+
puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
|
|
202
|
+
# "
|
|
203
|
+
exit 1 if probcount > 0
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
desc 'scan', 'Test the workspace for problems'
|
|
207
|
+
long_desc %(
|
|
208
|
+
A scan loads the entire workspace to make sure that the ASTs and
|
|
209
|
+
maps do not raise errors during analysis. It does not perform any type
|
|
210
|
+
checking or validation; it only confirms that the analysis itself is
|
|
211
|
+
error-free.
|
|
212
|
+
)
|
|
213
|
+
option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
|
|
214
|
+
option :verbose, type: :boolean, aliases: :v, desc: 'Verbose output', default: false
|
|
215
|
+
# @return [void]
|
|
216
|
+
def scan
|
|
217
|
+
directory = File.realpath(options[:directory])
|
|
218
|
+
# @type [Solargraph::ApiMap, nil]
|
|
219
|
+
api_map = nil
|
|
220
|
+
time = Benchmark.measure {
|
|
221
|
+
api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
|
|
222
|
+
api_map.pins.each do |pin|
|
|
223
|
+
begin
|
|
224
|
+
puts pin_description(pin) if options[:verbose]
|
|
225
|
+
pin.typify api_map
|
|
226
|
+
pin.probe api_map
|
|
227
|
+
rescue StandardError => e
|
|
228
|
+
STDERR.puts "Error testing #{pin_description(pin)} #{pin.location ? "at #{pin.location.filename}:#{pin.location.range.start.line + 1}" : ''}"
|
|
229
|
+
STDERR.puts "[#{e.class}]: #{e.message}"
|
|
230
|
+
STDERR.puts e.backtrace.join("\n")
|
|
231
|
+
exit 1
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
}
|
|
235
|
+
puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
desc 'list', 'List the files in the workspace and the total count'
|
|
239
|
+
option :count, type: :boolean, aliases: :c, desc: 'Display the file count only', default: false
|
|
240
|
+
option :directory, type: :string, aliases: :d, desc: 'The directory to read', default: '.'
|
|
241
|
+
# @return [void]
|
|
242
|
+
def list
|
|
243
|
+
workspace = Solargraph::Workspace.new(options[:directory])
|
|
244
|
+
puts workspace.filenames unless options[:count]
|
|
245
|
+
puts "#{workspace.filenames.length} files total."
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
desc 'pin [PATH]', 'Describe a pin', hide: true
|
|
249
|
+
option :rbs, type: :boolean, desc: 'Output the pin as RBS', default: false
|
|
250
|
+
option :typify, type: :boolean, desc: 'Output the calculated return type of the pin from annotations', default: false
|
|
251
|
+
option :references, type: :boolean, desc: 'Show references', default: false
|
|
252
|
+
option :probe, type: :boolean, desc: 'Output the calculated return type of the pin from annotations and inference', default: false
|
|
253
|
+
option :stack, type: :boolean, desc: 'Show entire stack of a method pin by including definitions in superclasses', default: false
|
|
254
|
+
# @param path [String] The path to the method pin, e.g. 'Class#method' or 'Class.method'
|
|
255
|
+
# @return [void]
|
|
256
|
+
def pin path
|
|
257
|
+
api_map = Solargraph::ApiMap.load_with_cache('.', $stderr)
|
|
258
|
+
is_method = path.include?('#') || path.include?('.')
|
|
259
|
+
if is_method && options[:stack]
|
|
260
|
+
scope, ns, meth = if path.include? '#'
|
|
261
|
+
[:instance, *path.split('#', 2)]
|
|
262
|
+
else
|
|
263
|
+
[:class, *path.split('.', 2)]
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# @sg-ignore Wrong argument type for
|
|
267
|
+
# Solargraph::ApiMap#get_method_stack: rooted_tag
|
|
268
|
+
# expected String, received Array<String>
|
|
269
|
+
pins = api_map.get_method_stack(ns, meth, scope: scope)
|
|
270
|
+
else
|
|
271
|
+
pins = api_map.get_path_pins path
|
|
272
|
+
end
|
|
273
|
+
# @type [Hash{Symbol => Pin::Base}]
|
|
274
|
+
references = {}
|
|
275
|
+
pin = pins.first
|
|
276
|
+
case pin
|
|
277
|
+
when nil
|
|
278
|
+
$stderr.puts "Pin not found for path '#{path}'"
|
|
279
|
+
exit 1
|
|
280
|
+
when Pin::Namespace
|
|
281
|
+
if options[:references]
|
|
282
|
+
superclass_tag = api_map.qualify_superclass(pin.return_type.tag)
|
|
283
|
+
superclass_pin = api_map.get_path_pins(superclass_tag).first if superclass_tag
|
|
284
|
+
references[:superclass] = superclass_pin if superclass_pin
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
pins.each do |pin|
|
|
289
|
+
if options[:typify] || options[:probe]
|
|
290
|
+
type = ComplexType::UNDEFINED
|
|
291
|
+
type = pin.typify(api_map) if options[:typify]
|
|
292
|
+
type = pin.probe(api_map) if options[:probe] && type.undefined?
|
|
293
|
+
print_type(type)
|
|
294
|
+
next
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
print_pin(pin)
|
|
298
|
+
end
|
|
299
|
+
references.each do |key, refpin|
|
|
300
|
+
puts "\n# #{key.to_s.capitalize}:\n\n"
|
|
301
|
+
print_pin(refpin)
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
private
|
|
306
|
+
|
|
307
|
+
# @param pin [Solargraph::Pin::Base]
|
|
308
|
+
# @return [String]
|
|
309
|
+
def pin_description pin
|
|
310
|
+
desc = if pin.path.nil? || pin.path.empty?
|
|
311
|
+
if pin.closure
|
|
312
|
+
"#{pin.closure.path} | #{pin.name}"
|
|
313
|
+
else
|
|
314
|
+
"#{pin.context.namespace} | #{pin.name}"
|
|
315
|
+
end
|
|
316
|
+
else
|
|
317
|
+
pin.path
|
|
318
|
+
end
|
|
319
|
+
desc += " (#{pin.location.filename} #{pin.location.range.start.line})" if pin.location
|
|
320
|
+
desc
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# @param gemspec [Gem::Specification]
|
|
324
|
+
# @param api_map [ApiMap]
|
|
325
|
+
# @return [void]
|
|
326
|
+
def do_cache gemspec, api_map
|
|
327
|
+
# @todo if the rebuild: option is passed as a positional arg,
|
|
328
|
+
# typecheck doesn't complain on the below line
|
|
329
|
+
api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# @param type [ComplexType]
|
|
333
|
+
# @return [void]
|
|
334
|
+
def print_type(type)
|
|
335
|
+
if options[:rbs]
|
|
336
|
+
puts type.to_rbs
|
|
337
|
+
else
|
|
338
|
+
puts type.rooted_tag
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# @param pin [Solargraph::Pin::Base]
|
|
343
|
+
# @return [void]
|
|
344
|
+
def print_pin(pin)
|
|
345
|
+
if options[:rbs]
|
|
346
|
+
puts pin.to_rbs
|
|
347
|
+
else
|
|
348
|
+
puts pin.inspect
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|