ruby-lsp 0.0.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -0
  3. data/.rubocop.yml +25 -0
  4. data/CHANGELOG.md +35 -0
  5. data/Gemfile +10 -6
  6. data/Gemfile.lock +63 -16
  7. data/README.md +41 -0
  8. data/Rakefile +8 -1
  9. data/VERSION +1 -1
  10. data/bin/console +19 -0
  11. data/bin/tapioca +29 -0
  12. data/dev.yml +3 -0
  13. data/exe/ruby-lsp +19 -4
  14. data/lib/ruby-lsp.rb +2 -1
  15. data/lib/ruby_lsp/cli.rb +13 -5
  16. data/lib/ruby_lsp/document.rb +43 -14
  17. data/lib/ruby_lsp/handler.rb +107 -37
  18. data/lib/ruby_lsp/internal.rb +7 -0
  19. data/lib/ruby_lsp/requests/base_request.rb +18 -5
  20. data/lib/ruby_lsp/requests/code_actions.rb +20 -8
  21. data/lib/ruby_lsp/requests/diagnostics.rb +25 -7
  22. data/lib/ruby_lsp/requests/document_highlight.rb +113 -0
  23. data/lib/ruby_lsp/requests/document_symbol.rb +56 -16
  24. data/lib/ruby_lsp/requests/folding_ranges.rb +70 -34
  25. data/lib/ruby_lsp/requests/formatting.rb +24 -14
  26. data/lib/ruby_lsp/requests/selection_ranges.rb +18 -4
  27. data/lib/ruby_lsp/requests/semantic_highlighting.rb +187 -34
  28. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +16 -3
  29. data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +61 -0
  30. data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +50 -0
  31. data/lib/ruby_lsp/requests/support/selection_range.rb +4 -0
  32. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +24 -3
  33. data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +6 -0
  34. data/lib/ruby_lsp/requests.rb +13 -1
  35. data/lib/ruby_lsp/store.rb +20 -3
  36. data/rakelib/check_docs.rake +34 -6
  37. data/ruby-lsp.gemspec +7 -5
  38. data/sorbet/config +4 -0
  39. data/sorbet/rbi/.rubocop.yml +8 -0
  40. data/sorbet/rbi/gems/ansi@1.5.0.rbi +338 -0
  41. data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
  42. data/sorbet/rbi/gems/builder@3.2.4.rbi +418 -0
  43. data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
  44. data/sorbet/rbi/gems/debug@1.5.0.rbi +1273 -0
  45. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +867 -0
  46. data/sorbet/rbi/gems/io-console@0.5.11.rbi +8 -0
  47. data/sorbet/rbi/gems/irb@1.4.1.rbi +376 -0
  48. data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +7325 -0
  49. data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
  50. data/sorbet/rbi/gems/minitest-reporters@1.5.0.rbi +612 -0
  51. data/sorbet/rbi/gems/minitest@5.15.0.rbi +994 -0
  52. data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
  53. data/sorbet/rbi/gems/parser@3.1.2.0.rbi +3968 -0
  54. data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +734 -0
  55. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  56. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +227 -0
  57. data/sorbet/rbi/gems/rake@13.0.6.rbi +1853 -0
  58. data/sorbet/rbi/gems/rbi@0.0.14.rbi +2337 -0
  59. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +1854 -0
  60. data/sorbet/rbi/gems/reline@0.3.1.rbi +1274 -0
  61. data/sorbet/rbi/gems/rexml@3.2.5.rbi +3852 -0
  62. data/sorbet/rbi/gems/rubocop-ast@1.18.0.rbi +4180 -0
  63. data/sorbet/rbi/gems/rubocop-minitest@0.20.0.rbi +1369 -0
  64. data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +246 -0
  65. data/sorbet/rbi/gems/rubocop-shopify@2.6.0.rbi +8 -0
  66. data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +652 -0
  67. data/sorbet/rbi/gems/rubocop@1.30.0.rbi +36729 -0
  68. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +732 -0
  69. data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
  70. data/sorbet/rbi/gems/syntax_tree@2.7.1.rbi +6777 -0
  71. data/sorbet/rbi/gems/tapioca@0.8.1.rbi +1972 -0
  72. data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
  73. data/sorbet/rbi/gems/unicode-display_width@2.1.0.rbi +27 -0
  74. data/sorbet/rbi/gems/unparser@0.6.5.rbi +2789 -0
  75. data/sorbet/rbi/gems/webrick@1.7.0.rbi +1779 -0
  76. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +289 -0
  77. data/sorbet/rbi/gems/yard@0.9.27.rbi +13048 -0
  78. data/sorbet/rbi/shims/fiddle.rbi +4 -0
  79. data/sorbet/rbi/shims/hash.rbi +6 -0
  80. data/sorbet/rbi/shims/rdoc.rbi +4 -0
  81. data/sorbet/tapioca/config.yml +13 -0
  82. data/sorbet/tapioca/require.rb +7 -0
  83. metadata +62 -13
  84. data/lib/ruby_lsp/requests/rubocop_request.rb +0 -49
  85. data/shipit.production.yml +0 -1
@@ -1,7 +1,10 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
4
5
  module Requests
6
+ # ![Document symbol demo](../../misc/document_symbol.gif)
7
+ #
5
8
  # The [document
6
9
  # symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) request
7
10
  # informs the editor of all the important symbols, such as classes, variables, and methods, defined in a file. With
@@ -24,7 +27,9 @@ module RubyLsp
24
27
  # end
25
28
  # ```
26
29
  class DocumentSymbol < BaseRequest
27
- SYMBOL_KIND = {
30
+ extend T::Sig
31
+
32
+ SYMBOL_KIND = T.let({
28
33
  file: 1,
29
34
  module: 2,
30
35
  namespace: 3,
@@ -51,33 +56,43 @@ module RubyLsp
51
56
  event: 24,
52
57
  operator: 25,
53
58
  typeparameter: 26,
54
- }.freeze
59
+ }.freeze, T::Hash[Symbol, Integer])
55
60
 
56
- ATTR_ACCESSORS = ["attr_reader", "attr_writer", "attr_accessor"].freeze
61
+ ATTR_ACCESSORS = T.let(["attr_reader", "attr_writer", "attr_accessor"].freeze, T::Array[String])
57
62
 
58
63
  class SymbolHierarchyRoot
64
+ extend T::Sig
65
+
66
+ sig { returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
59
67
  attr_reader :children
60
68
 
69
+ sig { void }
61
70
  def initialize
62
- @children = []
71
+ @children = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentSymbol])
63
72
  end
64
73
  end
65
74
 
75
+ sig { params(document: Document).void }
66
76
  def initialize(document)
67
77
  super
68
78
 
69
- @root = SymbolHierarchyRoot.new
70
- @stack = [@root]
79
+ @root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
80
+ @stack = T.let(
81
+ [@root],
82
+ T::Array[T.any(SymbolHierarchyRoot, LanguageServer::Protocol::Interface::DocumentSymbol)]
83
+ )
71
84
  end
72
85
 
86
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol], Object)) }
73
87
  def run
74
88
  visit(@document.tree)
75
89
  @root.children
76
90
  end
77
91
 
92
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
78
93
  def visit_class(node)
79
94
  symbol = create_document_symbol(
80
- name: node.constant.constant.value,
95
+ name: fully_qualified_name(node),
81
96
  kind: :class,
82
97
  range_node: node,
83
98
  selection_range_node: node.constant
@@ -88,6 +103,7 @@ module RubyLsp
88
103
  @stack.pop
89
104
  end
90
105
 
106
+ sig { params(node: SyntaxTree::Command).void }
91
107
  def visit_command(node)
92
108
  return unless ATTR_ACCESSORS.include?(node.message.value)
93
109
 
@@ -103,6 +119,7 @@ module RubyLsp
103
119
  end
104
120
  end
105
121
 
122
+ sig { params(node: SyntaxTree::ConstPathField).void }
106
123
  def visit_const_path_field(node)
107
124
  create_document_symbol(
108
125
  name: node.constant.value,
@@ -112,6 +129,7 @@ module RubyLsp
112
129
  )
113
130
  end
114
131
 
132
+ sig { params(node: SyntaxTree::Def).void }
115
133
  def visit_def(node)
116
134
  name = node.name.value
117
135
 
@@ -127,6 +145,7 @@ module RubyLsp
127
145
  @stack.pop
128
146
  end
129
147
 
148
+ sig { params(node: SyntaxTree::DefEndless).void }
130
149
  def visit_def_endless(node)
131
150
  name = node.name.value
132
151
 
@@ -142,6 +161,7 @@ module RubyLsp
142
161
  @stack.pop
143
162
  end
144
163
 
164
+ sig { params(node: SyntaxTree::Defs).void }
145
165
  def visit_defs(node)
146
166
  symbol = create_document_symbol(
147
167
  name: "self.#{node.name.value}",
@@ -155,9 +175,10 @@ module RubyLsp
155
175
  @stack.pop
156
176
  end
157
177
 
178
+ sig { params(node: SyntaxTree::ModuleDeclaration).void }
158
179
  def visit_module(node)
159
180
  symbol = create_document_symbol(
160
- name: node.constant.constant.value,
181
+ name: fully_qualified_name(node),
161
182
  kind: :module,
162
183
  range_node: node,
163
184
  selection_range_node: node.constant
@@ -168,6 +189,7 @@ module RubyLsp
168
189
  @stack.pop
169
190
  end
170
191
 
192
+ sig { params(node: SyntaxTree::TopConstField).void }
171
193
  def visit_top_const_field(node)
172
194
  create_document_symbol(
173
195
  name: node.constant.value,
@@ -177,6 +199,7 @@ module RubyLsp
177
199
  )
178
200
  end
179
201
 
202
+ sig { params(node: SyntaxTree::VarField).void }
180
203
  def visit_var_field(node)
181
204
  kind = case node.value
182
205
  when SyntaxTree::Const
@@ -197,6 +220,14 @@ module RubyLsp
197
220
 
198
221
  private
199
222
 
223
+ sig do
224
+ params(
225
+ name: String,
226
+ kind: Symbol,
227
+ range_node: SyntaxTree::Node,
228
+ selection_range_node: SyntaxTree::Node
229
+ ).returns(LanguageServer::Protocol::Interface::DocumentSymbol)
230
+ end
200
231
  def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
201
232
  symbol = LanguageServer::Protocol::Interface::DocumentSymbol.new(
202
233
  name: name,
@@ -206,19 +237,28 @@ module RubyLsp
206
237
  children: [],
207
238
  )
208
239
 
209
- @stack.last.children << symbol
240
+ T.must(@stack.last).children << symbol
210
241
 
211
242
  symbol
212
243
  end
213
244
 
214
- def range_from_syntax_tree_node(node)
215
- loc = node.location
245
+ sig { params(node: T.any(SyntaxTree::ClassDeclaration, SyntaxTree::ModuleDeclaration)).returns(String) }
246
+ def fully_qualified_name(node)
247
+ constant = T.let(node.constant, SyntaxTree::Node)
248
+ name = +node.constant.constant.value
216
249
 
217
- LanguageServer::Protocol::Interface::Range.new(
218
- start: LanguageServer::Protocol::Interface::Position.new(line: loc.start_line - 1,
219
- character: loc.start_column),
220
- end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
221
- )
250
+ while constant.is_a?(SyntaxTree::ConstPathRef)
251
+ constant = constant.parent
252
+
253
+ case constant
254
+ when SyntaxTree::ConstPathRef
255
+ name.prepend("#{constant.constant.value}::")
256
+ when SyntaxTree::VarRef
257
+ name.prepend("#{constant.value.value}::")
258
+ end
259
+ end
260
+
261
+ name
222
262
  end
223
263
  end
224
264
  end
@@ -1,18 +1,24 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
4
5
  module Requests
6
+ # ![Folding ranges demo](../../misc/folding_ranges.gif)
7
+ #
5
8
  # The [folding ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange)
6
- # request informs the editor of the ranges where code can be folded.
9
+ # request informs the editor of the ranges where and how code can be folded.
7
10
  #
8
11
  # # Example
12
+ #
9
13
  # ```ruby
10
14
  # def say_hello # <-- folding range start
11
15
  # puts "Hello"
12
16
  # end # <-- folding range end
13
17
  # ```
14
18
  class FoldingRanges < BaseRequest
15
- SIMPLE_FOLDABLES = [
19
+ extend T::Sig
20
+
21
+ SIMPLE_FOLDABLES = T.let([
16
22
  SyntaxTree::ArrayLiteral,
17
23
  SyntaxTree::BraceBlock,
18
24
  SyntaxTree::Case,
@@ -29,24 +35,36 @@ module RubyLsp
29
35
  SyntaxTree::Unless,
30
36
  SyntaxTree::Until,
31
37
  SyntaxTree::While,
32
- ].freeze
33
-
34
- NODES_WITH_STATEMENTS = [
35
38
  SyntaxTree::Else,
36
- SyntaxTree::Elsif,
37
39
  SyntaxTree::Ensure,
40
+ SyntaxTree::Begin,
41
+ ].freeze, T::Array[T.class_of(SyntaxTree::Node)])
42
+
43
+ NODES_WITH_STATEMENTS = T.let([
44
+ SyntaxTree::Elsif,
38
45
  SyntaxTree::In,
39
46
  SyntaxTree::Rescue,
40
47
  SyntaxTree::When,
41
- ].freeze
48
+ ].freeze, T::Array[T.class_of(SyntaxTree::Node)])
49
+
50
+ StatementNode = T.type_alias do
51
+ T.any(
52
+ SyntaxTree::Elsif,
53
+ SyntaxTree::In,
54
+ SyntaxTree::Rescue,
55
+ SyntaxTree::When,
56
+ )
57
+ end
42
58
 
59
+ sig { params(document: Document).void }
43
60
  def initialize(document)
44
61
  super
45
62
 
46
- @ranges = []
47
- @partial_range = nil
63
+ @ranges = T.let([], T::Array[LanguageServer::Protocol::Interface::FoldingRange])
64
+ @partial_range = T.let(nil, T.nilable(PartialRange))
48
65
  end
49
66
 
67
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::FoldingRange], Object)) }
50
68
  def run
51
69
  visit(@document.tree)
52
70
  emit_partial_range
@@ -55,16 +73,16 @@ module RubyLsp
55
73
 
56
74
  private
57
75
 
76
+ sig { params(node: T.nilable(SyntaxTree::Node)).void }
58
77
  def visit(node)
59
78
  return unless handle_partial_range(node)
60
79
 
61
80
  case node
62
81
  when *SIMPLE_FOLDABLES
63
- add_node_range(node)
82
+ location = T.must(node).location
83
+ add_lines_range(location.start_line, location.end_line - 1)
64
84
  when *NODES_WITH_STATEMENTS
65
- add_statements_range(node, node.statements)
66
- when SyntaxTree::Begin
67
- add_statements_range(node, node.bodystmt.statements)
85
+ add_statements_range(T.must(node), T.cast(node, StatementNode).statements)
68
86
  when SyntaxTree::Call, SyntaxTree::CommandCall
69
87
  add_call_range(node)
70
88
  return
@@ -79,27 +97,38 @@ module RubyLsp
79
97
  end
80
98
 
81
99
  class PartialRange
82
- attr_reader :kind, :end_line
100
+ extend T::Sig
101
+
102
+ sig { returns(String) }
103
+ attr_reader :kind
104
+
105
+ sig { returns(Integer) }
106
+ attr_reader :end_line
83
107
 
108
+ sig { params(node: SyntaxTree::Node, kind: String).returns(PartialRange) }
84
109
  def self.from(node, kind)
85
110
  new(node.location.start_line - 1, node.location.end_line - 1, kind)
86
111
  end
87
112
 
113
+ sig { params(start_line: Integer, end_line: Integer, kind: String).void }
88
114
  def initialize(start_line, end_line, kind)
89
115
  @start_line = start_line
90
116
  @end_line = end_line
91
117
  @kind = kind
92
118
  end
93
119
 
120
+ sig { params(node: SyntaxTree::Node).returns(PartialRange) }
94
121
  def extend_to(node)
95
122
  @end_line = node.location.end_line - 1
96
123
  self
97
124
  end
98
125
 
126
+ sig { params(node: SyntaxTree::Node).returns(T::Boolean) }
99
127
  def new_section?(node)
100
128
  node.is_a?(SyntaxTree::Comment) && @end_line + 1 != node.location.start_line - 1
101
129
  end
102
130
 
131
+ sig { returns(LanguageServer::Protocol::Interface::FoldingRange) }
103
132
  def to_range
104
133
  LanguageServer::Protocol::Interface::FoldingRange.new(
105
134
  start_line: @start_line,
@@ -107,8 +136,14 @@ module RubyLsp
107
136
  kind: @kind
108
137
  )
109
138
  end
139
+
140
+ sig { returns(T::Boolean) }
141
+ def multiline?
142
+ @end_line > @start_line
143
+ end
110
144
  end
111
145
 
146
+ sig { params(node: T.nilable(SyntaxTree::Node)).returns(T::Boolean) }
112
147
  def handle_partial_range(node)
113
148
  kind = partial_range_kind(node)
114
149
 
@@ -117,18 +152,20 @@ module RubyLsp
117
152
  return true
118
153
  end
119
154
 
155
+ target_node = T.must(node)
120
156
  @partial_range = if @partial_range.nil?
121
- PartialRange.from(node, kind)
122
- elsif @partial_range.kind != kind || @partial_range.new_section?(node)
157
+ PartialRange.from(target_node, kind)
158
+ elsif @partial_range.kind != kind || @partial_range.new_section?(target_node)
123
159
  emit_partial_range
124
- PartialRange.from(node, kind)
160
+ PartialRange.from(target_node, kind)
125
161
  else
126
- @partial_range.extend_to(node)
162
+ @partial_range.extend_to(target_node)
127
163
  end
128
164
 
129
165
  false
130
166
  end
131
167
 
168
+ sig { params(node: T.nilable(SyntaxTree::Node)).returns(T.nilable(String)) }
132
169
  def partial_range_kind(node)
133
170
  case node
134
171
  when SyntaxTree::Comment
@@ -140,15 +177,17 @@ module RubyLsp
140
177
  end
141
178
  end
142
179
 
180
+ sig { void }
143
181
  def emit_partial_range
144
182
  return if @partial_range.nil?
145
183
 
146
- @ranges << @partial_range.to_range
184
+ @ranges << @partial_range.to_range if @partial_range.multiline?
147
185
  @partial_range = nil
148
186
  end
149
187
 
188
+ sig { params(node: T.any(SyntaxTree::Call, SyntaxTree::CommandCall)).void }
150
189
  def add_call_range(node)
151
- receiver = node.receiver
190
+ receiver = T.let(node.receiver, SyntaxTree::Node)
152
191
  loop do
153
192
  case receiver
154
193
  when SyntaxTree::Call
@@ -162,42 +201,39 @@ module RubyLsp
162
201
  end
163
202
  end
164
203
 
165
- add_lines_range(receiver.location.start_line, node.location.end_line)
204
+ add_lines_range(receiver.location.start_line, node.location.end_line - 1)
166
205
 
167
206
  visit(node.arguments)
168
207
  end
169
208
 
209
+ sig { params(node: T.any(SyntaxTree::Def, SyntaxTree::Defs)).void }
170
210
  def add_def_range(node)
171
211
  params_location = node.params.location
172
212
 
173
213
  if params_location.start_line < params_location.end_line
174
- add_lines_range(params_location.end_line, node.location.end_line)
214
+ add_lines_range(params_location.end_line, node.location.end_line - 1)
175
215
  else
176
- add_node_range(node)
216
+ location = node.location
217
+ add_lines_range(location.start_line, location.end_line - 1)
177
218
  end
178
219
 
179
220
  visit(node.bodystmt.statements)
180
221
  end
181
222
 
223
+ sig { params(node: SyntaxTree::Node, statements: SyntaxTree::Statements).void }
182
224
  def add_statements_range(node, statements)
183
- add_lines_range(node.location.start_line, statements.location.end_line) unless statements.empty?
225
+ add_lines_range(node.location.start_line, statements.body.last.location.end_line) unless statements.empty?
184
226
  end
185
227
 
228
+ sig { params(node: SyntaxTree::StringConcat).void }
186
229
  def add_string_concat(node)
187
- left = node.left
230
+ left = T.let(node.left, SyntaxTree::Node)
188
231
  left = left.left while left.is_a?(SyntaxTree::StringConcat)
189
232
 
190
- add_lines_range(left.location.start_line, node.right.location.end_line)
191
- end
192
-
193
- def add_node_range(node)
194
- add_location_range(node.location)
195
- end
196
-
197
- def add_location_range(location)
198
- add_lines_range(location.start_line, location.end_line)
233
+ add_lines_range(left.location.start_line, node.right.location.end_line - 1)
199
234
  end
200
235
 
236
+ sig { params(start_line: Integer, end_line: Integer).void }
201
237
  def add_lines_range(start_line, end_line)
202
238
  return if start_line >= end_line
203
239
 
@@ -1,7 +1,12 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
4
+ require "ruby_lsp/requests/support/rubocop_formatting_runner"
5
+
3
6
  module RubyLsp
4
7
  module Requests
8
+ # ![Formatting symbol demo](../../misc/formatting.gif)
9
+ #
5
10
  # The [formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting)
6
11
  # request uses RuboCop to fix auto-correctable offenses in the document. This requires enabling format on save and
7
12
  # registering the ruby-lsp as the Ruby formatter.
@@ -13,38 +18,43 @@ module RubyLsp
13
18
  # puts "Hello" # --> formatting: fixes the indentation on save
14
19
  # end
15
20
  # ```
16
- class Formatting < RuboCopRequest
17
- RUBOCOP_FLAGS = (COMMON_RUBOCOP_FLAGS + ["--auto-correct"]).freeze
21
+ class Formatting < BaseRequest
22
+ extend T::Sig
18
23
 
24
+ sig { params(uri: String, document: Document).void }
19
25
  def initialize(uri, document)
20
- super
21
- @formatted_text = nil
26
+ super(document)
27
+
28
+ @uri = uri
22
29
  end
23
30
 
31
+ sig { override.returns(T.nilable(T.all(T::Array[LanguageServer::Protocol::Interface::TextEdit], Object))) }
24
32
  def run
25
- super
33
+ formatted_text = formatted_file
34
+ return unless formatted_text
26
35
 
27
- @formatted_text = @options[:stdin] # Rubocop applies the corrections on stdin
28
- return unless @formatted_text
36
+ size = @document.source.size
29
37
 
30
38
  [
31
39
  LanguageServer::Protocol::Interface::TextEdit.new(
32
40
  range: LanguageServer::Protocol::Interface::Range.new(
33
41
  start: LanguageServer::Protocol::Interface::Position.new(line: 0, character: 0),
34
- end: LanguageServer::Protocol::Interface::Position.new(
35
- line: text.size,
36
- character: text.size
37
- )
42
+ end: LanguageServer::Protocol::Interface::Position.new(line: size, character: size)
38
43
  ),
39
- new_text: @formatted_text
44
+ new_text: formatted_text
40
45
  ),
41
46
  ]
42
47
  end
43
48
 
44
49
  private
45
50
 
46
- def rubocop_flags
47
- RUBOCOP_FLAGS
51
+ sig { returns(T.nilable(String)) }
52
+ def formatted_file
53
+ if defined?(Support::RuboCopFormattingRunner)
54
+ Support::RuboCopFormattingRunner.instance.run(@uri, @document)
55
+ else
56
+ SyntaxTree.format(@document.source)
57
+ end
48
58
  end
49
59
  end
50
60
  end
@@ -1,7 +1,10 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
4
5
  module Requests
6
+ # ![Selection ranges demo](../../misc/selection_ranges.gif)
7
+ #
5
8
  # The [selection ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange)
6
9
  # request informs the editor of ranges that the user may want to select based on the location(s)
7
10
  # of their cursor(s).
@@ -16,7 +19,9 @@ module RubyLsp
16
19
  # end
17
20
  # ```
18
21
  class SelectionRanges < BaseRequest
19
- NODES_THAT_CAN_BE_PARENTS = [
22
+ extend T::Sig
23
+
24
+ NODES_THAT_CAN_BE_PARENTS = T.let([
20
25
  SyntaxTree::Assign,
21
26
  SyntaxTree::ArrayLiteral,
22
27
  SyntaxTree::Begin,
@@ -53,15 +58,17 @@ module RubyLsp
53
58
  SyntaxTree::VCall,
54
59
  SyntaxTree::When,
55
60
  SyntaxTree::While,
56
- ].freeze
61
+ ].freeze, T::Array[T.class_of(SyntaxTree::Node)])
57
62
 
63
+ sig { params(document: Document).void }
58
64
  def initialize(document)
59
65
  super(document)
60
66
 
61
- @ranges = []
62
- @stack = []
67
+ @ranges = T.let([], T::Array[Support::SelectionRange])
68
+ @stack = T.let([], T::Array[Support::SelectionRange])
63
69
  end
64
70
 
71
+ sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
65
72
  def run
66
73
  visit(@document.tree)
67
74
  @ranges.reverse!
@@ -69,6 +76,7 @@ module RubyLsp
69
76
 
70
77
  private
71
78
 
79
+ sig { params(node: T.nilable(SyntaxTree::Node)).void }
72
80
  def visit(node)
73
81
  return if node.nil?
74
82
 
@@ -82,6 +90,12 @@ module RubyLsp
82
90
  @stack.pop if NODES_THAT_CAN_BE_PARENTS.include?(node.class)
83
91
  end
84
92
 
93
+ sig do
94
+ params(
95
+ location: SyntaxTree::Location,
96
+ parent: T.nilable(Support::SelectionRange)
97
+ ).returns(Support::SelectionRange)
98
+ end
85
99
  def create_selection_range(location, parent = nil)
86
100
  RubyLsp::Requests::Support::SelectionRange.new(
87
101
  range: LanguageServer::Protocol::Interface::Range.new(