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