cosmicgraph 0.49.0
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/.github/FUNDING.yml +1 -0
- data/.github/workflows/rspec.yml +41 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +1150 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.md +136 -0
- data/Rakefile +25 -0
- data/SPONSORS.md +15 -0
- data/bin/solargraph +5 -0
- data/cosmicgraph.gemspec +44 -0
- data/lib/.rubocop.yml +22 -0
- data/lib/solargraph/api_map/bundler_methods.rb +22 -0
- data/lib/solargraph/api_map/cache.rb +70 -0
- data/lib/solargraph/api_map/source_to_yard.rb +81 -0
- data/lib/solargraph/api_map/store.rb +268 -0
- data/lib/solargraph/api_map.rb +704 -0
- data/lib/solargraph/bench.rb +27 -0
- data/lib/solargraph/cache.rb +51 -0
- data/lib/solargraph/complex_type/type_methods.rb +134 -0
- data/lib/solargraph/complex_type/unique_type.rb +132 -0
- data/lib/solargraph/complex_type.rb +254 -0
- data/lib/solargraph/convention/base.rb +33 -0
- data/lib/solargraph/convention/gemfile.rb +15 -0
- data/lib/solargraph/convention/gemspec.rb +22 -0
- data/lib/solargraph/convention/rakefile.rb +17 -0
- data/lib/solargraph/convention/rspec.rb +30 -0
- data/lib/solargraph/convention.rb +49 -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/diagnostics/base.rb +29 -0
- data/lib/solargraph/diagnostics/require_not_found.rb +53 -0
- data/lib/solargraph/diagnostics/rubocop.rb +112 -0
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +65 -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/diagnostics.rb +55 -0
- data/lib/solargraph/documentor.rb +76 -0
- data/lib/solargraph/environ.rb +45 -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/cataloger.rb +56 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -0
- data/lib/solargraph/language_server/host/dispatch.rb +111 -0
- data/lib/solargraph/language_server/host/message_worker.rb +59 -0
- data/lib/solargraph/language_server/host/sources.rb +156 -0
- data/lib/solargraph/language_server/host.rb +869 -0
- data/lib/solargraph/language_server/message/base.rb +89 -0
- data/lib/solargraph/language_server/message/cancel_request.rb +13 -0
- data/lib/solargraph/language_server/message/client/register_capability.rb +15 -0
- data/lib/solargraph/language_server/message/client.rb +11 -0
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -0
- data/lib/solargraph/language_server/message/completion_item.rb +11 -0
- data/lib/solargraph/language_server/message/exit_notification.rb +13 -0
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +100 -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 +19 -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/extended.rb +21 -0
- data/lib/solargraph/language_server/message/initialize.rb +164 -0
- data/lib/solargraph/language_server/message/initialized.rb +27 -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/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 +59 -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_highlight.rb +16 -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 +126 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +56 -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 +24 -0
- data/lib/solargraph/language_server/message/text_document.rb +28 -0
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +30 -0
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +40 -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/workspace.rb +14 -0
- data/lib/solargraph/language_server/message.rb +93 -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/adapter.rb +53 -0
- data/lib/solargraph/language_server/transport/data_reader.rb +72 -0
- data/lib/solargraph/language_server/transport.rb +13 -0
- data/lib/solargraph/language_server/uri_helpers.rb +49 -0
- data/lib/solargraph/language_server.rb +19 -0
- data/lib/solargraph/library.rb +547 -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/comment_ripper.rb +52 -0
- data/lib/solargraph/parser/legacy/class_methods.rb +135 -0
- data/lib/solargraph/parser/legacy/flawed_builder.rb +16 -0
- data/lib/solargraph/parser/legacy/node_chainer.rb +148 -0
- data/lib/solargraph/parser/legacy/node_methods.rb +325 -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 +42 -0
- data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +35 -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 +42 -0
- data/lib/solargraph/parser/legacy/node_processors/send_node.rb +257 -0
- data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +18 -0
- data/lib/solargraph/parser/legacy/node_processors.rb +54 -0
- data/lib/solargraph/parser/legacy.rb +12 -0
- data/lib/solargraph/parser/node_methods.rb +43 -0
- data/lib/solargraph/parser/node_processor/base.rb +77 -0
- data/lib/solargraph/parser/node_processor.rb +43 -0
- data/lib/solargraph/parser/region.rb +66 -0
- data/lib/solargraph/parser/rubyvm/class_methods.rb +149 -0
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +160 -0
- data/lib/solargraph/parser/rubyvm/node_methods.rb +315 -0
- data/lib/solargraph/parser/rubyvm/node_processors/alias_node.rb +23 -0
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +85 -0
- data/lib/solargraph/parser/rubyvm/node_processors/begin_node.rb +15 -0
- data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +42 -0
- data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +33 -0
- data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +23 -0
- data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +75 -0
- data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +68 -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 +26 -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 +32 -0
- data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +15 -0
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +279 -0
- data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +18 -0
- data/lib/solargraph/parser/rubyvm/node_processors.rb +63 -0
- data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
- data/lib/solargraph/parser/rubyvm.rb +40 -0
- data/lib/solargraph/parser/snippet.rb +13 -0
- data/lib/solargraph/parser.rb +26 -0
- data/lib/solargraph/pin/base.rb +299 -0
- data/lib/solargraph/pin/base_variable.rb +84 -0
- data/lib/solargraph/pin/block.rb +73 -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 +92 -0
- data/lib/solargraph/pin/documenting.rb +105 -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 +55 -0
- data/lib/solargraph/pin/method.rb +335 -0
- data/lib/solargraph/pin/method_alias.rb +31 -0
- data/lib/solargraph/pin/namespace.rb +94 -0
- data/lib/solargraph/pin/parameter.rb +206 -0
- data/lib/solargraph/pin/proxy_type.rb +29 -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/reference.rb +14 -0
- data/lib/solargraph/pin/search.rb +56 -0
- data/lib/solargraph/pin/signature.rb +23 -0
- data/lib/solargraph/pin/singleton.rb +11 -0
- data/lib/solargraph/pin/symbol.rb +47 -0
- data/lib/solargraph/pin.rb +38 -0
- data/lib/solargraph/position.rb +100 -0
- data/lib/solargraph/range.rb +95 -0
- data/lib/solargraph/rbs_map/conversions.rb +394 -0
- data/lib/solargraph/rbs_map/core_fills.rb +61 -0
- data/lib/solargraph/rbs_map/core_map.rb +38 -0
- data/lib/solargraph/rbs_map/core_signs.rb +33 -0
- data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
- data/lib/solargraph/rbs_map.rb +73 -0
- data/lib/solargraph/server_methods.rb +16 -0
- data/lib/solargraph/shell.rb +234 -0
- data/lib/solargraph/source/chain/block_variable.rb +13 -0
- data/lib/solargraph/source/chain/call.rb +215 -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/hash.rb +28 -0
- data/lib/solargraph/source/chain/head.rb +19 -0
- data/lib/solargraph/source/chain/instance_variable.rb +13 -0
- data/lib/solargraph/source/chain/link.rb +71 -0
- data/lib/solargraph/source/chain/literal.rb +23 -0
- data/lib/solargraph/source/chain/or.rb +23 -0
- data/lib/solargraph/source/chain/q_call.rb +11 -0
- data/lib/solargraph/source/chain/variable.rb +13 -0
- data/lib/solargraph/source/chain/z_super.rb +30 -0
- data/lib/solargraph/source/chain.rb +179 -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 +191 -0
- data/lib/solargraph/source/updater.rb +54 -0
- data/lib/solargraph/source.rb +522 -0
- data/lib/solargraph/source_map/clip.rb +229 -0
- data/lib/solargraph/source_map/completion.rb +23 -0
- data/lib/solargraph/source_map/mapper.rb +241 -0
- data/lib/solargraph/source_map.rb +180 -0
- data/lib/solargraph/type_checker/checks.rb +112 -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 +57 -0
- data/lib/solargraph/type_checker.rb +549 -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/config.rb +231 -0
- data/lib/solargraph/workspace.rb +212 -0
- data/lib/solargraph/yard_map/cache.rb +19 -0
- data/lib/solargraph/yard_map/helpers.rb +16 -0
- data/lib/solargraph/yard_map/mapper/to_constant.rb +25 -0
- data/lib/solargraph/yard_map/mapper/to_method.rb +81 -0
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +27 -0
- data/lib/solargraph/yard_map/mapper.rb +77 -0
- data/lib/solargraph/yard_map/to_method.rb +79 -0
- data/lib/solargraph/yard_map.rb +301 -0
- data/lib/solargraph.rb +69 -0
- data/lib/yard-solargraph.rb +33 -0
- metadata +587 -0
@@ -0,0 +1,547 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Solargraph
|
6
|
+
# A Library handles coordination between a Workspace and an ApiMap.
|
7
|
+
#
|
8
|
+
class Library
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
# @return [Solargraph::Workspace]
|
12
|
+
attr_reader :workspace
|
13
|
+
|
14
|
+
# @return [String, nil]
|
15
|
+
attr_reader :name
|
16
|
+
|
17
|
+
# @return [Source, nil]
|
18
|
+
attr_reader :current
|
19
|
+
|
20
|
+
# @param workspace [Solargraph::Workspace]
|
21
|
+
# @param name [String, nil]
|
22
|
+
def initialize workspace = Solargraph::Workspace.new, name = nil
|
23
|
+
@workspace = workspace
|
24
|
+
@name = name
|
25
|
+
@synchronized = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
# Let's not deal with insane data dumps in spec failures
|
30
|
+
to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
# True if the ApiMap is up to date with the library's workspace and open
|
34
|
+
# files.
|
35
|
+
#
|
36
|
+
# @return [Boolean]
|
37
|
+
def synchronized?
|
38
|
+
@synchronized
|
39
|
+
end
|
40
|
+
|
41
|
+
# Attach a source to the library.
|
42
|
+
#
|
43
|
+
# The attached source does not need to be a part of the workspace. The
|
44
|
+
# library will include it in the ApiMap while it's attached. Only one
|
45
|
+
# source can be attached to the library at a time.
|
46
|
+
#
|
47
|
+
# @param source [Source, nil]
|
48
|
+
# @return [void]
|
49
|
+
def attach source
|
50
|
+
mutex.synchronize do
|
51
|
+
if @current && (!source || @current.filename != source.filename) && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
|
52
|
+
source_map_hash.delete @current.filename
|
53
|
+
source_map_external_require_hash.delete @current.filename
|
54
|
+
@external_requires = nil
|
55
|
+
@synchronized = false
|
56
|
+
end
|
57
|
+
@current = source
|
58
|
+
maybe_map @current
|
59
|
+
catalog_inlock
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# True if the specified file is currently attached.
|
64
|
+
#
|
65
|
+
# @param filename [String]
|
66
|
+
# @return [Boolean]
|
67
|
+
def attached? filename
|
68
|
+
!@current.nil? && @current.filename == filename
|
69
|
+
end
|
70
|
+
alias open? attached?
|
71
|
+
|
72
|
+
# Detach the specified file if it is currently attached to the library.
|
73
|
+
#
|
74
|
+
# @param filename [String]
|
75
|
+
# @return [Boolean] True if the specified file was detached
|
76
|
+
def detach filename
|
77
|
+
return false if @current.nil? || @current.filename != filename
|
78
|
+
attach nil
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
# True if the specified file is included in the workspace (but not
|
83
|
+
# necessarily open).
|
84
|
+
#
|
85
|
+
# @param filename [String]
|
86
|
+
# @return [Boolean]
|
87
|
+
def contain? filename
|
88
|
+
workspace.has_file?(filename)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Create a source to be added to the workspace. The file is ignored if it is
|
92
|
+
# neither open in the library nor included in the workspace.
|
93
|
+
#
|
94
|
+
# @param filename [String]
|
95
|
+
# @param text [String] The contents of the file
|
96
|
+
# @return [Boolean] True if the file was added to the workspace.
|
97
|
+
def create filename, text
|
98
|
+
result = false
|
99
|
+
mutex.synchronize do
|
100
|
+
next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
|
101
|
+
@synchronized = false
|
102
|
+
source = Solargraph::Source.load_string(text, filename)
|
103
|
+
workspace.merge(source)
|
104
|
+
result = true
|
105
|
+
end
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create file sources from files on disk. A file is ignored if it is
|
110
|
+
# neither open in the library nor included in the workspace.
|
111
|
+
#
|
112
|
+
# @param filenames [Array<String>]
|
113
|
+
# @return [Boolean] True if at least one file was added to the workspace.
|
114
|
+
def create_from_disk *filenames
|
115
|
+
result = false
|
116
|
+
mutex.synchronize do
|
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 }
|
122
|
+
end
|
123
|
+
result
|
124
|
+
end
|
125
|
+
|
126
|
+
# Delete files from the library. Deleting a file will make it unavailable
|
127
|
+
# for checkout and optionally remove it from the workspace unless the
|
128
|
+
# workspace configuration determines that it should still exist.
|
129
|
+
#
|
130
|
+
# @param filenames [Array<String>]
|
131
|
+
# @return [Boolean] True if any file was deleted
|
132
|
+
def delete *filenames
|
133
|
+
result = false
|
134
|
+
filenames.each do |filename|
|
135
|
+
detach filename
|
136
|
+
mutex.synchronize do
|
137
|
+
result ||= workspace.remove(filename)
|
138
|
+
@synchronized = !result if synchronized?
|
139
|
+
end
|
140
|
+
end
|
141
|
+
result
|
142
|
+
end
|
143
|
+
|
144
|
+
# Close a file in the library. Closing a file will make it unavailable for
|
145
|
+
# checkout although it may still exist in the workspace.
|
146
|
+
#
|
147
|
+
# @param filename [String]
|
148
|
+
# @return [void]
|
149
|
+
def close filename
|
150
|
+
mutex.synchronize do
|
151
|
+
@synchronized = false
|
152
|
+
@current = nil if @current && @current.filename == filename
|
153
|
+
catalog
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Get completion suggestions at the specified file and location.
|
158
|
+
#
|
159
|
+
# @param filename [String] The file to analyze
|
160
|
+
# @param line [Integer] The zero-based line number
|
161
|
+
# @param column [Integer] The zero-based column number
|
162
|
+
# @return [SourceMap::Completion]
|
163
|
+
# @todo Take a Location instead of filename/line/column
|
164
|
+
def completions_at filename, line, column
|
165
|
+
position = Position.new(line, column)
|
166
|
+
cursor = Source::Cursor.new(read(filename), position)
|
167
|
+
api_map.clip(cursor).complete
|
168
|
+
rescue FileNotFoundError => e
|
169
|
+
handle_file_not_found filename, e
|
170
|
+
end
|
171
|
+
|
172
|
+
# Get definition suggestions for the expression at the specified file and
|
173
|
+
# location.
|
174
|
+
#
|
175
|
+
# @param filename [String] The file to analyze
|
176
|
+
# @param line [Integer] The zero-based line number
|
177
|
+
# @param column [Integer] The zero-based column number
|
178
|
+
# @return [Array<Solargraph::Pin::Base>]
|
179
|
+
# @todo Take filename/position instead of filename/line/column
|
180
|
+
def definitions_at filename, line, column
|
181
|
+
position = Position.new(line, column)
|
182
|
+
cursor = Source::Cursor.new(read(filename), position)
|
183
|
+
if cursor.comment?
|
184
|
+
source = read(filename)
|
185
|
+
offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
|
186
|
+
lft = source.code[0..offset-1].match(/\[[a-z0-9_:<, ]*?([a-z0-9_:]*)\z/i)
|
187
|
+
rgt = source.code[offset..-1].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
|
188
|
+
if lft && rgt
|
189
|
+
tag = (lft[1] + rgt[1]).sub(/:+$/, '')
|
190
|
+
clip = api_map.clip(cursor)
|
191
|
+
clip.translate tag
|
192
|
+
else
|
193
|
+
[]
|
194
|
+
end
|
195
|
+
else
|
196
|
+
api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
|
197
|
+
end
|
198
|
+
rescue FileNotFoundError => e
|
199
|
+
handle_file_not_found(filename, e)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Get signature suggestions for the method at the specified file and
|
203
|
+
# location.
|
204
|
+
#
|
205
|
+
# @param filename [String] The file to analyze
|
206
|
+
# @param line [Integer] The zero-based line number
|
207
|
+
# @param column [Integer] The zero-based column number
|
208
|
+
# @return [Array<Solargraph::Pin::Base>]
|
209
|
+
# @todo Take filename/position instead of filename/line/column
|
210
|
+
def signatures_at filename, line, column
|
211
|
+
position = Position.new(line, column)
|
212
|
+
cursor = Source::Cursor.new(read(filename), position)
|
213
|
+
api_map.clip(cursor).signify
|
214
|
+
end
|
215
|
+
|
216
|
+
# @param filename [String]
|
217
|
+
# @param line [Integer]
|
218
|
+
# @param column [Integer]
|
219
|
+
# @param strip [Boolean] Strip special characters from variable names
|
220
|
+
# @param only [Boolean] Search for references in the current file only
|
221
|
+
# @return [Array<Solargraph::Range>]
|
222
|
+
# @todo Take a Location instead of filename/line/column
|
223
|
+
def references_from filename, line, column, strip: false, only: false
|
224
|
+
cursor = api_map.cursor_at(filename, Position.new(line, column))
|
225
|
+
clip = api_map.clip(cursor)
|
226
|
+
pin = clip.define.first
|
227
|
+
return [] unless pin
|
228
|
+
result = []
|
229
|
+
files = if only
|
230
|
+
[api_map.source_map(filename)]
|
231
|
+
else
|
232
|
+
(workspace.sources + (@current ? [@current] : []))
|
233
|
+
end
|
234
|
+
files.uniq(&:filename).each do |source|
|
235
|
+
found = source.references(pin.name)
|
236
|
+
found.select! do |loc|
|
237
|
+
referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
|
238
|
+
referenced && referenced.path == pin.path
|
239
|
+
end
|
240
|
+
# HACK: for language clients that exclude special characters from the start of variable names
|
241
|
+
if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
|
242
|
+
found.map! do |loc|
|
243
|
+
Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
|
244
|
+
end
|
245
|
+
end
|
246
|
+
result.concat(found.sort do |a, b|
|
247
|
+
a.range.start.line <=> b.range.start.line
|
248
|
+
end)
|
249
|
+
end
|
250
|
+
result.uniq
|
251
|
+
end
|
252
|
+
|
253
|
+
# Get the pins at the specified location or nil if the pin does not exist.
|
254
|
+
#
|
255
|
+
# @param location [Location]
|
256
|
+
# @return [Array<Solargraph::Pin::Base>]
|
257
|
+
def locate_pins location
|
258
|
+
api_map.locate_pins(location).map { |pin| pin.realize(api_map) }
|
259
|
+
end
|
260
|
+
|
261
|
+
def locate_ref location
|
262
|
+
map = source_map_hash[location.filename]
|
263
|
+
return if map.nil?
|
264
|
+
pin = map.requires.select { |p| p.location.range.contain?(location.range.start) }.first
|
265
|
+
return nil if pin.nil?
|
266
|
+
workspace.require_paths.each do |path|
|
267
|
+
full = Pathname.new(path).join("#{pin.name}.rb").to_s
|
268
|
+
next unless source_map_hash.key?(full)
|
269
|
+
return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
|
270
|
+
end
|
271
|
+
# api_map.yard_map.require_reference(pin.name)
|
272
|
+
rescue FileNotFoundError
|
273
|
+
nil
|
274
|
+
end
|
275
|
+
|
276
|
+
# Get an array of pins that match a path.
|
277
|
+
#
|
278
|
+
# @param path [String]
|
279
|
+
# @return [Array<Solargraph::Pin::Base>]
|
280
|
+
def get_path_pins path
|
281
|
+
api_map.get_path_suggestions(path)
|
282
|
+
end
|
283
|
+
|
284
|
+
# @param query [String]
|
285
|
+
# @return [Array<YARD::CodeObjects::Base>]
|
286
|
+
def document query
|
287
|
+
api_map.document query
|
288
|
+
end
|
289
|
+
|
290
|
+
# @param query [String]
|
291
|
+
# @return [Array<String>]
|
292
|
+
def search query
|
293
|
+
api_map.search query
|
294
|
+
end
|
295
|
+
|
296
|
+
# Get an array of all symbols in the workspace that match the query.
|
297
|
+
#
|
298
|
+
# @param query [String]
|
299
|
+
# @return [Array<Pin::Base>]
|
300
|
+
def query_symbols query
|
301
|
+
api_map.query_symbols query
|
302
|
+
end
|
303
|
+
|
304
|
+
# Get an array of document symbols.
|
305
|
+
#
|
306
|
+
# Document symbols are composed of namespace, method, and constant pins.
|
307
|
+
# The results of this query are appropriate for building the response to a
|
308
|
+
# textDocument/documentSymbol message in the language server protocol.
|
309
|
+
#
|
310
|
+
# @param filename [String]
|
311
|
+
# @return [Array<Solargraph::Pin::Base>]
|
312
|
+
def document_symbols filename
|
313
|
+
api_map.document_symbols(filename)
|
314
|
+
end
|
315
|
+
|
316
|
+
# @param path [String]
|
317
|
+
# @return [Array<Solargraph::Pin::Base>]
|
318
|
+
def path_pins path
|
319
|
+
api_map.get_path_suggestions(path)
|
320
|
+
end
|
321
|
+
|
322
|
+
def source_maps
|
323
|
+
source_map_hash.values
|
324
|
+
end
|
325
|
+
|
326
|
+
# Get the current text of a file in the library.
|
327
|
+
#
|
328
|
+
# @param filename [String]
|
329
|
+
# @return [String]
|
330
|
+
def read_text filename
|
331
|
+
source = read(filename)
|
332
|
+
source.code
|
333
|
+
end
|
334
|
+
|
335
|
+
# Get diagnostics about a file.
|
336
|
+
#
|
337
|
+
# @param filename [String]
|
338
|
+
# @return [Array<Hash>]
|
339
|
+
def diagnose filename
|
340
|
+
# @todo Only open files get diagnosed. Determine whether anything or
|
341
|
+
# everything in the workspace should get diagnosed, or if there should
|
342
|
+
# be an option to do so.
|
343
|
+
#
|
344
|
+
return [] unless open?(filename)
|
345
|
+
result = []
|
346
|
+
source = read(filename)
|
347
|
+
catalog
|
348
|
+
repargs = {}
|
349
|
+
workspace.config.reporters.each do |line|
|
350
|
+
if line == 'all!'
|
351
|
+
Diagnostics.reporters.each do |reporter|
|
352
|
+
repargs[reporter] ||= []
|
353
|
+
end
|
354
|
+
else
|
355
|
+
args = line.split(':').map(&:strip)
|
356
|
+
name = args.shift
|
357
|
+
reporter = Diagnostics.reporter(name)
|
358
|
+
raise DiagnosticsError, "Diagnostics reporter #{name} does not exist" if reporter.nil?
|
359
|
+
repargs[reporter] ||= []
|
360
|
+
repargs[reporter].concat args
|
361
|
+
end
|
362
|
+
end
|
363
|
+
repargs.each_pair do |reporter, args|
|
364
|
+
result.concat reporter.new(*args.uniq).diagnose(source, api_map)
|
365
|
+
end
|
366
|
+
result
|
367
|
+
end
|
368
|
+
|
369
|
+
# Update the ApiMap from the library's workspace and open files.
|
370
|
+
#
|
371
|
+
# @return [void]
|
372
|
+
def catalog
|
373
|
+
mutex.synchronize do
|
374
|
+
catalog_inlock
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
private def catalog_inlock
|
379
|
+
return if synchronized?
|
380
|
+
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
381
|
+
api_map.catalog bench
|
382
|
+
@synchronized = true
|
383
|
+
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)" if logger.info?
|
384
|
+
end
|
385
|
+
|
386
|
+
def bench
|
387
|
+
Bench.new(
|
388
|
+
source_maps: source_map_hash.values,
|
389
|
+
workspace: workspace,
|
390
|
+
external_requires: external_requires
|
391
|
+
)
|
392
|
+
end
|
393
|
+
|
394
|
+
# Get an array of foldable ranges for the specified file.
|
395
|
+
#
|
396
|
+
# @deprecated The library should not need to handle folding ranges. The
|
397
|
+
# source itself has all the information it needs.
|
398
|
+
#
|
399
|
+
# @param filename [String]
|
400
|
+
# @return [Array<Range>]
|
401
|
+
def folding_ranges filename
|
402
|
+
read(filename).folding_ranges
|
403
|
+
end
|
404
|
+
|
405
|
+
# Create a library from a directory.
|
406
|
+
#
|
407
|
+
# @param directory [String] The path to be used for the workspace
|
408
|
+
# @param name [String, nil]
|
409
|
+
# @return [Solargraph::Library]
|
410
|
+
def self.load directory = '', name = nil
|
411
|
+
Solargraph::Library.new(Solargraph::Workspace.new(directory), name)
|
412
|
+
end
|
413
|
+
|
414
|
+
# Try to merge a source into the library's workspace. If the workspace is
|
415
|
+
# not configured to include the source, it gets ignored.
|
416
|
+
#
|
417
|
+
# @param source [Source]
|
418
|
+
# @return [Boolean] True if the source was merged into the workspace.
|
419
|
+
def merge source
|
420
|
+
Logging.logger.debug "Merging source: #{source.filename}"
|
421
|
+
result = false
|
422
|
+
mutex.synchronize do
|
423
|
+
result = workspace.merge(source)
|
424
|
+
maybe_map source
|
425
|
+
end
|
426
|
+
# catalog
|
427
|
+
result
|
428
|
+
end
|
429
|
+
|
430
|
+
def source_map_hash
|
431
|
+
@source_map_hash ||= {}
|
432
|
+
end
|
433
|
+
|
434
|
+
def mapped?
|
435
|
+
(workspace.filenames - source_map_hash.keys).empty?
|
436
|
+
end
|
437
|
+
|
438
|
+
def next_map
|
439
|
+
return false if mapped?
|
440
|
+
mutex.synchronize do
|
441
|
+
@synchronized = false
|
442
|
+
src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
|
443
|
+
if src
|
444
|
+
Logging.logger.debug "Mapping #{src.filename}"
|
445
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
446
|
+
find_external_requires(source_map_hash[src.filename])
|
447
|
+
source_map_hash[src.filename]
|
448
|
+
else
|
449
|
+
false
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def map!
|
455
|
+
workspace.sources.each do |src|
|
456
|
+
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
457
|
+
find_external_requires(source_map_hash[src.filename])
|
458
|
+
end
|
459
|
+
self
|
460
|
+
end
|
461
|
+
|
462
|
+
def pins
|
463
|
+
@pins ||= []
|
464
|
+
end
|
465
|
+
|
466
|
+
def external_requires
|
467
|
+
@external_requires ||= source_map_external_require_hash.values.flatten.to_set
|
468
|
+
end
|
469
|
+
|
470
|
+
private
|
471
|
+
|
472
|
+
def source_map_external_require_hash
|
473
|
+
@source_map_external_require_hash ||= {}
|
474
|
+
end
|
475
|
+
|
476
|
+
# @param source_map [SourceMap]
|
477
|
+
def find_external_requires source_map
|
478
|
+
new_set = source_map.requires.map(&:name).to_set
|
479
|
+
# return if new_set == source_map_external_require_hash[source_map.filename]
|
480
|
+
source_map_external_require_hash[source_map.filename] = new_set.reject do |path|
|
481
|
+
workspace.require_paths.any? do |base|
|
482
|
+
full = Pathname.new(base).join("#{path}.rb").to_s
|
483
|
+
workspace.filenames.include?(full)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
@external_requires = nil
|
487
|
+
end
|
488
|
+
|
489
|
+
# @return [Mutex]
|
490
|
+
def mutex
|
491
|
+
@mutex ||= Mutex.new
|
492
|
+
end
|
493
|
+
|
494
|
+
# @return [ApiMap]
|
495
|
+
def api_map
|
496
|
+
@api_map ||= Solargraph::ApiMap.new
|
497
|
+
end
|
498
|
+
|
499
|
+
# Get the source for an open file or create a new source if the file
|
500
|
+
# exists on disk. Sources created from disk are not added to the open
|
501
|
+
# workspace files, i.e., the version on disk remains the authoritative
|
502
|
+
# version.
|
503
|
+
#
|
504
|
+
# @raise [FileNotFoundError] if the file does not exist
|
505
|
+
# @param filename [String]
|
506
|
+
# @return [Solargraph::Source]
|
507
|
+
def read filename
|
508
|
+
return @current if @current && @current.filename == filename
|
509
|
+
raise FileNotFoundError, "File not found: #{filename}" unless workspace.has_file?(filename)
|
510
|
+
workspace.source(filename)
|
511
|
+
end
|
512
|
+
|
513
|
+
def handle_file_not_found filename, error
|
514
|
+
if workspace.source(filename)
|
515
|
+
Solargraph.logger.debug "#{filename} is not cataloged in the ApiMap"
|
516
|
+
nil
|
517
|
+
else
|
518
|
+
raise error
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
def maybe_map source
|
523
|
+
return unless source
|
524
|
+
return unless @current == source || workspace.has_file?(source.filename)
|
525
|
+
if source_map_hash.key?(source.filename)
|
526
|
+
return if source_map_hash[source.filename].code == source.code &&
|
527
|
+
source_map_hash[source.filename].source.synchronized? &&
|
528
|
+
source.synchronized?
|
529
|
+
if source.synchronized?
|
530
|
+
new_map = Solargraph::SourceMap.map(source)
|
531
|
+
unless source_map_hash[source.filename].try_merge!(new_map)
|
532
|
+
source_map_hash[source.filename] = new_map
|
533
|
+
find_external_requires(source_map_hash[source.filename])
|
534
|
+
@synchronized = false
|
535
|
+
end
|
536
|
+
else
|
537
|
+
# @todo Smelly instance variable access
|
538
|
+
source_map_hash[source.filename].instance_variable_set(:@source, source)
|
539
|
+
end
|
540
|
+
else
|
541
|
+
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
542
|
+
find_external_requires(source_map_hash[source.filename])
|
543
|
+
@synchronized = false
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solargraph
|
4
|
+
# A section of text identified by its filename and range.
|
5
|
+
#
|
6
|
+
class Location
|
7
|
+
# @return [String]
|
8
|
+
attr_reader :filename
|
9
|
+
|
10
|
+
# @return [Solargraph::Range]
|
11
|
+
attr_reader :range
|
12
|
+
|
13
|
+
# @param filename [String]
|
14
|
+
# @param range [Solargraph::Range]
|
15
|
+
def initialize filename, range
|
16
|
+
@filename = filename
|
17
|
+
@range = range
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Hash]
|
21
|
+
def to_hash
|
22
|
+
{
|
23
|
+
filename: filename,
|
24
|
+
range: range.to_hash
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def == other
|
29
|
+
return false unless other.is_a?(Location)
|
30
|
+
filename == other.filename and range == other.range
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
"#<#{self.class} #{filename}, #{range.inspect}>"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Solargraph
|
6
|
+
module Logging
|
7
|
+
DEFAULT_LOG_LEVEL = Logger::WARN
|
8
|
+
|
9
|
+
LOG_LEVELS = {
|
10
|
+
'warn' => Logger::WARN,
|
11
|
+
'info' => Logger::INFO,
|
12
|
+
'debug' => Logger::DEBUG
|
13
|
+
}
|
14
|
+
|
15
|
+
@@logger = Logger.new(STDERR, level: DEFAULT_LOG_LEVEL)
|
16
|
+
@@logger.formatter = proc do |severity, datetime, progname, msg|
|
17
|
+
"[#{severity}] #{msg}\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
# @return [Logger]
|
23
|
+
def logger
|
24
|
+
@@logger
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
require 'tilt'
|
5
|
+
require 'yard'
|
6
|
+
require 'cgi'
|
7
|
+
|
8
|
+
module Solargraph
|
9
|
+
class Page
|
10
|
+
class Binder < OpenStruct
|
11
|
+
# @param locals [Hash]
|
12
|
+
# @param render_method [Proc]
|
13
|
+
def initialize locals, render_method
|
14
|
+
super(locals)
|
15
|
+
define_singleton_method :render do |template, layout: false, locals: {}|
|
16
|
+
render_method.call(template, layout: layout, locals: locals)
|
17
|
+
end
|
18
|
+
define_singleton_method :erb do |template, layout: false, locals: {}|
|
19
|
+
render_method.call(template, layout: layout, locals: locals)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param text [String]
|
24
|
+
# @return [String]
|
25
|
+
def htmlify text
|
26
|
+
YARD::Templates::Helpers::Markup::RDocMarkup.new(text).to_html
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param text [String]
|
30
|
+
# @return [String]
|
31
|
+
def escape text
|
32
|
+
CGI.escapeHTML(text)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param code [String]
|
36
|
+
# @return [String]
|
37
|
+
def ruby_to_html code
|
38
|
+
code
|
39
|
+
end
|
40
|
+
end
|
41
|
+
private_constant :Binder
|
42
|
+
|
43
|
+
# @param directory [String]
|
44
|
+
def initialize directory = VIEWS_PATH
|
45
|
+
directory = VIEWS_PATH if directory.nil? or !File.directory?(directory)
|
46
|
+
directories = [directory]
|
47
|
+
directories.push VIEWS_PATH if directory != VIEWS_PATH
|
48
|
+
# @type [Proc]
|
49
|
+
# @param template [String]
|
50
|
+
# @param layout [Boolean]
|
51
|
+
# @param locals [Hash]
|
52
|
+
@render_method = proc { |template, layout: false, locals: {}|
|
53
|
+
binder = Binder.new(locals, @render_method)
|
54
|
+
if layout
|
55
|
+
Tilt::ERBTemplate.new(Page.select_template(directories, 'layout')).render(binder) do
|
56
|
+
Tilt::ERBTemplate.new(Page.select_template(directories, template)).render(binder)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
Tilt::ERBTemplate.new(Page.select_template(directories, template)).render(binder)
|
60
|
+
end
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# @param template [String]
|
65
|
+
# @param layout [Boolean]
|
66
|
+
# @param locals [Hash]
|
67
|
+
# @return [String]
|
68
|
+
def render template, layout: true, locals: {}
|
69
|
+
@render_method.call(template, layout: layout, locals: locals)
|
70
|
+
end
|
71
|
+
|
72
|
+
# @param directories [Array<String>]
|
73
|
+
# @param name [String]
|
74
|
+
# @return [String]
|
75
|
+
def self.select_template directories, name
|
76
|
+
directories.each do |dir|
|
77
|
+
path = File.join(dir, "#{name}.erb")
|
78
|
+
return path if File.file?(path)
|
79
|
+
end
|
80
|
+
raise FileNotFoundError, "Template not found: #{name}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|