ruby-lsp 0.13.2 → 0.13.4

Sign up to get free protection for your applications and to get access to all the features.
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