ruby-lsp 0.23.11 → 0.25.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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -4
  5. data/exe/ruby-lsp-check +0 -4
  6. data/exe/ruby-lsp-launcher +45 -22
  7. data/exe/ruby-lsp-test-exec +18 -0
  8. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
  9. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
  10. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
  11. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +140 -183
  12. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +106 -236
  14. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +155 -281
  15. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  16. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
  17. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +25 -57
  18. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
  19. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  20. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  21. data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
  22. data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
  23. data/lib/ruby_indexer/test/configuration_test.rb +49 -8
  24. data/lib/ruby_indexer/test/constant_test.rb +34 -34
  25. data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
  26. data/lib/ruby_indexer/test/index_test.rb +170 -135
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +61 -37
  28. data/lib/ruby_indexer/test/method_test.rb +166 -123
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +21 -21
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +70 -75
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  32. data/lib/ruby_indexer/test/test_case.rb +9 -3
  33. data/lib/ruby_indexer/test/uri_test.rb +15 -2
  34. data/lib/ruby_lsp/addon.rb +73 -86
  35. data/lib/ruby_lsp/base_server.rb +41 -42
  36. data/lib/ruby_lsp/client_capabilities.rb +16 -13
  37. data/lib/ruby_lsp/document.rb +201 -98
  38. data/lib/ruby_lsp/erb_document.rb +45 -47
  39. data/lib/ruby_lsp/global_state.rb +73 -57
  40. data/lib/ruby_lsp/internal.rb +8 -3
  41. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  42. data/lib/ruby_lsp/listeners/completion.rb +76 -74
  43. data/lib/ruby_lsp/listeners/definition.rb +44 -58
  44. data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
  45. data/lib/ruby_lsp/listeners/document_link.rb +50 -70
  46. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  47. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  48. data/lib/ruby_lsp/listeners/hover.rb +107 -115
  49. data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
  50. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  51. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  52. data/lib/ruby_lsp/listeners/spec_style.rb +214 -0
  53. data/lib/ruby_lsp/listeners/test_discovery.rb +92 -0
  54. data/lib/ruby_lsp/listeners/test_style.rb +203 -95
  55. data/lib/ruby_lsp/node_context.rb +12 -39
  56. data/lib/ruby_lsp/rbs_document.rb +10 -11
  57. data/lib/ruby_lsp/requests/code_action_resolve.rb +65 -61
  58. data/lib/ruby_lsp/requests/code_actions.rb +14 -26
  59. data/lib/ruby_lsp/requests/code_lens.rb +31 -21
  60. data/lib/ruby_lsp/requests/completion.rb +8 -21
  61. data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
  62. data/lib/ruby_lsp/requests/definition.rb +8 -20
  63. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  64. data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
  65. data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
  66. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  67. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  68. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  69. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  70. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +85 -0
  71. data/lib/ruby_lsp/requests/hover.rb +12 -25
  72. data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
  73. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  74. data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
  75. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  76. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  77. data/lib/ruby_lsp/requests/references.rb +17 -57
  78. data/lib/ruby_lsp/requests/rename.rb +27 -51
  79. data/lib/ruby_lsp/requests/request.rb +13 -25
  80. data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
  81. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  82. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  83. data/lib/ruby_lsp/requests/signature_help.rb +9 -27
  84. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  85. data/lib/ruby_lsp/requests/support/common.rb +16 -58
  86. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  87. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  88. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
  89. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +30 -36
  90. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  91. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  92. data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
  93. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  94. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  95. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  96. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
  97. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +6 -9
  98. data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
  99. data/lib/ruby_lsp/response_builders/hover.rb +12 -18
  100. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
  101. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
  102. data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
  103. data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
  104. data/lib/ruby_lsp/ruby_document.rb +32 -98
  105. data/lib/ruby_lsp/scope.rb +7 -11
  106. data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
  107. data/lib/ruby_lsp/server.rb +266 -143
  108. data/lib/ruby_lsp/setup_bundler.rb +113 -82
  109. data/lib/ruby_lsp/static_docs.rb +12 -7
  110. data/lib/ruby_lsp/store.rb +21 -49
  111. data/lib/ruby_lsp/test_helper.rb +3 -16
  112. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +236 -0
  113. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
  114. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
  115. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  116. data/lib/ruby_lsp/utils.rb +138 -93
  117. data/static_docs/break.md +103 -0
  118. metadata +14 -20
  119. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -12,12 +12,12 @@ module RubyIndexer
12
12
 
13
13
  def test_from_path_on_windows
14
14
  uri = URI::Generic.from_path(path: "C:/some/windows/path/to/file.rb")
15
- assert_equal("/C:/some/windows/path/to/file.rb", uri.path)
15
+ assert_equal("/C%3A/some/windows/path/to/file.rb", uri.path)
16
16
  end
17
17
 
18
18
  def test_from_path_on_windows_with_lowercase_drive
19
19
  uri = URI::Generic.from_path(path: "c:/some/windows/path/to/file.rb")
20
- assert_equal("/c:/some/windows/path/to/file.rb", uri.path)
20
+ assert_equal("/c%3A/some/windows/path/to/file.rb", uri.path)
21
21
  end
22
22
 
23
23
  def test_to_standardized_path_on_unix
@@ -68,5 +68,18 @@ module RubyIndexer
68
68
  uri.add_require_path_from_load_entry("/some/unix/path")
69
69
  assert_equal("to/file", uri.require_path)
70
70
  end
71
+
72
+ def test_from_path_escapes_colon_characters
73
+ uri = URI::Generic.from_path(path: "c:/some/windows/path with/spaces/file.rb")
74
+ assert_equal("c:/some/windows/path with/spaces/file.rb", uri.to_standardized_path)
75
+ assert_equal("file:///c%3A/some/windows/path%20with/spaces/file.rb", uri.to_s)
76
+ end
77
+
78
+ def test_from_path_with_unicode_characters
79
+ path = "/path/with/unicode/文件.rb"
80
+ uri = URI::Generic.from_path(path: path)
81
+ assert_equal(path, uri.to_standardized_path)
82
+ assert_equal("file:///path/with/unicode/%E6%96%87%E4%BB%B6.rb", uri.to_s)
83
+ end
71
84
  end
72
85
  end
@@ -19,48 +19,36 @@ module RubyLsp
19
19
  # end
20
20
  # end
21
21
  # ```
22
+ # @abstract
22
23
  class Addon
23
- extend T::Sig
24
- extend T::Helpers
25
-
26
- abstract!
27
-
28
- @addons = T.let([], T::Array[Addon])
29
- @addon_classes = T.let([], T::Array[T.class_of(Addon)])
24
+ @addons = [] #: Array[Addon]
25
+ @addon_classes = [] #: Array[singleton(Addon)]
30
26
  # Add-on instances that have declared a handler to accept file watcher events
31
- @file_watcher_addons = T.let([], T::Array[Addon])
27
+ @file_watcher_addons = [] #: Array[Addon]
32
28
 
33
29
  AddonNotFoundError = Class.new(StandardError)
34
30
 
35
31
  class IncompatibleApiError < StandardError; end
36
32
 
37
33
  class << self
38
- extend T::Sig
39
-
40
- sig { returns(T::Array[Addon]) }
34
+ #: Array[Addon]
41
35
  attr_accessor :addons
42
36
 
43
- sig { returns(T::Array[Addon]) }
37
+ #: Array[Addon]
44
38
  attr_accessor :file_watcher_addons
45
39
 
46
- sig { returns(T::Array[T.class_of(Addon)]) }
40
+ #: Array[singleton(Addon)]
47
41
  attr_reader :addon_classes
48
42
 
49
43
  # Automatically track and instantiate add-on classes
50
- sig { params(child_class: T.class_of(Addon)).void }
44
+ #: (singleton(Addon) child_class) -> void
51
45
  def inherited(child_class)
52
46
  addon_classes << child_class
53
47
  super
54
48
  end
55
49
 
56
50
  # Discovers and loads all add-ons. Returns a list of errors when trying to require add-ons
57
- sig do
58
- params(
59
- global_state: GlobalState,
60
- outgoing_queue: Thread::Queue,
61
- include_project_addons: T::Boolean,
62
- ).returns(T::Array[StandardError])
63
- end
51
+ #: (GlobalState global_state, Thread::Queue outgoing_queue, ?include_project_addons: bool) -> Array[StandardError]
64
52
  def load_addons(global_state, outgoing_queue, include_project_addons: true)
65
53
  # Require all add-ons entry points, which should be placed under
66
54
  # `some_gem/lib/ruby_lsp/your_gem_name/addon.rb` or in the workspace under
@@ -68,7 +56,13 @@ module RubyLsp
68
56
  addon_files = Gem.find_files("ruby_lsp/**/addon.rb")
69
57
 
70
58
  if include_project_addons
71
- addon_files.concat(Dir.glob(File.join(global_state.workspace_path, "**", "ruby_lsp/**/addon.rb")))
59
+ project_addons = Dir.glob("#{global_state.workspace_path}/**/ruby_lsp/**/addon.rb")
60
+
61
+ # Ignore add-ons from dependencies if the bundle is stored inside the project. We already found those with
62
+ # `Gem.find_files`
63
+ bundle_path = Bundler.bundle_path.to_s
64
+ project_addons.reject! { |path| path.start_with?(bundle_path) }
65
+ addon_files.concat(project_addons)
72
66
  end
73
67
 
74
68
  errors = addon_files.filter_map do |addon_path|
@@ -98,7 +92,7 @@ module RubyLsp
98
92
  end
99
93
 
100
94
  # Unloads all add-ons. Only intended to be invoked once when shutting down the Ruby LSP server
101
- sig { void }
95
+ #: -> void
102
96
  def unload_addons
103
97
  @addons.each(&:deactivate)
104
98
  @addons.clear
@@ -112,7 +106,7 @@ module RubyLsp
112
106
  # Important: if the add-on is not found, AddonNotFoundError will be raised. If the add-on is found, but its
113
107
  # current version does not satisfy the given version constraint, then IncompatibleApiError will be raised. It is
114
108
  # the responsibility of the add-ons using this API to handle these errors appropriately.
115
- sig { params(addon_name: String, version_constraints: String).returns(Addon) }
109
+ #: (String addon_name, *String version_constraints) -> Addon
116
110
  def get(addon_name, *version_constraints)
117
111
  if version_constraints.empty?
118
112
  raise IncompatibleApiError, "Must specify version constraints when accessing other add-ons"
@@ -144,7 +138,7 @@ module RubyLsp
144
138
  # end
145
139
  # end
146
140
  # ```
147
- sig { params(version_constraints: String).void }
141
+ #: (*String version_constraints) -> void
148
142
  def depend_on_ruby_lsp!(*version_constraints)
149
143
  version_object = Gem::Version.new(RubyLsp::VERSION)
150
144
 
@@ -155,23 +149,23 @@ module RubyLsp
155
149
  end
156
150
  end
157
151
 
158
- sig { void }
152
+ #: -> void
159
153
  def initialize
160
- @errors = T.let([], T::Array[StandardError])
154
+ @errors = [] #: Array[StandardError]
161
155
  end
162
156
 
163
- sig { params(error: StandardError).returns(T.self_type) }
157
+ #: (StandardError error) -> self
164
158
  def add_error(error)
165
159
  @errors << error
166
160
  self
167
161
  end
168
162
 
169
- sig { returns(T::Boolean) }
163
+ #: -> bool
170
164
  def error?
171
165
  @errors.any?
172
166
  end
173
167
 
174
- sig { returns(String) }
168
+ #: -> String
175
169
  def formatted_errors
176
170
  <<~ERRORS
177
171
  #{name}:
@@ -179,97 +173,90 @@ module RubyLsp
179
173
  ERRORS
180
174
  end
181
175
 
182
- sig { returns(String) }
176
+ #: -> String
183
177
  def errors_details
184
178
  @errors.map(&:full_message).join("\n\n")
185
179
  end
186
180
 
187
181
  # Each add-on should implement `MyAddon#activate` and use to perform any sort of initialization, such as
188
182
  # reading information into memory or even spawning a separate process
189
- sig { abstract.params(global_state: GlobalState, outgoing_queue: Thread::Queue).void }
190
- def activate(global_state, outgoing_queue); end
183
+ # @abstract
184
+ #: (GlobalState, Thread::Queue) -> void
185
+ def activate(global_state, outgoing_queue)
186
+ raise AbstractMethodInvokedError
187
+ end
191
188
 
192
- # Each add-on should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
189
+ # Each add-on must implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
193
190
  # child process
194
- sig { abstract.void }
195
- def deactivate; end
191
+ # @abstract
192
+ #: -> void
193
+ def deactivate
194
+ raise AbstractMethodInvokedError
195
+ end
196
196
 
197
197
  # Add-ons should override the `name` method to return the add-on name
198
- sig { abstract.returns(String) }
199
- def name; end
198
+ # @abstract
199
+ #: -> String
200
+ def name
201
+ raise AbstractMethodInvokedError
202
+ end
200
203
 
201
204
  # Add-ons should override the `version` method to return a semantic version string representing the add-on's
202
205
  # version. This is used for compatibility checks
203
- sig { abstract.returns(String) }
204
- def version; end
206
+ # @abstract
207
+ #: -> String
208
+ def version
209
+ raise AbstractMethodInvokedError
210
+ end
205
211
 
206
212
  # Handle a response from a window/showMessageRequest request. Add-ons must include the addon_name as part of the
207
213
  # original request so that the response is delegated to the correct add-on and must override this method to handle
208
214
  # the response
209
215
  # https://microsoft.github.io/language-server-protocol/specification#window_showMessageRequest
210
- sig { overridable.params(title: String).void }
216
+ # @overridable
217
+ #: (String title) -> void
211
218
  def handle_window_show_message_response(title); end
212
219
 
213
220
  # Creates a new CodeLens listener. This method is invoked on every CodeLens request
214
- sig do
215
- overridable.params(
216
- response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
217
- uri: URI::Generic,
218
- dispatcher: Prism::Dispatcher,
219
- ).void
220
- end
221
+ # @overridable
222
+ #: (ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens] response_builder, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
221
223
  def create_code_lens_listener(response_builder, uri, dispatcher); end
222
224
 
223
225
  # Creates a new Hover listener. This method is invoked on every Hover request
224
- sig do
225
- overridable.params(
226
- response_builder: ResponseBuilders::Hover,
227
- node_context: NodeContext,
228
- dispatcher: Prism::Dispatcher,
229
- ).void
230
- end
226
+ # @overridable
227
+ #: (ResponseBuilders::Hover response_builder, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
231
228
  def create_hover_listener(response_builder, node_context, dispatcher); end
232
229
 
233
230
  # Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
234
- sig do
235
- overridable.params(
236
- response_builder: ResponseBuilders::DocumentSymbol,
237
- dispatcher: Prism::Dispatcher,
238
- ).void
239
- end
231
+ # @overridable
232
+ #: (ResponseBuilders::DocumentSymbol response_builder, Prism::Dispatcher dispatcher) -> void
240
233
  def create_document_symbol_listener(response_builder, dispatcher); end
241
234
 
242
- sig do
243
- overridable.params(
244
- response_builder: ResponseBuilders::SemanticHighlighting,
245
- dispatcher: Prism::Dispatcher,
246
- ).void
247
- end
235
+ # @overridable
236
+ #: (ResponseBuilders::SemanticHighlighting response_builder, Prism::Dispatcher dispatcher) -> void
248
237
  def create_semantic_highlighting_listener(response_builder, dispatcher); end
249
238
 
250
239
  # Creates a new Definition listener. This method is invoked on every Definition request
251
- sig do
252
- overridable.params(
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
240
+ # @overridable
241
+ #: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
262
242
  def create_definition_listener(response_builder, uri, node_context, dispatcher); end
263
243
 
264
244
  # Creates a new Completion listener. This method is invoked on every Completion request
265
- sig do
266
- overridable.params(
267
- response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
268
- node_context: NodeContext,
269
- dispatcher: Prism::Dispatcher,
270
- uri: URI::Generic,
271
- ).void
272
- end
245
+ # @overridable
246
+ #: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, NodeContext node_context, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
273
247
  def create_completion_listener(response_builder, node_context, dispatcher, uri); end
248
+
249
+ # Creates a new Discover Tests listener. This method is invoked on every DiscoverTests request
250
+ # @overridable
251
+ #: (ResponseBuilders::TestCollection response_builder, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
252
+ def create_discover_tests_listener(response_builder, dispatcher, uri); end
253
+
254
+ # Resolves the minimal set of commands required to execute the requested tests. Add-ons are responsible for only
255
+ # handling items related to the framework they add support for and have discovered themselves
256
+ # @overridable
257
+ #: (Array[Hash[Symbol, untyped]]) -> Array[String]
258
+ def resolve_test_commands(items)
259
+ []
260
+ end
274
261
  end
275
262
  end
@@ -2,36 +2,29 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
+ # @abstract
5
6
  class BaseServer
6
- extend T::Sig
7
- extend T::Helpers
8
-
9
- abstract!
10
-
11
- sig { params(options: T.untyped).void }
7
+ #: (**untyped options) -> void
12
8
  def initialize(**options)
13
- @test_mode = T.let(options[:test_mode], T.nilable(T::Boolean))
14
- @setup_error = T.let(options[:setup_error], T.nilable(StandardError))
15
- @install_error = T.let(options[:install_error], T.nilable(StandardError))
16
- @writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
17
- @reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
18
- @incoming_queue = T.let(Thread::Queue.new, Thread::Queue)
19
- @outgoing_queue = T.let(Thread::Queue.new, Thread::Queue)
20
- @cancelled_requests = T.let([], T::Array[Integer])
21
- @worker = T.let(new_worker, Thread)
22
- @current_request_id = T.let(1, Integer)
23
- @global_state = T.let(GlobalState.new, GlobalState)
24
- @store = T.let(Store.new(@global_state), Store)
25
- @outgoing_dispatcher = T.let(
26
- Thread.new do
27
- unless @test_mode
28
- while (message = @outgoing_queue.pop)
29
- @global_state.synchronize { @writer.write(message.to_hash) }
30
- end
9
+ @reader = MessageReader.new(options[:reader] || $stdin) #: MessageReader
10
+ @writer = MessageWriter.new(options[:writer] || $stdout) #: MessageWriter
11
+ @test_mode = options[:test_mode] #: bool?
12
+ @setup_error = options[:setup_error] #: StandardError?
13
+ @install_error = options[:install_error] #: StandardError?
14
+ @incoming_queue = Thread::Queue.new #: Thread::Queue
15
+ @outgoing_queue = Thread::Queue.new #: Thread::Queue
16
+ @cancelled_requests = [] #: Array[Integer]
17
+ @worker = new_worker #: Thread
18
+ @current_request_id = 1 #: Integer
19
+ @global_state = GlobalState.new #: GlobalState
20
+ @store = Store.new(@global_state) #: Store
21
+ @outgoing_dispatcher = Thread.new do
22
+ unless @test_mode
23
+ while (message = @outgoing_queue.pop)
24
+ @global_state.synchronize { @writer.write(message.to_hash) }
31
25
  end
32
- end,
33
- Thread,
34
- )
26
+ end
27
+ end #: Thread
35
28
 
36
29
  Thread.main.priority = 1
37
30
 
@@ -41,9 +34,9 @@ module RubyLsp
41
34
  process_message(initialize_request) if initialize_request
42
35
  end
43
36
 
44
- sig { void }
37
+ #: -> void
45
38
  def start
46
- @reader.read do |message|
39
+ @reader.each_message do |message|
47
40
  method = message[:method]
48
41
 
49
42
  # We must parse the document under a mutex lock or else we might switch threads and accept text edits in the
@@ -108,7 +101,7 @@ module RubyLsp
108
101
  end
109
102
  end
110
103
 
111
- sig { void }
104
+ #: -> void
112
105
  def run_shutdown
113
106
  @incoming_queue.clear
114
107
  @outgoing_queue.clear
@@ -122,33 +115,39 @@ module RubyLsp
122
115
  end
123
116
 
124
117
  # This method is only intended to be used in tests! Pops the latest response that would be sent to the client
125
- sig { returns(T.untyped) }
118
+ #: -> untyped
126
119
  def pop_response
127
120
  @outgoing_queue.pop
128
121
  end
129
122
 
130
123
  # This method is only intended to be used in tests! Pushes a message to the incoming queue directly
131
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
124
+ #: (Hash[Symbol, untyped] message) -> void
132
125
  def push_message(message)
133
126
  @incoming_queue << message
134
127
  end
135
128
 
136
- sig { abstract.params(message: T::Hash[Symbol, T.untyped]).void }
137
- def process_message(message); end
129
+ # @abstract
130
+ #: (Hash[Symbol, untyped] message) -> void
131
+ def process_message(message)
132
+ raise AbstractMethodInvokedError
133
+ end
138
134
 
139
- sig { abstract.void }
140
- def shutdown; end
135
+ # @abstract
136
+ #: -> void
137
+ def shutdown
138
+ raise AbstractMethodInvokedError
139
+ end
141
140
 
142
- sig { params(id: Integer, message: String, type: Integer).void }
141
+ #: (Integer id, String message, ?type: Integer) -> void
143
142
  def fail_request_and_notify(id, message, type: Constant::MessageType::INFO)
144
143
  send_message(Error.new(id: id, code: Constant::ErrorCodes::REQUEST_FAILED, message: message))
145
144
  send_message(Notification.window_show_message(message, type: type))
146
145
  end
147
146
 
148
- sig { returns(Thread) }
147
+ #: -> Thread
149
148
  def new_worker
150
149
  Thread.new do
151
- while (message = T.let(@incoming_queue.pop, T.nilable(T::Hash[Symbol, T.untyped])))
150
+ while (message = @incoming_queue.pop)
152
151
  id = message[:id]
153
152
 
154
153
  # Check if the request was cancelled before trying to process it
@@ -165,7 +164,7 @@ module RubyLsp
165
164
  end
166
165
  end
167
166
 
168
- sig { params(message: T.any(Result, Error, Notification, Request)).void }
167
+ #: ((Result | Error | Notification | Request) message) -> void
169
168
  def send_message(message)
170
169
  # When we're shutting down the server, there's a small race condition between closing the thread queues and
171
170
  # finishing remaining requests. We may close the queue in the middle of processing a request, which will then fail
@@ -176,12 +175,12 @@ module RubyLsp
176
175
  @current_request_id += 1 if message.is_a?(Request)
177
176
  end
178
177
 
179
- sig { params(id: Integer).void }
178
+ #: (Integer id) -> void
180
179
  def send_empty_response(id)
181
180
  send_message(Result.new(id: id, response: nil))
182
181
  end
183
182
 
184
- sig { params(message: String, type: Integer).void }
183
+ #: (String message, ?type: Integer) -> void
185
184
  def send_log_message(message, type: Constant::MessageType::LOG)
186
185
  send_message(Notification.window_log_message(message, type: Constant::MessageType::LOG))
187
186
  end
@@ -5,40 +5,42 @@ 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
- extend T::Sig
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
- :supports_diagnostic_refresh
13
+ :supports_diagnostic_refresh,
14
+ :supports_code_lens_refresh
16
15
 
17
- sig { void }
16
+ #: -> void
18
17
  def initialize
19
18
  # The editor supports watching files. This requires two capabilities: dynamic registration and relative pattern
20
19
  # support
21
- @supports_watching_files = T.let(false, T::Boolean)
20
+ @supports_watching_files = false #: bool
22
21
 
23
22
  # The editor supports request delegation. This is an experimental capability since request delegation has not been
24
23
  # standardized into the LSP spec yet
25
- @supports_request_delegation = T.let(false, T::Boolean)
24
+ @supports_request_delegation = false #: bool
26
25
 
27
26
  # The editor supports extra arbitrary properties for `window/showMessageRequest`. Necessary for add-ons to show
28
27
  # dialogs with user interactions
29
- @window_show_message_supports_extra_properties = T.let(false, T::Boolean)
28
+ @window_show_message_supports_extra_properties = false #: bool
30
29
 
31
30
  # Which resource operations the editor supports, like renaming files
32
- @supported_resource_operations = T.let([], T::Array[String])
31
+ @supported_resource_operations = [] #: Array[String]
33
32
 
34
33
  # The editor supports displaying progress requests
35
- @supports_progress = T.let(false, T::Boolean)
34
+ @supports_progress = false #: bool
36
35
 
37
36
  # The editor supports server initiated refresh for diagnostics
38
- @supports_diagnostic_refresh = T.let(false, T::Boolean)
37
+ @supports_diagnostic_refresh = false #: bool
38
+
39
+ # The editor supports server initiated refresh for code lenses
40
+ @supports_code_lens_refresh = false #: bool
39
41
  end
40
42
 
41
- sig { params(capabilities: T::Hash[Symbol, T.untyped]).void }
43
+ #: (Hash[Symbol, untyped] capabilities) -> void
42
44
  def apply_client_capabilities(capabilities)
43
45
  workspace_capabilities = capabilities[:workspace] || {}
44
46
 
@@ -63,9 +65,10 @@ module RubyLsp
63
65
  @supports_progress = progress if progress
64
66
 
65
67
  @supports_diagnostic_refresh = workspace_capabilities.dig(:diagnostics, :refreshSupport) || false
68
+ @supports_code_lens_refresh = workspace_capabilities.dig(:codeLens, :refreshSupport) || false
66
69
  end
67
70
 
68
- sig { returns(T::Boolean) }
71
+ #: -> bool
69
72
  def supports_rename?
70
73
  @supported_resource_operations.include?("rename")
71
74
  end