ruby-lsp 0.3.2 → 0.3.4
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/VERSION +1 -1
- data/lib/ruby_lsp/document.rb +12 -4
- data/lib/ruby_lsp/handler.rb +4 -4
- data/lib/ruby_lsp/queue.rb +11 -5
- data/lib/ruby_lsp/requests/base_request.rb +49 -0
- data/lib/ruby_lsp/requests/code_actions.rb +1 -1
- data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +15 -20
- data/lib/ruby_lsp/requests/document_link.rb +4 -4
- data/lib/ruby_lsp/requests/document_symbol.rb +21 -21
- data/lib/ruby_lsp/requests/folding_ranges.rb +8 -5
- data/lib/ruby_lsp/requests/formatting.rb +2 -2
- data/lib/ruby_lsp/requests/hover.rb +74 -0
- data/lib/ruby_lsp/requests/inlay_hints.rb +56 -0
- data/lib/ruby_lsp/requests/on_type_formatting.rb +6 -6
- data/lib/ruby_lsp/requests/selection_ranges.rb +4 -4
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +20 -30
- data/lib/ruby_lsp/requests/support/rails_document_client.rb +114 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +10 -10
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -0
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +1 -1
- data/lib/ruby_lsp/requests/support/source_uri.rb +1 -1
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +1 -1
- data/lib/ruby_lsp/requests.rb +5 -0
- data/lib/ruby_lsp/server.rb +34 -10
- data/lib/ruby_lsp/store.rb +3 -6
- metadata +7 -5
- data/CHANGELOG.md +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a8db1decbd8a8d3a05226ececbd13ba54aa2a0b5e727fd9a752ccda5b52322d
|
4
|
+
data.tar.gz: 4f49ca2d80313dcd41e0410a1583ddc3f0c913305b4c3347611181a752561265
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 510bd7ef4da254c79da9af3437403ffe70a054718e9b0a33efc52b1bb49f93cf9c951729e6528ad4cbcf7d383fa7904835f8e0496482611c3891c3ed12ba784c
|
7
|
+
data.tar.gz: 2df5df95106e85a37c834c4ff77a5a19609e1946326ca86828292abb4440787b0eb8f38c9fd8f6f3cd2eb5460e8c27d0c41bb1c025d317f01502ab21afad4161
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.4
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -24,6 +24,7 @@ module RubyLsp
|
|
24
24
|
@syntax_error_edits = T.let([], T::Array[EditShape])
|
25
25
|
@source = T.let(source, String)
|
26
26
|
@parsable_source = T.let(source.dup, String)
|
27
|
+
@unparsed_edits = T.let([], T::Array[EditShape])
|
27
28
|
@tree = T.let(SyntaxTree.parse(@source), T.nilable(SyntaxTree::Node))
|
28
29
|
rescue SyntaxTree::Parser::ParseError
|
29
30
|
# Do not raise if we failed to parse
|
@@ -38,7 +39,7 @@ module RubyLsp
|
|
38
39
|
type_parameters(:T)
|
39
40
|
.params(
|
40
41
|
request_name: Symbol,
|
41
|
-
block: T.proc.params(document: Document).returns(T.type_parameter(:T))
|
42
|
+
block: T.proc.params(document: Document).returns(T.type_parameter(:T)),
|
42
43
|
).returns(T.type_parameter(:T))
|
43
44
|
end
|
44
45
|
def cache_fetch(request_name, &block)
|
@@ -55,13 +56,21 @@ module RubyLsp
|
|
55
56
|
# Apply the edits on the real source
|
56
57
|
edits.each { |edit| apply_edit(@source, edit[:range], edit[:text]) }
|
57
58
|
|
59
|
+
@unparsed_edits.concat(edits)
|
58
60
|
@cache.clear
|
61
|
+
end
|
62
|
+
|
63
|
+
sig { void }
|
64
|
+
def parse
|
65
|
+
return if @unparsed_edits.empty?
|
66
|
+
|
59
67
|
@tree = SyntaxTree.parse(@source)
|
60
68
|
@syntax_error_edits.clear
|
69
|
+
@unparsed_edits.clear
|
61
70
|
@parsable_source = @source.dup
|
62
|
-
nil
|
63
71
|
rescue SyntaxTree::Parser::ParseError
|
64
|
-
|
72
|
+
@syntax_error_edits = @unparsed_edits
|
73
|
+
update_parsable_source(@unparsed_edits)
|
65
74
|
end
|
66
75
|
|
67
76
|
sig { returns(T::Boolean) }
|
@@ -81,7 +90,6 @@ module RubyLsp
|
|
81
90
|
# If the new edits caused a syntax error, make all edits blank spaces and line breaks to adjust the line and
|
82
91
|
# column numbers. This is attempt to make the document parsable while partial edits are being applied
|
83
92
|
edits.each do |edit|
|
84
|
-
@syntax_error_edits << edit
|
85
93
|
next if edit[:text].empty? # skip deletions, since they may have caused the syntax error
|
86
94
|
|
87
95
|
apply_edit(@parsable_source, edit[:range], edit[:text].gsub(/[^\r\n]/, " "))
|
data/lib/ruby_lsp/handler.rb
CHANGED
@@ -26,7 +26,7 @@ module RubyLsp
|
|
26
26
|
# for displaying window messages on errors
|
27
27
|
sig do
|
28
28
|
params(
|
29
|
-
block: T.proc.bind(Handler).params(error: Exception, request: T::Hash[Symbol, T.untyped]).void
|
29
|
+
block: T.proc.bind(Handler).params(error: Exception, request: T::Hash[Symbol, T.untyped]).void,
|
30
30
|
).void
|
31
31
|
end
|
32
32
|
def on_error(&block)
|
@@ -85,7 +85,7 @@ module RubyLsp
|
|
85
85
|
params(
|
86
86
|
msg: String,
|
87
87
|
parallel: T::Boolean,
|
88
|
-
blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
|
88
|
+
blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped),
|
89
89
|
).returns(RequestHandler)
|
90
90
|
end
|
91
91
|
def on(msg, parallel: false, &blk)
|
@@ -103,7 +103,7 @@ module RubyLsp
|
|
103
103
|
def clear_diagnostics(uri)
|
104
104
|
@writer.write(
|
105
105
|
method: "textDocument/publishDiagnostics",
|
106
|
-
params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: [])
|
106
|
+
params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: []),
|
107
107
|
)
|
108
108
|
end
|
109
109
|
|
@@ -111,7 +111,7 @@ module RubyLsp
|
|
111
111
|
def show_message(type, message)
|
112
112
|
@writer.write(
|
113
113
|
method: "window/showMessage",
|
114
|
-
params: Interface::ShowMessageParams.new(type: type, message: message)
|
114
|
+
params: Interface::ShowMessageParams.new(type: type, message: message),
|
115
115
|
)
|
116
116
|
end
|
117
117
|
end
|
data/lib/ruby_lsp/queue.rb
CHANGED
@@ -28,7 +28,7 @@ module RubyLsp
|
|
28
28
|
sig do
|
29
29
|
params(
|
30
30
|
writer: LanguageServer::Protocol::Transport::Stdio::Writer,
|
31
|
-
handlers: T::Hash[String, Handler::RequestHandler]
|
31
|
+
handlers: T::Hash[String, Handler::RequestHandler],
|
32
32
|
).void
|
33
33
|
end
|
34
34
|
def initialize(writer, handlers)
|
@@ -94,7 +94,7 @@ module RubyLsp
|
|
94
94
|
sig do
|
95
95
|
params(
|
96
96
|
result: Result,
|
97
|
-
request: T::Hash[Symbol, T.untyped]
|
97
|
+
request: T::Hash[Symbol, T.untyped],
|
98
98
|
).void
|
99
99
|
end
|
100
100
|
def finalize_request(result, request)
|
@@ -107,7 +107,7 @@ module RubyLsp
|
|
107
107
|
id: request[:id],
|
108
108
|
error: {
|
109
109
|
code: LanguageServer::Protocol::Constant::ErrorCodes::INTERNAL_ERROR,
|
110
|
-
message:
|
110
|
+
message: error.inspect,
|
111
111
|
data: request.to_json,
|
112
112
|
},
|
113
113
|
)
|
@@ -117,7 +117,7 @@ module RubyLsp
|
|
117
117
|
|
118
118
|
request_time = result.request_time
|
119
119
|
if request_time
|
120
|
-
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time,
|
120
|
+
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
|
121
121
|
end
|
122
122
|
end
|
123
123
|
end
|
@@ -152,7 +152,7 @@ module RubyLsp
|
|
152
152
|
params(
|
153
153
|
request: T::Hash[Symbol, T.untyped],
|
154
154
|
request_time: Float,
|
155
|
-
error: T.nilable(Exception)
|
155
|
+
error: T.nilable(Exception),
|
156
156
|
).returns(T::Hash[Symbol, T.any(String, Float)])
|
157
157
|
end
|
158
158
|
def telemetry_params(request, request_time, error)
|
@@ -167,6 +167,12 @@ module RubyLsp
|
|
167
167
|
if error
|
168
168
|
params[:errorClass] = error.class.name
|
169
169
|
params[:errorMessage] = error.message
|
170
|
+
|
171
|
+
log_params = request[:params]&.reject { |k, _| k == :textDocument }
|
172
|
+
params[:params] = log_params.to_json if log_params&.any?
|
173
|
+
|
174
|
+
backtrace = error.backtrace
|
175
|
+
params[:backtrace] = backtrace.map { |bt| bt.sub(/^#{Dir.home}/, "~") }.join("\n") if backtrace
|
170
176
|
end
|
171
177
|
|
172
178
|
params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
|
@@ -14,6 +14,10 @@ module RubyLsp
|
|
14
14
|
def initialize(document)
|
15
15
|
@document = document
|
16
16
|
|
17
|
+
# Parsing the document here means we're taking a lazy approach by only doing it when the first feature request
|
18
|
+
# is received by the server. This happens because {Document#parse} remembers if there are new edits to be parsed
|
19
|
+
@document.parse
|
20
|
+
|
17
21
|
super()
|
18
22
|
end
|
19
23
|
|
@@ -30,6 +34,51 @@ module RubyLsp
|
|
30
34
|
end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
31
35
|
)
|
32
36
|
end
|
37
|
+
|
38
|
+
sig { params(node: SyntaxTree::ConstPathRef).returns(String) }
|
39
|
+
def full_constant_name(node)
|
40
|
+
name = +node.constant.value
|
41
|
+
constant = T.let(node, SyntaxTree::Node)
|
42
|
+
|
43
|
+
while constant.is_a?(SyntaxTree::ConstPathRef)
|
44
|
+
constant = constant.parent
|
45
|
+
|
46
|
+
case constant
|
47
|
+
when SyntaxTree::ConstPathRef
|
48
|
+
name.prepend("#{constant.constant.value}::")
|
49
|
+
when SyntaxTree::VarRef
|
50
|
+
name.prepend("#{constant.value.value}::")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
name
|
55
|
+
end
|
56
|
+
|
57
|
+
sig do
|
58
|
+
params(
|
59
|
+
parent: SyntaxTree::Node,
|
60
|
+
target_nodes: T::Array[T.class_of(SyntaxTree::Node)],
|
61
|
+
position: Integer,
|
62
|
+
).returns(T::Array[SyntaxTree::Node])
|
63
|
+
end
|
64
|
+
def locate_node_and_parent(parent, target_nodes, position)
|
65
|
+
matched = parent.child_nodes.compact.bsearch do |child|
|
66
|
+
if (child.location.start_char...child.location.end_char).cover?(position)
|
67
|
+
0
|
68
|
+
else
|
69
|
+
position <=> child.location.start_char
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
case matched
|
74
|
+
when *target_nodes
|
75
|
+
[matched, parent]
|
76
|
+
when SyntaxTree::Node
|
77
|
+
locate_node_and_parent(matched, target_nodes, position)
|
78
|
+
else
|
79
|
+
[]
|
80
|
+
end
|
81
|
+
end
|
33
82
|
end
|
34
83
|
end
|
35
84
|
end
|
@@ -37,13 +37,11 @@ module RubyLsp
|
|
37
37
|
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight], Object)) }
|
38
38
|
def run
|
39
39
|
# no @target means the target is not highlightable
|
40
|
-
|
41
|
-
|
42
|
-
visit(@document.tree)
|
40
|
+
visit(@document.tree) if @document.parsed? && @target
|
43
41
|
@highlights
|
44
42
|
end
|
45
43
|
|
46
|
-
sig { params(node: T.nilable(SyntaxTree::Node)).void }
|
44
|
+
sig { override.params(node: T.nilable(SyntaxTree::Node)).void }
|
47
45
|
def visit(node)
|
48
46
|
return if node.nil?
|
49
47
|
|
@@ -55,6 +53,14 @@ module RubyLsp
|
|
55
53
|
|
56
54
|
private
|
57
55
|
|
56
|
+
DIRECT_HIGHLIGHTS = T.let([
|
57
|
+
SyntaxTree::GVar,
|
58
|
+
SyntaxTree::IVar,
|
59
|
+
SyntaxTree::Const,
|
60
|
+
SyntaxTree::CVar,
|
61
|
+
SyntaxTree::VarField,
|
62
|
+
], T::Array[T.class_of(SyntaxTree::Node)])
|
63
|
+
|
58
64
|
sig do
|
59
65
|
params(
|
60
66
|
node: SyntaxTree::Node,
|
@@ -62,27 +68,16 @@ module RubyLsp
|
|
62
68
|
).returns(T.nilable(Support::HighlightTarget))
|
63
69
|
end
|
64
70
|
def find(node, position)
|
65
|
-
matched =
|
66
|
-
|
67
|
-
|
68
|
-
0
|
69
|
-
else
|
70
|
-
position <=> child.location.start_char
|
71
|
-
end
|
72
|
-
end
|
71
|
+
matched, parent = locate_node_and_parent(node, DIRECT_HIGHLIGHTS + [SyntaxTree::Ident], position)
|
72
|
+
|
73
|
+
return unless matched && parent
|
73
74
|
|
74
75
|
case matched
|
75
|
-
when
|
76
|
-
SyntaxTree::IVar,
|
77
|
-
SyntaxTree::Const,
|
78
|
-
SyntaxTree::CVar,
|
79
|
-
SyntaxTree::VarField
|
76
|
+
when *DIRECT_HIGHLIGHTS
|
80
77
|
Support::HighlightTarget.new(matched)
|
81
78
|
when SyntaxTree::Ident
|
82
|
-
relevant_node =
|
79
|
+
relevant_node = parent.is_a?(SyntaxTree::Params) ? matched : parent
|
83
80
|
Support::HighlightTarget.new(relevant_node)
|
84
|
-
when SyntaxTree::Node
|
85
|
-
find(matched, position)
|
86
81
|
end
|
87
82
|
end
|
88
83
|
|
@@ -25,7 +25,7 @@ module RubyLsp
|
|
25
25
|
[*::Gem::Specification.default_stubs, *::Gem::Specification.stubs].map! do |s|
|
26
26
|
[s.name, s.version.to_s]
|
27
27
|
end.to_h.freeze,
|
28
|
-
T::Hash[String, String]
|
28
|
+
T::Hash[String, String],
|
29
29
|
)
|
30
30
|
|
31
31
|
class << self
|
@@ -78,11 +78,11 @@ module RubyLsp
|
|
78
78
|
|
79
79
|
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentLink], Object)) }
|
80
80
|
def run
|
81
|
-
visit(@document.tree)
|
81
|
+
visit(@document.tree) if @document.parsed?
|
82
82
|
@links
|
83
83
|
end
|
84
84
|
|
85
|
-
sig { params(node: SyntaxTree::Comment).void }
|
85
|
+
sig { override.params(node: SyntaxTree::Comment).void }
|
86
86
|
def visit_comment(node)
|
87
87
|
match = node.value.match(%r{source://.*#\d+$})
|
88
88
|
return unless match
|
@@ -95,7 +95,7 @@ module RubyLsp
|
|
95
95
|
@links << LanguageServer::Protocol::Interface::DocumentLink.new(
|
96
96
|
range: range_from_syntax_tree_node(node),
|
97
97
|
target: "file://#{file_path}##{uri.line_number}",
|
98
|
-
tooltip: "Jump to #{file_path}##{uri.line_number}"
|
98
|
+
tooltip: "Jump to #{file_path}##{uri.line_number}",
|
99
99
|
)
|
100
100
|
end
|
101
101
|
|
@@ -79,23 +79,23 @@ module RubyLsp
|
|
79
79
|
@root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
|
80
80
|
@stack = T.let(
|
81
81
|
[@root],
|
82
|
-
T::Array[T.any(SymbolHierarchyRoot, LanguageServer::Protocol::Interface::DocumentSymbol)]
|
82
|
+
T::Array[T.any(SymbolHierarchyRoot, LanguageServer::Protocol::Interface::DocumentSymbol)],
|
83
83
|
)
|
84
84
|
end
|
85
85
|
|
86
86
|
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol], Object)) }
|
87
87
|
def run
|
88
|
-
visit(@document.tree)
|
88
|
+
visit(@document.tree) if @document.parsed?
|
89
89
|
@root.children
|
90
90
|
end
|
91
91
|
|
92
|
-
sig { params(node: SyntaxTree::ClassDeclaration).void }
|
92
|
+
sig { override.params(node: SyntaxTree::ClassDeclaration).void }
|
93
93
|
def visit_class(node)
|
94
94
|
symbol = create_document_symbol(
|
95
95
|
name: fully_qualified_name(node),
|
96
96
|
kind: :class,
|
97
97
|
range_node: node,
|
98
|
-
selection_range_node: node.constant
|
98
|
+
selection_range_node: node.constant,
|
99
99
|
)
|
100
100
|
|
101
101
|
@stack << symbol
|
@@ -103,7 +103,7 @@ module RubyLsp
|
|
103
103
|
@stack.pop
|
104
104
|
end
|
105
105
|
|
106
|
-
sig { params(node: SyntaxTree::Command).void }
|
106
|
+
sig { override.params(node: SyntaxTree::Command).void }
|
107
107
|
def visit_command(node)
|
108
108
|
return unless ATTR_ACCESSORS.include?(node.message.value)
|
109
109
|
|
@@ -114,22 +114,22 @@ module RubyLsp
|
|
114
114
|
name: argument.value.value,
|
115
115
|
kind: :field,
|
116
116
|
range_node: argument,
|
117
|
-
selection_range_node: argument.value
|
117
|
+
selection_range_node: argument.value,
|
118
118
|
)
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
sig { params(node: SyntaxTree::ConstPathField).void }
|
122
|
+
sig { override.params(node: SyntaxTree::ConstPathField).void }
|
123
123
|
def visit_const_path_field(node)
|
124
124
|
create_document_symbol(
|
125
125
|
name: node.constant.value,
|
126
126
|
kind: :constant,
|
127
127
|
range_node: node,
|
128
|
-
selection_range_node: node.constant
|
128
|
+
selection_range_node: node.constant,
|
129
129
|
)
|
130
130
|
end
|
131
131
|
|
132
|
-
sig { params(node: SyntaxTree::Def).void }
|
132
|
+
sig { override.params(node: SyntaxTree::Def).void }
|
133
133
|
def visit_def(node)
|
134
134
|
name = node.name.value
|
135
135
|
|
@@ -137,7 +137,7 @@ module RubyLsp
|
|
137
137
|
name: name,
|
138
138
|
kind: name == "initialize" ? :constructor : :method,
|
139
139
|
range_node: node,
|
140
|
-
selection_range_node: node.name
|
140
|
+
selection_range_node: node.name,
|
141
141
|
)
|
142
142
|
|
143
143
|
@stack << symbol
|
@@ -145,7 +145,7 @@ module RubyLsp
|
|
145
145
|
@stack.pop
|
146
146
|
end
|
147
147
|
|
148
|
-
sig { params(node: SyntaxTree::DefEndless).void }
|
148
|
+
sig { override.params(node: SyntaxTree::DefEndless).void }
|
149
149
|
def visit_def_endless(node)
|
150
150
|
name = node.name.value
|
151
151
|
|
@@ -153,7 +153,7 @@ module RubyLsp
|
|
153
153
|
name: name,
|
154
154
|
kind: name == "initialize" ? :constructor : :method,
|
155
155
|
range_node: node,
|
156
|
-
selection_range_node: node.name
|
156
|
+
selection_range_node: node.name,
|
157
157
|
)
|
158
158
|
|
159
159
|
@stack << symbol
|
@@ -161,13 +161,13 @@ module RubyLsp
|
|
161
161
|
@stack.pop
|
162
162
|
end
|
163
163
|
|
164
|
-
sig { params(node: SyntaxTree::Defs).void }
|
164
|
+
sig { override.params(node: SyntaxTree::Defs).void }
|
165
165
|
def visit_defs(node)
|
166
166
|
symbol = create_document_symbol(
|
167
167
|
name: "self.#{node.name.value}",
|
168
168
|
kind: :method,
|
169
169
|
range_node: node,
|
170
|
-
selection_range_node: node.name
|
170
|
+
selection_range_node: node.name,
|
171
171
|
)
|
172
172
|
|
173
173
|
@stack << symbol
|
@@ -175,13 +175,13 @@ module RubyLsp
|
|
175
175
|
@stack.pop
|
176
176
|
end
|
177
177
|
|
178
|
-
sig { params(node: SyntaxTree::ModuleDeclaration).void }
|
178
|
+
sig { override.params(node: SyntaxTree::ModuleDeclaration).void }
|
179
179
|
def visit_module(node)
|
180
180
|
symbol = create_document_symbol(
|
181
181
|
name: fully_qualified_name(node),
|
182
182
|
kind: :module,
|
183
183
|
range_node: node,
|
184
|
-
selection_range_node: node.constant
|
184
|
+
selection_range_node: node.constant,
|
185
185
|
)
|
186
186
|
|
187
187
|
@stack << symbol
|
@@ -189,17 +189,17 @@ module RubyLsp
|
|
189
189
|
@stack.pop
|
190
190
|
end
|
191
191
|
|
192
|
-
sig { params(node: SyntaxTree::TopConstField).void }
|
192
|
+
sig { override.params(node: SyntaxTree::TopConstField).void }
|
193
193
|
def visit_top_const_field(node)
|
194
194
|
create_document_symbol(
|
195
195
|
name: node.constant.value,
|
196
196
|
kind: :constant,
|
197
197
|
range_node: node,
|
198
|
-
selection_range_node: node.constant
|
198
|
+
selection_range_node: node.constant,
|
199
199
|
)
|
200
200
|
end
|
201
201
|
|
202
|
-
sig { params(node: SyntaxTree::VarField).void }
|
202
|
+
sig { override.params(node: SyntaxTree::VarField).void }
|
203
203
|
def visit_var_field(node)
|
204
204
|
kind = case node.value
|
205
205
|
when SyntaxTree::Const
|
@@ -214,7 +214,7 @@ module RubyLsp
|
|
214
214
|
name: node.value.value,
|
215
215
|
kind: kind,
|
216
216
|
range_node: node,
|
217
|
-
selection_range_node: node.value
|
217
|
+
selection_range_node: node.value,
|
218
218
|
)
|
219
219
|
end
|
220
220
|
|
@@ -225,7 +225,7 @@ module RubyLsp
|
|
225
225
|
name: String,
|
226
226
|
kind: Symbol,
|
227
227
|
range_node: SyntaxTree::Node,
|
228
|
-
selection_range_node: SyntaxTree::Node
|
228
|
+
selection_range_node: SyntaxTree::Node,
|
229
229
|
).returns(LanguageServer::Protocol::Interface::DocumentSymbol)
|
230
230
|
end
|
231
231
|
def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
|
@@ -66,14 +66,17 @@ module RubyLsp
|
|
66
66
|
|
67
67
|
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::FoldingRange], Object)) }
|
68
68
|
def run
|
69
|
-
|
70
|
-
|
69
|
+
if @document.parsed?
|
70
|
+
visit(@document.tree)
|
71
|
+
emit_partial_range
|
72
|
+
end
|
73
|
+
|
71
74
|
@ranges
|
72
75
|
end
|
73
76
|
|
74
77
|
private
|
75
78
|
|
76
|
-
sig { params(node: T.nilable(SyntaxTree::Node)).void }
|
79
|
+
sig { override.params(node: T.nilable(SyntaxTree::Node)).void }
|
77
80
|
def visit(node)
|
78
81
|
return unless handle_partial_range(node)
|
79
82
|
|
@@ -137,7 +140,7 @@ module RubyLsp
|
|
137
140
|
LanguageServer::Protocol::Interface::FoldingRange.new(
|
138
141
|
start_line: @start_line,
|
139
142
|
end_line: @end_line,
|
140
|
-
kind: @kind
|
143
|
+
kind: @kind,
|
141
144
|
)
|
142
145
|
end
|
143
146
|
|
@@ -248,7 +251,7 @@ module RubyLsp
|
|
248
251
|
@ranges << LanguageServer::Protocol::Interface::FoldingRange.new(
|
249
252
|
start_line: start_line - 1,
|
250
253
|
end_line: end_line - 1,
|
251
|
-
kind: "region"
|
254
|
+
kind: "region",
|
252
255
|
)
|
253
256
|
end
|
254
257
|
end
|
@@ -42,9 +42,9 @@ module RubyLsp
|
|
42
42
|
LanguageServer::Protocol::Interface::TextEdit.new(
|
43
43
|
range: LanguageServer::Protocol::Interface::Range.new(
|
44
44
|
start: LanguageServer::Protocol::Interface::Position.new(line: 0, character: 0),
|
45
|
-
end: LanguageServer::Protocol::Interface::Position.new(line: size, character: size)
|
45
|
+
end: LanguageServer::Protocol::Interface::Position.new(line: size, character: size),
|
46
46
|
),
|
47
|
-
new_text: formatted_text
|
47
|
+
new_text: formatted_text,
|
48
48
|
),
|
49
49
|
]
|
50
50
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "ruby_lsp/requests/support/rails_document_client"
|
5
|
+
|
6
|
+
module RubyLsp
|
7
|
+
module Requests
|
8
|
+
# 
|
9
|
+
#
|
10
|
+
# The [hover request](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover)
|
11
|
+
# renders a clickable link to the code's official documentation.
|
12
|
+
# It currently only supports Rails' documentation: when hovering over Rails DSLs/constants under certain paths,
|
13
|
+
# like `before_save :callback` in `models/post.rb`, it generates a link to `before_save`'s API documentation.
|
14
|
+
#
|
15
|
+
# # Example
|
16
|
+
#
|
17
|
+
# ```ruby
|
18
|
+
# class Post < ApplicationRecord
|
19
|
+
# before_save :do_something # when hovering on before_save, the link will be rendered
|
20
|
+
# end
|
21
|
+
# ```
|
22
|
+
class Hover < BaseRequest
|
23
|
+
extend T::Sig
|
24
|
+
|
25
|
+
sig { params(document: Document, position: Document::PositionShape).void }
|
26
|
+
def initialize(document, position)
|
27
|
+
super(document)
|
28
|
+
|
29
|
+
@position = T.let(Document::Scanner.new(document.source).find_position(position), Integer)
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { override.returns(T.nilable(LanguageServer::Protocol::Interface::Hover)) }
|
33
|
+
def run
|
34
|
+
return unless @document.parsed?
|
35
|
+
|
36
|
+
target, _ = locate_node_and_parent(
|
37
|
+
T.must(@document.tree), [SyntaxTree::Command, SyntaxTree::FCall, SyntaxTree::ConstPathRef], @position
|
38
|
+
)
|
39
|
+
|
40
|
+
case target
|
41
|
+
when SyntaxTree::Command
|
42
|
+
message = target.message
|
43
|
+
generate_rails_document_link_hover(message.value, message)
|
44
|
+
when SyntaxTree::FCall
|
45
|
+
message = target.value
|
46
|
+
generate_rails_document_link_hover(message.value, message)
|
47
|
+
when SyntaxTree::ConstPathRef
|
48
|
+
constant_name = full_constant_name(target)
|
49
|
+
generate_rails_document_link_hover(constant_name, target)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
sig do
|
56
|
+
params(name: String, node: SyntaxTree::Node).returns(T.nilable(LanguageServer::Protocol::Interface::Hover))
|
57
|
+
end
|
58
|
+
def generate_rails_document_link_hover(name, node)
|
59
|
+
urls = Support::RailsDocumentClient.generate_rails_document_urls(name)
|
60
|
+
|
61
|
+
return if urls.empty?
|
62
|
+
|
63
|
+
contents = LanguageServer::Protocol::Interface::MarkupContent.new(
|
64
|
+
kind: "markdown",
|
65
|
+
value: urls.join("\n\n"),
|
66
|
+
)
|
67
|
+
LanguageServer::Protocol::Interface::Hover.new(
|
68
|
+
range: range_from_syntax_tree_node(node),
|
69
|
+
contents: contents,
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# 
|
7
|
+
#
|
8
|
+
# [Inlay hints](https://microsoft.github.io/language-server-protocol/specification#textDocument_inlayHint)
|
9
|
+
# are labels added directly in the code that explicitly show the user something that might
|
10
|
+
# otherwise just be implied.
|
11
|
+
#
|
12
|
+
# # Example
|
13
|
+
#
|
14
|
+
# ```ruby
|
15
|
+
# begin
|
16
|
+
# puts "do something that might raise"
|
17
|
+
# rescue # Label "StandardError" goes here as a bare rescue implies rescuing StandardError
|
18
|
+
# puts "handle some rescue"
|
19
|
+
# end
|
20
|
+
# ```
|
21
|
+
class InlayHints < BaseRequest
|
22
|
+
RESCUE_STRING_LENGTH = T.let("rescue".length, Integer)
|
23
|
+
|
24
|
+
sig { params(document: Document, range: T::Range[Integer]).void }
|
25
|
+
def initialize(document, range)
|
26
|
+
super(document)
|
27
|
+
|
28
|
+
@hints = T.let([], T::Array[LanguageServer::Protocol::Interface::InlayHint])
|
29
|
+
@range = range
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::InlayHint], Object)) }
|
33
|
+
def run
|
34
|
+
visit(@document.tree) if @document.parsed?
|
35
|
+
@hints
|
36
|
+
end
|
37
|
+
|
38
|
+
sig { override.params(node: SyntaxTree::Rescue).void }
|
39
|
+
def visit_rescue(node)
|
40
|
+
return unless node.exception.nil?
|
41
|
+
|
42
|
+
loc = node.location
|
43
|
+
return unless @range.cover?(loc.start_line - 1) && @range.cover?(loc.end_line - 1)
|
44
|
+
|
45
|
+
@hints << LanguageServer::Protocol::Interface::InlayHint.new(
|
46
|
+
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
|
47
|
+
label: "StandardError",
|
48
|
+
padding_left: true,
|
49
|
+
tooltip: "StandardError is implied in a bare rescue",
|
50
|
+
)
|
51
|
+
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|