ruby-lsp 0.13.2 → 0.13.4

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -0
  3. data/VERSION +1 -1
  4. data/lib/ruby_lsp/check_docs.rb +3 -3
  5. data/lib/ruby_lsp/document.rb +12 -0
  6. data/lib/ruby_lsp/executor.rb +77 -266
  7. data/lib/ruby_lsp/listener.rb +1 -50
  8. data/lib/ruby_lsp/listeners/code_lens.rb +233 -0
  9. data/lib/ruby_lsp/listeners/completion.rb +275 -0
  10. data/lib/ruby_lsp/listeners/definition.rb +158 -0
  11. data/lib/ruby_lsp/listeners/document_highlight.rb +556 -0
  12. data/lib/ruby_lsp/listeners/document_link.rb +162 -0
  13. data/lib/ruby_lsp/listeners/document_symbol.rb +223 -0
  14. data/lib/ruby_lsp/listeners/folding_ranges.rb +271 -0
  15. data/lib/ruby_lsp/listeners/hover.rb +152 -0
  16. data/lib/ruby_lsp/listeners/inlay_hints.rb +80 -0
  17. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +430 -0
  18. data/lib/ruby_lsp/listeners/signature_help.rb +74 -0
  19. data/lib/ruby_lsp/requests/code_action_resolve.rb +4 -4
  20. data/lib/ruby_lsp/requests/code_actions.rb +13 -4
  21. data/lib/ruby_lsp/requests/code_lens.rb +21 -221
  22. data/lib/ruby_lsp/requests/completion.rb +64 -244
  23. data/lib/ruby_lsp/requests/definition.rb +34 -147
  24. data/lib/ruby_lsp/requests/diagnostics.rb +17 -5
  25. data/lib/ruby_lsp/requests/document_highlight.rb +12 -536
  26. data/lib/ruby_lsp/requests/document_link.rb +11 -132
  27. data/lib/ruby_lsp/requests/document_symbol.rb +23 -210
  28. data/lib/ruby_lsp/requests/folding_ranges.rb +16 -252
  29. data/lib/ruby_lsp/requests/formatting.rb +4 -4
  30. data/lib/ruby_lsp/requests/hover.rb +48 -92
  31. data/lib/ruby_lsp/requests/inlay_hints.rb +23 -56
  32. data/lib/ruby_lsp/requests/on_type_formatting.rb +16 -4
  33. data/lib/ruby_lsp/requests/request.rb +17 -0
  34. data/lib/ruby_lsp/requests/selection_ranges.rb +4 -3
  35. data/lib/ruby_lsp/requests/semantic_highlighting.rb +21 -408
  36. data/lib/ruby_lsp/requests/show_syntax_tree.rb +4 -4
  37. data/lib/ruby_lsp/requests/signature_help.rb +43 -51
  38. data/lib/ruby_lsp/requests/support/common.rb +3 -2
  39. data/lib/ruby_lsp/requests/support/dependency_detector.rb +2 -0
  40. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
  41. data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
  42. data/lib/ruby_lsp/requests.rb +1 -1
  43. data/lib/ruby_lsp/utils.rb +8 -0
  44. metadata +17 -6
  45. data/lib/ruby_lsp/requests/base_request.rb +0 -24
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "ruby_lsp/listeners/folding_ranges"
5
+
4
6
  module RubyLsp
5
7
  module Requests
6
8
  # ![Folding ranges demo](../../folding_ranges.gif)
@@ -15,268 +17,30 @@ module RubyLsp
15
17
  # puts "Hello"
16
18
  # end # <-- folding range end
17
19
  # ```
18
- class FoldingRanges < Listener
20
+ class FoldingRanges < Request
19
21
  extend T::Sig
20
22
  extend T::Generic
21
23
 
22
- ResponseType = type_member { { fixed: T::Array[Interface::FoldingRange] } }
23
-
24
- sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
25
- def initialize(comments, dispatcher)
26
- super(dispatcher)
27
-
28
- @_response = T.let([], ResponseType)
29
- @requires = T.let([], T::Array[Prism::CallNode])
30
- @finalized_response = T.let(false, T::Boolean)
31
- @comments = comments
24
+ class << self
25
+ extend T::Sig
32
26
 
33
- dispatcher.register(
34
- self,
35
- :on_if_node_enter,
36
- :on_in_node_enter,
37
- :on_rescue_node_enter,
38
- :on_when_node_enter,
39
- :on_interpolated_string_node_enter,
40
- :on_array_node_enter,
41
- :on_block_node_enter,
42
- :on_case_node_enter,
43
- :on_case_match_node_enter,
44
- :on_class_node_enter,
45
- :on_module_node_enter,
46
- :on_for_node_enter,
47
- :on_hash_node_enter,
48
- :on_singleton_class_node_enter,
49
- :on_unless_node_enter,
50
- :on_until_node_enter,
51
- :on_while_node_enter,
52
- :on_else_node_enter,
53
- :on_ensure_node_enter,
54
- :on_begin_node_enter,
55
- :on_def_node_enter,
56
- :on_call_node_enter,
57
- :on_lambda_node_enter,
58
- )
59
- end
60
-
61
- sig { override.returns(ResponseType) }
62
- def _response
63
- unless @finalized_response
64
- push_comment_ranges
65
- emit_requires_range
66
- @finalized_response = true
27
+ sig { returns(Interface::FoldingRangeClientCapabilities) }
28
+ def provider
29
+ Interface::FoldingRangeClientCapabilities.new(line_folding_only: true)
67
30
  end
68
-
69
- @_response
70
- end
71
-
72
- sig { params(node: Prism::IfNode).void }
73
- def on_if_node_enter(node)
74
- add_statements_range(node)
75
- end
76
-
77
- sig { params(node: Prism::InNode).void }
78
- def on_in_node_enter(node)
79
- add_statements_range(node)
80
- end
81
-
82
- sig { params(node: Prism::RescueNode).void }
83
- def on_rescue_node_enter(node)
84
- add_statements_range(node)
85
- end
86
-
87
- sig { params(node: Prism::WhenNode).void }
88
- def on_when_node_enter(node)
89
- add_statements_range(node)
90
- end
91
-
92
- sig { params(node: Prism::InterpolatedStringNode).void }
93
- def on_interpolated_string_node_enter(node)
94
- opening_loc = node.opening_loc || node.location
95
- closing_loc = node.closing_loc || node.parts.last&.location || node.location
96
-
97
- add_lines_range(opening_loc.start_line, closing_loc.start_line - 1)
98
31
  end
99
32
 
100
- sig { params(node: Prism::ArrayNode).void }
101
- def on_array_node_enter(node)
102
- add_simple_range(node)
103
- end
104
-
105
- sig { params(node: Prism::BlockNode).void }
106
- def on_block_node_enter(node)
107
- add_simple_range(node)
108
- end
109
-
110
- sig { params(node: Prism::CaseNode).void }
111
- def on_case_node_enter(node)
112
- add_simple_range(node)
113
- end
114
-
115
- sig { params(node: Prism::CaseMatchNode).void }
116
- def on_case_match_node_enter(node)
117
- add_simple_range(node)
118
- end
119
-
120
- sig { params(node: Prism::ClassNode).void }
121
- def on_class_node_enter(node)
122
- add_simple_range(node)
123
- end
124
-
125
- sig { params(node: Prism::ModuleNode).void }
126
- def on_module_node_enter(node)
127
- add_simple_range(node)
128
- end
129
-
130
- sig { params(node: Prism::ForNode).void }
131
- def on_for_node_enter(node)
132
- add_simple_range(node)
133
- end
134
-
135
- sig { params(node: Prism::HashNode).void }
136
- def on_hash_node_enter(node)
137
- add_simple_range(node)
138
- end
139
-
140
- sig { params(node: Prism::SingletonClassNode).void }
141
- def on_singleton_class_node_enter(node)
142
- add_simple_range(node)
143
- end
144
-
145
- sig { params(node: Prism::UnlessNode).void }
146
- def on_unless_node_enter(node)
147
- add_simple_range(node)
148
- end
149
-
150
- sig { params(node: Prism::UntilNode).void }
151
- def on_until_node_enter(node)
152
- add_simple_range(node)
153
- end
154
-
155
- sig { params(node: Prism::WhileNode).void }
156
- def on_while_node_enter(node)
157
- add_simple_range(node)
158
- end
159
-
160
- sig { params(node: Prism::ElseNode).void }
161
- def on_else_node_enter(node)
162
- add_simple_range(node)
163
- end
164
-
165
- sig { params(node: Prism::EnsureNode).void }
166
- def on_ensure_node_enter(node)
167
- add_simple_range(node)
168
- end
169
-
170
- sig { params(node: Prism::BeginNode).void }
171
- def on_begin_node_enter(node)
172
- add_simple_range(node)
173
- end
174
-
175
- sig { params(node: Prism::DefNode).void }
176
- def on_def_node_enter(node)
177
- params = node.parameters
178
- parameter_loc = params&.location
179
- location = node.location
180
-
181
- if params && parameter_loc.end_line > location.start_line
182
- # Multiline parameters
183
- add_lines_range(location.start_line, parameter_loc.end_line)
184
- add_lines_range(parameter_loc.end_line + 1, location.end_line - 1)
185
- else
186
- add_lines_range(location.start_line, location.end_line - 1)
187
- end
188
- end
189
-
190
- sig { params(node: Prism::CallNode).void }
191
- def on_call_node_enter(node)
192
- # If we find a require, don't visit the child nodes (prevent `super`), so that we can keep accumulating into
193
- # the `@requires` array and then push the range whenever we find a node that isn't a CallNode
194
- if require?(node)
195
- @requires << node
196
- return
197
- end
198
-
199
- location = node.location
200
- add_lines_range(location.start_line, location.end_line - 1)
201
- end
202
-
203
- sig { params(node: Prism::LambdaNode).void }
204
- def on_lambda_node_enter(node)
205
- add_simple_range(node)
206
- end
207
-
208
- private
209
-
210
- sig { void }
211
- def push_comment_ranges
212
- # Group comments that are on consecutive lines and then push ranges for each group that has at least 2 comments
213
- @comments.chunk_while do |this, other|
214
- this.location.end_line + 1 == other.location.start_line
215
- end.each do |chunk|
216
- next if chunk.length == 1
217
-
218
- @_response << Interface::FoldingRange.new(
219
- start_line: T.must(chunk.first).location.start_line - 1,
220
- end_line: T.must(chunk.last).location.end_line - 1,
221
- kind: "comment",
222
- )
223
- end
224
- end
225
-
226
- sig { void }
227
- def emit_requires_range
228
- if @requires.length > 1
229
- @_response << Interface::FoldingRange.new(
230
- start_line: T.must(@requires.first).location.start_line - 1,
231
- end_line: T.must(@requires.last).location.end_line - 1,
232
- kind: "imports",
233
- )
234
- end
235
-
236
- @requires.clear
237
- end
238
-
239
- sig { params(node: Prism::CallNode).returns(T::Boolean) }
240
- def require?(node)
241
- message = node.message
242
- return false unless message == "require" || message == "require_relative"
243
-
244
- receiver = node.receiver
245
- return false unless receiver.nil? || receiver.slice == "Kernel"
246
-
247
- arguments = node.arguments&.arguments
248
- return false unless arguments
249
-
250
- arguments.length == 1 && arguments.first.is_a?(Prism::StringNode)
251
- end
252
-
253
- sig { params(node: T.any(Prism::IfNode, Prism::InNode, Prism::RescueNode, Prism::WhenNode)).void }
254
- def add_statements_range(node)
255
- statements = node.statements
256
- return unless statements
257
-
258
- body = statements.body
259
- return if body.empty?
260
-
261
- add_lines_range(node.location.start_line, T.must(body.last).location.end_line)
262
- end
33
+ ResponseType = type_member { { fixed: T::Array[Interface::FoldingRange] } }
263
34
 
264
- sig { params(node: Prism::Node).void }
265
- def add_simple_range(node)
266
- location = node.location
267
- add_lines_range(location.start_line, location.end_line - 1)
35
+ sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
36
+ def initialize(comments, dispatcher)
37
+ super()
38
+ @listener = T.let(Listeners::FoldingRanges.new(comments, dispatcher), Listener[ResponseType])
268
39
  end
269
40
 
270
- sig { params(start_line: Integer, end_line: Integer).void }
271
- def add_lines_range(start_line, end_line)
272
- emit_requires_range
273
- return if start_line >= end_line
274
-
275
- @_response << Interface::FoldingRange.new(
276
- start_line: start_line - 1,
277
- end_line: end_line - 1,
278
- kind: "region",
279
- )
41
+ sig { override.returns(ResponseType) }
42
+ def perform
43
+ @listener.response
280
44
  end
281
45
  end
282
46
  end
@@ -25,7 +25,7 @@ module RubyLsp
25
25
  # puts "Hello" # --> formatting: fixes the indentation on save
26
26
  # end
27
27
  # ```
28
- class Formatting < BaseRequest
28
+ class Formatting < Request
29
29
  class Error < StandardError; end
30
30
  class InvalidFormatter < StandardError; end
31
31
 
@@ -55,14 +55,14 @@ module RubyLsp
55
55
 
56
56
  sig { params(document: Document, formatter: String).void }
57
57
  def initialize(document, formatter: "auto")
58
- super(document)
59
-
58
+ super()
59
+ @document = document
60
60
  @uri = T.let(document.uri, URI::Generic)
61
61
  @formatter = formatter
62
62
  end
63
63
 
64
64
  sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
65
- def run
65
+ def perform
66
66
  return if @formatter == "none"
67
67
  return if @document.syntax_error?
68
68
 
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "ruby_lsp/listeners/hover"
5
+
4
6
  module RubyLsp
5
7
  module Requests
6
8
  # ![Hover demo](../../hover.gif)
@@ -13,123 +15,77 @@ module RubyLsp
13
15
  # ```ruby
14
16
  # String # -> Hovering over the class reference will show all declaration locations and the documentation
15
17
  # ```
16
- class Hover < ExtensibleListener
18
+ class Hover < Request
17
19
  extend T::Sig
18
20
  extend T::Generic
19
21
 
20
- ResponseType = type_member { { fixed: T.nilable(Interface::Hover) } }
22
+ class << self
23
+ extend T::Sig
21
24
 
22
- ALLOWED_TARGETS = T.let(
23
- [
24
- Prism::CallNode,
25
- Prism::ConstantReadNode,
26
- Prism::ConstantWriteNode,
27
- Prism::ConstantPathNode,
28
- ],
29
- T::Array[T.class_of(Prism::Node)],
30
- )
25
+ sig { returns(Interface::HoverClientCapabilities) }
26
+ def provider
27
+ Interface::HoverClientCapabilities.new(dynamic_registration: false)
28
+ end
29
+ end
31
30
 
32
- sig { override.returns(ResponseType) }
33
- attr_reader :_response
31
+ ResponseType = type_member { { fixed: T.nilable(Interface::Hover) } }
34
32
 
35
33
  sig do
36
34
  params(
35
+ document: Document,
37
36
  index: RubyIndexer::Index,
38
- nesting: T::Array[String],
37
+ position: T::Hash[Symbol, T.untyped],
39
38
  dispatcher: Prism::Dispatcher,
39
+ typechecker_enabled: T::Boolean,
40
40
  ).void
41
41
  end
42
- def initialize(index, nesting, dispatcher)
43
- @index = index
44
- @nesting = nesting
45
- @_response = T.let(nil, ResponseType)
46
-
47
- super(dispatcher)
48
- dispatcher.register(
49
- self,
50
- :on_constant_read_node_enter,
51
- :on_constant_write_node_enter,
52
- :on_constant_path_node_enter,
53
- :on_call_node_enter,
42
+ def initialize(document, index, position, dispatcher, typechecker_enabled)
43
+ super()
44
+ target, parent, nesting = document.locate_node(
45
+ position,
46
+ node_types: Listeners::Hover::ALLOWED_TARGETS,
54
47
  )
55
- end
56
48
 
57
- sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
58
- def initialize_external_listener(addon)
59
- addon.create_hover_listener(@nesting, @index, @dispatcher)
60
- end
61
-
62
- # Merges responses from other hover listeners
63
- sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
64
- def merge_response!(other)
65
- other_response = other.response
66
- return self unless other_response
67
-
68
- if @_response.nil?
69
- @_response = other.response
70
- else
71
- @_response.contents.value << "\n\n" << other_response.contents.value
49
+ if (Listeners::Hover::ALLOWED_TARGETS.include?(parent.class) &&
50
+ !Listeners::Hover::ALLOWED_TARGETS.include?(target.class)) ||
51
+ (parent.is_a?(Prism::ConstantPathNode) && target.is_a?(Prism::ConstantReadNode))
52
+ target = parent
72
53
  end
73
54
 
74
- self
75
- end
76
-
77
- sig { params(node: Prism::ConstantReadNode).void }
78
- def on_constant_read_node_enter(node)
79
- return if DependencyDetector.instance.typechecker
80
-
81
- generate_hover(node.slice, node.location)
82
- end
55
+ @listeners = T.let([], T::Array[Listener[ResponseType]])
83
56
 
84
- sig { params(node: Prism::ConstantWriteNode).void }
85
- def on_constant_write_node_enter(node)
86
- return if DependencyDetector.instance.typechecker
57
+ # Don't need to instantiate any listeners if there's no target
58
+ return unless target
87
59
 
88
- generate_hover(node.name.to_s, node.name_loc)
89
- end
90
-
91
- sig { params(node: Prism::ConstantPathNode).void }
92
- def on_constant_path_node_enter(node)
93
- return if DependencyDetector.instance.typechecker
60
+ uri = document.uri
61
+ @listeners = T.let(
62
+ [Listeners::Hover.new(uri, nesting, index, dispatcher, typechecker_enabled)],
63
+ T::Array[Listener[ResponseType]],
64
+ )
65
+ Addon.addons.each do |addon|
66
+ addon_listener = addon.create_hover_listener(nesting, index, dispatcher)
67
+ @listeners << addon_listener if addon_listener
68
+ end
94
69
 
95
- generate_hover(node.slice, node.location)
70
+ @target = T.let(target, Prism::Node)
71
+ @dispatcher = dispatcher
96
72
  end
97
73
 
98
- sig { params(node: Prism::CallNode).void }
99
- def on_call_node_enter(node)
100
- return if DependencyDetector.instance.typechecker
101
- return unless self_receiver?(node)
102
-
103
- message = node.message
104
- return unless message
105
-
106
- target_method = @index.resolve_method(message, @nesting.join("::"))
107
- return unless target_method
108
-
109
- location = target_method.location
110
-
111
- @_response = Interface::Hover.new(
112
- range: range_from_location(location),
113
- contents: markdown_from_index_entries(message, target_method),
114
- )
115
- end
74
+ sig { override.returns(ResponseType) }
75
+ def perform
76
+ @dispatcher.dispatch_once(@target)
77
+ responses = @listeners.map(&:response).compact
116
78
 
117
- private
79
+ first_response, *other_responses = responses
118
80
 
119
- sig { params(name: String, location: Prism::Location).void }
120
- def generate_hover(name, location)
121
- entries = @index.resolve(name, @nesting)
122
- return unless entries
81
+ return unless first_response
123
82
 
124
- # We should only show hover for private constants if the constant is defined in the same namespace as the
125
- # reference
126
- first_entry = T.must(entries.first)
127
- return if first_entry.visibility == :private && first_entry.name != "#{@nesting.join("::")}::#{name}"
83
+ # TODO: other_responses should never be nil. Check Sorbet
84
+ T.must(other_responses).each do |other_response|
85
+ first_response.contents.value << "\n\n" << other_response.contents.value
86
+ end
128
87
 
129
- @_response = Interface::Hover.new(
130
- range: range_from_location(location),
131
- contents: markdown_from_index_entries(name, entries),
132
- )
88
+ first_response
133
89
  end
134
90
  end
135
91
  end
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "ruby_lsp/listeners/inlay_hints"
5
+
4
6
  module RubyLsp
5
7
  module Requests
6
8
  # ![Inlay hint demo](../../inlay_hints.gif)
@@ -36,77 +38,42 @@ module RubyLsp
36
38
  # a: "hello",
37
39
  # }
38
40
  # ```
39
- class InlayHints < Listener
41
+ class InlayHints < Request
40
42
  extend T::Sig
41
43
  extend T::Generic
42
44
 
43
- ResponseType = type_member { { fixed: T::Array[Interface::InlayHint] } }
45
+ class << self
46
+ extend T::Sig
44
47
 
45
- RESCUE_STRING_LENGTH = T.let("rescue".length, Integer)
48
+ sig { returns(Interface::InlayHintOptions) }
49
+ def provider
50
+ Interface::InlayHintOptions.new(resolve_provider: false)
51
+ end
52
+ end
46
53
 
47
- sig { override.returns(ResponseType) }
48
- attr_reader :_response
54
+ ResponseType = type_member { { fixed: T::Array[Interface::InlayHint] } }
49
55
 
50
56
  sig do
51
57
  params(
52
- range: T::Range[Integer],
58
+ document: Document,
59
+ range: T::Hash[Symbol, T.untyped],
53
60
  hints_configuration: RequestConfig,
54
61
  dispatcher: Prism::Dispatcher,
55
62
  ).void
56
63
  end
57
- def initialize(range, hints_configuration, dispatcher)
58
- super(dispatcher)
59
-
60
- @_response = T.let([], ResponseType)
61
- @range = range
62
- @hints_configuration = hints_configuration
63
-
64
- dispatcher.register(self, :on_rescue_node_enter, :on_implicit_node_enter)
65
- end
66
-
67
- sig { params(node: Prism::RescueNode).void }
68
- def on_rescue_node_enter(node)
69
- return unless @hints_configuration.enabled?(:implicitRescue)
70
- return unless node.exceptions.empty?
71
-
72
- loc = node.location
73
- return unless visible?(node, @range)
74
-
75
- @_response << Interface::InlayHint.new(
76
- position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
77
- label: "StandardError",
78
- padding_left: true,
79
- tooltip: "StandardError is implied in a bare rescue",
64
+ def initialize(document, range, hints_configuration, dispatcher)
65
+ super()
66
+ start_line = range.dig(:start, :line)
67
+ end_line = range.dig(:end, :line)
68
+ @listener = T.let(
69
+ Listeners::InlayHints.new(start_line..end_line, hints_configuration, dispatcher),
70
+ Listener[ResponseType],
80
71
  )
81
72
  end
82
73
 
83
- sig { params(node: Prism::ImplicitNode).void }
84
- def on_implicit_node_enter(node)
85
- return unless @hints_configuration.enabled?(:implicitHashValue)
86
- return unless visible?(node, @range)
87
-
88
- node_value = node.value
89
- loc = node.location
90
- tooltip = ""
91
- node_name = ""
92
- case node_value
93
- when Prism::CallNode
94
- node_name = node_value.name
95
- tooltip = "This is a method call. Method name: #{node_name}"
96
- when Prism::ConstantReadNode
97
- node_name = node_value.name
98
- tooltip = "This is a constant: #{node_name}"
99
- when Prism::LocalVariableReadNode
100
- node_name = node_value.name
101
- tooltip = "This is a local variable: #{node_name}"
102
- end
103
-
104
- @_response << Interface::InlayHint.new(
105
- position: { line: loc.start_line - 1, character: loc.start_column + node_name.length + 1 },
106
- label: node_name,
107
- padding_left: true,
108
- tooltip: tooltip,
109
- )
74
+ sig { override.returns(ResponseType) }
75
+ def perform
76
+ @listener.response
110
77
  end
111
78
  end
112
79
  end
@@ -15,9 +15,21 @@ module RubyLsp
15
15
  # # <-- cursor ends up here
16
16
  # end # <-- end is automatically added
17
17
  # ```
18
- class OnTypeFormatting < BaseRequest
18
+ class OnTypeFormatting < Request
19
19
  extend T::Sig
20
20
 
21
+ class << self
22
+ extend T::Sig
23
+
24
+ sig { returns(Interface::DocumentOnTypeFormattingOptions) }
25
+ def provider
26
+ Interface::DocumentOnTypeFormattingOptions.new(
27
+ first_trigger_character: "{",
28
+ more_trigger_character: ["\n", "|", "d"],
29
+ )
30
+ end
31
+ end
32
+
21
33
  END_REGEXES = T.let(
22
34
  [
23
35
  /\b(if|unless|for|while|class|module|until|def|case)\b.*/,
@@ -28,8 +40,8 @@ module RubyLsp
28
40
 
29
41
  sig { params(document: Document, position: T::Hash[Symbol, T.untyped], trigger_character: String).void }
30
42
  def initialize(document, position, trigger_character)
31
- super(document)
32
-
43
+ super()
44
+ @document = document
33
45
  @lines = T.let(@document.source.lines, T::Array[String])
34
46
  line = @lines[[position[:line] - 1, 0].max]
35
47
 
@@ -41,7 +53,7 @@ module RubyLsp
41
53
  end
42
54
 
43
55
  sig { override.returns(T.all(T::Array[Interface::TextEdit], Object)) }
44
- def run
56
+ def perform
45
57
  case @trigger_character
46
58
  when "{"
47
59
  handle_curly_brace if @document.syntax_error?
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # :nodoc:
7
+ class Request
8
+ extend T::Sig
9
+ extend T::Generic
10
+
11
+ abstract!
12
+
13
+ sig { abstract.returns(T.anything) }
14
+ def perform; end
15
+ end
16
+ end
17
+ end
@@ -20,18 +20,19 @@ module RubyLsp
20
20
  # puts "Hello, world!" # --> Cursor is on this line
21
21
  # end
22
22
  # ```
23
- class SelectionRanges
23
+ class SelectionRanges < Request
24
24
  extend T::Sig
25
25
  include Support::Common
26
26
  sig { params(document: Document).void }
27
27
  def initialize(document)
28
+ super()
28
29
  @document = document
29
30
  @ranges = T.let([], T::Array[Support::SelectionRange])
30
31
  @stack = T.let([], T::Array[Support::SelectionRange])
31
32
  end
32
33
 
33
- sig { returns(T.all(T::Array[Support::SelectionRange], Object)) }
34
- def run
34
+ sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
35
+ def perform
35
36
  # [node, parent]
36
37
  queue = [[@document.tree, nil]]
37
38