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,869 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'diff/lcs'
|
4
|
+
require 'observer'
|
5
|
+
require 'securerandom'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
module Solargraph
|
9
|
+
module LanguageServer
|
10
|
+
# The language server protocol's data provider. Hosts are responsible for
|
11
|
+
# querying the library and processing messages. They also provide thread
|
12
|
+
# safety for multi-threaded transports.
|
13
|
+
#
|
14
|
+
class Host
|
15
|
+
autoload :Diagnoser, 'solargraph/language_server/host/diagnoser'
|
16
|
+
autoload :Cataloger, 'solargraph/language_server/host/cataloger'
|
17
|
+
autoload :Sources, 'solargraph/language_server/host/sources'
|
18
|
+
autoload :Dispatch, 'solargraph/language_server/host/dispatch'
|
19
|
+
autoload :MessageWorker, 'solargraph/language_server/host/message_worker'
|
20
|
+
|
21
|
+
include UriHelpers
|
22
|
+
include Logging
|
23
|
+
include Dispatch
|
24
|
+
include Observable
|
25
|
+
|
26
|
+
attr_writer :client_capabilities
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@cancel_semaphore = Mutex.new
|
30
|
+
@buffer_semaphore = Mutex.new
|
31
|
+
@request_mutex = Mutex.new
|
32
|
+
@cancel = []
|
33
|
+
@buffer = String.new
|
34
|
+
@stopped = true
|
35
|
+
@next_request_id = 1
|
36
|
+
@dynamic_capabilities = Set.new
|
37
|
+
@registered_capabilities = Set.new
|
38
|
+
end
|
39
|
+
|
40
|
+
# Start asynchronous process handling.
|
41
|
+
#
|
42
|
+
# @return [void]
|
43
|
+
def start
|
44
|
+
return unless stopped?
|
45
|
+
@stopped = false
|
46
|
+
diagnoser.start
|
47
|
+
cataloger.start
|
48
|
+
sources.start
|
49
|
+
message_worker.start
|
50
|
+
end
|
51
|
+
|
52
|
+
# Update the configuration options with the provided hash.
|
53
|
+
#
|
54
|
+
# @param update [Hash]
|
55
|
+
# @return [void]
|
56
|
+
def configure update
|
57
|
+
return if update.nil?
|
58
|
+
options.merge! update
|
59
|
+
logger.level = LOG_LEVELS[options['logLevel']] || DEFAULT_LOG_LEVEL
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Hash]
|
63
|
+
def options
|
64
|
+
@options ||= default_configuration
|
65
|
+
end
|
66
|
+
|
67
|
+
# Cancel the method with the specified ID.
|
68
|
+
#
|
69
|
+
# @param id [Integer]
|
70
|
+
# @return [void]
|
71
|
+
def cancel id
|
72
|
+
@cancel_semaphore.synchronize { @cancel.push id }
|
73
|
+
end
|
74
|
+
|
75
|
+
# True if the host received a request to cancel the method with the
|
76
|
+
# specified ID.
|
77
|
+
#
|
78
|
+
# @param id [Integer]
|
79
|
+
# @return [Boolean]
|
80
|
+
def cancel? id
|
81
|
+
result = false
|
82
|
+
@cancel_semaphore.synchronize { result = @cancel.include? id }
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
# Delete the specified ID from the list of cancelled IDs if it exists.
|
87
|
+
#
|
88
|
+
# @param id [Integer]
|
89
|
+
# @return [void]
|
90
|
+
def clear id
|
91
|
+
@cancel_semaphore.synchronize { @cancel.delete id }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Called by adapter, to handle the request
|
95
|
+
# @param request [Hash]
|
96
|
+
# @return [void]
|
97
|
+
def process request
|
98
|
+
message_worker.queue(request)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Start processing a request from the client. After the message is
|
102
|
+
# processed, caller is responsible for sending the response.
|
103
|
+
#
|
104
|
+
# @param request [Hash] The contents of the message.
|
105
|
+
# @return [Solargraph::LanguageServer::Message::Base] The message handler.
|
106
|
+
def receive request
|
107
|
+
if request['method']
|
108
|
+
logger.info "Server received #{request['method']}"
|
109
|
+
logger.debug request
|
110
|
+
message = Message.select(request['method']).new(self, request)
|
111
|
+
begin
|
112
|
+
message.process
|
113
|
+
rescue StandardError => e
|
114
|
+
logger.warn "Error processing request: [#{e.class}] #{e.message}"
|
115
|
+
logger.warn e.backtrace.join("\n")
|
116
|
+
message.set_error Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}"
|
117
|
+
end
|
118
|
+
message
|
119
|
+
elsif request['id']
|
120
|
+
if requests[request['id']]
|
121
|
+
requests[request['id']].process(request['result'])
|
122
|
+
requests.delete request['id']
|
123
|
+
else
|
124
|
+
logger.warn "Discarding client response to unrecognized message #{request['id']}"
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
else
|
128
|
+
logger.warn "Invalid message received."
|
129
|
+
logger.debug request
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Respond to a notification that files were created in the workspace.
|
134
|
+
# The libraries will determine whether the files should be merged; see
|
135
|
+
# Solargraph::Library#create_from_disk.
|
136
|
+
#
|
137
|
+
# @param uris [Array<String>] The URIs of the files.
|
138
|
+
# @return [Boolean] True if at least one library accepted at least one file.
|
139
|
+
def create *uris
|
140
|
+
filenames = uris.map { |uri| uri_to_file(uri) }
|
141
|
+
result = false
|
142
|
+
libraries.each do |lib|
|
143
|
+
result = true if lib.create_from_disk(*filenames)
|
144
|
+
end
|
145
|
+
uris.each do |uri|
|
146
|
+
diagnoser.schedule uri if open?(uri)
|
147
|
+
end
|
148
|
+
result
|
149
|
+
end
|
150
|
+
|
151
|
+
# Delete the specified files from the library.
|
152
|
+
#
|
153
|
+
# @param uris [Array<String>] The file uris.
|
154
|
+
# @return [void]
|
155
|
+
def delete *uris
|
156
|
+
filenames = uris.map { |uri| uri_to_file(uri) }
|
157
|
+
libraries.each do |lib|
|
158
|
+
lib.delete(*filenames)
|
159
|
+
end
|
160
|
+
uris.each do |uri|
|
161
|
+
send_notification "textDocument/publishDiagnostics", {
|
162
|
+
uri: uri,
|
163
|
+
diagnostics: []
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Open the specified file in the library.
|
169
|
+
#
|
170
|
+
# @param uri [String] The file uri.
|
171
|
+
# @param text [String] The contents of the file.
|
172
|
+
# @param version [Integer] A version number.
|
173
|
+
# @return [void]
|
174
|
+
def open uri, text, version
|
175
|
+
src = sources.open(uri, text, version)
|
176
|
+
libraries.each do |lib|
|
177
|
+
lib.merge src
|
178
|
+
end
|
179
|
+
diagnoser.schedule uri
|
180
|
+
end
|
181
|
+
|
182
|
+
# @param uri [String]
|
183
|
+
# @return [void]
|
184
|
+
def open_from_disk uri
|
185
|
+
sources.open_from_disk(uri)
|
186
|
+
diagnoser.schedule uri
|
187
|
+
end
|
188
|
+
|
189
|
+
# True if the specified file is currently open in the library.
|
190
|
+
#
|
191
|
+
# @param uri [String]
|
192
|
+
# @return [Boolean]
|
193
|
+
def open? uri
|
194
|
+
sources.include? uri
|
195
|
+
end
|
196
|
+
|
197
|
+
# Close the file specified by the URI.
|
198
|
+
#
|
199
|
+
# @param uri [String]
|
200
|
+
# @return [void]
|
201
|
+
def close uri
|
202
|
+
logger.info "Closing #{uri}"
|
203
|
+
sources.close uri
|
204
|
+
diagnoser.schedule uri
|
205
|
+
end
|
206
|
+
|
207
|
+
# @param uri [String]
|
208
|
+
# @return [void]
|
209
|
+
def diagnose uri
|
210
|
+
if sources.include?(uri)
|
211
|
+
library = library_for(uri)
|
212
|
+
if library.mapped? && library.synchronized?
|
213
|
+
logger.info "Diagnosing #{uri}"
|
214
|
+
begin
|
215
|
+
results = library.diagnose uri_to_file(uri)
|
216
|
+
send_notification "textDocument/publishDiagnostics", {
|
217
|
+
uri: uri,
|
218
|
+
diagnostics: results
|
219
|
+
}
|
220
|
+
rescue DiagnosticsError => e
|
221
|
+
logger.warn "Error in diagnostics: #{e.message}"
|
222
|
+
options['diagnostics'] = false
|
223
|
+
send_notification 'window/showMessage', {
|
224
|
+
type: LanguageServer::MessageTypes::ERROR,
|
225
|
+
message: "Error in diagnostics: #{e.message}"
|
226
|
+
}
|
227
|
+
rescue FileNotFoundError => e
|
228
|
+
# @todo This appears to happen when an external file is open and
|
229
|
+
# scheduled for diagnosis, but the file was closed (i.e., the
|
230
|
+
# editor moved to a different file) before diagnosis started
|
231
|
+
logger.warn "Unable to diagnose #{uri} : #{e.message}"
|
232
|
+
send_notification 'textDocument/publishDiagnostics', {
|
233
|
+
uri: uri,
|
234
|
+
diagnostics: []
|
235
|
+
}
|
236
|
+
end
|
237
|
+
else
|
238
|
+
logger.info "Deferring diagnosis of #{uri}"
|
239
|
+
diagnoser.schedule uri
|
240
|
+
end
|
241
|
+
else
|
242
|
+
send_notification 'textDocument/publishDiagnostics', {
|
243
|
+
uri: uri,
|
244
|
+
diagnostics: []
|
245
|
+
}
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Update a document from the parameters of a textDocument/didChange
|
250
|
+
# method.
|
251
|
+
#
|
252
|
+
# @param params [Hash]
|
253
|
+
# @return [void]
|
254
|
+
def change params
|
255
|
+
updater = generate_updater(params)
|
256
|
+
sources.async_update params['textDocument']['uri'], updater
|
257
|
+
diagnoser.schedule params['textDocument']['uri']
|
258
|
+
end
|
259
|
+
|
260
|
+
# Queue a message to be sent to the client.
|
261
|
+
#
|
262
|
+
# @param message [String] The message to send.
|
263
|
+
# @return [void]
|
264
|
+
def queue message
|
265
|
+
@buffer_semaphore.synchronize { @buffer += message }
|
266
|
+
changed
|
267
|
+
notify_observers
|
268
|
+
end
|
269
|
+
|
270
|
+
# Clear the message buffer and return the most recent data.
|
271
|
+
#
|
272
|
+
# @return [String] The most recent data or an empty string.
|
273
|
+
def flush
|
274
|
+
tmp = ''
|
275
|
+
@buffer_semaphore.synchronize do
|
276
|
+
tmp = @buffer.clone
|
277
|
+
@buffer.clear
|
278
|
+
end
|
279
|
+
tmp
|
280
|
+
end
|
281
|
+
|
282
|
+
# Prepare a library for the specified directory.
|
283
|
+
#
|
284
|
+
# @param directory [String]
|
285
|
+
# @param name [String, nil]
|
286
|
+
# @return [void]
|
287
|
+
def prepare directory, name = nil
|
288
|
+
# No need to create a library without a directory. The generic library
|
289
|
+
# will handle it.
|
290
|
+
return if directory.nil?
|
291
|
+
logger.info "Preparing library for #{directory}"
|
292
|
+
path = ''
|
293
|
+
path = normalize_separators(directory) unless directory.nil?
|
294
|
+
begin
|
295
|
+
lib = Solargraph::Library.load(path, name)
|
296
|
+
libraries.push lib
|
297
|
+
async_library_map lib
|
298
|
+
rescue WorkspaceTooLargeError => e
|
299
|
+
send_notification 'window/showMessage', {
|
300
|
+
'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
|
301
|
+
'message' => e.message
|
302
|
+
}
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# Prepare multiple folders.
|
307
|
+
#
|
308
|
+
# @param array [Array<Hash{String => String}>]
|
309
|
+
# @return [void]
|
310
|
+
def prepare_folders array
|
311
|
+
return if array.nil?
|
312
|
+
array.each do |folder|
|
313
|
+
prepare uri_to_file(folder['uri']), folder['name']
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# Remove a directory.
|
318
|
+
#
|
319
|
+
# @param directory [String]
|
320
|
+
# @return [void]
|
321
|
+
def remove directory
|
322
|
+
logger.info "Removing library for #{directory}"
|
323
|
+
# @param lib [Library]
|
324
|
+
libraries.delete_if do |lib|
|
325
|
+
next false if lib.workspace.directory != directory
|
326
|
+
true
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# @param array [Array<Hash>]
|
331
|
+
# @return [void]
|
332
|
+
def remove_folders array
|
333
|
+
array.each do |folder|
|
334
|
+
remove uri_to_file(folder['uri'])
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# @return [Array<String>]
|
339
|
+
def folders
|
340
|
+
libraries.map { |lib| lib.workspace.directory }
|
341
|
+
end
|
342
|
+
|
343
|
+
# Send a notification to the client.
|
344
|
+
#
|
345
|
+
# @param method [String] The message method
|
346
|
+
# @param params [Hash] The method parameters
|
347
|
+
# @return [void]
|
348
|
+
def send_notification method, params
|
349
|
+
response = {
|
350
|
+
jsonrpc: "2.0",
|
351
|
+
method: method,
|
352
|
+
params: params
|
353
|
+
}
|
354
|
+
json = response.to_json
|
355
|
+
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
356
|
+
queue envelope
|
357
|
+
logger.info "Server sent #{method}"
|
358
|
+
logger.debug params
|
359
|
+
end
|
360
|
+
|
361
|
+
# Send a request to the client and execute the provided block to process
|
362
|
+
# the response. If an ID is not provided, the host will use an auto-
|
363
|
+
# incrementing integer.
|
364
|
+
#
|
365
|
+
# @param method [String] The message method
|
366
|
+
# @param params [Hash] The method parameters
|
367
|
+
# @param block [Proc] The block that processes the response
|
368
|
+
# @yieldparam [Hash] The result sent by the client
|
369
|
+
# @return [void]
|
370
|
+
def send_request method, params, &block
|
371
|
+
@request_mutex.synchronize do
|
372
|
+
message = {
|
373
|
+
jsonrpc: "2.0",
|
374
|
+
method: method,
|
375
|
+
params: params,
|
376
|
+
id: @next_request_id
|
377
|
+
}
|
378
|
+
json = message.to_json
|
379
|
+
requests[@next_request_id] = Request.new(@next_request_id, &block)
|
380
|
+
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
381
|
+
queue envelope
|
382
|
+
@next_request_id += 1
|
383
|
+
logger.info "Server sent #{method}"
|
384
|
+
logger.debug params
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Register the methods as capabilities with the client.
|
389
|
+
# This method will avoid duplicating registrations and ignore methods
|
390
|
+
# that were not flagged for dynamic registration by the client.
|
391
|
+
#
|
392
|
+
# @param methods [Array<String>] The methods to register
|
393
|
+
# @return [void]
|
394
|
+
def register_capabilities methods
|
395
|
+
logger.debug "Registering capabilities: #{methods}"
|
396
|
+
registrations = methods.select { |m| can_register?(m) and !registered?(m) }.map do |m|
|
397
|
+
@registered_capabilities.add m
|
398
|
+
{
|
399
|
+
id: m,
|
400
|
+
method: m,
|
401
|
+
registerOptions: dynamic_capability_options[m]
|
402
|
+
}
|
403
|
+
end
|
404
|
+
return if registrations.empty?
|
405
|
+
send_request 'client/registerCapability', { registrations: registrations }
|
406
|
+
end
|
407
|
+
|
408
|
+
# Unregister the methods with the client.
|
409
|
+
# This method will avoid duplicating unregistrations and ignore methods
|
410
|
+
# that were not flagged for dynamic registration by the client.
|
411
|
+
#
|
412
|
+
# @param methods [Array<String>] The methods to unregister
|
413
|
+
# @return [void]
|
414
|
+
def unregister_capabilities methods
|
415
|
+
logger.debug "Unregistering capabilities: #{methods}"
|
416
|
+
unregisterations = methods.select{|m| registered?(m)}.map{ |m|
|
417
|
+
@registered_capabilities.delete m
|
418
|
+
{
|
419
|
+
id: m,
|
420
|
+
method: m
|
421
|
+
}
|
422
|
+
}
|
423
|
+
return if unregisterations.empty?
|
424
|
+
send_request 'client/unregisterCapability', { unregisterations: unregisterations }
|
425
|
+
end
|
426
|
+
|
427
|
+
# Flag a method as available for dynamic registration.
|
428
|
+
#
|
429
|
+
# @param method [String] The method name, e.g., 'textDocument/completion'
|
430
|
+
# @return [void]
|
431
|
+
def allow_registration method
|
432
|
+
@dynamic_capabilities.add method
|
433
|
+
end
|
434
|
+
|
435
|
+
# True if the specified LSP method can be dynamically registered.
|
436
|
+
#
|
437
|
+
# @param method [String]
|
438
|
+
# @return [Boolean]
|
439
|
+
def can_register? method
|
440
|
+
@dynamic_capabilities.include?(method)
|
441
|
+
end
|
442
|
+
|
443
|
+
# True if the specified method has been registered.
|
444
|
+
#
|
445
|
+
# @param method [String] The method name, e.g., 'textDocument/completion'
|
446
|
+
# @return [Boolean]
|
447
|
+
def registered? method
|
448
|
+
@registered_capabilities.include?(method)
|
449
|
+
end
|
450
|
+
|
451
|
+
def synchronizing?
|
452
|
+
!libraries.all?(&:synchronized?)
|
453
|
+
end
|
454
|
+
|
455
|
+
# @return [void]
|
456
|
+
def stop
|
457
|
+
return if @stopped
|
458
|
+
@stopped = true
|
459
|
+
message_worker.stop
|
460
|
+
cataloger.stop
|
461
|
+
diagnoser.stop
|
462
|
+
sources.stop
|
463
|
+
changed
|
464
|
+
notify_observers
|
465
|
+
end
|
466
|
+
|
467
|
+
def stopped?
|
468
|
+
@stopped
|
469
|
+
end
|
470
|
+
|
471
|
+
# Locate multiple pins that match a completion item. The first match is
|
472
|
+
# based on the corresponding location in a library source if available.
|
473
|
+
# Subsequent matches are based on path.
|
474
|
+
#
|
475
|
+
# @param params [Hash] A hash representation of a completion item
|
476
|
+
# @return [Array<Pin::Base>]
|
477
|
+
def locate_pins params
|
478
|
+
return [] unless params['data'] && params['data']['uri']
|
479
|
+
library = library_for(params['data']['uri'])
|
480
|
+
result = []
|
481
|
+
if params['data']['location']
|
482
|
+
location = Location.new(
|
483
|
+
params['data']['location']['filename'],
|
484
|
+
Range.from_to(
|
485
|
+
params['data']['location']['range']['start']['line'],
|
486
|
+
params['data']['location']['range']['start']['character'],
|
487
|
+
params['data']['location']['range']['end']['line'],
|
488
|
+
params['data']['location']['range']['end']['character']
|
489
|
+
)
|
490
|
+
)
|
491
|
+
result.concat library.locate_pins(location).select{ |pin| pin.name == params['label'] }
|
492
|
+
end
|
493
|
+
if params['data']['path']
|
494
|
+
result.concat library.path_pins(params['data']['path'])
|
495
|
+
end
|
496
|
+
# Selecting by both location and path can result in duplicate pins
|
497
|
+
result.uniq { |p| [p.path, p.location] }
|
498
|
+
end
|
499
|
+
|
500
|
+
# @param uri [String]
|
501
|
+
# @return [String]
|
502
|
+
def read_text uri
|
503
|
+
library = library_for(uri)
|
504
|
+
filename = uri_to_file(uri)
|
505
|
+
library.read_text(filename)
|
506
|
+
end
|
507
|
+
|
508
|
+
def formatter_config uri
|
509
|
+
library = library_for(uri)
|
510
|
+
library.workspace.config.formatter
|
511
|
+
end
|
512
|
+
|
513
|
+
# @param uri [String]
|
514
|
+
# @param line [Integer]
|
515
|
+
# @param column [Integer]
|
516
|
+
# @return [Solargraph::SourceMap::Completion]
|
517
|
+
def completions_at uri, line, column
|
518
|
+
library = library_for(uri)
|
519
|
+
library.completions_at uri_to_file(uri), line, column
|
520
|
+
end
|
521
|
+
|
522
|
+
# @return [Bool] if has pending completion request
|
523
|
+
def has_pending_completions?
|
524
|
+
message_worker.messages.reverse_each.any? { |req| req['method'] == 'textDocument/completion' }
|
525
|
+
end
|
526
|
+
|
527
|
+
# @param uri [String]
|
528
|
+
# @param line [Integer]
|
529
|
+
# @param column [Integer]
|
530
|
+
# @return [Array<Solargraph::Pin::Base>]
|
531
|
+
def definitions_at uri, line, column
|
532
|
+
library = library_for(uri)
|
533
|
+
library.definitions_at(uri_to_file(uri), line, column)
|
534
|
+
end
|
535
|
+
|
536
|
+
# @param uri [String]
|
537
|
+
# @param line [Integer]
|
538
|
+
# @param column [Integer]
|
539
|
+
# @return [Array<Solargraph::Pin::Base>]
|
540
|
+
def signatures_at uri, line, column
|
541
|
+
library = library_for(uri)
|
542
|
+
library.signatures_at(uri_to_file(uri), line, column)
|
543
|
+
end
|
544
|
+
|
545
|
+
# @param uri [String]
|
546
|
+
# @param line [Integer]
|
547
|
+
# @param column [Integer]
|
548
|
+
# @param strip [Boolean] Strip special characters from variable names
|
549
|
+
# @param only [Boolean] If true, search current file only
|
550
|
+
# @return [Array<Solargraph::Range>]
|
551
|
+
def references_from uri, line, column, strip: true, only: false
|
552
|
+
library = library_for(uri)
|
553
|
+
library.references_from(uri_to_file(uri), line, column, strip: strip, only: only)
|
554
|
+
end
|
555
|
+
|
556
|
+
# @param query [String]
|
557
|
+
# @return [Array<Solargraph::Pin::Base>]
|
558
|
+
def query_symbols query
|
559
|
+
result = []
|
560
|
+
(libraries + [generic_library]).each { |lib| result.concat lib.query_symbols(query) }
|
561
|
+
result.uniq
|
562
|
+
end
|
563
|
+
|
564
|
+
# @param query [String]
|
565
|
+
# @return [Array<String>]
|
566
|
+
def search query
|
567
|
+
result = []
|
568
|
+
libraries.each { |lib| result.concat lib.search(query) }
|
569
|
+
result
|
570
|
+
end
|
571
|
+
|
572
|
+
# @param query [String]
|
573
|
+
# @return [Array]
|
574
|
+
def document query
|
575
|
+
result = []
|
576
|
+
libraries.each { |lib| result.concat lib.document(query) }
|
577
|
+
result
|
578
|
+
end
|
579
|
+
|
580
|
+
# @param uri [String]
|
581
|
+
# @return [Array<Solargraph::Pin::Base>]
|
582
|
+
def document_symbols uri
|
583
|
+
library = library_for(uri)
|
584
|
+
# At this level, document symbols should be unique; e.g., a
|
585
|
+
# module_function method should return the location for Module.method
|
586
|
+
# or Module#method, but not both.
|
587
|
+
library.document_symbols(uri_to_file(uri)).uniq(&:location)
|
588
|
+
end
|
589
|
+
|
590
|
+
# Send a notification to the client.
|
591
|
+
#
|
592
|
+
# @param text [String]
|
593
|
+
# @param type [Integer] A MessageType constant
|
594
|
+
# @return [void]
|
595
|
+
def show_message text, type = LanguageServer::MessageTypes::INFO
|
596
|
+
send_notification 'window/showMessage', {
|
597
|
+
type: type,
|
598
|
+
message: text
|
599
|
+
}
|
600
|
+
end
|
601
|
+
|
602
|
+
# Send a notification with optional responses.
|
603
|
+
#
|
604
|
+
# @param text [String]
|
605
|
+
# @param type [Integer] A MessageType constant
|
606
|
+
# @param actions [Array<String>] Response options for the client
|
607
|
+
# @param block The block that processes the response
|
608
|
+
# @yieldparam [String] The action received from the client
|
609
|
+
# @return [void]
|
610
|
+
def show_message_request text, type, actions, &block
|
611
|
+
send_request 'window/showMessageRequest', {
|
612
|
+
type: type,
|
613
|
+
message: text,
|
614
|
+
actions: actions
|
615
|
+
}, &block
|
616
|
+
end
|
617
|
+
|
618
|
+
# Get a list of IDs for server requests that are waiting for responses
|
619
|
+
# from the client.
|
620
|
+
#
|
621
|
+
# @return [Array<Integer>]
|
622
|
+
def pending_requests
|
623
|
+
requests.keys
|
624
|
+
end
|
625
|
+
|
626
|
+
# @return [Hash{String => Object}]
|
627
|
+
def default_configuration
|
628
|
+
{
|
629
|
+
'completion' => true,
|
630
|
+
'hover' => true,
|
631
|
+
'symbols' => true,
|
632
|
+
'definitions' => true,
|
633
|
+
'rename' => true,
|
634
|
+
'references' => true,
|
635
|
+
'autoformat' => false,
|
636
|
+
'diagnostics' => false,
|
637
|
+
'formatting' => false,
|
638
|
+
'folding' => true,
|
639
|
+
'highlights' => true,
|
640
|
+
'logLevel' => 'warn'
|
641
|
+
}
|
642
|
+
end
|
643
|
+
|
644
|
+
# @param uri [String]
|
645
|
+
# @return [Array<Range>]
|
646
|
+
def folding_ranges uri
|
647
|
+
sources.find(uri).folding_ranges
|
648
|
+
end
|
649
|
+
|
650
|
+
# @return [void]
|
651
|
+
def catalog
|
652
|
+
return unless libraries.all?(&:mapped?)
|
653
|
+
libraries.each(&:catalog)
|
654
|
+
end
|
655
|
+
|
656
|
+
def client_capabilities
|
657
|
+
@client_capabilities ||= {}
|
658
|
+
end
|
659
|
+
|
660
|
+
private
|
661
|
+
|
662
|
+
# @return [MessageWorker]
|
663
|
+
def message_worker
|
664
|
+
@message_worker ||= MessageWorker.new(self)
|
665
|
+
end
|
666
|
+
|
667
|
+
# @return [Diagnoser]
|
668
|
+
def diagnoser
|
669
|
+
@diagnoser ||= Diagnoser.new(self)
|
670
|
+
end
|
671
|
+
|
672
|
+
# @return [Cataloger]
|
673
|
+
def cataloger
|
674
|
+
@cataloger ||= Cataloger.new(self)
|
675
|
+
end
|
676
|
+
|
677
|
+
# A hash of client requests by ID. The host uses this to keep track of
|
678
|
+
# pending responses.
|
679
|
+
#
|
680
|
+
# @return [Hash{Integer => Hash}]
|
681
|
+
def requests
|
682
|
+
@requests ||= {}
|
683
|
+
end
|
684
|
+
|
685
|
+
# @param path [String]
|
686
|
+
# @return [String]
|
687
|
+
def normalize_separators path
|
688
|
+
return path if File::ALT_SEPARATOR.nil?
|
689
|
+
path.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
|
690
|
+
end
|
691
|
+
|
692
|
+
# @param params [Hash]
|
693
|
+
# @return [Source::Updater]
|
694
|
+
def generate_updater params
|
695
|
+
changes = []
|
696
|
+
params['contentChanges'].each do |recvd|
|
697
|
+
chng = check_diff(params['textDocument']['uri'], recvd)
|
698
|
+
changes.push Solargraph::Source::Change.new(
|
699
|
+
(chng['range'].nil? ?
|
700
|
+
nil :
|
701
|
+
Solargraph::Range.from_to(chng['range']['start']['line'], chng['range']['start']['character'], chng['range']['end']['line'], chng['range']['end']['character'])
|
702
|
+
),
|
703
|
+
chng['text']
|
704
|
+
)
|
705
|
+
end
|
706
|
+
Solargraph::Source::Updater.new(
|
707
|
+
uri_to_file(params['textDocument']['uri']),
|
708
|
+
params['textDocument']['version'],
|
709
|
+
changes
|
710
|
+
)
|
711
|
+
end
|
712
|
+
|
713
|
+
# @param uri [String]
|
714
|
+
# @param change [Hash]
|
715
|
+
# @return [Hash]
|
716
|
+
def check_diff uri, change
|
717
|
+
return change if change['range']
|
718
|
+
source = sources.find(uri)
|
719
|
+
return change if source.code.length + 1 != change['text'].length
|
720
|
+
diffs = Diff::LCS.diff(source.code, change['text'])
|
721
|
+
return change if diffs.length.zero? || diffs.length > 1 || diffs.first.length > 1
|
722
|
+
# @type [Diff::LCS::Change]
|
723
|
+
diff = diffs.first.first
|
724
|
+
return change unless diff.adding? && ['.', ':', '(', ',', ' '].include?(diff.element)
|
725
|
+
position = Solargraph::Position.from_offset(source.code, diff.position)
|
726
|
+
{
|
727
|
+
'range' => {
|
728
|
+
'start' => {
|
729
|
+
'line' => position.line,
|
730
|
+
'character' => position.character
|
731
|
+
},
|
732
|
+
'end' => {
|
733
|
+
'line' => position.line,
|
734
|
+
'character' => position.character
|
735
|
+
}
|
736
|
+
},
|
737
|
+
'text' => diff.element
|
738
|
+
}
|
739
|
+
rescue Solargraph::FileNotFoundError
|
740
|
+
change
|
741
|
+
end
|
742
|
+
|
743
|
+
# @return [Hash]
|
744
|
+
def dynamic_capability_options
|
745
|
+
@dynamic_capability_options ||= {
|
746
|
+
# textDocumentSync: 2, # @todo What should this be?
|
747
|
+
'textDocument/completion' => {
|
748
|
+
resolveProvider: true,
|
749
|
+
triggerCharacters: ['.', ':', '@']
|
750
|
+
},
|
751
|
+
# hoverProvider: true,
|
752
|
+
# definitionProvider: true,
|
753
|
+
'textDocument/signatureHelp' => {
|
754
|
+
triggerCharacters: ['(', ',', ' ']
|
755
|
+
},
|
756
|
+
# documentFormattingProvider: true,
|
757
|
+
'textDocument/onTypeFormatting' => {
|
758
|
+
firstTriggerCharacter: '{',
|
759
|
+
moreTriggerCharacter: ['(']
|
760
|
+
},
|
761
|
+
# documentSymbolProvider: true,
|
762
|
+
# workspaceSymbolProvider: true,
|
763
|
+
# workspace: {
|
764
|
+
# workspaceFolders: {
|
765
|
+
# supported: true,
|
766
|
+
# changeNotifications: true
|
767
|
+
# }
|
768
|
+
# }
|
769
|
+
'textDocument/definition' => {
|
770
|
+
definitionProvider: true
|
771
|
+
},
|
772
|
+
'textDocument/references' => {
|
773
|
+
referencesProvider: true
|
774
|
+
},
|
775
|
+
'textDocument/rename' => {
|
776
|
+
renameProvider: prepare_rename? ? { prepareProvider: true } : true
|
777
|
+
},
|
778
|
+
'textDocument/documentSymbol' => {
|
779
|
+
documentSymbolProvider: true
|
780
|
+
},
|
781
|
+
'workspace/symbol' => {
|
782
|
+
workspaceSymbolProvider: true
|
783
|
+
},
|
784
|
+
'textDocument/formatting' => {
|
785
|
+
formattingProvider: true
|
786
|
+
},
|
787
|
+
'textDocument/foldingRange' => {
|
788
|
+
foldingRangeProvider: true
|
789
|
+
},
|
790
|
+
'textDocument/codeAction' => {
|
791
|
+
codeActionProvider: true
|
792
|
+
},
|
793
|
+
'textDocument/documentHighlight' => {
|
794
|
+
documentHighlightProvider: true
|
795
|
+
}
|
796
|
+
}
|
797
|
+
end
|
798
|
+
|
799
|
+
def prepare_rename?
|
800
|
+
client_capabilities['rename'] && client_capabilities['rename']['prepareSupport']
|
801
|
+
end
|
802
|
+
|
803
|
+
def client_supports_progress?
|
804
|
+
client_capabilities['window'] && client_capabilities['window']['workDoneProgress']
|
805
|
+
end
|
806
|
+
|
807
|
+
# @param library [Library]
|
808
|
+
# @return [void]
|
809
|
+
def async_library_map library
|
810
|
+
return if library.mapped?
|
811
|
+
Thread.new do
|
812
|
+
if client_supports_progress?
|
813
|
+
uuid = SecureRandom.uuid
|
814
|
+
send_request 'window/workDoneProgress/create', {
|
815
|
+
token: uuid
|
816
|
+
} do |response|
|
817
|
+
do_async_library_map library, response.nil? ? uuid : nil
|
818
|
+
end
|
819
|
+
else
|
820
|
+
do_async_library_map library
|
821
|
+
end
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
def do_async_library_map library, uuid = nil
|
826
|
+
total = library.workspace.sources.length
|
827
|
+
if uuid
|
828
|
+
send_notification '$/progress', {
|
829
|
+
token: uuid,
|
830
|
+
value: {
|
831
|
+
kind: 'begin',
|
832
|
+
title: "Mapping workspace",
|
833
|
+
message: "0/#{total} files",
|
834
|
+
cancellable: false,
|
835
|
+
percentage: 0
|
836
|
+
}
|
837
|
+
}
|
838
|
+
end
|
839
|
+
pct = 0
|
840
|
+
mod = 10
|
841
|
+
while library.next_map
|
842
|
+
next unless uuid
|
843
|
+
cur = ((library.source_map_hash.keys.length.to_f / total.to_f) * 100).to_i
|
844
|
+
if cur > pct && cur % mod == 0
|
845
|
+
pct = cur
|
846
|
+
send_notification '$/progress', {
|
847
|
+
token: uuid,
|
848
|
+
value: {
|
849
|
+
kind: 'report',
|
850
|
+
cancellable: false,
|
851
|
+
message: "#{library.source_map_hash.keys.length}/#{total} files",
|
852
|
+
percentage: pct
|
853
|
+
}
|
854
|
+
}
|
855
|
+
end
|
856
|
+
end
|
857
|
+
if uuid
|
858
|
+
send_notification '$/progress', {
|
859
|
+
token: uuid,
|
860
|
+
value: {
|
861
|
+
kind: 'end',
|
862
|
+
message: 'Mapping complete'
|
863
|
+
}
|
864
|
+
}
|
865
|
+
end
|
866
|
+
end
|
867
|
+
end
|
868
|
+
end
|
869
|
+
end
|