ruby-lsp 0.0.2 → 0.1.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.
- 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
|