ruby-lsp 0.0.3 → 0.2.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 (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(