ruby-lsp 0.0.4 → 0.2.1
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/.rubocop.yml +11 -1
- data/CHANGELOG.md +35 -0
- data/Gemfile +4 -3
- data/Gemfile.lock +26 -24
- data/README.md +3 -2
- data/Rakefile +8 -1
- data/VERSION +1 -1
- data/bin/console +19 -0
- data/exe/ruby-lsp +1 -3
- data/lib/ruby_lsp/document.rb +17 -4
- data/lib/ruby_lsp/handler.rb +54 -141
- data/lib/{internal.rb → ruby_lsp/internal.rb} +4 -2
- data/lib/ruby_lsp/requests/base_request.rb +9 -7
- data/lib/ruby_lsp/requests/code_actions.rb +20 -9
- data/lib/ruby_lsp/requests/diagnostics.rb +25 -8
- data/lib/ruby_lsp/requests/document_highlight.rb +32 -32
- data/lib/ruby_lsp/requests/document_symbol.rb +59 -10
- data/lib/ruby_lsp/requests/folding_ranges.rb +73 -34
- data/lib/ruby_lsp/requests/formatting.rb +25 -15
- data/lib/ruby_lsp/requests/selection_ranges.rb +18 -5
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +179 -36
- data/lib/ruby_lsp/requests/support/highlight_target.rb +87 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +16 -4
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +61 -0
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +50 -0
- data/lib/ruby_lsp/requests/support/selection_range.rb +4 -1
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +13 -3
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +6 -1
- data/lib/ruby_lsp/requests.rb +13 -2
- data/lib/ruby_lsp/server.rb +160 -0
- data/lib/ruby_lsp/store.rb +17 -9
- data/rakelib/check_docs.rake +30 -5
- data/ruby-lsp.gemspec +6 -5
- data/sorbet/tapioca/require.rb +1 -1
- metadata +14 -26
- data/lib/ruby_lsp/cli.rb +0 -88
- data/lib/ruby_lsp/requests/rubocop_request.rb +0 -50
- data/shipit.production.yml +0 -1
@@ -1,8 +1,12 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "ruby_lsp/requests/support/rubocop_diagnostics_runner"
|
5
|
+
|
4
6
|
module RubyLsp
|
5
7
|
module Requests
|
8
|
+
# 
|
9
|
+
#
|
6
10
|
# The
|
7
11
|
# [diagnostics](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics)
|
8
12
|
# request informs the editor of RuboCop offenses for a given file.
|
@@ -14,21 +18,34 @@ module RubyLsp
|
|
14
18
|
# puts "Hello" # --> diagnostics: incorrect indentantion
|
15
19
|
# end
|
16
20
|
# ```
|
17
|
-
class Diagnostics <
|
18
|
-
|
19
|
-
return syntax_error_diagnostics if @document.syntax_errors?
|
21
|
+
class Diagnostics < BaseRequest
|
22
|
+
extend T::Sig
|
20
23
|
|
21
|
-
|
24
|
+
sig { params(uri: String, document: Document).void }
|
25
|
+
def initialize(uri, document)
|
26
|
+
super(document)
|
22
27
|
|
23
|
-
@
|
28
|
+
@uri = uri
|
24
29
|
end
|
25
30
|
|
26
|
-
|
27
|
-
|
31
|
+
sig do
|
32
|
+
override.returns(
|
33
|
+
T.any(
|
34
|
+
T.all(T::Array[Support::RuboCopDiagnostic], Object),
|
35
|
+
T.all(T::Array[Support::SyntaxErrorDiagnostic], Object),
|
36
|
+
)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
def run
|
40
|
+
return syntax_error_diagnostics if @document.syntax_errors?
|
41
|
+
return [] unless defined?(Support::RuboCopDiagnosticsRunner)
|
42
|
+
|
43
|
+
Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
|
28
44
|
end
|
29
45
|
|
30
46
|
private
|
31
47
|
|
48
|
+
sig { returns(T::Array[Support::SyntaxErrorDiagnostic]) }
|
32
49
|
def syntax_error_diagnostics
|
33
50
|
@document.syntax_error_edits.map { |e| Support::SyntaxErrorDiagnostic.new(e) }
|
34
51
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
+
# 
|
7
|
+
#
|
6
8
|
# The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
|
7
9
|
# informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
|
8
10
|
# the cursor is on the `F` of the constant `FOO`, the editor should identify other occurences of `FOO`
|
@@ -21,18 +23,18 @@ module RubyLsp
|
|
21
23
|
# end
|
22
24
|
# ```
|
23
25
|
class DocumentHighlight < BaseRequest
|
24
|
-
|
25
|
-
new(document, position).run
|
26
|
-
end
|
26
|
+
extend T::Sig
|
27
27
|
|
28
|
+
sig { params(document: Document, position: Document::PositionShape).void }
|
28
29
|
def initialize(document, position)
|
29
|
-
@highlights = []
|
30
|
+
@highlights = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
|
30
31
|
position = Document::Scanner.new(document.source).find_position(position)
|
31
|
-
@target = find(document.tree, position)
|
32
|
+
@target = T.let(find(T.must(document.tree), position), T.nilable(Support::HighlightTarget))
|
32
33
|
|
33
34
|
super(document)
|
34
35
|
end
|
35
36
|
|
37
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight], Object)) }
|
36
38
|
def run
|
37
39
|
# no @target means the target is not highlightable
|
38
40
|
return [] unless @target
|
@@ -41,30 +43,24 @@ module RubyLsp
|
|
41
43
|
@highlights
|
42
44
|
end
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
node.value,
|
48
|
-
LanguageServer::Protocol::Constant::DocumentHighlightKind::WRITE
|
49
|
-
)
|
50
|
-
end
|
51
|
-
|
52
|
-
super
|
53
|
-
end
|
46
|
+
sig { params(node: T.nilable(SyntaxTree::Node)).void }
|
47
|
+
def visit(node)
|
48
|
+
return if node.nil?
|
54
49
|
|
55
|
-
|
56
|
-
if
|
57
|
-
add_highlight(
|
58
|
-
node.value,
|
59
|
-
LanguageServer::Protocol::Constant::DocumentHighlightKind::READ
|
60
|
-
)
|
61
|
-
end
|
50
|
+
match = T.must(@target).highlight_type(node)
|
51
|
+
add_highlight(match) if match
|
62
52
|
|
63
53
|
super
|
64
54
|
end
|
65
55
|
|
66
56
|
private
|
67
57
|
|
58
|
+
sig do
|
59
|
+
params(
|
60
|
+
node: SyntaxTree::Node,
|
61
|
+
position: Integer,
|
62
|
+
).returns(T.nilable(Support::HighlightTarget))
|
63
|
+
end
|
68
64
|
def find(node, position)
|
69
65
|
matched =
|
70
66
|
node.child_nodes.compact.bsearch do |child|
|
@@ -76,20 +72,24 @@ module RubyLsp
|
|
76
72
|
end
|
77
73
|
|
78
74
|
case matched
|
79
|
-
when SyntaxTree::GVar,
|
80
|
-
|
75
|
+
when SyntaxTree::GVar,
|
76
|
+
SyntaxTree::IVar,
|
77
|
+
SyntaxTree::Const,
|
78
|
+
SyntaxTree::CVar,
|
79
|
+
SyntaxTree::VarField
|
80
|
+
Support::HighlightTarget.new(matched)
|
81
|
+
when SyntaxTree::Ident
|
82
|
+
relevant_node = node.is_a?(SyntaxTree::Params) ? matched : node
|
83
|
+
Support::HighlightTarget.new(relevant_node)
|
81
84
|
when SyntaxTree::Node
|
82
85
|
find(matched, position)
|
83
86
|
end
|
84
87
|
end
|
85
88
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
def add_highlight(node, kind)
|
91
|
-
range = range_from_syntax_tree_node(node)
|
92
|
-
@highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: kind)
|
89
|
+
sig { params(match: Support::HighlightTarget::HighlightMatch).void }
|
90
|
+
def add_highlight(match)
|
91
|
+
range = range_from_syntax_tree_node(match.node)
|
92
|
+
@highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: match.type)
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
+
# 
|
7
|
+
#
|
6
8
|
# The [document
|
7
9
|
# symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) request
|
8
10
|
# informs the editor of all the important symbols, such as classes, variables, and methods, defined in a file. With
|
@@ -25,7 +27,9 @@ module RubyLsp
|
|
25
27
|
# end
|
26
28
|
# ```
|
27
29
|
class DocumentSymbol < BaseRequest
|
28
|
-
|
30
|
+
extend T::Sig
|
31
|
+
|
32
|
+
SYMBOL_KIND = T.let({
|
29
33
|
file: 1,
|
30
34
|
module: 2,
|
31
35
|
namespace: 3,
|
@@ -52,33 +56,43 @@ module RubyLsp
|
|
52
56
|
event: 24,
|
53
57
|
operator: 25,
|
54
58
|
typeparameter: 26,
|
55
|
-
}.freeze
|
59
|
+
}.freeze, T::Hash[Symbol, Integer])
|
56
60
|
|
57
|
-
ATTR_ACCESSORS = ["attr_reader", "attr_writer", "attr_accessor"].freeze
|
61
|
+
ATTR_ACCESSORS = T.let(["attr_reader", "attr_writer", "attr_accessor"].freeze, T::Array[String])
|
58
62
|
|
59
63
|
class SymbolHierarchyRoot
|
64
|
+
extend T::Sig
|
65
|
+
|
66
|
+
sig { returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
|
60
67
|
attr_reader :children
|
61
68
|
|
69
|
+
sig { void }
|
62
70
|
def initialize
|
63
|
-
@children = []
|
71
|
+
@children = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentSymbol])
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
75
|
+
sig { params(document: Document).void }
|
67
76
|
def initialize(document)
|
68
77
|
super
|
69
78
|
|
70
|
-
@root = SymbolHierarchyRoot.new
|
71
|
-
@stack =
|
79
|
+
@root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
|
80
|
+
@stack = T.let(
|
81
|
+
[@root],
|
82
|
+
T::Array[T.any(SymbolHierarchyRoot, LanguageServer::Protocol::Interface::DocumentSymbol)]
|
83
|
+
)
|
72
84
|
end
|
73
85
|
|
86
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol], Object)) }
|
74
87
|
def run
|
75
88
|
visit(@document.tree)
|
76
89
|
@root.children
|
77
90
|
end
|
78
91
|
|
92
|
+
sig { params(node: SyntaxTree::ClassDeclaration).void }
|
79
93
|
def visit_class(node)
|
80
94
|
symbol = create_document_symbol(
|
81
|
-
name: node
|
95
|
+
name: fully_qualified_name(node),
|
82
96
|
kind: :class,
|
83
97
|
range_node: node,
|
84
98
|
selection_range_node: node.constant
|
@@ -89,6 +103,7 @@ module RubyLsp
|
|
89
103
|
@stack.pop
|
90
104
|
end
|
91
105
|
|
106
|
+
sig { params(node: SyntaxTree::Command).void }
|
92
107
|
def visit_command(node)
|
93
108
|
return unless ATTR_ACCESSORS.include?(node.message.value)
|
94
109
|
|
@@ -104,6 +119,7 @@ module RubyLsp
|
|
104
119
|
end
|
105
120
|
end
|
106
121
|
|
122
|
+
sig { params(node: SyntaxTree::ConstPathField).void }
|
107
123
|
def visit_const_path_field(node)
|
108
124
|
create_document_symbol(
|
109
125
|
name: node.constant.value,
|
@@ -113,6 +129,7 @@ module RubyLsp
|
|
113
129
|
)
|
114
130
|
end
|
115
131
|
|
132
|
+
sig { params(node: SyntaxTree::Def).void }
|
116
133
|
def visit_def(node)
|
117
134
|
name = node.name.value
|
118
135
|
|
@@ -128,6 +145,7 @@ module RubyLsp
|
|
128
145
|
@stack.pop
|
129
146
|
end
|
130
147
|
|
148
|
+
sig { params(node: SyntaxTree::DefEndless).void }
|
131
149
|
def visit_def_endless(node)
|
132
150
|
name = node.name.value
|
133
151
|
|
@@ -143,6 +161,7 @@ module RubyLsp
|
|
143
161
|
@stack.pop
|
144
162
|
end
|
145
163
|
|
164
|
+
sig { params(node: SyntaxTree::Defs).void }
|
146
165
|
def visit_defs(node)
|
147
166
|
symbol = create_document_symbol(
|
148
167
|
name: "self.#{node.name.value}",
|
@@ -156,9 +175,10 @@ module RubyLsp
|
|
156
175
|
@stack.pop
|
157
176
|
end
|
158
177
|
|
178
|
+
sig { params(node: SyntaxTree::ModuleDeclaration).void }
|
159
179
|
def visit_module(node)
|
160
180
|
symbol = create_document_symbol(
|
161
|
-
name: node
|
181
|
+
name: fully_qualified_name(node),
|
162
182
|
kind: :module,
|
163
183
|
range_node: node,
|
164
184
|
selection_range_node: node.constant
|
@@ -169,6 +189,7 @@ module RubyLsp
|
|
169
189
|
@stack.pop
|
170
190
|
end
|
171
191
|
|
192
|
+
sig { params(node: SyntaxTree::TopConstField).void }
|
172
193
|
def visit_top_const_field(node)
|
173
194
|
create_document_symbol(
|
174
195
|
name: node.constant.value,
|
@@ -178,6 +199,7 @@ module RubyLsp
|
|
178
199
|
)
|
179
200
|
end
|
180
201
|
|
202
|
+
sig { params(node: SyntaxTree::VarField).void }
|
181
203
|
def visit_var_field(node)
|
182
204
|
kind = case node.value
|
183
205
|
when SyntaxTree::Const
|
@@ -198,6 +220,14 @@ module RubyLsp
|
|
198
220
|
|
199
221
|
private
|
200
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
|
201
231
|
def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
|
202
232
|
symbol = LanguageServer::Protocol::Interface::DocumentSymbol.new(
|
203
233
|
name: name,
|
@@ -207,10 +237,29 @@ module RubyLsp
|
|
207
237
|
children: [],
|
208
238
|
)
|
209
239
|
|
210
|
-
@stack.last.children << symbol
|
240
|
+
T.must(@stack.last).children << symbol
|
211
241
|
|
212
242
|
symbol
|
213
243
|
end
|
244
|
+
|
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
|
249
|
+
|
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
|
262
|
+
end
|
214
263
|
end
|
215
264
|
end
|
216
265
|
end
|
@@ -1,19 +1,24 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
+
# 
|
7
|
+
#
|
6
8
|
# 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.
|
9
|
+
# request informs the editor of the ranges where and how code can be folded.
|
8
10
|
#
|
9
11
|
# # Example
|
12
|
+
#
|
10
13
|
# ```ruby
|
11
14
|
# def say_hello # <-- folding range start
|
12
15
|
# puts "Hello"
|
13
16
|
# end # <-- folding range end
|
14
17
|
# ```
|
15
18
|
class FoldingRanges < BaseRequest
|
16
|
-
|
19
|
+
extend T::Sig
|
20
|
+
|
21
|
+
SIMPLE_FOLDABLES = T.let([
|
17
22
|
SyntaxTree::ArrayLiteral,
|
18
23
|
SyntaxTree::BraceBlock,
|
19
24
|
SyntaxTree::Case,
|
@@ -30,24 +35,36 @@ module RubyLsp
|
|
30
35
|
SyntaxTree::Unless,
|
31
36
|
SyntaxTree::Until,
|
32
37
|
SyntaxTree::While,
|
33
|
-
].freeze
|
34
|
-
|
35
|
-
NODES_WITH_STATEMENTS = [
|
36
38
|
SyntaxTree::Else,
|
37
|
-
SyntaxTree::Elsif,
|
38
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,
|
39
45
|
SyntaxTree::In,
|
40
46
|
SyntaxTree::Rescue,
|
41
47
|
SyntaxTree::When,
|
42
|
-
].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
|
43
58
|
|
59
|
+
sig { params(document: Document).void }
|
44
60
|
def initialize(document)
|
45
61
|
super
|
46
62
|
|
47
|
-
@ranges = []
|
48
|
-
@partial_range = nil
|
63
|
+
@ranges = T.let([], T::Array[LanguageServer::Protocol::Interface::FoldingRange])
|
64
|
+
@partial_range = T.let(nil, T.nilable(PartialRange))
|
49
65
|
end
|
50
66
|
|
67
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::FoldingRange], Object)) }
|
51
68
|
def run
|
52
69
|
visit(@document.tree)
|
53
70
|
emit_partial_range
|
@@ -56,16 +73,16 @@ module RubyLsp
|
|
56
73
|
|
57
74
|
private
|
58
75
|
|
76
|
+
sig { params(node: T.nilable(SyntaxTree::Node)).void }
|
59
77
|
def visit(node)
|
60
78
|
return unless handle_partial_range(node)
|
61
79
|
|
62
80
|
case node
|
63
81
|
when *SIMPLE_FOLDABLES
|
64
|
-
|
82
|
+
location = T.must(node).location
|
83
|
+
add_lines_range(location.start_line, location.end_line - 1)
|
65
84
|
when *NODES_WITH_STATEMENTS
|
66
|
-
add_statements_range(node, node.statements)
|
67
|
-
when SyntaxTree::Begin
|
68
|
-
add_statements_range(node, node.bodystmt.statements)
|
85
|
+
add_statements_range(T.must(node), T.cast(node, StatementNode).statements)
|
69
86
|
when SyntaxTree::Call, SyntaxTree::CommandCall
|
70
87
|
add_call_range(node)
|
71
88
|
return
|
@@ -80,27 +97,38 @@ module RubyLsp
|
|
80
97
|
end
|
81
98
|
|
82
99
|
class PartialRange
|
83
|
-
|
100
|
+
extend T::Sig
|
84
101
|
|
102
|
+
sig { returns(String) }
|
103
|
+
attr_reader :kind
|
104
|
+
|
105
|
+
sig { returns(Integer) }
|
106
|
+
attr_reader :end_line
|
107
|
+
|
108
|
+
sig { params(node: SyntaxTree::Node, kind: String).returns(PartialRange) }
|
85
109
|
def self.from(node, kind)
|
86
110
|
new(node.location.start_line - 1, node.location.end_line - 1, kind)
|
87
111
|
end
|
88
112
|
|
113
|
+
sig { params(start_line: Integer, end_line: Integer, kind: String).void }
|
89
114
|
def initialize(start_line, end_line, kind)
|
90
115
|
@start_line = start_line
|
91
116
|
@end_line = end_line
|
92
117
|
@kind = kind
|
93
118
|
end
|
94
119
|
|
120
|
+
sig { params(node: SyntaxTree::Node).returns(PartialRange) }
|
95
121
|
def extend_to(node)
|
96
122
|
@end_line = node.location.end_line - 1
|
97
123
|
self
|
98
124
|
end
|
99
125
|
|
126
|
+
sig { params(node: SyntaxTree::Node).returns(T::Boolean) }
|
100
127
|
def new_section?(node)
|
101
128
|
node.is_a?(SyntaxTree::Comment) && @end_line + 1 != node.location.start_line - 1
|
102
129
|
end
|
103
130
|
|
131
|
+
sig { returns(LanguageServer::Protocol::Interface::FoldingRange) }
|
104
132
|
def to_range
|
105
133
|
LanguageServer::Protocol::Interface::FoldingRange.new(
|
106
134
|
start_line: @start_line,
|
@@ -108,8 +136,14 @@ module RubyLsp
|
|
108
136
|
kind: @kind
|
109
137
|
)
|
110
138
|
end
|
139
|
+
|
140
|
+
sig { returns(T::Boolean) }
|
141
|
+
def multiline?
|
142
|
+
@end_line > @start_line
|
143
|
+
end
|
111
144
|
end
|
112
145
|
|
146
|
+
sig { params(node: T.nilable(SyntaxTree::Node)).returns(T::Boolean) }
|
113
147
|
def handle_partial_range(node)
|
114
148
|
kind = partial_range_kind(node)
|
115
149
|
|
@@ -118,18 +152,20 @@ module RubyLsp
|
|
118
152
|
return true
|
119
153
|
end
|
120
154
|
|
155
|
+
target_node = T.must(node)
|
121
156
|
@partial_range = if @partial_range.nil?
|
122
|
-
PartialRange.from(
|
123
|
-
elsif @partial_range.kind != kind || @partial_range.new_section?(
|
157
|
+
PartialRange.from(target_node, kind)
|
158
|
+
elsif @partial_range.kind != kind || @partial_range.new_section?(target_node)
|
124
159
|
emit_partial_range
|
125
|
-
PartialRange.from(
|
160
|
+
PartialRange.from(target_node, kind)
|
126
161
|
else
|
127
|
-
@partial_range.extend_to(
|
162
|
+
@partial_range.extend_to(target_node)
|
128
163
|
end
|
129
164
|
|
130
165
|
false
|
131
166
|
end
|
132
167
|
|
168
|
+
sig { params(node: T.nilable(SyntaxTree::Node)).returns(T.nilable(String)) }
|
133
169
|
def partial_range_kind(node)
|
134
170
|
case node
|
135
171
|
when SyntaxTree::Comment
|
@@ -141,13 +177,15 @@ module RubyLsp
|
|
141
177
|
end
|
142
178
|
end
|
143
179
|
|
180
|
+
sig { void }
|
144
181
|
def emit_partial_range
|
145
182
|
return if @partial_range.nil?
|
146
183
|
|
147
|
-
@ranges << @partial_range.to_range
|
184
|
+
@ranges << @partial_range.to_range if @partial_range.multiline?
|
148
185
|
@partial_range = nil
|
149
186
|
end
|
150
187
|
|
188
|
+
sig { params(node: T.any(SyntaxTree::Call, SyntaxTree::CommandCall)).void }
|
151
189
|
def add_call_range(node)
|
152
190
|
receiver = T.let(node.receiver, SyntaxTree::Node)
|
153
191
|
loop do
|
@@ -157,48 +195,49 @@ module RubyLsp
|
|
157
195
|
receiver = receiver.receiver
|
158
196
|
when SyntaxTree::MethodAddBlock
|
159
197
|
visit(receiver.block)
|
160
|
-
receiver = receiver.call
|
198
|
+
receiver = receiver.call
|
199
|
+
|
200
|
+
if receiver.is_a?(SyntaxTree::Call) || receiver.is_a?(SyntaxTree::CommandCall)
|
201
|
+
receiver = receiver.receiver
|
202
|
+
end
|
161
203
|
else
|
162
204
|
break
|
163
205
|
end
|
164
206
|
end
|
165
207
|
|
166
|
-
add_lines_range(receiver.location.start_line, node.location.end_line)
|
208
|
+
add_lines_range(receiver.location.start_line, node.location.end_line - 1)
|
167
209
|
|
168
210
|
visit(node.arguments)
|
169
211
|
end
|
170
212
|
|
213
|
+
sig { params(node: T.any(SyntaxTree::Def, SyntaxTree::Defs)).void }
|
171
214
|
def add_def_range(node)
|
172
215
|
params_location = node.params.location
|
173
216
|
|
174
217
|
if params_location.start_line < params_location.end_line
|
175
|
-
add_lines_range(params_location.end_line, node.location.end_line)
|
218
|
+
add_lines_range(params_location.end_line, node.location.end_line - 1)
|
176
219
|
else
|
177
|
-
|
220
|
+
location = node.location
|
221
|
+
add_lines_range(location.start_line, location.end_line - 1)
|
178
222
|
end
|
179
223
|
|
180
224
|
visit(node.bodystmt.statements)
|
181
225
|
end
|
182
226
|
|
227
|
+
sig { params(node: SyntaxTree::Node, statements: SyntaxTree::Statements).void }
|
183
228
|
def add_statements_range(node, statements)
|
184
|
-
add_lines_range(node.location.start_line, statements.location.end_line) unless statements.empty?
|
229
|
+
add_lines_range(node.location.start_line, statements.body.last.location.end_line) unless statements.empty?
|
185
230
|
end
|
186
231
|
|
232
|
+
sig { params(node: SyntaxTree::StringConcat).void }
|
187
233
|
def add_string_concat(node)
|
188
234
|
left = T.let(node.left, SyntaxTree::Node)
|
189
235
|
left = left.left while left.is_a?(SyntaxTree::StringConcat)
|
190
236
|
|
191
|
-
add_lines_range(left.location.start_line, node.right.location.end_line)
|
192
|
-
end
|
193
|
-
|
194
|
-
def add_node_range(node)
|
195
|
-
add_location_range(node.location)
|
196
|
-
end
|
197
|
-
|
198
|
-
def add_location_range(location)
|
199
|
-
add_lines_range(location.start_line, location.end_line)
|
237
|
+
add_lines_range(left.location.start_line, node.right.location.end_line - 1)
|
200
238
|
end
|
201
239
|
|
240
|
+
sig { params(start_line: Integer, end_line: Integer).void }
|
202
241
|
def add_lines_range(start_line, end_line)
|
203
242
|
return if start_line >= end_line
|
204
243
|
|
@@ -1,8 +1,12 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "ruby_lsp/requests/support/rubocop_formatting_runner"
|
5
|
+
|
4
6
|
module RubyLsp
|
5
7
|
module Requests
|
8
|
+
# 
|
9
|
+
#
|
6
10
|
# The [formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting)
|
7
11
|
# request uses RuboCop to fix auto-correctable offenses in the document. This requires enabling format on save and
|
8
12
|
# registering the ruby-lsp as the Ruby formatter.
|
@@ -14,38 +18,44 @@ module RubyLsp
|
|
14
18
|
# puts "Hello" # --> formatting: fixes the indentation on save
|
15
19
|
# end
|
16
20
|
# ```
|
17
|
-
class Formatting <
|
18
|
-
|
21
|
+
class Formatting < BaseRequest
|
22
|
+
extend T::Sig
|
19
23
|
|
24
|
+
sig { params(uri: String, document: Document).void }
|
20
25
|
def initialize(uri, document)
|
21
|
-
super
|
22
|
-
|
26
|
+
super(document)
|
27
|
+
|
28
|
+
@uri = uri
|
23
29
|
end
|
24
30
|
|
31
|
+
sig { override.returns(T.nilable(T.all(T::Array[LanguageServer::Protocol::Interface::TextEdit], Object))) }
|
25
32
|
def run
|
26
|
-
|
33
|
+
formatted_text = formatted_file
|
34
|
+
return unless formatted_text
|
27
35
|
|
28
|
-
|
29
|
-
return
|
36
|
+
size = @document.source.size
|
37
|
+
return if formatted_text.size == size && formatted_text == @document.source
|
30
38
|
|
31
39
|
[
|
32
40
|
LanguageServer::Protocol::Interface::TextEdit.new(
|
33
41
|
range: LanguageServer::Protocol::Interface::Range.new(
|
34
42
|
start: LanguageServer::Protocol::Interface::Position.new(line: 0, character: 0),
|
35
|
-
end: LanguageServer::Protocol::Interface::Position.new(
|
36
|
-
line: text.size,
|
37
|
-
character: text.size
|
38
|
-
)
|
43
|
+
end: LanguageServer::Protocol::Interface::Position.new(line: size, character: size)
|
39
44
|
),
|
40
|
-
new_text:
|
45
|
+
new_text: formatted_text
|
41
46
|
),
|
42
47
|
]
|
43
48
|
end
|
44
49
|
|
45
50
|
private
|
46
51
|
|
47
|
-
|
48
|
-
|
52
|
+
sig { returns(T.nilable(String)) }
|
53
|
+
def formatted_file
|
54
|
+
if defined?(Support::RuboCopFormattingRunner)
|
55
|
+
Support::RuboCopFormattingRunner.instance.run(@uri, @document)
|
56
|
+
else
|
57
|
+
SyntaxTree.format(@document.source)
|
58
|
+
end
|
49
59
|
end
|
50
60
|
end
|
51
61
|
end
|