ruby-lsp 0.23.11 → 0.23.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp-launcher +12 -11
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -1
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +81 -115
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +117 -166
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +9 -7
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +88 -200
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +56 -192
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +14 -16
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +22 -45
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +42 -60
- data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +9 -16
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +5 -9
- data/lib/ruby_indexer/test/configuration_test.rb +42 -3
- data/lib/ruby_indexer/test/method_test.rb +28 -2
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_lsp/addon.rb +44 -71
- data/lib/ruby_lsp/base_server.rb +29 -32
- data/lib/ruby_lsp/client_capabilities.rb +10 -12
- data/lib/ruby_lsp/document.rb +34 -45
- data/lib/ruby_lsp/erb_document.rb +24 -36
- data/lib/ruby_lsp/global_state.rb +51 -56
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +81 -88
- data/lib/ruby_lsp/listeners/completion.rb +36 -55
- data/lib/ruby_lsp/listeners/definition.rb +37 -51
- data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
- data/lib/ruby_lsp/listeners/document_link.rb +43 -62
- data/lib/ruby_lsp/listeners/document_symbol.rb +35 -49
- data/lib/ruby_lsp/listeners/folding_ranges.rb +32 -39
- data/lib/ruby_lsp/listeners/hover.rb +81 -100
- data/lib/ruby_lsp/listeners/inlay_hints.rb +4 -11
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +42 -51
- data/lib/ruby_lsp/listeners/signature_help.rb +6 -25
- data/lib/ruby_lsp/listeners/spec_style.rb +155 -0
- data/lib/ruby_lsp/listeners/test_discovery.rb +89 -0
- data/lib/ruby_lsp/listeners/test_style.rb +160 -88
- data/lib/ruby_lsp/node_context.rb +12 -39
- data/lib/ruby_lsp/rbs_document.rb +8 -6
- data/lib/ruby_lsp/requests/code_action_resolve.rb +10 -10
- data/lib/ruby_lsp/requests/code_actions.rb +14 -26
- data/lib/ruby_lsp/requests/code_lens.rb +6 -17
- data/lib/ruby_lsp/requests/completion.rb +7 -20
- data/lib/ruby_lsp/requests/completion_resolve.rb +5 -5
- data/lib/ruby_lsp/requests/definition.rb +8 -17
- data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
- data/lib/ruby_lsp/requests/discover_tests.rb +18 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +5 -15
- data/lib/ruby_lsp/requests/document_link.rb +6 -17
- data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
- data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
- data/lib/ruby_lsp/requests/formatting.rb +6 -9
- data/lib/ruby_lsp/requests/go_to_relevant_file.rb +87 -0
- data/lib/ruby_lsp/requests/hover.rb +8 -18
- data/lib/ruby_lsp/requests/inlay_hints.rb +6 -17
- data/lib/ruby_lsp/requests/on_type_formatting.rb +28 -38
- data/lib/ruby_lsp/requests/prepare_rename.rb +4 -9
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +4 -13
- data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
- data/lib/ruby_lsp/requests/references.rb +6 -36
- data/lib/ruby_lsp/requests/rename.rb +11 -37
- data/lib/ruby_lsp/requests/request.rb +7 -19
- data/lib/ruby_lsp/requests/selection_ranges.rb +5 -5
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +12 -31
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +5 -6
- data/lib/ruby_lsp/requests/signature_help.rb +8 -26
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +13 -50
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +9 -12
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +22 -34
- data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
- data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
- data/lib/ruby_lsp/requests/support/source_uri.rb +16 -30
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
- data/lib/ruby_lsp/requests/support/test_item.rb +10 -14
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
- data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
- data/lib/ruby_lsp/response_builders/collection_response_builder.rb +5 -5
- data/lib/ruby_lsp/response_builders/document_symbol.rb +10 -16
- data/lib/ruby_lsp/response_builders/hover.rb +10 -13
- data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +59 -87
- data/lib/ruby_lsp/response_builders/signature_help.rb +5 -6
- data/lib/ruby_lsp/response_builders/test_collection.rb +6 -10
- data/lib/ruby_lsp/ruby_document.rb +22 -60
- data/lib/ruby_lsp/ruby_lsp_reporter_plugin.rb +109 -0
- data/lib/ruby_lsp/scope.rb +7 -11
- data/lib/ruby_lsp/server.rb +133 -74
- data/lib/ruby_lsp/setup_bundler.rb +58 -57
- data/lib/ruby_lsp/static_docs.rb +4 -7
- data/lib/ruby_lsp/store.rb +21 -40
- data/lib/ruby_lsp/test_helper.rb +3 -12
- data/lib/ruby_lsp/test_reporter.rb +207 -0
- data/lib/ruby_lsp/test_unit_test_runner.rb +98 -0
- data/lib/ruby_lsp/type_inferrer.rb +9 -13
- data/lib/ruby_lsp/utils.rb +37 -81
- metadata +9 -3
@@ -5,29 +5,25 @@ module RubyIndexer
|
|
5
5
|
# Represents the visibility scope in a Ruby namespace. This keeps track of whether methods are in a public, private or
|
6
6
|
# protected section, and whether they are module functions.
|
7
7
|
class VisibilityScope
|
8
|
-
extend T::Sig
|
9
|
-
|
10
8
|
class << self
|
11
|
-
|
12
|
-
|
13
|
-
sig { returns(T.attached_class) }
|
9
|
+
#: -> instance
|
14
10
|
def module_function_scope
|
15
11
|
new(module_func: true, visibility: Entry::Visibility::PRIVATE)
|
16
12
|
end
|
17
13
|
|
18
|
-
|
14
|
+
#: -> instance
|
19
15
|
def public_scope
|
20
16
|
new
|
21
17
|
end
|
22
18
|
end
|
23
19
|
|
24
|
-
|
20
|
+
#: Entry::Visibility
|
25
21
|
attr_reader :visibility
|
26
22
|
|
27
|
-
|
23
|
+
#: bool
|
28
24
|
attr_reader :module_func
|
29
25
|
|
30
|
-
|
26
|
+
#: (?visibility: Entry::Visibility, ?module_func: bool) -> void
|
31
27
|
def initialize(visibility: Entry::Visibility::PUBLIC, module_func: false)
|
32
28
|
@visibility = visibility
|
33
29
|
@module_func = module_func
|
@@ -12,7 +12,7 @@ module RubyIndexer
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_load_configuration_executes_configure_block
|
15
|
-
@config.apply_config({ "excluded_patterns" => ["**/fixtures
|
15
|
+
@config.apply_config({ "excluded_patterns" => ["**/fixtures/**/*"] })
|
16
16
|
uris = @config.indexable_uris
|
17
17
|
|
18
18
|
bundle_path = Bundler.bundle_path.join("gems")
|
@@ -39,7 +39,11 @@ module RubyIndexer
|
|
39
39
|
next if lazy_spec.name == "ruby-lsp"
|
40
40
|
|
41
41
|
spec = Gem::Specification.find_by_name(lazy_spec.name)
|
42
|
-
|
42
|
+
|
43
|
+
test_uris = uris.select do |uri|
|
44
|
+
File.fnmatch?(File.join(spec.full_gem_path, "test/**/*"), uri.full_path, File::Constants::FNM_PATHNAME)
|
45
|
+
end
|
46
|
+
assert_empty(test_uris)
|
43
47
|
rescue Gem::MissingSpecError
|
44
48
|
# Transitive dependencies might be missing when running tests on Windows
|
45
49
|
end
|
@@ -143,17 +147,26 @@ module RubyIndexer
|
|
143
147
|
uris = @config.indexable_uris
|
144
148
|
assert(uris.none? { |uri| uri.full_path.start_with?(File.join(dir, "ignore")) })
|
145
149
|
|
150
|
+
# The regular default gem path is ~/.rubies/3.4.1/lib/ruby/3.4.0
|
151
|
+
# The alternative default gem path is ~/.rubies/3.4.1/lib/ruby/gems/3.4.0
|
152
|
+
# Here part_1 contains ~/.rubies/3.4.1/lib/ruby/ and part_2 contains 3.4.0, so that we can turn it into the
|
153
|
+
# alternative path
|
154
|
+
part_1, part_2 = Pathname.new(RbConfig::CONFIG["rubylibdir"]).split
|
155
|
+
other_default_gem_dir = part_1.join("gems").join(part_2).to_s
|
156
|
+
|
146
157
|
# After switching the workspace path, all indexable URIs will be found in one of these places:
|
147
158
|
# - The new workspace path
|
148
159
|
# - The Ruby LSP's own code (because Bundler is requiring the dependency from source)
|
149
160
|
# - Bundled gems
|
150
161
|
# - Default gems
|
162
|
+
# - Other default gem directory
|
151
163
|
assert(
|
152
164
|
uris.all? do |u|
|
153
165
|
u.full_path.start_with?(dir) ||
|
154
166
|
u.full_path.start_with?(File.join(Dir.pwd, "lib")) ||
|
155
167
|
u.full_path.start_with?(Bundler.bundle_path.to_s) ||
|
156
|
-
u.full_path.start_with?(RbConfig::CONFIG["rubylibdir"])
|
168
|
+
u.full_path.start_with?(RbConfig::CONFIG["rubylibdir"]) ||
|
169
|
+
u.full_path.start_with?(other_default_gem_dir)
|
157
170
|
end,
|
158
171
|
)
|
159
172
|
end
|
@@ -235,5 +248,31 @@ module RubyIndexer
|
|
235
248
|
end
|
236
249
|
end
|
237
250
|
end
|
251
|
+
|
252
|
+
def test_indexables_include_non_test_files_in_test_directories
|
253
|
+
# In order to linearize test parent classes and accurately detect the framework being used, then intermediate
|
254
|
+
# parent classes _must_ also be indexed. Otherwise, we have no way of linearizing the rest of the ancestors to
|
255
|
+
# determine what the test class ultimately inherits from.
|
256
|
+
#
|
257
|
+
# Therefore, we need to ensure that test files are excluded, but non test files inside test directories have to be
|
258
|
+
# indexed
|
259
|
+
FileUtils.touch("test/test_case.rb")
|
260
|
+
|
261
|
+
uris = @config.indexable_uris
|
262
|
+
project_paths = uris.filter_map do |uri|
|
263
|
+
path = uri.full_path
|
264
|
+
next if path.start_with?(Bundler.bundle_path.to_s) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
|
265
|
+
|
266
|
+
Pathname.new(path).relative_path_from(Dir.pwd).to_s
|
267
|
+
end
|
268
|
+
|
269
|
+
begin
|
270
|
+
assert_includes(project_paths, "test/requests/support/expectations_test_runner.rb")
|
271
|
+
assert_includes(project_paths, "test/test_helper.rb")
|
272
|
+
assert_includes(project_paths, "test/test_case.rb")
|
273
|
+
ensure
|
274
|
+
FileUtils.rm("test/test_case.rb")
|
275
|
+
end
|
276
|
+
end
|
238
277
|
end
|
239
278
|
end
|
@@ -924,16 +924,42 @@ module RubyIndexer
|
|
924
924
|
RUBY
|
925
925
|
end
|
926
926
|
|
927
|
+
def test_changing_visibility_post_definition
|
928
|
+
index(<<~RUBY)
|
929
|
+
class Foo
|
930
|
+
def bar; end
|
931
|
+
private :bar
|
932
|
+
|
933
|
+
def baz; end
|
934
|
+
protected :baz
|
935
|
+
|
936
|
+
private
|
937
|
+
def qux; end
|
938
|
+
|
939
|
+
public :qux
|
940
|
+
end
|
941
|
+
RUBY
|
942
|
+
|
943
|
+
entry = T.must(@index["bar"].first)
|
944
|
+
assert_predicate(entry, :private?)
|
945
|
+
|
946
|
+
entry = T.must(@index["baz"].first)
|
947
|
+
assert_predicate(entry, :protected?)
|
948
|
+
|
949
|
+
entry = T.must(@index["qux"].first)
|
950
|
+
assert_predicate(entry, :public?)
|
951
|
+
end
|
952
|
+
|
927
953
|
private
|
928
954
|
|
929
|
-
|
955
|
+
#: (Entry::Method entry, String call_string) -> void
|
930
956
|
def assert_signature_matches(entry, call_string)
|
931
957
|
sig = T.must(entry.signatures.first)
|
932
958
|
arguments = parse_prism_args(call_string)
|
933
959
|
assert(sig.matches?(arguments), "Expected #{call_string} to match #{entry.name}#{entry.decorated_parameters}")
|
934
960
|
end
|
935
961
|
|
936
|
-
|
962
|
+
#: (Entry::Method entry, String call_string) -> void
|
937
963
|
def refute_signature_matches(entry, call_string)
|
938
964
|
sig = T.must(entry.signatures.first)
|
939
965
|
arguments = parse_prism_args(call_string)
|
@@ -359,7 +359,7 @@ module RubyIndexer
|
|
359
359
|
assert_equal("all?", entry.old_name)
|
360
360
|
assert_equal("Array", entry.owner.name)
|
361
361
|
assert(entry.file_path.end_with?("core/array.rbs"))
|
362
|
-
|
362
|
+
refute_empty(entry.comments)
|
363
363
|
end
|
364
364
|
|
365
365
|
def test_indexing_untyped_functions
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -25,42 +25,34 @@ module RubyLsp
|
|
25
25
|
|
26
26
|
abstract!
|
27
27
|
|
28
|
-
@addons =
|
29
|
-
@addon_classes =
|
28
|
+
@addons = [] #: Array[Addon]
|
29
|
+
@addon_classes = [] #: Array[singleton(Addon)]
|
30
30
|
# Add-on instances that have declared a handler to accept file watcher events
|
31
|
-
@file_watcher_addons =
|
31
|
+
@file_watcher_addons = [] #: Array[Addon]
|
32
32
|
|
33
33
|
AddonNotFoundError = Class.new(StandardError)
|
34
34
|
|
35
35
|
class IncompatibleApiError < StandardError; end
|
36
36
|
|
37
37
|
class << self
|
38
|
-
|
39
|
-
|
40
|
-
sig { returns(T::Array[Addon]) }
|
38
|
+
#: Array[Addon]
|
41
39
|
attr_accessor :addons
|
42
40
|
|
43
|
-
|
41
|
+
#: Array[Addon]
|
44
42
|
attr_accessor :file_watcher_addons
|
45
43
|
|
46
|
-
|
44
|
+
#: Array[singleton(Addon)]
|
47
45
|
attr_reader :addon_classes
|
48
46
|
|
49
47
|
# Automatically track and instantiate add-on classes
|
50
|
-
|
48
|
+
#: (singleton(Addon) child_class) -> void
|
51
49
|
def inherited(child_class)
|
52
50
|
addon_classes << child_class
|
53
51
|
super
|
54
52
|
end
|
55
53
|
|
56
54
|
# Discovers and loads all add-ons. Returns a list of errors when trying to require add-ons
|
57
|
-
|
58
|
-
params(
|
59
|
-
global_state: GlobalState,
|
60
|
-
outgoing_queue: Thread::Queue,
|
61
|
-
include_project_addons: T::Boolean,
|
62
|
-
).returns(T::Array[StandardError])
|
63
|
-
end
|
55
|
+
#: (GlobalState global_state, Thread::Queue outgoing_queue, ?include_project_addons: bool) -> Array[StandardError]
|
64
56
|
def load_addons(global_state, outgoing_queue, include_project_addons: true)
|
65
57
|
# Require all add-ons entry points, which should be placed under
|
66
58
|
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb` or in the workspace under
|
@@ -98,7 +90,7 @@ module RubyLsp
|
|
98
90
|
end
|
99
91
|
|
100
92
|
# Unloads all add-ons. Only intended to be invoked once when shutting down the Ruby LSP server
|
101
|
-
|
93
|
+
#: -> void
|
102
94
|
def unload_addons
|
103
95
|
@addons.each(&:deactivate)
|
104
96
|
@addons.clear
|
@@ -112,7 +104,7 @@ module RubyLsp
|
|
112
104
|
# Important: if the add-on is not found, AddonNotFoundError will be raised. If the add-on is found, but its
|
113
105
|
# current version does not satisfy the given version constraint, then IncompatibleApiError will be raised. It is
|
114
106
|
# the responsibility of the add-ons using this API to handle these errors appropriately.
|
115
|
-
|
107
|
+
#: (String addon_name, *String version_constraints) -> Addon
|
116
108
|
def get(addon_name, *version_constraints)
|
117
109
|
if version_constraints.empty?
|
118
110
|
raise IncompatibleApiError, "Must specify version constraints when accessing other add-ons"
|
@@ -144,7 +136,7 @@ module RubyLsp
|
|
144
136
|
# end
|
145
137
|
# end
|
146
138
|
# ```
|
147
|
-
|
139
|
+
#: (*String version_constraints) -> void
|
148
140
|
def depend_on_ruby_lsp!(*version_constraints)
|
149
141
|
version_object = Gem::Version.new(RubyLsp::VERSION)
|
150
142
|
|
@@ -155,23 +147,23 @@ module RubyLsp
|
|
155
147
|
end
|
156
148
|
end
|
157
149
|
|
158
|
-
|
150
|
+
#: -> void
|
159
151
|
def initialize
|
160
|
-
@errors =
|
152
|
+
@errors = [] #: Array[StandardError]
|
161
153
|
end
|
162
154
|
|
163
|
-
|
155
|
+
#: (StandardError error) -> self
|
164
156
|
def add_error(error)
|
165
157
|
@errors << error
|
166
158
|
self
|
167
159
|
end
|
168
160
|
|
169
|
-
|
161
|
+
#: -> bool
|
170
162
|
def error?
|
171
163
|
@errors.any?
|
172
164
|
end
|
173
165
|
|
174
|
-
|
166
|
+
#: -> String
|
175
167
|
def formatted_errors
|
176
168
|
<<~ERRORS
|
177
169
|
#{name}:
|
@@ -179,7 +171,7 @@ module RubyLsp
|
|
179
171
|
ERRORS
|
180
172
|
end
|
181
173
|
|
182
|
-
|
174
|
+
#: -> String
|
183
175
|
def errors_details
|
184
176
|
@errors.map(&:full_message).join("\n\n")
|
185
177
|
end
|
@@ -207,69 +199,50 @@ module RubyLsp
|
|
207
199
|
# original request so that the response is delegated to the correct add-on and must override this method to handle
|
208
200
|
# the response
|
209
201
|
# https://microsoft.github.io/language-server-protocol/specification#window_showMessageRequest
|
210
|
-
|
202
|
+
# @overridable
|
203
|
+
#: (String title) -> void
|
211
204
|
def handle_window_show_message_response(title); end
|
212
205
|
|
213
206
|
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
|
214
|
-
|
215
|
-
|
216
|
-
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
|
217
|
-
uri: URI::Generic,
|
218
|
-
dispatcher: Prism::Dispatcher,
|
219
|
-
).void
|
220
|
-
end
|
207
|
+
# @overridable
|
208
|
+
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens] response_builder, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
|
221
209
|
def create_code_lens_listener(response_builder, uri, dispatcher); end
|
222
210
|
|
223
211
|
# Creates a new Hover listener. This method is invoked on every Hover request
|
224
|
-
|
225
|
-
|
226
|
-
response_builder: ResponseBuilders::Hover,
|
227
|
-
node_context: NodeContext,
|
228
|
-
dispatcher: Prism::Dispatcher,
|
229
|
-
).void
|
230
|
-
end
|
212
|
+
# @overridable
|
213
|
+
#: (ResponseBuilders::Hover response_builder, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
|
231
214
|
def create_hover_listener(response_builder, node_context, dispatcher); end
|
232
215
|
|
233
216
|
# Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
|
234
|
-
|
235
|
-
|
236
|
-
response_builder: ResponseBuilders::DocumentSymbol,
|
237
|
-
dispatcher: Prism::Dispatcher,
|
238
|
-
).void
|
239
|
-
end
|
217
|
+
# @overridable
|
218
|
+
#: (ResponseBuilders::DocumentSymbol response_builder, Prism::Dispatcher dispatcher) -> void
|
240
219
|
def create_document_symbol_listener(response_builder, dispatcher); end
|
241
220
|
|
242
|
-
|
243
|
-
|
244
|
-
response_builder: ResponseBuilders::SemanticHighlighting,
|
245
|
-
dispatcher: Prism::Dispatcher,
|
246
|
-
).void
|
247
|
-
end
|
221
|
+
# @overridable
|
222
|
+
#: (ResponseBuilders::SemanticHighlighting response_builder, Prism::Dispatcher dispatcher) -> void
|
248
223
|
def create_semantic_highlighting_listener(response_builder, dispatcher); end
|
249
224
|
|
250
225
|
# Creates a new Definition listener. This method is invoked on every Definition request
|
251
|
-
|
252
|
-
|
253
|
-
response_builder: ResponseBuilders::CollectionResponseBuilder[T.any(
|
254
|
-
Interface::Location,
|
255
|
-
Interface::LocationLink,
|
256
|
-
)],
|
257
|
-
uri: URI::Generic,
|
258
|
-
node_context: NodeContext,
|
259
|
-
dispatcher: Prism::Dispatcher,
|
260
|
-
).void
|
261
|
-
end
|
226
|
+
# @overridable
|
227
|
+
#: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
|
262
228
|
def create_definition_listener(response_builder, uri, node_context, dispatcher); end
|
263
229
|
|
264
230
|
# Creates a new Completion listener. This method is invoked on every Completion request
|
265
|
-
|
266
|
-
|
267
|
-
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
|
268
|
-
node_context: NodeContext,
|
269
|
-
dispatcher: Prism::Dispatcher,
|
270
|
-
uri: URI::Generic,
|
271
|
-
).void
|
272
|
-
end
|
231
|
+
# @overridable
|
232
|
+
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, NodeContext node_context, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
|
273
233
|
def create_completion_listener(response_builder, node_context, dispatcher, uri); end
|
234
|
+
|
235
|
+
# Creates a new Discover Tests listener. This method is invoked on every DiscoverTests request
|
236
|
+
# @overridable
|
237
|
+
#: (ResponseBuilders::TestCollection response_builder, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
|
238
|
+
def create_discover_tests_listener(response_builder, dispatcher, uri); end
|
239
|
+
|
240
|
+
# Resolves the minimal set of commands required to execute the requested tests. Add-ons are responsible for only
|
241
|
+
# handling items related to the framework they add support for and have discovered themselves
|
242
|
+
# @overridable
|
243
|
+
#: (Array[Hash[Symbol, untyped]]) -> Array[String]
|
244
|
+
def resolve_test_commands(items)
|
245
|
+
[]
|
246
|
+
end
|
274
247
|
end
|
275
248
|
end
|
data/lib/ruby_lsp/base_server.rb
CHANGED
@@ -8,30 +8,27 @@ module RubyLsp
|
|
8
8
|
|
9
9
|
abstract!
|
10
10
|
|
11
|
-
|
11
|
+
#: (**untyped options) -> void
|
12
12
|
def initialize(**options)
|
13
|
-
@test_mode =
|
14
|
-
@setup_error =
|
15
|
-
@install_error =
|
16
|
-
@writer =
|
17
|
-
@reader =
|
18
|
-
@incoming_queue =
|
19
|
-
@outgoing_queue =
|
20
|
-
@cancelled_requests =
|
21
|
-
@worker =
|
22
|
-
@current_request_id =
|
23
|
-
@global_state =
|
24
|
-
@store =
|
25
|
-
@outgoing_dispatcher =
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@global_state.synchronize { @writer.write(message.to_hash) }
|
30
|
-
end
|
13
|
+
@test_mode = options[:test_mode] #: bool?
|
14
|
+
@setup_error = options[:setup_error] #: StandardError?
|
15
|
+
@install_error = options[:install_error] #: StandardError?
|
16
|
+
@writer = Transport::Stdio::Writer.new #: Transport::Stdio::Writer
|
17
|
+
@reader = Transport::Stdio::Reader.new #: Transport::Stdio::Reader
|
18
|
+
@incoming_queue = Thread::Queue.new #: Thread::Queue
|
19
|
+
@outgoing_queue = Thread::Queue.new #: Thread::Queue
|
20
|
+
@cancelled_requests = [] #: Array[Integer]
|
21
|
+
@worker = new_worker #: Thread
|
22
|
+
@current_request_id = 1 #: Integer
|
23
|
+
@global_state = GlobalState.new #: GlobalState
|
24
|
+
@store = Store.new(@global_state) #: Store
|
25
|
+
@outgoing_dispatcher = Thread.new do
|
26
|
+
unless @test_mode
|
27
|
+
while (message = @outgoing_queue.pop)
|
28
|
+
@global_state.synchronize { @writer.write(message.to_hash) }
|
31
29
|
end
|
32
|
-
end
|
33
|
-
|
34
|
-
)
|
30
|
+
end
|
31
|
+
end #: Thread
|
35
32
|
|
36
33
|
Thread.main.priority = 1
|
37
34
|
|
@@ -41,7 +38,7 @@ module RubyLsp
|
|
41
38
|
process_message(initialize_request) if initialize_request
|
42
39
|
end
|
43
40
|
|
44
|
-
|
41
|
+
#: -> void
|
45
42
|
def start
|
46
43
|
@reader.read do |message|
|
47
44
|
method = message[:method]
|
@@ -108,7 +105,7 @@ module RubyLsp
|
|
108
105
|
end
|
109
106
|
end
|
110
107
|
|
111
|
-
|
108
|
+
#: -> void
|
112
109
|
def run_shutdown
|
113
110
|
@incoming_queue.clear
|
114
111
|
@outgoing_queue.clear
|
@@ -122,13 +119,13 @@ module RubyLsp
|
|
122
119
|
end
|
123
120
|
|
124
121
|
# This method is only intended to be used in tests! Pops the latest response that would be sent to the client
|
125
|
-
|
122
|
+
#: -> untyped
|
126
123
|
def pop_response
|
127
124
|
@outgoing_queue.pop
|
128
125
|
end
|
129
126
|
|
130
127
|
# This method is only intended to be used in tests! Pushes a message to the incoming queue directly
|
131
|
-
|
128
|
+
#: (Hash[Symbol, untyped] message) -> void
|
132
129
|
def push_message(message)
|
133
130
|
@incoming_queue << message
|
134
131
|
end
|
@@ -139,16 +136,16 @@ module RubyLsp
|
|
139
136
|
sig { abstract.void }
|
140
137
|
def shutdown; end
|
141
138
|
|
142
|
-
|
139
|
+
#: (Integer id, String message, ?type: Integer) -> void
|
143
140
|
def fail_request_and_notify(id, message, type: Constant::MessageType::INFO)
|
144
141
|
send_message(Error.new(id: id, code: Constant::ErrorCodes::REQUEST_FAILED, message: message))
|
145
142
|
send_message(Notification.window_show_message(message, type: type))
|
146
143
|
end
|
147
144
|
|
148
|
-
|
145
|
+
#: -> Thread
|
149
146
|
def new_worker
|
150
147
|
Thread.new do
|
151
|
-
while (message =
|
148
|
+
while (message = @incoming_queue.pop)
|
152
149
|
id = message[:id]
|
153
150
|
|
154
151
|
# Check if the request was cancelled before trying to process it
|
@@ -165,7 +162,7 @@ module RubyLsp
|
|
165
162
|
end
|
166
163
|
end
|
167
164
|
|
168
|
-
|
165
|
+
#: ((Result | Error | Notification | Request) message) -> void
|
169
166
|
def send_message(message)
|
170
167
|
# When we're shutting down the server, there's a small race condition between closing the thread queues and
|
171
168
|
# finishing remaining requests. We may close the queue in the middle of processing a request, which will then fail
|
@@ -176,12 +173,12 @@ module RubyLsp
|
|
176
173
|
@current_request_id += 1 if message.is_a?(Request)
|
177
174
|
end
|
178
175
|
|
179
|
-
|
176
|
+
#: (Integer id) -> void
|
180
177
|
def send_empty_response(id)
|
181
178
|
send_message(Result.new(id: id, response: nil))
|
182
179
|
end
|
183
180
|
|
184
|
-
|
181
|
+
#: (String message, ?type: Integer) -> void
|
185
182
|
def send_log_message(message, type: Constant::MessageType::LOG)
|
186
183
|
send_message(Notification.window_log_message(message, type: Constant::MessageType::LOG))
|
187
184
|
end
|
@@ -5,40 +5,38 @@ module RubyLsp
|
|
5
5
|
# This class stores all client capabilities that the Ruby LSP and its add-ons depend on to ensure that we're
|
6
6
|
# not enabling functionality unsupported by the editor connecting to the server
|
7
7
|
class ClientCapabilities
|
8
|
-
|
9
|
-
|
10
|
-
sig { returns(T::Boolean) }
|
8
|
+
#: bool
|
11
9
|
attr_reader :supports_watching_files,
|
12
10
|
:supports_request_delegation,
|
13
11
|
:window_show_message_supports_extra_properties,
|
14
12
|
:supports_progress,
|
15
13
|
:supports_diagnostic_refresh
|
16
14
|
|
17
|
-
|
15
|
+
#: -> void
|
18
16
|
def initialize
|
19
17
|
# The editor supports watching files. This requires two capabilities: dynamic registration and relative pattern
|
20
18
|
# support
|
21
|
-
@supports_watching_files =
|
19
|
+
@supports_watching_files = false #: bool
|
22
20
|
|
23
21
|
# The editor supports request delegation. This is an experimental capability since request delegation has not been
|
24
22
|
# standardized into the LSP spec yet
|
25
|
-
@supports_request_delegation =
|
23
|
+
@supports_request_delegation = false #: bool
|
26
24
|
|
27
25
|
# The editor supports extra arbitrary properties for `window/showMessageRequest`. Necessary for add-ons to show
|
28
26
|
# dialogs with user interactions
|
29
|
-
@window_show_message_supports_extra_properties =
|
27
|
+
@window_show_message_supports_extra_properties = false #: bool
|
30
28
|
|
31
29
|
# Which resource operations the editor supports, like renaming files
|
32
|
-
@supported_resource_operations =
|
30
|
+
@supported_resource_operations = [] #: Array[String]
|
33
31
|
|
34
32
|
# The editor supports displaying progress requests
|
35
|
-
@supports_progress =
|
33
|
+
@supports_progress = false #: bool
|
36
34
|
|
37
35
|
# The editor supports server initiated refresh for diagnostics
|
38
|
-
@supports_diagnostic_refresh =
|
36
|
+
@supports_diagnostic_refresh = false #: bool
|
39
37
|
end
|
40
38
|
|
41
|
-
|
39
|
+
#: (Hash[Symbol, untyped] capabilities) -> void
|
42
40
|
def apply_client_capabilities(capabilities)
|
43
41
|
workspace_capabilities = capabilities[:workspace] || {}
|
44
42
|
|
@@ -65,7 +63,7 @@ module RubyLsp
|
|
65
63
|
@supports_diagnostic_refresh = workspace_capabilities.dig(:diagnostics, :refreshSupport) || false
|
66
64
|
end
|
67
65
|
|
68
|
-
|
66
|
+
#: -> bool
|
69
67
|
def supports_rename?
|
70
68
|
@supported_resource_operations.include?("rename")
|
71
69
|
end
|