solargraph 0.39.7
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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +28 -0
- data/.yardopts +2 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/Rakefile +14 -0
- data/SPONSORS.md +9 -0
- data/bin/solargraph +5 -0
- data/lib/.rubocop.yml +21 -0
- data/lib/solargraph.rb +66 -0
- data/lib/solargraph/api_map.rb +745 -0
- data/lib/solargraph/api_map/bundler_methods.rb +27 -0
- data/lib/solargraph/api_map/cache.rb +66 -0
- data/lib/solargraph/api_map/source_to_yard.rb +81 -0
- data/lib/solargraph/api_map/store.rb +267 -0
- data/lib/solargraph/bundle.rb +26 -0
- data/lib/solargraph/complex_type.rb +213 -0
- data/lib/solargraph/complex_type/type_methods.rb +127 -0
- data/lib/solargraph/complex_type/unique_type.rb +75 -0
- data/lib/solargraph/convention.rb +38 -0
- data/lib/solargraph/convention/base.rb +25 -0
- data/lib/solargraph/convention/gemfile.rb +18 -0
- data/lib/solargraph/convention/gemspec.rb +25 -0
- data/lib/solargraph/convention/rspec.rb +24 -0
- data/lib/solargraph/converters/dd.rb +12 -0
- data/lib/solargraph/converters/dl.rb +12 -0
- data/lib/solargraph/converters/dt.rb +12 -0
- data/lib/solargraph/converters/misc.rb +1 -0
- data/lib/solargraph/core_fills.rb +159 -0
- data/lib/solargraph/diagnostics.rb +55 -0
- data/lib/solargraph/diagnostics/base.rb +29 -0
- data/lib/solargraph/diagnostics/require_not_found.rb +37 -0
- data/lib/solargraph/diagnostics/rubocop.rb +90 -0
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +64 -0
- data/lib/solargraph/diagnostics/severities.rb +15 -0
- data/lib/solargraph/diagnostics/type_check.rb +54 -0
- data/lib/solargraph/diagnostics/update_errors.rb +41 -0
- data/lib/solargraph/documentor.rb +76 -0
- data/lib/solargraph/environ.rb +40 -0
- data/lib/solargraph/language_server.rb +19 -0
- data/lib/solargraph/language_server/completion_item_kinds.rb +35 -0
- data/lib/solargraph/language_server/error_codes.rb +20 -0
- data/lib/solargraph/language_server/host.rb +741 -0
- data/lib/solargraph/language_server/host/cataloger.rb +56 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +81 -0
- data/lib/solargraph/language_server/host/dispatch.rb +112 -0
- data/lib/solargraph/language_server/host/sources.rb +156 -0
- data/lib/solargraph/language_server/message.rb +92 -0
- data/lib/solargraph/language_server/message/base.rb +85 -0
- data/lib/solargraph/language_server/message/cancel_request.rb +13 -0
- data/lib/solargraph/language_server/message/client.rb +11 -0
- data/lib/solargraph/language_server/message/client/register_capability.rb +15 -0
- data/lib/solargraph/language_server/message/completion_item.rb +11 -0
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +57 -0
- data/lib/solargraph/language_server/message/exit_notification.rb +13 -0
- data/lib/solargraph/language_server/message/extended.rb +21 -0
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +95 -0
- data/lib/solargraph/language_server/message/extended/document.rb +20 -0
- data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -0
- data/lib/solargraph/language_server/message/extended/download_core.rb +23 -0
- data/lib/solargraph/language_server/message/extended/environment.rb +25 -0
- data/lib/solargraph/language_server/message/extended/search.rb +20 -0
- data/lib/solargraph/language_server/message/initialize.rb +153 -0
- data/lib/solargraph/language_server/message/initialized.rb +26 -0
- data/lib/solargraph/language_server/message/method_not_found.rb +16 -0
- data/lib/solargraph/language_server/message/method_not_implemented.rb +14 -0
- data/lib/solargraph/language_server/message/shutdown.rb +13 -0
- data/lib/solargraph/language_server/message/text_document.rb +28 -0
- data/lib/solargraph/language_server/message/text_document/base.rb +19 -0
- data/lib/solargraph/language_server/message/text_document/code_action.rb +17 -0
- data/lib/solargraph/language_server/message/text_document/completion.rb +57 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +38 -0
- data/lib/solargraph/language_server/message/text_document/did_change.rb +15 -0
- data/lib/solargraph/language_server/message/text_document/did_close.rb +15 -0
- data/lib/solargraph/language_server/message/text_document/did_open.rb +15 -0
- data/lib/solargraph/language_server/message/text_document/did_save.rb +17 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +23 -0
- data/lib/solargraph/language_server/message/text_document/folding_range.rb +26 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +78 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +44 -0
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +34 -0
- data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -0
- data/lib/solargraph/language_server/message/text_document/references.rb +16 -0
- data/lib/solargraph/language_server/message/text_document/rename.rb +19 -0
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +29 -0
- data/lib/solargraph/language_server/message/workspace.rb +14 -0
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -0
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +33 -0
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -0
- data/lib/solargraph/language_server/message_types.rb +14 -0
- data/lib/solargraph/language_server/request.rb +24 -0
- data/lib/solargraph/language_server/symbol_kinds.rb +36 -0
- data/lib/solargraph/language_server/transport.rb +13 -0
- data/lib/solargraph/language_server/transport/adapter.rb +56 -0
- data/lib/solargraph/language_server/transport/data_reader.rb +72 -0
- data/lib/solargraph/language_server/uri_helpers.rb +49 -0
- data/lib/solargraph/library.rb +414 -0
- data/lib/solargraph/location.rb +37 -0
- data/lib/solargraph/logging.rb +27 -0
- data/lib/solargraph/page.rb +83 -0
- data/lib/solargraph/parser.rb +26 -0
- data/lib/solargraph/parser/comment_ripper.rb +52 -0
- data/lib/solargraph/parser/legacy.rb +12 -0
- data/lib/solargraph/parser/legacy/class_methods.rb +109 -0
- data/lib/solargraph/parser/legacy/flawed_builder.rb +16 -0
- data/lib/solargraph/parser/legacy/node_chainer.rb +118 -0
- data/lib/solargraph/parser/legacy/node_methods.rb +300 -0
- data/lib/solargraph/parser/legacy/node_processors.rb +54 -0
- data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +23 -0
- data/lib/solargraph/parser/legacy/node_processors/args_node.rb +35 -0
- data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +15 -0
- data/lib/solargraph/parser/legacy/node_processors/block_node.rb +22 -0
- data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +25 -0
- data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +23 -0
- data/lib/solargraph/parser/legacy/node_processors/def_node.rb +63 -0
- data/lib/solargraph/parser/legacy/node_processors/defs_node.rb +36 -0
- data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +23 -0
- data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +38 -0
- data/lib/solargraph/parser/legacy/node_processors/lvasgn_node.rb +28 -0
- data/lib/solargraph/parser/legacy/node_processors/namespace_node.rb +39 -0
- data/lib/solargraph/parser/legacy/node_processors/orasgn_node.rb +16 -0
- data/lib/solargraph/parser/legacy/node_processors/resbody_node.rb +36 -0
- data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +21 -0
- data/lib/solargraph/parser/legacy/node_processors/send_node.rb +234 -0
- data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +18 -0
- data/lib/solargraph/parser/node_methods.rb +43 -0
- data/lib/solargraph/parser/node_processor.rb +43 -0
- data/lib/solargraph/parser/node_processor/base.rb +77 -0
- data/lib/solargraph/parser/region.rb +66 -0
- data/lib/solargraph/parser/rubyvm.rb +40 -0
- data/lib/solargraph/parser/rubyvm/class_methods.rb +150 -0
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +135 -0
- data/lib/solargraph/parser/rubyvm/node_methods.rb +284 -0
- data/lib/solargraph/parser/rubyvm/node_processors.rb +61 -0
- data/lib/solargraph/parser/rubyvm/node_processors/alias_node.rb +23 -0
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +62 -0
- data/lib/solargraph/parser/rubyvm/node_processors/begin_node.rb +15 -0
- data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +22 -0
- data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +22 -0
- data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +23 -0
- data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +64 -0
- data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +57 -0
- data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +23 -0
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +38 -0
- data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +39 -0
- data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +20 -0
- data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +27 -0
- data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +39 -0
- data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +31 -0
- data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +15 -0
- data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +45 -0
- data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +21 -0
- data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +15 -0
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +255 -0
- data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +18 -0
- data/lib/solargraph/parser/snippet.rb +13 -0
- data/lib/solargraph/pin.rb +39 -0
- data/lib/solargraph/pin/attribute.rb +49 -0
- data/lib/solargraph/pin/base.rb +296 -0
- data/lib/solargraph/pin/base_method.rb +141 -0
- data/lib/solargraph/pin/base_variable.rb +84 -0
- data/lib/solargraph/pin/block.rb +48 -0
- data/lib/solargraph/pin/class_variable.rb +8 -0
- data/lib/solargraph/pin/closure.rb +37 -0
- data/lib/solargraph/pin/common.rb +70 -0
- data/lib/solargraph/pin/constant.rb +43 -0
- data/lib/solargraph/pin/conversions.rb +97 -0
- data/lib/solargraph/pin/documenting.rb +110 -0
- data/lib/solargraph/pin/duck_method.rb +16 -0
- data/lib/solargraph/pin/global_variable.rb +8 -0
- data/lib/solargraph/pin/instance_variable.rb +30 -0
- data/lib/solargraph/pin/keyword.rb +15 -0
- data/lib/solargraph/pin/keyword_param.rb +8 -0
- data/lib/solargraph/pin/local_variable.rb +21 -0
- data/lib/solargraph/pin/localized.rb +43 -0
- data/lib/solargraph/pin/method.rb +111 -0
- data/lib/solargraph/pin/method_alias.rb +31 -0
- data/lib/solargraph/pin/namespace.rb +85 -0
- data/lib/solargraph/pin/parameter.rb +206 -0
- data/lib/solargraph/pin/proxy_type.rb +29 -0
- data/lib/solargraph/pin/reference.rb +14 -0
- data/lib/solargraph/pin/reference/extend.rb +10 -0
- data/lib/solargraph/pin/reference/include.rb +10 -0
- data/lib/solargraph/pin/reference/override.rb +29 -0
- data/lib/solargraph/pin/reference/prepend.rb +10 -0
- data/lib/solargraph/pin/reference/require.rb +14 -0
- data/lib/solargraph/pin/reference/superclass.rb +10 -0
- data/lib/solargraph/pin/singleton.rb +11 -0
- data/lib/solargraph/pin/symbol.rb +47 -0
- data/lib/solargraph/pin/yard_pin.rb +12 -0
- data/lib/solargraph/pin/yard_pin/constant.rb +25 -0
- data/lib/solargraph/pin/yard_pin/method.rb +65 -0
- data/lib/solargraph/pin/yard_pin/namespace.rb +27 -0
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +26 -0
- data/lib/solargraph/position.rb +112 -0
- data/lib/solargraph/range.rb +95 -0
- data/lib/solargraph/server_methods.rb +16 -0
- data/lib/solargraph/shell.rb +221 -0
- data/lib/solargraph/source.rb +533 -0
- data/lib/solargraph/source/chain.rb +172 -0
- data/lib/solargraph/source/chain/block_variable.rb +13 -0
- data/lib/solargraph/source/chain/call.rb +203 -0
- data/lib/solargraph/source/chain/class_variable.rb +13 -0
- data/lib/solargraph/source/chain/constant.rb +75 -0
- data/lib/solargraph/source/chain/global_variable.rb +13 -0
- data/lib/solargraph/source/chain/head.rb +35 -0
- data/lib/solargraph/source/chain/instance_variable.rb +13 -0
- data/lib/solargraph/source/chain/link.rb +67 -0
- data/lib/solargraph/source/chain/literal.rb +23 -0
- data/lib/solargraph/source/chain/or.rb +23 -0
- data/lib/solargraph/source/chain/variable.rb +13 -0
- data/lib/solargraph/source/chain/z_super.rb +184 -0
- data/lib/solargraph/source/change.rb +79 -0
- data/lib/solargraph/source/cursor.rb +164 -0
- data/lib/solargraph/source/encoding_fixes.rb +23 -0
- data/lib/solargraph/source/source_chainer.rb +189 -0
- data/lib/solargraph/source/updater.rb +54 -0
- data/lib/solargraph/source_map.rb +170 -0
- data/lib/solargraph/source_map/clip.rb +190 -0
- data/lib/solargraph/source_map/completion.rb +23 -0
- data/lib/solargraph/source_map/mapper.rb +199 -0
- data/lib/solargraph/stdlib_fills.rb +32 -0
- data/lib/solargraph/type_checker.rb +498 -0
- data/lib/solargraph/type_checker/checks.rb +95 -0
- data/lib/solargraph/type_checker/param_def.rb +35 -0
- data/lib/solargraph/type_checker/problem.rb +32 -0
- data/lib/solargraph/type_checker/rules.rb +53 -0
- data/lib/solargraph/version.rb +5 -0
- data/lib/solargraph/views/_method.erb +62 -0
- data/lib/solargraph/views/_name_type_tag.erb +10 -0
- data/lib/solargraph/views/_namespace.erb +24 -0
- data/lib/solargraph/views/document.erb +23 -0
- data/lib/solargraph/views/environment.erb +58 -0
- data/lib/solargraph/views/layout.erb +44 -0
- data/lib/solargraph/views/search.erb +11 -0
- data/lib/solargraph/workspace.rb +209 -0
- data/lib/solargraph/workspace/config.rb +215 -0
- data/lib/solargraph/yard_map.rb +420 -0
- data/lib/solargraph/yard_map/cache.rb +19 -0
- data/lib/solargraph/yard_map/core_docs.rb +170 -0
- data/lib/solargraph/yard_map/core_gen.rb +76 -0
- data/lib/solargraph/yard_map/mapper.rb +71 -0
- data/lib/solargraph/yard_map/rdoc_to_yard.rb +136 -0
- data/lib/yard-solargraph.rb +30 -0
- data/solargraph.gemspec +41 -0
- data/travis-bundler.rb +11 -0
- data/yardoc/2.2.2.tar.gz +0 -0
- metadata +575 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<h1>Search Results for <kbd><%= query %></kbd></h1>
|
|
2
|
+
|
|
3
|
+
<% unless results.empty? %>
|
|
4
|
+
<ul class="doc-list">
|
|
5
|
+
<% results.each do |result| %>
|
|
6
|
+
<li>
|
|
7
|
+
<a href="solargraph:/document?query=<%= CGI.escape(result) %>"><%= result %></a>
|
|
8
|
+
</li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
<% end %>
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
# A workspace consists of the files in a project's directory and the
|
|
5
|
+
# project's configuration. It provides a Source for each file to be used
|
|
6
|
+
# in an associated Library or ApiMap.
|
|
7
|
+
#
|
|
8
|
+
class Workspace
|
|
9
|
+
autoload :Config, 'solargraph/workspace/config'
|
|
10
|
+
|
|
11
|
+
# @return [String]
|
|
12
|
+
attr_reader :directory
|
|
13
|
+
|
|
14
|
+
# The require paths associated with the workspace.
|
|
15
|
+
#
|
|
16
|
+
# @return [Array<String>]
|
|
17
|
+
attr_reader :require_paths
|
|
18
|
+
|
|
19
|
+
# @return [Array<String>]
|
|
20
|
+
attr_reader :gemnames
|
|
21
|
+
|
|
22
|
+
# @param directory [String]
|
|
23
|
+
# @param config [Config, nil]
|
|
24
|
+
def initialize directory = '', config = nil
|
|
25
|
+
@directory = directory
|
|
26
|
+
@config = config
|
|
27
|
+
load_sources
|
|
28
|
+
@gemnames = []
|
|
29
|
+
@require_paths = generate_require_paths
|
|
30
|
+
require_plugins
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [Solargraph::Workspace::Config]
|
|
34
|
+
def config
|
|
35
|
+
@config ||= Solargraph::Workspace::Config.new(directory)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Merge the source. A merge will update the existing source for the file
|
|
39
|
+
# or add it to the sources if the workspace is configured to include it.
|
|
40
|
+
# The source is ignored if the configuration excludes it.
|
|
41
|
+
#
|
|
42
|
+
# @param source [Solargraph::Source]
|
|
43
|
+
# @return [Boolean] True if the source was added to the workspace
|
|
44
|
+
def merge source
|
|
45
|
+
unless directory == '*' || source_hash.key?(source.filename)
|
|
46
|
+
# Reload the config to determine if a new source should be included
|
|
47
|
+
@config = Solargraph::Workspace::Config.new(directory)
|
|
48
|
+
return false unless config.calculated.include?(source.filename)
|
|
49
|
+
end
|
|
50
|
+
source_hash[source.filename] = source
|
|
51
|
+
true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Determine whether a file would be merged into the workspace.
|
|
55
|
+
#
|
|
56
|
+
# @param filename [String]
|
|
57
|
+
# @return [Boolean]
|
|
58
|
+
def would_merge? filename
|
|
59
|
+
return true if directory == '*' || source_hash.include?(filename)
|
|
60
|
+
@config = Solargraph::Workspace::Config.new(directory)
|
|
61
|
+
config.calculated.include?(filename)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Remove a source from the workspace. The source will not be removed if
|
|
65
|
+
# its file exists and the workspace is configured to include it.
|
|
66
|
+
#
|
|
67
|
+
# @param filename [String]
|
|
68
|
+
# @return [Boolean] True if the source was removed from the workspace
|
|
69
|
+
def remove filename
|
|
70
|
+
return false unless source_hash.key?(filename)
|
|
71
|
+
source_hash.delete filename
|
|
72
|
+
true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [Array<String>]
|
|
76
|
+
def filenames
|
|
77
|
+
source_hash.keys
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Array<Solargraph::Source>]
|
|
81
|
+
def sources
|
|
82
|
+
source_hash.values
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @param filename [String]
|
|
86
|
+
# @return [Boolean]
|
|
87
|
+
def has_file? filename
|
|
88
|
+
source_hash.key?(filename)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Get a source by its filename.
|
|
92
|
+
#
|
|
93
|
+
# @param filename [String]
|
|
94
|
+
# @return [Solargraph::Source]
|
|
95
|
+
def source filename
|
|
96
|
+
source_hash[filename]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# True if the path resolves to a file in the workspace's require paths.
|
|
100
|
+
#
|
|
101
|
+
# @param path [String]
|
|
102
|
+
# @return [Boolean]
|
|
103
|
+
def would_require? path
|
|
104
|
+
require_paths.each do |rp|
|
|
105
|
+
return true if File.exist?(File.join(rp, "#{path}.rb"))
|
|
106
|
+
end
|
|
107
|
+
false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# True if the workspace contains at least one gemspec file.
|
|
111
|
+
#
|
|
112
|
+
# @return [Boolean]
|
|
113
|
+
def gemspec?
|
|
114
|
+
!gemspecs.empty?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Get an array of all gemspec files in the workspace.
|
|
118
|
+
#
|
|
119
|
+
# @return [Array<String>]
|
|
120
|
+
def gemspecs
|
|
121
|
+
return [] if directory.empty? || directory == '*'
|
|
122
|
+
@gemspecs ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
|
|
123
|
+
config.allow? gs
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Synchronize the workspace from the provided updater.
|
|
128
|
+
#
|
|
129
|
+
# @param updater [Source::Updater]
|
|
130
|
+
# @return [void]
|
|
131
|
+
def synchronize! updater
|
|
132
|
+
source_hash[updater.filename] = source_hash[updater.filename].synchronize(updater)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
# @return [Hash{String => Solargraph::Source}]
|
|
138
|
+
def source_hash
|
|
139
|
+
@source_hash ||= {}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @return [void]
|
|
143
|
+
def load_sources
|
|
144
|
+
source_hash.clear
|
|
145
|
+
unless directory.empty? || directory == '*'
|
|
146
|
+
size = config.calculated.length
|
|
147
|
+
raise WorkspaceTooLargeError, "The workspace is too large to index (#{size} files, #{config.max_files} max)" if config.max_files > 0 and size > config.max_files
|
|
148
|
+
config.calculated.each do |filename|
|
|
149
|
+
begin
|
|
150
|
+
source_hash[filename] = Solargraph::Source.load(filename)
|
|
151
|
+
rescue Errno::ENOENT => e
|
|
152
|
+
Solargraph.logger.warn("Error loading #{filename}: [#{e.class}] #{e.message}")
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Generate require paths from gemspecs if they exist or assume the default
|
|
159
|
+
# lib directory.
|
|
160
|
+
#
|
|
161
|
+
# @return [Array<String>]
|
|
162
|
+
def generate_require_paths
|
|
163
|
+
return configured_require_paths unless gemspec?
|
|
164
|
+
result = []
|
|
165
|
+
gemspecs.each do |file|
|
|
166
|
+
base = File.dirname(file)
|
|
167
|
+
# HACK: Evaluating gemspec files violates the goal of not running
|
|
168
|
+
# workspace code, but this is how Gem::Specification.load does it
|
|
169
|
+
# anyway.
|
|
170
|
+
Dir.chdir base do
|
|
171
|
+
begin
|
|
172
|
+
# @type [Gem::Specification]
|
|
173
|
+
spec = eval(File.read(file), TOPLEVEL_BINDING, file)
|
|
174
|
+
next unless Gem::Specification === spec
|
|
175
|
+
@gemnames.push spec.name
|
|
176
|
+
result.concat(spec.require_paths.map { |path| File.join(base, path) })
|
|
177
|
+
rescue RuntimeError, ScriptError, Errno::ENOENT => e
|
|
178
|
+
# Don't die if we have an error during eval-ing a gem spec.
|
|
179
|
+
# Concat the default lib directory instead.
|
|
180
|
+
Solargraph.logger.warn "Error reading #{file}: [#{e.class}] #{e.message}"
|
|
181
|
+
result.push File.join(base, 'lib')
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
result.concat config.require_paths
|
|
186
|
+
result.push File.join(directory, 'lib') if result.empty?
|
|
187
|
+
result
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Get additional require paths defined in the configuration.
|
|
191
|
+
#
|
|
192
|
+
# @return [Array<String>]
|
|
193
|
+
def configured_require_paths
|
|
194
|
+
return ['lib'] if directory.empty?
|
|
195
|
+
return [File.join(directory, 'lib')] if config.require_paths.empty?
|
|
196
|
+
config.require_paths.map{|p| File.join(directory, p)}
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def require_plugins
|
|
200
|
+
config.plugins.each do |plugin|
|
|
201
|
+
begin
|
|
202
|
+
require plugin
|
|
203
|
+
rescue LoadError
|
|
204
|
+
Solargraph.logger.warn "Failed to load plugin '#{plugin}'"
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Solargraph
|
|
6
|
+
class Workspace
|
|
7
|
+
# Configuration data for a workspace.
|
|
8
|
+
#
|
|
9
|
+
class Config
|
|
10
|
+
# The maximum number of files that can be added to a workspace.
|
|
11
|
+
# The workspace's .solargraph.yml can override this value.
|
|
12
|
+
MAX_FILES = 5000
|
|
13
|
+
|
|
14
|
+
# @return [String]
|
|
15
|
+
attr_reader :directory
|
|
16
|
+
|
|
17
|
+
# @return [Hash]
|
|
18
|
+
attr_reader :raw_data
|
|
19
|
+
|
|
20
|
+
# @param directory [String]
|
|
21
|
+
def initialize directory = ''
|
|
22
|
+
@directory = directory
|
|
23
|
+
@raw_data = config_data
|
|
24
|
+
included
|
|
25
|
+
excluded
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# An array of files included in the workspace (before calculating excluded files).
|
|
29
|
+
#
|
|
30
|
+
# @return [Array<String>]
|
|
31
|
+
def included
|
|
32
|
+
return [] if directory.empty? || directory == '*'
|
|
33
|
+
@included ||= process_globs(@raw_data['include'])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# An array of files excluded from the workspace.
|
|
37
|
+
#
|
|
38
|
+
# @return [Array<String>]
|
|
39
|
+
def excluded
|
|
40
|
+
return [] if directory.empty? || directory == '*'
|
|
41
|
+
@excluded ||= process_exclusions(@raw_data['exclude'])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def allow? filename
|
|
45
|
+
filename.start_with?(directory) &&
|
|
46
|
+
!excluded.include?(filename) &&
|
|
47
|
+
excluded_directories.none? { |d| filename.start_with?(d) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The calculated array of (included - excluded) files in the workspace.
|
|
51
|
+
#
|
|
52
|
+
# @return [Array<String>]
|
|
53
|
+
def calculated
|
|
54
|
+
Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
|
|
55
|
+
@calculated ||= included - excluded
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# An array of domains configured for the workspace.
|
|
59
|
+
# A domain is a namespace that the ApiMap should include in the global
|
|
60
|
+
# namespace. It's typically used to identify available DSLs.
|
|
61
|
+
#
|
|
62
|
+
# @return [Array<String>]
|
|
63
|
+
def domains
|
|
64
|
+
raw_data['domains']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# An array of required paths to add to the workspace.
|
|
68
|
+
#
|
|
69
|
+
# @return [Array<String>]
|
|
70
|
+
def required
|
|
71
|
+
raw_data['require']
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# An array of load paths for required paths.
|
|
75
|
+
#
|
|
76
|
+
# @return [Array<String>]
|
|
77
|
+
def require_paths
|
|
78
|
+
raw_data['require_paths'] || []
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# An array of reporters to use for diagnostics.
|
|
82
|
+
#
|
|
83
|
+
# @return [Array<String>]
|
|
84
|
+
def reporters
|
|
85
|
+
raw_data['reporters']
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# An array of plugins to require.
|
|
89
|
+
#
|
|
90
|
+
# @return [Array<String>]
|
|
91
|
+
def plugins
|
|
92
|
+
raw_data['plugins']
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# The maximum number of files to parse from the workspace.
|
|
96
|
+
#
|
|
97
|
+
# @return [Integer]
|
|
98
|
+
def max_files
|
|
99
|
+
raw_data['max_files']
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# @return [String]
|
|
105
|
+
def global_config_path
|
|
106
|
+
ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
|
|
107
|
+
File.join(Dir.home, '.config', 'solargraph', 'config.yml')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# @return [String]
|
|
111
|
+
def workspace_config_path
|
|
112
|
+
return '' if @directory.empty?
|
|
113
|
+
File.join(@directory, '.solargraph.yml')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [Hash]
|
|
117
|
+
def config_data
|
|
118
|
+
workspace_config = read_config(workspace_config_path)
|
|
119
|
+
global_config = read_config(global_config_path)
|
|
120
|
+
|
|
121
|
+
defaults = default_config
|
|
122
|
+
defaults.merge({'exclude' => []}) unless workspace_config.nil?
|
|
123
|
+
|
|
124
|
+
defaults
|
|
125
|
+
.merge(global_config || {})
|
|
126
|
+
.merge(workspace_config || {})
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Read a .solargraph yaml config
|
|
130
|
+
#
|
|
131
|
+
# @param directory [String]
|
|
132
|
+
# @return [Hash, nil]
|
|
133
|
+
def read_config config_path = ''
|
|
134
|
+
return nil if config_path.empty?
|
|
135
|
+
return nil unless File.file?(config_path)
|
|
136
|
+
YAML.safe_load(File.read(config_path))
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# @return [Hash]
|
|
140
|
+
def default_config
|
|
141
|
+
{
|
|
142
|
+
'include' => ['**/*.rb'],
|
|
143
|
+
'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
|
|
144
|
+
'require' => [],
|
|
145
|
+
'domains' => [],
|
|
146
|
+
'reporters' => %w[rubocop require_not_found],
|
|
147
|
+
'require_paths' => [],
|
|
148
|
+
'plugins' => [],
|
|
149
|
+
'max_files' => MAX_FILES
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Get an array of files from the provided globs.
|
|
154
|
+
#
|
|
155
|
+
# @param globs [Array<String>]
|
|
156
|
+
# @return [Array<String>]
|
|
157
|
+
def process_globs globs
|
|
158
|
+
result = []
|
|
159
|
+
globs.each do |glob|
|
|
160
|
+
result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
|
|
161
|
+
end
|
|
162
|
+
result
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Modify the included files based on excluded directories and get an
|
|
166
|
+
# array of additional files to exclude.
|
|
167
|
+
#
|
|
168
|
+
# @param globs [Array<String>]
|
|
169
|
+
# @return [Array<String>]
|
|
170
|
+
def process_exclusions globs
|
|
171
|
+
remainder = globs.select do |glob|
|
|
172
|
+
if glob_is_directory?(glob)
|
|
173
|
+
exdir = File.join(directory, glob_to_directory(glob))
|
|
174
|
+
included.delete_if { |file| file.start_with?(exdir) }
|
|
175
|
+
false
|
|
176
|
+
else
|
|
177
|
+
true
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
process_globs remainder
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# True if the glob translates to a whole directory.
|
|
184
|
+
#
|
|
185
|
+
# @example
|
|
186
|
+
# glob_is_directory?('path/to/dir') # => true
|
|
187
|
+
# glob_is_directory?('path/to/dir/**/*) # => true
|
|
188
|
+
# glob_is_directory?('path/to/file.txt') # => false
|
|
189
|
+
# glob_is_directory?('path/to/*.txt') # => false
|
|
190
|
+
#
|
|
191
|
+
# @param glob [String]
|
|
192
|
+
# @return [Boolean]
|
|
193
|
+
def glob_is_directory? glob
|
|
194
|
+
File.directory?(glob) || File.directory?(glob_to_directory(glob))
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Translate a glob to a base directory if applicable
|
|
198
|
+
#
|
|
199
|
+
# @example
|
|
200
|
+
# glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
|
|
201
|
+
#
|
|
202
|
+
# @param glob [String]
|
|
203
|
+
# @return [String]
|
|
204
|
+
def glob_to_directory glob
|
|
205
|
+
glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def excluded_directories
|
|
209
|
+
@raw_data['exclude']
|
|
210
|
+
.select { |g| glob_is_directory?(g) }
|
|
211
|
+
.map { |g| File.join(directory, glob_to_directory(g)) }
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yard'
|
|
4
|
+
require 'yard-solargraph'
|
|
5
|
+
require 'rubygems/package'
|
|
6
|
+
|
|
7
|
+
module Solargraph
|
|
8
|
+
# The YardMap provides access to YARD documentation for the Ruby core, the
|
|
9
|
+
# stdlib, and gems.
|
|
10
|
+
#
|
|
11
|
+
class YardMap
|
|
12
|
+
autoload :Cache, 'solargraph/yard_map/cache'
|
|
13
|
+
autoload :CoreDocs, 'solargraph/yard_map/core_docs'
|
|
14
|
+
autoload :CoreGen, 'solargraph/yard_map/core_gen'
|
|
15
|
+
autoload :Mapper, 'solargraph/yard_map/mapper'
|
|
16
|
+
autoload :RdocToYard, 'solargraph/yard_map/rdoc_to_yard'
|
|
17
|
+
|
|
18
|
+
CoreDocs.require_minimum
|
|
19
|
+
|
|
20
|
+
def stdlib_paths
|
|
21
|
+
@@stdlib_paths ||= begin
|
|
22
|
+
result = {}
|
|
23
|
+
YARD::Registry.load! CoreDocs.yardoc_stdlib_file
|
|
24
|
+
YARD::Registry.all.each do |co|
|
|
25
|
+
next if co.file.nil?
|
|
26
|
+
path = co.file.sub(/^(ext|lib)\//, '').sub(/\.(rb|c)$/, '')
|
|
27
|
+
base = path.split('/').first
|
|
28
|
+
result[base] ||= []
|
|
29
|
+
result[base].push co
|
|
30
|
+
end
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Array<String>]
|
|
36
|
+
attr_reader :required
|
|
37
|
+
|
|
38
|
+
# @return [Boolean]
|
|
39
|
+
attr_writer :with_dependencies
|
|
40
|
+
|
|
41
|
+
# A hash of gem names and the version numbers to include in the map.
|
|
42
|
+
#
|
|
43
|
+
# @return [Hash{String => String}]
|
|
44
|
+
attr_reader :gemset
|
|
45
|
+
|
|
46
|
+
# @param required [Array<String>]
|
|
47
|
+
# @param gemset [Hash{String => String}]
|
|
48
|
+
# @param with_dependencies [Boolean]
|
|
49
|
+
def initialize(required: [], gemset: {}, with_dependencies: true)
|
|
50
|
+
# HACK: YardMap needs its own copy of this array
|
|
51
|
+
@required = required.clone
|
|
52
|
+
@with_dependencies = with_dependencies
|
|
53
|
+
@gem_paths = {}
|
|
54
|
+
@stdlib_namespaces = []
|
|
55
|
+
@gemset = gemset
|
|
56
|
+
@source_gems = []
|
|
57
|
+
process_requires
|
|
58
|
+
yardocs.uniq!
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
62
|
+
def pins
|
|
63
|
+
@pins ||= []
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def with_dependencies?
|
|
67
|
+
@with_dependencies ||= true unless @with_dependencies == false
|
|
68
|
+
@with_dependencies
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @param new_requires [Array<String>]
|
|
72
|
+
# @param new_gemset [Hash{String => String}]
|
|
73
|
+
# @return [Boolean]
|
|
74
|
+
def change new_requires, new_gemset, source_gems = []
|
|
75
|
+
if new_requires.uniq.sort == required.uniq.sort && new_gemset == gemset && @source_gems.uniq.sort == source_gems.uniq.sort
|
|
76
|
+
false
|
|
77
|
+
else
|
|
78
|
+
required.clear
|
|
79
|
+
required.concat new_requires
|
|
80
|
+
@gemset = new_gemset
|
|
81
|
+
@source_gems = source_gems
|
|
82
|
+
process_requires
|
|
83
|
+
true
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [Array<String>]
|
|
88
|
+
def yardocs
|
|
89
|
+
@yardocs ||= []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Array<String>]
|
|
93
|
+
def unresolved_requires
|
|
94
|
+
@unresolved_requires ||= []
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @param y [String]
|
|
98
|
+
# @return [YARD::Registry]
|
|
99
|
+
def load_yardoc y
|
|
100
|
+
if y.is_a?(Array)
|
|
101
|
+
YARD::Registry.load y, true
|
|
102
|
+
else
|
|
103
|
+
YARD::Registry.load! y
|
|
104
|
+
end
|
|
105
|
+
rescue StandardError => e
|
|
106
|
+
Solargraph::Logging.logger.warn "Error loading yardoc '#{y}' #{e.class} #{e.message}"
|
|
107
|
+
yardocs.delete y
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
112
|
+
def core_pins
|
|
113
|
+
# Using a class variable to reduce loads
|
|
114
|
+
@@core_pins ||= load_core_pins
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @param path [String]
|
|
118
|
+
# @return [Pin::Base]
|
|
119
|
+
def path_pin path
|
|
120
|
+
pins.select{ |p| p.path == path }.first
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Get the location of a file referenced by a require path.
|
|
124
|
+
#
|
|
125
|
+
# @param path [String]
|
|
126
|
+
# @return [Location]
|
|
127
|
+
def require_reference path
|
|
128
|
+
# @type [Gem::Specification]
|
|
129
|
+
spec = spec_for_require(path)
|
|
130
|
+
spec.full_require_paths.each do |rp|
|
|
131
|
+
file = File.join(rp, "#{path}.rb")
|
|
132
|
+
next unless File.file?(file)
|
|
133
|
+
return Solargraph::Location.new(file, Solargraph::Range.from_to(0, 0, 0, 0))
|
|
134
|
+
end
|
|
135
|
+
nil
|
|
136
|
+
rescue Gem::LoadError
|
|
137
|
+
nil
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
# @return [YardMap::Cache]
|
|
143
|
+
def cache
|
|
144
|
+
@cache ||= YardMap::Cache.new
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @param ns [YARD::CodeObjects::NamespaceObject]
|
|
148
|
+
# @return [Array<YARD::CodeObjects::Base>]
|
|
149
|
+
def recurse_namespace_object ns
|
|
150
|
+
result = []
|
|
151
|
+
ns.children.each do |c|
|
|
152
|
+
result.push c
|
|
153
|
+
result.concat recurse_namespace_object(c) if c.respond_to?(:children)
|
|
154
|
+
end
|
|
155
|
+
result
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @return [void]
|
|
159
|
+
def process_requires
|
|
160
|
+
pins.clear
|
|
161
|
+
unresolved_requires.clear
|
|
162
|
+
# stdnames = {}
|
|
163
|
+
done = []
|
|
164
|
+
from_std = []
|
|
165
|
+
required.each do |r|
|
|
166
|
+
next if r.nil? || r.empty? || done.include?(r)
|
|
167
|
+
done.push r
|
|
168
|
+
cached = cache.get_path_pins(r)
|
|
169
|
+
unless cached.nil?
|
|
170
|
+
pins.concat cached
|
|
171
|
+
next
|
|
172
|
+
end
|
|
173
|
+
result = []
|
|
174
|
+
begin
|
|
175
|
+
spec = spec_for_require(r)
|
|
176
|
+
if @source_gems.include?(spec.name)
|
|
177
|
+
next
|
|
178
|
+
end
|
|
179
|
+
next if @gem_paths.key?(spec.name)
|
|
180
|
+
yd = yardoc_file_for_spec(spec)
|
|
181
|
+
# YARD detects gems for certain libraries that do not have a yardoc
|
|
182
|
+
# but exist in the stdlib. `fileutils` is an example. Treat those
|
|
183
|
+
# cases as errors and check the stdlib yardoc.
|
|
184
|
+
raise Gem::LoadError if yd.nil?
|
|
185
|
+
@gem_paths[spec.name] = spec.full_gem_path
|
|
186
|
+
unless yardocs.include?(yd)
|
|
187
|
+
yardocs.unshift yd
|
|
188
|
+
result.concat process_yardoc yd, spec
|
|
189
|
+
result.concat add_gem_dependencies(spec) if with_dependencies?
|
|
190
|
+
stdlib_fill r, result
|
|
191
|
+
end
|
|
192
|
+
rescue Gem::LoadError => e
|
|
193
|
+
base = r.split('/').first
|
|
194
|
+
next if from_std.include?(base)
|
|
195
|
+
from_std.push base
|
|
196
|
+
stdtmp = load_stdlib_pins(base)
|
|
197
|
+
if stdtmp.empty?
|
|
198
|
+
unresolved_requires.push r
|
|
199
|
+
else
|
|
200
|
+
stdlib_fill base, stdtmp
|
|
201
|
+
result.concat stdtmp
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
result.delete_if(&:nil?)
|
|
205
|
+
unless result.empty?
|
|
206
|
+
cache.set_path_pins r, result
|
|
207
|
+
pins.concat result
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
pins.concat core_pins
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# @param spec [Gem::Specification]
|
|
214
|
+
# @return [void]
|
|
215
|
+
def add_gem_dependencies spec
|
|
216
|
+
result = []
|
|
217
|
+
(spec.dependencies - spec.development_dependencies).each do |dep|
|
|
218
|
+
begin
|
|
219
|
+
next if @source_gems.include?(dep.name) || @gem_paths.key?(dep.name)
|
|
220
|
+
depspec = Gem::Specification.find_by_name(dep.name)
|
|
221
|
+
next if depspec.nil?
|
|
222
|
+
@gem_paths[depspec.name] = depspec.full_gem_path
|
|
223
|
+
gy = yardoc_file_for_spec(depspec)
|
|
224
|
+
if gy.nil?
|
|
225
|
+
unresolved_requires.push dep.name
|
|
226
|
+
else
|
|
227
|
+
next if yardocs.include?(gy)
|
|
228
|
+
yardocs.unshift gy
|
|
229
|
+
result.concat process_yardoc gy, depspec
|
|
230
|
+
result.concat add_gem_dependencies(depspec)
|
|
231
|
+
end
|
|
232
|
+
rescue Gem::LoadError
|
|
233
|
+
# This error probably indicates a bug in an installed gem
|
|
234
|
+
Solargraph::Logging.logger.warn "Failed to resolve #{dep.name} gem dependency for #{spec.name}"
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
result
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @param y [String, nil]
|
|
241
|
+
# @param spec [Gem::Specification, nil]
|
|
242
|
+
# @return [Array<Pin::Base>]
|
|
243
|
+
def process_yardoc y, spec = nil
|
|
244
|
+
return [] if y.nil?
|
|
245
|
+
size = Dir.glob(File.join(y, '**', '*'))
|
|
246
|
+
.map{ |f| File.size(f) }
|
|
247
|
+
.inject(:+)
|
|
248
|
+
if spec
|
|
249
|
+
ser = File.join(CoreDocs.cache_dir, 'gems', "#{spec.name}-#{spec.version}.ser")
|
|
250
|
+
if File.file?(ser)
|
|
251
|
+
Solargraph.logger.info "Loading #{spec.name} #{spec.version} from cache"
|
|
252
|
+
file = File.open(ser, 'rb')
|
|
253
|
+
dump = file.read
|
|
254
|
+
file.close
|
|
255
|
+
begin
|
|
256
|
+
return Marshal.load(dump)
|
|
257
|
+
rescue StandardError => e
|
|
258
|
+
Solargraph.logger.warn "Error loading pin cache: [#{e.class}] #{e.message}"
|
|
259
|
+
File.unlink ser
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
if !size.nil? && size > 20_000_000
|
|
264
|
+
Solargraph::Logging.logger.warn "Yardoc at #{y} is too large to process (#{size} bytes)"
|
|
265
|
+
return []
|
|
266
|
+
end
|
|
267
|
+
load_yardoc y
|
|
268
|
+
Solargraph.logger.info "Loading #{spec.name} #{spec.version} from yardoc"
|
|
269
|
+
result = Mapper.new(YARD::Registry.all, spec).map
|
|
270
|
+
if spec
|
|
271
|
+
ser = File.join(CoreDocs.cache_dir, 'gems', "#{spec.name}-#{spec.version}.ser")
|
|
272
|
+
file = File.open(ser, 'wb')
|
|
273
|
+
file.write Marshal.dump(result)
|
|
274
|
+
file.close
|
|
275
|
+
end
|
|
276
|
+
result
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @param spec [Gem::Specification]
|
|
280
|
+
# @return [String]
|
|
281
|
+
def yardoc_file_for_spec spec
|
|
282
|
+
cache_dir = File.join(Solargraph::YardMap::CoreDocs.cache_dir, 'gems', "#{spec.name}-#{spec.version}", 'yardoc')
|
|
283
|
+
if File.exist?(cache_dir)
|
|
284
|
+
Solargraph.logger.info "Using cached documentation for #{spec.name} at #{cache_dir}"
|
|
285
|
+
cache_dir
|
|
286
|
+
else
|
|
287
|
+
YARD::Registry.yardoc_file_for_gem(spec.name, "= #{spec.version}")
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @param path [String]
|
|
292
|
+
# @return [Gem::Specification]
|
|
293
|
+
def spec_for_require path
|
|
294
|
+
spec = Gem::Specification.find_by_path(path) || Gem::Specification.find_by_name(path.split('/').first)
|
|
295
|
+
# Avoid loading the spec again if it's going to be skipped anyway
|
|
296
|
+
return spec if @source_gems.include?(spec.name)
|
|
297
|
+
# Avoid loading the spec again if it's already the correct version
|
|
298
|
+
if @gemset[spec.name] && @gemset[spec.name] != spec.version
|
|
299
|
+
begin
|
|
300
|
+
return Gem::Specification.find_by_name(spec.name, "= #{@gemset[spec.name]}")
|
|
301
|
+
rescue Gem::LoadError
|
|
302
|
+
Solargraph.logger.warn "Unable to load #{spec.name} #{@gemset[spec.name]} specified by workspace, using #{spec.version} instead"
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
spec
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# @param path [String]
|
|
309
|
+
# @param pins [Array<Pin::Base>]
|
|
310
|
+
# @return [void]
|
|
311
|
+
def stdlib_fill path, pins
|
|
312
|
+
StdlibFills.get(path).each do |ovr|
|
|
313
|
+
pin = pins.select { |p| p.path == ovr.name }.first
|
|
314
|
+
next if pin.nil?
|
|
315
|
+
(ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
|
|
316
|
+
pin.docstring.delete_tags tag.to_sym
|
|
317
|
+
end
|
|
318
|
+
ovr.tags.each do |tag|
|
|
319
|
+
pin.docstring.add_tag(tag)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def load_core_pins
|
|
325
|
+
yd = CoreDocs.yardoc_file
|
|
326
|
+
ser = File.join(File.dirname(yd), 'core.ser')
|
|
327
|
+
result = if File.file?(ser)
|
|
328
|
+
file = File.open(ser, 'rb')
|
|
329
|
+
dump = file.read
|
|
330
|
+
file.close
|
|
331
|
+
begin
|
|
332
|
+
Marshal.load(dump)
|
|
333
|
+
rescue StandardError => e
|
|
334
|
+
Solargraph.logger.warn "Error loading core pin cache: [#{e.class}] #{e.message}"
|
|
335
|
+
File.unlink ser
|
|
336
|
+
read_core_and_save_cache(yd, ser)
|
|
337
|
+
end
|
|
338
|
+
else
|
|
339
|
+
read_core_and_save_cache(yd, ser)
|
|
340
|
+
end
|
|
341
|
+
# HACK: Add Errno exception classes
|
|
342
|
+
errno = result.select{ |pin| pin.path == 'Errno' }.first
|
|
343
|
+
Errno.constants.each do |const|
|
|
344
|
+
result.push Solargraph::Pin::Namespace.new(type: :class, name: const.to_s, closure: errno)
|
|
345
|
+
result.push Solargraph::Pin::Reference::Superclass.new(closure: result.last, name: 'SystemCallError')
|
|
346
|
+
end
|
|
347
|
+
CoreFills::OVERRIDES.each do |ovr|
|
|
348
|
+
pin = result.select { |p| p.path == ovr.name }.first
|
|
349
|
+
next if pin.nil?
|
|
350
|
+
(ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
|
|
351
|
+
pin.docstring.delete_tags tag.to_sym
|
|
352
|
+
end
|
|
353
|
+
ovr.tags.each do |tag|
|
|
354
|
+
pin.docstring.add_tag(tag)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
result
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def read_core_and_save_cache yd, ser
|
|
361
|
+
result = []
|
|
362
|
+
load_yardoc yd
|
|
363
|
+
result.concat Mapper.new(YARD::Registry.all).map
|
|
364
|
+
# HACK: Assume core methods with a single `args` parameter accept restarg
|
|
365
|
+
result.select { |pin| pin.is_a?(Solargraph::Pin::BaseMethod )}.each do |pin|
|
|
366
|
+
if pin.parameters.length == 1 && pin.parameters.first.name == 'args' && pin.parameters.first.decl == :arg
|
|
367
|
+
# @todo Smelly instance variable access
|
|
368
|
+
pin.parameters.first.instance_variable_set(:@decl, :restarg)
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
# HACK: Set missing parameters on `==` methods, e.g., `Symbol#==`
|
|
372
|
+
result.select { |pin| pin.name == '==' && pin.parameters.empty? }.each do |pin|
|
|
373
|
+
pin.parameters.push Pin::Parameter.new(decl: :arg, name: 'obj2')
|
|
374
|
+
end
|
|
375
|
+
dump = Marshal.dump(result)
|
|
376
|
+
file = File.open(ser, 'wb')
|
|
377
|
+
file.write dump
|
|
378
|
+
file.close
|
|
379
|
+
result
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def load_stdlib_pins base
|
|
383
|
+
ser = File.join(File.dirname(CoreDocs.yardoc_stdlib_file), "#{base}.ser")
|
|
384
|
+
if File.file?(ser)
|
|
385
|
+
Solargraph.logger.info "Loading #{base} stdlib from cache"
|
|
386
|
+
file = File.open(ser, 'rb')
|
|
387
|
+
dump = file.read
|
|
388
|
+
file.close
|
|
389
|
+
begin
|
|
390
|
+
Marshal.load(dump)
|
|
391
|
+
rescue StandardError => e
|
|
392
|
+
Solargraph.logger.warn "Error loading #{base} stdlib pin cache: [#{e.class}] #{e.message}"
|
|
393
|
+
File.unlink ser
|
|
394
|
+
read_stdlib_and_save_cache(base, ser)
|
|
395
|
+
end
|
|
396
|
+
else
|
|
397
|
+
read_stdlib_and_save_cache(base, ser)
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def read_stdlib_and_save_cache base, ser
|
|
402
|
+
result = []
|
|
403
|
+
if stdlib_paths[base]
|
|
404
|
+
Solargraph.logger.info "Loading #{base} stdlib from yardoc"
|
|
405
|
+
result.concat Mapper.new(stdlib_paths[base]).map
|
|
406
|
+
unless result.empty?
|
|
407
|
+
dump = Marshal.dump(result)
|
|
408
|
+
file = File.open(ser, 'wb')
|
|
409
|
+
file.write dump
|
|
410
|
+
file.close
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
result
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
Solargraph::YardMap::CoreDocs.require_minimum
|
|
419
|
+
# Change YARD log IO to avoid sending unexpected messages to STDOUT
|
|
420
|
+
YARD::Logger.instance.io = File.new(File::NULL, 'w')
|