rucoa 0.3.0 → 0.4.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/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/lib/rucoa/configuration.rb +8 -0
- data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +140 -0
- data/lib/rucoa/handlers/initialize_handler.rb +1 -0
- data/lib/rucoa/handlers/text_document_code_action_handler.rb +78 -3
- data/lib/rucoa/handlers/text_document_document_symbol_handler.rb +241 -0
- data/lib/rucoa/handlers/text_document_formatting_handler.rb +36 -5
- data/lib/rucoa/handlers/text_document_range_formatting_handler.rb +65 -13
- data/lib/rucoa/handlers/text_document_selection_range_handler.rb +124 -8
- data/lib/rucoa/handlers.rb +1 -0
- data/lib/rucoa/node_concerns/name_full_qualifiable.rb +20 -0
- data/lib/rucoa/node_concerns.rb +7 -0
- data/lib/rucoa/nodes/base.rb +13 -0
- data/lib/rucoa/nodes/casgn_node.rb +14 -0
- data/lib/rucoa/nodes/class_node.rb +8 -0
- data/lib/rucoa/nodes/const_node.rb +12 -0
- data/lib/rucoa/nodes/def_node.rb +12 -0
- data/lib/rucoa/nodes/defs_node.rb +12 -0
- data/lib/rucoa/nodes/module_node.rb +21 -0
- data/lib/rucoa/nodes/sclass_node.rb +8 -0
- data/lib/rucoa/nodes/send_node.rb +17 -0
- data/lib/rucoa/nodes/str_node.rb +4 -0
- data/lib/rucoa/nodes/sym_node.rb +12 -0
- data/lib/rucoa/nodes.rb +9 -0
- data/lib/rucoa/parser_builder.rb +19 -10
- data/lib/rucoa/server.rb +1 -0
- data/lib/rucoa/source.rb +2 -2
- data/lib/rucoa/version.rb +1 -1
- data/lib/rucoa.rb +1 -5
- metadata +14 -7
- data/lib/rucoa/code_action_provider.rb +0 -102
- data/lib/rucoa/diagnostic_provider.rb +0 -143
- data/lib/rucoa/formatting_provider.rb +0 -54
- data/lib/rucoa/range_formatting_provider.rb +0 -67
- data/lib/rucoa/selection_range_provider.rb +0 -99
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1656b3603d72a44829a30fd9bd0d0d876ab9daa3af05cad16ad78298fa6fce7d
|
4
|
+
data.tar.gz: ff2fffdb7e90ed0f23cf782bc5c25db77dabb327c3e5b1d0a92aad8d2a5dc201
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49421faba6f35b3cf0bd33c12ae521cf55125fc8c8b044f5a4d353b4ee9413150b0ca4082884e786329b1cefa3cb5eb5ab513b9723e638cb9786ab768d2f8dd0
|
7
|
+
data.tar.gz: 8ef7dfaf46a49d70eb9404558191aadb3e1778f761a4642c432b53c9e3b1f208ff57f64a5b43ec7aef527dc4b573baaed10f4d859043574e86452b0af60aecb4
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Language server for Ruby.
|
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
9
|
-
Install both rucoa gem and [vscode-rucoa](https://
|
9
|
+
Install both rucoa gem and [vscode-rucoa](https://marketplace.visualstudio.com/items?itemName=r7kamura.vscode-rucoa) extension, then open your Ruby project in VSCode.
|
10
10
|
|
11
11
|
To install rucoa gem, if your project is managed by bundler, add to your Gemfile:
|
12
12
|
|
@@ -36,6 +36,7 @@ gem install rucoa
|
|
36
36
|
- Formatting
|
37
37
|
- Quick Fix
|
38
38
|
- Selection Range
|
39
|
+
- Symbol
|
39
40
|
|
40
41
|
### Coming soon
|
41
42
|
|
@@ -44,4 +45,3 @@ gem install rucoa
|
|
44
45
|
- Go to Definition
|
45
46
|
- Highlight
|
46
47
|
- Semantic Tokens
|
47
|
-
- Symbol
|
data/lib/rucoa/configuration.rb
CHANGED
@@ -14,6 +14,9 @@ module Rucoa
|
|
14
14
|
'diagnostics' => {
|
15
15
|
'enable' => true
|
16
16
|
},
|
17
|
+
'documentSymbol' => {
|
18
|
+
'enable' => true
|
19
|
+
},
|
17
20
|
'formatting' => {
|
18
21
|
'enable' => true
|
19
22
|
},
|
@@ -37,6 +40,11 @@ module Rucoa
|
|
37
40
|
@settings.dig('feature', 'diagnostics', 'enable')
|
38
41
|
end
|
39
42
|
|
43
|
+
# @return [Boolean]
|
44
|
+
def enables_document_symbol?
|
45
|
+
@settings.dig('feature', 'documentSymbol', 'enable')
|
46
|
+
end
|
47
|
+
|
40
48
|
# @return [Boolean]
|
41
49
|
def enables_formatting?
|
42
50
|
@settings.dig('feature', 'formatting', 'enable')
|
@@ -27,6 +27,146 @@ module Rucoa
|
|
27
27
|
}
|
28
28
|
)
|
29
29
|
end
|
30
|
+
|
31
|
+
class DiagnosticProvider
|
32
|
+
# @param source [Rucoa::Source]
|
33
|
+
# @param uri [String]
|
34
|
+
# @return [Array<Hash>]
|
35
|
+
def self.call(source:, uri:)
|
36
|
+
new(
|
37
|
+
source: source,
|
38
|
+
uri: uri
|
39
|
+
).call
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param source [Rucoa::Source]
|
43
|
+
# @param uri [String]
|
44
|
+
def initialize(source:, uri:)
|
45
|
+
@source = source
|
46
|
+
@uri = uri
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array<Hash>]
|
50
|
+
def call
|
51
|
+
return [] unless RubocopConfigurationChecker.call
|
52
|
+
|
53
|
+
offenses.map do |offense|
|
54
|
+
OffenseToDiagnosticMapper.call(
|
55
|
+
offense,
|
56
|
+
source: @source,
|
57
|
+
uri: @uri
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# @return [Array<RuboCop::Cop::Offense>]
|
65
|
+
def offenses
|
66
|
+
RubocopInvestigator.call(source: @source)
|
67
|
+
end
|
68
|
+
|
69
|
+
class OffenseToDiagnosticMapper
|
70
|
+
LSP_SEVERITY_NAME_TO_VALUE_MAP = {
|
71
|
+
error: 1,
|
72
|
+
hint: 4,
|
73
|
+
information: 3,
|
74
|
+
warning: 2
|
75
|
+
}.freeze
|
76
|
+
private_constant :LSP_SEVERITY_NAME_TO_VALUE_MAP
|
77
|
+
|
78
|
+
RUBOCOP_SEVERITY_NAME_TO_LSP_SEVERITY_MAP = {
|
79
|
+
convention: LSP_SEVERITY_NAME_TO_VALUE_MAP[:information],
|
80
|
+
error: LSP_SEVERITY_NAME_TO_VALUE_MAP[:error],
|
81
|
+
fatal: LSP_SEVERITY_NAME_TO_VALUE_MAP[:error],
|
82
|
+
info: LSP_SEVERITY_NAME_TO_VALUE_MAP[:information],
|
83
|
+
refactor: LSP_SEVERITY_NAME_TO_VALUE_MAP[:hint],
|
84
|
+
warning: LSP_SEVERITY_NAME_TO_VALUE_MAP[:warning]
|
85
|
+
}.freeze
|
86
|
+
private_constant :RUBOCOP_SEVERITY_NAME_TO_LSP_SEVERITY_MAP
|
87
|
+
|
88
|
+
class << self
|
89
|
+
# @param offense [RuboCop::Cop::Offense]
|
90
|
+
# @param source [Rucoa::Source]
|
91
|
+
# @param uri [String]
|
92
|
+
# @return [Hash]
|
93
|
+
def call(offense, source:, uri:)
|
94
|
+
new(
|
95
|
+
offense,
|
96
|
+
source: source,
|
97
|
+
uri: uri
|
98
|
+
).call
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param offense [RuboCop::Cop::Offense]
|
103
|
+
# @param source [Rucoa::Source]
|
104
|
+
# @param uri [String]
|
105
|
+
def initialize(offense, source:, uri:)
|
106
|
+
@offense = offense
|
107
|
+
@source = source
|
108
|
+
@uri = uri
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Hash]
|
112
|
+
def call
|
113
|
+
{
|
114
|
+
code: code,
|
115
|
+
data: data,
|
116
|
+
message: message,
|
117
|
+
range: range,
|
118
|
+
severity: severity,
|
119
|
+
source: source
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# @return [String]
|
126
|
+
def code
|
127
|
+
@offense.cop_name
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [Hash]
|
131
|
+
def data
|
132
|
+
{
|
133
|
+
cop_name: @offense.cop_name,
|
134
|
+
edits: edits,
|
135
|
+
uri: @uri
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
# @return [Array<Hash>, nil]
|
140
|
+
def edits
|
141
|
+
@offense.corrector&.as_replacements&.map do |range, replacement|
|
142
|
+
{
|
143
|
+
newText: replacement,
|
144
|
+
range: Range.from_parser_range(range).to_vscode_range
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# @return [String]
|
150
|
+
def message
|
151
|
+
@offense.message.delete_prefix("#{@offense.cop_name}: ")
|
152
|
+
end
|
153
|
+
|
154
|
+
# @return [Hash]
|
155
|
+
def range
|
156
|
+
Range.from_parser_range(@offense.location).to_vscode_range
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Integer]
|
160
|
+
def severity
|
161
|
+
RUBOCOP_SEVERITY_NAME_TO_LSP_SEVERITY_MAP.fetch(@offense.severity.name, 1)
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [String]
|
165
|
+
def source
|
166
|
+
'RuboCop'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
30
170
|
end
|
31
171
|
end
|
32
172
|
end
|
@@ -15,15 +15,90 @@ module Rucoa
|
|
15
15
|
def code_actions
|
16
16
|
return [] unless configuration.enables_code_action?
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
correctable_diagnostics.map do |diagnostic|
|
19
|
+
DiagnosticToCodeActionMapper.call(diagnostic)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Array<Hash>]
|
24
|
+
def correctable_diagnostics
|
25
|
+
diagnostics.select do |diagnostic|
|
26
|
+
diagnostic.dig('data', 'edits')
|
27
|
+
end
|
21
28
|
end
|
22
29
|
|
23
30
|
# @return [Array<Hash>, nil]
|
24
31
|
def diagnostics
|
25
32
|
@diagnostics ||= request.dig('params', 'context', 'diagnostics')
|
26
33
|
end
|
34
|
+
|
35
|
+
class DiagnosticToCodeActionMapper
|
36
|
+
class << self
|
37
|
+
# @param diagnostic [Hash]
|
38
|
+
# @return [Hash]
|
39
|
+
def call(diagnostic)
|
40
|
+
new(diagnostic).call
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param diagnostic [Hash]
|
45
|
+
def initialize(diagnostic)
|
46
|
+
@diagnostic = diagnostic
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Hash]
|
50
|
+
def call
|
51
|
+
{
|
52
|
+
diagnostics: diagnostics,
|
53
|
+
edit: edit,
|
54
|
+
isPreferred: preferred?,
|
55
|
+
kind: kind,
|
56
|
+
title: title
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# @return [Hash]
|
63
|
+
def edit
|
64
|
+
{
|
65
|
+
documentChanges: [
|
66
|
+
{
|
67
|
+
edits: @diagnostic.dig('data', 'edits'),
|
68
|
+
textDocument: {
|
69
|
+
uri: @diagnostic.dig('data', 'uri'),
|
70
|
+
version: nil
|
71
|
+
}
|
72
|
+
}
|
73
|
+
]
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [String]
|
78
|
+
def cop_name
|
79
|
+
@diagnostic.dig('data', 'cop_name')
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [Array]
|
83
|
+
def diagnostics
|
84
|
+
[@diagnostic]
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Boolean]
|
88
|
+
def preferred?
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [String]
|
93
|
+
def kind
|
94
|
+
'quickfix'
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [String]
|
98
|
+
def title
|
99
|
+
"Autocorrect #{cop_name}"
|
100
|
+
end
|
101
|
+
end
|
27
102
|
end
|
28
103
|
end
|
29
104
|
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Rucoa
|
6
|
+
module Handlers
|
7
|
+
class TextDocumentDocumentSymbolHandler < Base
|
8
|
+
DOCUMENT_SYMBOL_KIND_FOR_FILE = 1
|
9
|
+
DOCUMENT_SYMBOL_KIND_FOR_MODULE = 2
|
10
|
+
DOCUMENT_SYMBOL_KIND_FOR_NAMESPACE = 3
|
11
|
+
DOCUMENT_SYMBOL_KIND_FOR_PACKAGE = 4
|
12
|
+
DOCUMENT_SYMBOL_KIND_FOR_CLASS = 5
|
13
|
+
DOCUMENT_SYMBOL_KIND_FOR_METHOD = 6
|
14
|
+
DOCUMENT_SYMBOL_KIND_FOR_PROPERTY = 7
|
15
|
+
DOCUMENT_SYMBOL_KIND_FOR_FIELD = 8
|
16
|
+
DOCUMENT_SYMBOL_KIND_FOR_CONSTRUCTOR = 9
|
17
|
+
DOCUMENT_SYMBOL_KIND_FOR_ENUM = 10
|
18
|
+
DOCUMENT_SYMBOL_KIND_FOR_INTERFACE = 11
|
19
|
+
DOCUMENT_SYMBOL_KIND_FOR_FUNCTION = 12
|
20
|
+
DOCUMENT_SYMBOL_KIND_FOR_VARIABLE = 13
|
21
|
+
DOCUMENT_SYMBOL_KIND_FOR_CONSTANT = 14
|
22
|
+
DOCUMENT_SYMBOL_KIND_FOR_STRING = 15
|
23
|
+
DOCUMENT_SYMBOL_KIND_FOR_NUMBER = 16
|
24
|
+
DOCUMENT_SYMBOL_KIND_FOR_BOOLEAN = 17
|
25
|
+
DOCUMENT_SYMBOL_KIND_FOR_ARRAY = 18
|
26
|
+
DOCUMENT_SYMBOL_KIND_FOR_OBJECT = 19
|
27
|
+
DOCUMENT_SYMBOL_KIND_FOR_KEY = 20
|
28
|
+
DOCUMENT_SYMBOL_KIND_FOR_NULL = 21
|
29
|
+
DOCUMENT_SYMBOL_KIND_FOR_ENUMMEMBER = 22
|
30
|
+
DOCUMENT_SYMBOL_KIND_FOR_STRUCT = 23
|
31
|
+
DOCUMENT_SYMBOL_KIND_FOR_EVENT = 24
|
32
|
+
DOCUMENT_SYMBOL_KIND_FOR_OPERATOR = 25
|
33
|
+
DOCUMENT_SYMBOL_KIND_FOR_TYPEPARAMETER = 26
|
34
|
+
|
35
|
+
# @return [Set<String>]
|
36
|
+
ATTRIBUTE_METHOD_NAMES = ::Set[
|
37
|
+
'attr_accessor',
|
38
|
+
'attr_reader',
|
39
|
+
'attr_writer',
|
40
|
+
]
|
41
|
+
|
42
|
+
def call
|
43
|
+
return unless respondable?
|
44
|
+
|
45
|
+
respond(document_symbols)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# @return [Array<Hash>]
|
51
|
+
def document_symbols
|
52
|
+
visit(source.root_node)
|
53
|
+
document_symbol_stack.first[:children]
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param node [Rucoa::Nodes::Base]
|
57
|
+
# @return [void]
|
58
|
+
def visit(node)
|
59
|
+
document_symbols = create_document_symbols_for(node)
|
60
|
+
document_symbol_stack.last[:children].push(*document_symbols)
|
61
|
+
with_document_symbol_stack(document_symbols.first) do
|
62
|
+
with_singleton_class_stack(node) do
|
63
|
+
node.each_child_node do |child_node|
|
64
|
+
visit(child_node)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param document_symbol [Hash, nil]
|
71
|
+
# @return [void]
|
72
|
+
def with_document_symbol_stack(document_symbol)
|
73
|
+
unless document_symbol
|
74
|
+
yield
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
document_symbol_stack.push(document_symbol)
|
79
|
+
yield
|
80
|
+
document_symbol_stack.pop
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param node [Rucoa::Nodes::Base]
|
84
|
+
def with_singleton_class_stack(node)
|
85
|
+
unless node.is_a?(Rucoa::Nodes::SclassNode)
|
86
|
+
yield
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
singleton_class_stack.push(node)
|
91
|
+
yield
|
92
|
+
singleton_class_stack.pop
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param node [Rucoa::Nodes::Base]
|
96
|
+
# @return [Array<Hash>]
|
97
|
+
def create_document_symbols_for(node)
|
98
|
+
case node
|
99
|
+
when Nodes::CasgnNode
|
100
|
+
create_document_symbols_for_casgn(node)
|
101
|
+
when Nodes::ClassNode
|
102
|
+
create_document_symbols_for_class(node)
|
103
|
+
when Nodes::DefNode
|
104
|
+
create_document_symbols_for_def(node)
|
105
|
+
when Nodes::DefsNode
|
106
|
+
create_document_symbols_for_defs(node)
|
107
|
+
when Nodes::ModuleNode
|
108
|
+
create_document_symbols_for_module(node)
|
109
|
+
when Nodes::SendNode
|
110
|
+
create_document_symbols_for_send(node)
|
111
|
+
else
|
112
|
+
[]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param node [Rucoa::Nodes::CasgnNode]
|
117
|
+
# @return [Array<Hash>]
|
118
|
+
def create_document_symbols_for_casgn(node)
|
119
|
+
[
|
120
|
+
{
|
121
|
+
children: [],
|
122
|
+
kind: DOCUMENT_SYMBOL_KIND_FOR_CONSTANT,
|
123
|
+
name: node.name,
|
124
|
+
range: Range.from_parser_range(node.location.expression).to_vscode_range,
|
125
|
+
selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
|
126
|
+
}
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
# @param node [Rucoa::Nodes::ClassNode]
|
131
|
+
# @return [Array<Hash>]
|
132
|
+
def create_document_symbols_for_class(node)
|
133
|
+
[
|
134
|
+
{
|
135
|
+
children: [],
|
136
|
+
kind: DOCUMENT_SYMBOL_KIND_FOR_CLASS,
|
137
|
+
name: node.name,
|
138
|
+
range: Range.from_parser_range(node.location.expression).to_vscode_range,
|
139
|
+
selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
|
140
|
+
}
|
141
|
+
]
|
142
|
+
end
|
143
|
+
|
144
|
+
# @param node [Rucoa::Nodes::ModuleNode]
|
145
|
+
# @return [Array<Hash>]
|
146
|
+
def create_document_symbols_for_module(node)
|
147
|
+
[
|
148
|
+
{
|
149
|
+
children: [],
|
150
|
+
kind: DOCUMENT_SYMBOL_KIND_FOR_MODULE,
|
151
|
+
name: node.name,
|
152
|
+
range: Range.from_parser_range(node.location.expression).to_vscode_range,
|
153
|
+
selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
|
154
|
+
}
|
155
|
+
]
|
156
|
+
end
|
157
|
+
|
158
|
+
# @param node [Rucoa::Nodes::DefNode]
|
159
|
+
# @return [Array<Hash>]
|
160
|
+
def create_document_symbols_for_def(node)
|
161
|
+
[
|
162
|
+
{
|
163
|
+
children: [],
|
164
|
+
kind: DOCUMENT_SYMBOL_KIND_FOR_METHOD,
|
165
|
+
name: singleton_class_stack.empty? ? "##{node.name}" : ".#{node.name}",
|
166
|
+
range: Range.from_parser_range(node.location.expression).to_vscode_range,
|
167
|
+
selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
|
168
|
+
}
|
169
|
+
]
|
170
|
+
end
|
171
|
+
|
172
|
+
# @param node [Rucoa::Nodes::DefNode]
|
173
|
+
# @return [Array<Hash>]
|
174
|
+
def create_document_symbols_for_defs(node)
|
175
|
+
[
|
176
|
+
{
|
177
|
+
children: [],
|
178
|
+
kind: DOCUMENT_SYMBOL_KIND_FOR_METHOD,
|
179
|
+
name: ".#{node.name}",
|
180
|
+
range: Range.from_parser_range(node.location.expression).to_vscode_range,
|
181
|
+
selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
|
182
|
+
}
|
183
|
+
]
|
184
|
+
end
|
185
|
+
|
186
|
+
# @param node [Rucoa::Nodes::SendNode]
|
187
|
+
# @return [Array<Hash>]
|
188
|
+
def create_document_symbols_for_send(node)
|
189
|
+
return [] unless ATTRIBUTE_METHOD_NAMES.include?(node.name)
|
190
|
+
|
191
|
+
simple_types = ::Set[
|
192
|
+
:str,
|
193
|
+
:sym
|
194
|
+
]
|
195
|
+
node.arguments.select do |argument|
|
196
|
+
simple_types.include?(argument.type)
|
197
|
+
end.map do |argument|
|
198
|
+
{
|
199
|
+
children: [],
|
200
|
+
kind: DOCUMENT_SYMBOL_KIND_FOR_FIELD,
|
201
|
+
name: argument.value.to_s,
|
202
|
+
range: Range.from_parser_range(argument.location.expression).to_vscode_range,
|
203
|
+
selectionRange: Range.from_parser_range(argument.location.expression).to_vscode_range
|
204
|
+
}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# @return [Boolean]
|
209
|
+
def respondable?
|
210
|
+
configuration.enables_document_symbol? && source
|
211
|
+
end
|
212
|
+
|
213
|
+
# @return [Rucoa::Source]
|
214
|
+
def source
|
215
|
+
@source ||= @server.source_store.get(uri)
|
216
|
+
end
|
217
|
+
|
218
|
+
# @return [String]
|
219
|
+
def uri
|
220
|
+
request.dig('params', 'textDocument', 'uri')
|
221
|
+
end
|
222
|
+
|
223
|
+
# @return [Arrah<Hash>]
|
224
|
+
def document_symbol_stack
|
225
|
+
@document_symbol_stack ||= [dummy_document_symbol]
|
226
|
+
end
|
227
|
+
|
228
|
+
# @return [Hash]
|
229
|
+
def dummy_document_symbol
|
230
|
+
{
|
231
|
+
children: []
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
235
|
+
# @return [Array<Rucoa::Nodes::SclassNode>]
|
236
|
+
def singleton_class_stack
|
237
|
+
@singleton_class_stack ||= []
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -9,14 +9,18 @@ module Rucoa
|
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
+
# @return [Boolean]
|
13
|
+
def formattable?
|
14
|
+
configuration.enables_formatting? &&
|
15
|
+
source &&
|
16
|
+
RubocopConfigurationChecker.call
|
17
|
+
end
|
18
|
+
|
12
19
|
# @return [Array<Hash>]
|
13
20
|
def edits
|
14
|
-
return unless
|
15
|
-
return unless source
|
21
|
+
return [] unless formattable?
|
16
22
|
|
17
|
-
|
18
|
-
source: source
|
19
|
-
)
|
23
|
+
[text_edit]
|
20
24
|
end
|
21
25
|
|
22
26
|
# @return [Rucoa::Source, nil]
|
@@ -28,6 +32,33 @@ module Rucoa
|
|
28
32
|
def uri
|
29
33
|
request.dig('params', 'textDocument', 'uri')
|
30
34
|
end
|
35
|
+
|
36
|
+
# @return [Hash]
|
37
|
+
def text_edit
|
38
|
+
{
|
39
|
+
newText: new_text,
|
40
|
+
range: range
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [String]
|
45
|
+
def new_text
|
46
|
+
RubocopAutocorrector.call(source: source)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Hash]
|
50
|
+
def range
|
51
|
+
Range.new(
|
52
|
+
Position.new(
|
53
|
+
column: 0,
|
54
|
+
line: 1
|
55
|
+
),
|
56
|
+
Position.new(
|
57
|
+
column: @source.content.lines.last.length,
|
58
|
+
line: @source.content.lines.count + 1
|
59
|
+
)
|
60
|
+
).to_vscode_range
|
61
|
+
end
|
31
62
|
end
|
32
63
|
end
|
33
64
|
end
|
@@ -4,21 +4,73 @@ module Rucoa
|
|
4
4
|
module Handlers
|
5
5
|
class TextDocumentRangeFormattingHandler < Base
|
6
6
|
def call
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
7
|
+
respond(edits)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# @return [Array<Hash>]
|
13
|
+
def edits
|
14
|
+
return [] unless formattable?
|
15
|
+
|
16
|
+
correctable_replacements.map do |replacement_range, replacement|
|
17
|
+
{
|
18
|
+
newText: replacement,
|
19
|
+
range: replacement_range.to_vscode_range
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Boolean]
|
25
|
+
def formattable?
|
26
|
+
configuration.enables_formatting? &&
|
27
|
+
source &&
|
28
|
+
RubocopConfigurationChecker.call
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Rucoa::Source]
|
32
|
+
def source
|
33
|
+
@source ||= source_store.get(uri)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String]
|
37
|
+
def uri
|
38
|
+
request.dig('params', 'textDocument', 'uri')
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Rucoa::Range]
|
42
|
+
def range
|
43
|
+
@range ||= Range.from_vscode_range(
|
44
|
+
request.dig('params', 'range')
|
20
45
|
)
|
21
46
|
end
|
47
|
+
|
48
|
+
# @return [Array<RuboCop::Cop::Corrector>]
|
49
|
+
def correctable_offenses
|
50
|
+
offenses.select(&:corrector)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Array(Rucoa::Range, String)]
|
54
|
+
def correctable_replacements
|
55
|
+
replacements.select do |replacement_range, _|
|
56
|
+
range.contains?(replacement_range)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Array<RuboCop::Cop::Offense>]
|
61
|
+
def offenses
|
62
|
+
RubocopInvestigator.call(source: source)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Array(Rucoa::Range, String)]
|
66
|
+
def replacements
|
67
|
+
correctable_offenses.map(&:corrector).flat_map(&:as_replacements).map do |replacement_range, replacement|
|
68
|
+
[
|
69
|
+
Range.from_parser_range(replacement_range),
|
70
|
+
replacement
|
71
|
+
]
|
72
|
+
end
|
73
|
+
end
|
22
74
|
end
|
23
75
|
end
|
24
76
|
end
|