ruby-lsp 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +29 -116
- data/VERSION +1 -1
- data/exe/ruby-lsp +10 -1
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +62 -0
- data/lib/ruby_lsp/check_docs.rb +112 -0
- data/lib/ruby_lsp/document.rb +87 -8
- data/lib/ruby_lsp/event_emitter.rb +120 -0
- data/lib/ruby_lsp/executor.rb +191 -44
- data/lib/ruby_lsp/extension.rb +104 -0
- data/lib/ruby_lsp/internal.rb +4 -0
- data/lib/ruby_lsp/listener.rb +42 -0
- data/lib/ruby_lsp/requests/base_request.rb +2 -90
- data/lib/ruby_lsp/requests/code_action_resolve.rb +47 -20
- data/lib/ruby_lsp/requests/code_actions.rb +6 -5
- data/lib/ruby_lsp/requests/code_lens.rb +151 -0
- data/lib/ruby_lsp/requests/diagnostics.rb +5 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +8 -10
- data/lib/ruby_lsp/requests/document_link.rb +17 -15
- data/lib/ruby_lsp/requests/document_symbol.rb +63 -40
- data/lib/ruby_lsp/requests/folding_ranges.rb +14 -10
- data/lib/ruby_lsp/requests/formatting.rb +15 -15
- data/lib/ruby_lsp/requests/hover.rb +45 -34
- data/lib/ruby_lsp/requests/inlay_hints.rb +6 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +5 -1
- data/lib/ruby_lsp/requests/path_completion.rb +21 -51
- data/lib/ruby_lsp/requests/selection_ranges.rb +4 -4
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +30 -16
- data/lib/ruby_lsp/requests/support/common.rb +91 -0
- data/lib/ruby_lsp/requests/support/highlight_target.rb +5 -4
- data/lib/ruby_lsp/requests/support/rails_document_client.rb +7 -6
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +0 -1
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +0 -1
- data/lib/ruby_lsp/requests/support/selection_range.rb +1 -1
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
- data/lib/ruby_lsp/requests/support/sorbet.rb +5 -15
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +42 -0
- data/lib/ruby_lsp/requests.rb +17 -14
- data/lib/ruby_lsp/server.rb +45 -9
- data/lib/ruby_lsp/store.rb +11 -11
- data/lib/ruby_lsp/utils.rb +9 -8
- metadata +13 -5
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![Folding ranges demo](../../
|
6
|
+
# ![Folding ranges demo](../../folding_ranges.gif)
|
7
7
|
#
|
8
8
|
# The [folding ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange)
|
9
9
|
# request informs the editor of the ranges where and how code can be folded.
|
@@ -63,11 +63,11 @@ module RubyLsp
|
|
63
63
|
def initialize(document)
|
64
64
|
super
|
65
65
|
|
66
|
-
@ranges = T.let([], T::Array[
|
66
|
+
@ranges = T.let([], T::Array[Interface::FoldingRange])
|
67
67
|
@partial_range = T.let(nil, T.nilable(PartialRange))
|
68
68
|
end
|
69
69
|
|
70
|
-
sig { override.returns(T.all(T::Array[
|
70
|
+
sig { override.returns(T.all(T::Array[Interface::FoldingRange], Object)) }
|
71
71
|
def run
|
72
72
|
if @document.parsed?
|
73
73
|
visit(@document.tree)
|
@@ -161,9 +161,9 @@ module RubyLsp
|
|
161
161
|
node.is_a?(SyntaxTree::Comment) && @end_line + 1 != node.location.start_line - 1
|
162
162
|
end
|
163
163
|
|
164
|
-
sig { returns(
|
164
|
+
sig { returns(Interface::FoldingRange) }
|
165
165
|
def to_range
|
166
|
-
|
166
|
+
Interface::FoldingRange.new(
|
167
167
|
start_line: @start_line,
|
168
168
|
end_line: @end_line,
|
169
169
|
kind: @kind,
|
@@ -220,7 +220,8 @@ module RubyLsp
|
|
220
220
|
|
221
221
|
sig { params(node: T.any(SyntaxTree::CallNode, SyntaxTree::CommandCall)).void }
|
222
222
|
def add_call_range(node)
|
223
|
-
receiver = T.let(node.receiver, SyntaxTree::Node)
|
223
|
+
receiver = T.let(node.receiver, T.nilable(SyntaxTree::Node))
|
224
|
+
|
224
225
|
loop do
|
225
226
|
case receiver
|
226
227
|
when SyntaxTree::CallNode
|
@@ -255,9 +256,10 @@ module RubyLsp
|
|
255
256
|
def add_def_range(node)
|
256
257
|
# For an endless method with no arguments, `node.params` returns `nil` for Ruby 3.0, but a `Syntax::Params`
|
257
258
|
# for Ruby 3.1
|
258
|
-
|
259
|
+
params = node.params
|
260
|
+
return unless params
|
259
261
|
|
260
|
-
params_location =
|
262
|
+
params_location = params.location
|
261
263
|
|
262
264
|
if params_location.start_line < params_location.end_line
|
263
265
|
add_lines_range(params_location.end_line, node.location.end_line - 1)
|
@@ -276,7 +278,9 @@ module RubyLsp
|
|
276
278
|
|
277
279
|
sig { params(node: SyntaxTree::Node, statements: SyntaxTree::Statements).void }
|
278
280
|
def add_statements_range(node, statements)
|
279
|
-
|
281
|
+
return if statements.empty?
|
282
|
+
|
283
|
+
add_lines_range(node.location.start_line, T.must(statements.body.last).location.end_line)
|
280
284
|
end
|
281
285
|
|
282
286
|
sig { params(node: SyntaxTree::StringConcat).void }
|
@@ -291,7 +295,7 @@ module RubyLsp
|
|
291
295
|
def add_lines_range(start_line, end_line)
|
292
296
|
return if start_line >= end_line
|
293
297
|
|
294
|
-
@ranges <<
|
298
|
+
@ranges << Interface::FoldingRange.new(
|
295
299
|
start_line: start_line - 1,
|
296
300
|
end_line: end_line - 1,
|
297
301
|
kind: "region",
|
@@ -2,16 +2,21 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "ruby_lsp/requests/support/rubocop_formatting_runner"
|
5
|
+
require "ruby_lsp/requests/support/syntax_tree_formatting_runner"
|
5
6
|
|
6
7
|
module RubyLsp
|
7
8
|
module Requests
|
8
|
-
# ![Formatting symbol demo](../../
|
9
|
+
# ![Formatting symbol demo](../../formatting.gif)
|
9
10
|
#
|
10
11
|
# The [formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting)
|
11
12
|
# request uses RuboCop to fix auto-correctable offenses in the document. This requires enabling format on save and
|
12
13
|
# registering the ruby-lsp as the Ruby formatter.
|
13
14
|
#
|
14
|
-
#
|
15
|
+
# The `rubyLsp.formatter` setting specifies which formatter to use.
|
16
|
+
# If set to `auto`` then it behaves as follows:
|
17
|
+
# * It will use RuboCop if it is part of the bundle.
|
18
|
+
# * If RuboCop is not available, and `syntax_tree` is a direct dependency, it will use that.
|
19
|
+
# * Otherwise, no formatting will be applied.
|
15
20
|
#
|
16
21
|
# # Example
|
17
22
|
#
|
@@ -26,19 +31,12 @@ module RubyLsp
|
|
26
31
|
|
27
32
|
extend T::Sig
|
28
33
|
|
29
|
-
sig { params(
|
30
|
-
def initialize(
|
34
|
+
sig { params(document: Document, formatter: String).void }
|
35
|
+
def initialize(document, formatter: "auto")
|
31
36
|
super(document)
|
32
37
|
|
33
|
-
@uri = uri
|
34
|
-
@formatter =
|
35
|
-
if formatter == "auto"
|
36
|
-
defined?(Support::RuboCopFormattingRunner) ? "rubocop" : "syntax_tree"
|
37
|
-
else
|
38
|
-
formatter
|
39
|
-
end,
|
40
|
-
String,
|
41
|
-
)
|
38
|
+
@uri = T.let(document.uri, String)
|
39
|
+
@formatter = formatter
|
42
40
|
end
|
43
41
|
|
44
42
|
sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
|
@@ -71,9 +69,11 @@ module RubyLsp
|
|
71
69
|
def formatted_file
|
72
70
|
case @formatter
|
73
71
|
when "rubocop"
|
74
|
-
Support::RuboCopFormattingRunner
|
72
|
+
if defined?(Support::RuboCopFormattingRunner)
|
73
|
+
Support::RuboCopFormattingRunner.instance.run(@uri, @document)
|
74
|
+
end
|
75
75
|
when "syntax_tree"
|
76
|
-
|
76
|
+
Support::SyntaxTreeFormattingRunner.instance.run(@uri, @document)
|
77
77
|
else
|
78
78
|
raise InvalidFormatter, "Unknown formatter: #{@formatter}"
|
79
79
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![Hover demo](../../
|
6
|
+
# ![Hover demo](../../rails_document_link_hover.gif)
|
7
7
|
#
|
8
8
|
# The [hover request](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover)
|
9
9
|
# renders a clickable link to the code's official documentation.
|
@@ -17,8 +17,11 @@ module RubyLsp
|
|
17
17
|
# before_save :do_something # when hovering on before_save, the link will be rendered
|
18
18
|
# end
|
19
19
|
# ```
|
20
|
-
class Hover <
|
20
|
+
class Hover < Listener
|
21
21
|
extend T::Sig
|
22
|
+
extend T::Generic
|
23
|
+
|
24
|
+
ResponseType = type_member { { fixed: T.nilable(Interface::Hover) } }
|
22
25
|
|
23
26
|
ALLOWED_TARGETS = T.let(
|
24
27
|
[
|
@@ -29,52 +32,60 @@ module RubyLsp
|
|
29
32
|
T::Array[T.class_of(SyntaxTree::Node)],
|
30
33
|
)
|
31
34
|
|
32
|
-
sig {
|
33
|
-
|
34
|
-
|
35
|
+
sig { override.returns(ResponseType) }
|
36
|
+
attr_reader :response
|
37
|
+
|
38
|
+
sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
|
39
|
+
def initialize(emitter, message_queue)
|
40
|
+
super
|
35
41
|
|
36
|
-
@
|
42
|
+
@response = T.let(nil, ResponseType)
|
43
|
+
emitter.register(self, :on_command, :on_const_path_ref, :on_call)
|
37
44
|
end
|
38
45
|
|
39
|
-
|
40
|
-
|
41
|
-
|
46
|
+
# Merges responses from other hover listeners
|
47
|
+
sig { params(other: Listener[ResponseType]).returns(T.self_type) }
|
48
|
+
def merge_response!(other)
|
49
|
+
other_response = other.response
|
50
|
+
return self unless other_response
|
42
51
|
|
43
|
-
|
44
|
-
|
52
|
+
if @response.nil?
|
53
|
+
@response = other.response
|
54
|
+
else
|
55
|
+
@response.contents.value << other_response.contents.value << "\n\n"
|
56
|
+
end
|
45
57
|
|
46
|
-
|
47
|
-
|
48
|
-
message = target.message
|
49
|
-
generate_rails_document_link_hover(message.value, message)
|
50
|
-
when SyntaxTree::CallNode
|
51
|
-
return if target.message == :call
|
58
|
+
self
|
59
|
+
end
|
52
60
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
61
|
+
sig { params(node: SyntaxTree::Command).void }
|
62
|
+
def on_command(node)
|
63
|
+
message = node.message
|
64
|
+
@response = generate_rails_document_link_hover(message.value, message)
|
58
65
|
end
|
59
66
|
|
60
|
-
|
67
|
+
sig { params(node: SyntaxTree::ConstPathRef).void }
|
68
|
+
def on_const_path_ref(node)
|
69
|
+
@response = generate_rails_document_link_hover(full_constant_name(node), node)
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { params(node: SyntaxTree::CallNode).void }
|
73
|
+
def on_call(node)
|
74
|
+
message = node.message
|
75
|
+
return if message.is_a?(Symbol)
|
61
76
|
|
62
|
-
|
63
|
-
params(name: String, node: SyntaxTree::Node).returns(T.nilable(LanguageServer::Protocol::Interface::Hover))
|
77
|
+
@response = generate_rails_document_link_hover(message.value, message)
|
64
78
|
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
sig { params(name: String, node: SyntaxTree::Node).returns(T.nilable(Interface::Hover)) }
|
65
83
|
def generate_rails_document_link_hover(name, node)
|
66
84
|
urls = Support::RailsDocumentClient.generate_rails_document_urls(name)
|
67
|
-
|
68
85
|
return if urls.empty?
|
69
86
|
|
70
|
-
contents =
|
71
|
-
|
72
|
-
value: urls.join("\n\n"),
|
73
|
-
)
|
74
|
-
LanguageServer::Protocol::Interface::Hover.new(
|
75
|
-
range: range_from_syntax_tree_node(node),
|
76
|
-
contents: contents,
|
77
|
-
)
|
87
|
+
contents = Interface::MarkupContent.new(kind: "markdown", value: urls.join("\n\n"))
|
88
|
+
Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
|
78
89
|
end
|
79
90
|
end
|
80
91
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![Inlay hint demo](../../
|
6
|
+
# ![Inlay hint demo](../../inlay_hint.gif)
|
7
7
|
#
|
8
8
|
# [Inlay hints](https://microsoft.github.io/language-server-protocol/specification#textDocument_inlayHint)
|
9
9
|
# are labels added directly in the code that explicitly show the user something that might
|
@@ -25,11 +25,11 @@ module RubyLsp
|
|
25
25
|
def initialize(document, range)
|
26
26
|
super(document)
|
27
27
|
|
28
|
-
@hints = T.let([], T::Array[
|
28
|
+
@hints = T.let([], T::Array[Interface::InlayHint])
|
29
29
|
@range = range
|
30
30
|
end
|
31
31
|
|
32
|
-
sig { override.returns(T.all(T::Array[
|
32
|
+
sig { override.returns(T.all(T::Array[Interface::InlayHint], Object)) }
|
33
33
|
def run
|
34
34
|
visit(@document.tree) if @document.parsed?
|
35
35
|
@hints
|
@@ -37,12 +37,13 @@ module RubyLsp
|
|
37
37
|
|
38
38
|
sig { override.params(node: SyntaxTree::Rescue).void }
|
39
39
|
def visit_rescue(node)
|
40
|
-
|
40
|
+
exception = node.exception
|
41
|
+
return unless exception.nil? || exception.exceptions.nil?
|
41
42
|
|
42
43
|
loc = node.location
|
43
44
|
return unless visible?(node, @range)
|
44
45
|
|
45
|
-
@hints <<
|
46
|
+
@hints << Interface::InlayHint.new(
|
46
47
|
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
|
47
48
|
label: "StandardError",
|
48
49
|
padding_left: true,
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![On type formatting demo](../../
|
6
|
+
# ![On type formatting demo](../../on_type_formatting.gif)
|
7
7
|
#
|
8
8
|
# The [on type formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_onTypeFormatting)
|
9
9
|
# request formats code as the user is typing. For example, automatically adding `end` to class definitions.
|
@@ -80,6 +80,10 @@ module RubyLsp
|
|
80
80
|
|
81
81
|
sig { void }
|
82
82
|
def handle_statement_end
|
83
|
+
# If a keyword occurs in a line which appears be a comment or a string, we will not try to format it, since
|
84
|
+
# it could be a coincidental match. This approach is not perfect, but it should cover most cases.
|
85
|
+
return if @previous_line.start_with?(/["'#]/)
|
86
|
+
|
83
87
|
return unless END_REGEXES.any? { |regex| regex.match?(@previous_line) }
|
84
88
|
|
85
89
|
indents = " " * @indentation
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![Path completion demo](../../
|
6
|
+
# ![Path completion demo](../../path_completion.gif)
|
7
7
|
#
|
8
8
|
# The [completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
9
9
|
# request looks up Ruby files in the $LOAD_PATH to suggest path completion inside `require` statements.
|
@@ -13,30 +13,28 @@ module RubyLsp
|
|
13
13
|
# ```ruby
|
14
14
|
# require "ruby_lsp/requests" # --> completion: suggests `base_request`, `code_actions`, ...
|
15
15
|
# ```
|
16
|
-
class PathCompletion <
|
16
|
+
class PathCompletion < Listener
|
17
17
|
extend T::Sig
|
18
|
+
extend T::Generic
|
18
19
|
|
19
|
-
|
20
|
-
def initialize(document, position)
|
21
|
-
super(document)
|
20
|
+
ResponseType = type_member { { fixed: T::Array[Interface::CompletionItem] } }
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
22
|
+
sig { override.returns(ResponseType) }
|
23
|
+
attr_reader :response
|
26
24
|
|
27
|
-
sig {
|
28
|
-
def
|
29
|
-
|
30
|
-
|
25
|
+
sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
|
26
|
+
def initialize(emitter, message_queue)
|
27
|
+
super
|
28
|
+
@response = T.let([], ResponseType)
|
29
|
+
@tree = T.let(Support::PrefixTree.new(collect_load_path_files), Support::PrefixTree)
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
# no target means the we are not inside a `require` call
|
35
|
-
return [] unless target
|
31
|
+
emitter.register(self, :on_tstring_content)
|
32
|
+
end
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
sig { params(node: SyntaxTree::TStringContent).void }
|
35
|
+
def on_tstring_content(node)
|
36
|
+
@tree.search(node.value).sort.each do |path|
|
37
|
+
@response << build_completion(path, node)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -51,41 +49,13 @@ module RubyLsp
|
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
|
-
sig { params(
|
55
|
-
def
|
56
|
-
matched, parent = locate(
|
57
|
-
T.must(@document.tree),
|
58
|
-
position,
|
59
|
-
node_types: [SyntaxTree::Command, SyntaxTree::CommandCall, SyntaxTree::CallNode],
|
60
|
-
)
|
61
|
-
|
62
|
-
return unless matched && parent
|
63
|
-
|
64
|
-
case matched
|
65
|
-
when SyntaxTree::Command, SyntaxTree::CallNode, SyntaxTree::CommandCall
|
66
|
-
return unless matched.message.value == "require"
|
67
|
-
|
68
|
-
args = matched.arguments
|
69
|
-
args = args.arguments if args.is_a?(SyntaxTree::ArgParen)
|
70
|
-
|
71
|
-
path_node = args.parts.first.parts.first
|
72
|
-
return unless path_node
|
73
|
-
return unless (path_node.location.start_char..path_node.location.end_char).cover?(position)
|
74
|
-
|
75
|
-
path_node
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
sig { params(label: String, insert_text: String).returns(Interface::CompletionItem) }
|
80
|
-
def build_completion(label, insert_text)
|
52
|
+
sig { params(label: String, node: SyntaxTree::TStringContent).returns(Interface::CompletionItem) }
|
53
|
+
def build_completion(label, node)
|
81
54
|
Interface::CompletionItem.new(
|
82
55
|
label: label,
|
83
56
|
text_edit: Interface::TextEdit.new(
|
84
|
-
range:
|
85
|
-
|
86
|
-
end: @position,
|
87
|
-
),
|
88
|
-
new_text: insert_text,
|
57
|
+
range: range_from_syntax_tree_node(node),
|
58
|
+
new_text: label,
|
89
59
|
),
|
90
60
|
kind: Constant::CompletionItemKind::REFERENCE,
|
91
61
|
)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![Selection ranges demo](../../
|
6
|
+
# ![Selection ranges demo](../../selection_ranges.gif)
|
7
7
|
#
|
8
8
|
# The [selection ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange)
|
9
9
|
# request informs the editor of ranges that the user may want to select based on the location(s)
|
@@ -100,12 +100,12 @@ module RubyLsp
|
|
100
100
|
end
|
101
101
|
def create_selection_range(location, parent = nil)
|
102
102
|
RubyLsp::Requests::Support::SelectionRange.new(
|
103
|
-
range:
|
104
|
-
start:
|
103
|
+
range: Interface::Range.new(
|
104
|
+
start: Interface::Position.new(
|
105
105
|
line: location.start_line - 1,
|
106
106
|
character: location.start_column,
|
107
107
|
),
|
108
|
-
end:
|
108
|
+
end: Interface::Position.new(
|
109
109
|
line: location.end_line - 1,
|
110
110
|
character: location.end_column,
|
111
111
|
),
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# ![Semantic highlighting demo](../../
|
6
|
+
# ![Semantic highlighting demo](../../semantic_highlighting.gif)
|
7
7
|
#
|
8
8
|
# The [semantic
|
9
9
|
# highlighting](https://microsoft.github.io/language-server-protocol/specification#textDocument_semanticTokens)
|
@@ -122,7 +122,7 @@ module RubyLsp
|
|
122
122
|
sig do
|
123
123
|
override.returns(
|
124
124
|
T.any(
|
125
|
-
|
125
|
+
Interface::SemanticTokens,
|
126
126
|
T.all(T::Array[SemanticToken], Object),
|
127
127
|
),
|
128
128
|
)
|
@@ -143,7 +143,7 @@ module RubyLsp
|
|
143
143
|
visit(node.receiver)
|
144
144
|
|
145
145
|
message = node.message
|
146
|
-
if message
|
146
|
+
if !message.is_a?(Symbol) && !special_method?(message.value)
|
147
147
|
type = Support::Sorbet.annotation?(node) ? :type : :method
|
148
148
|
|
149
149
|
add_token(message.location, type)
|
@@ -168,7 +168,8 @@ module RubyLsp
|
|
168
168
|
return super unless visible?(node, @range)
|
169
169
|
|
170
170
|
visit(node.receiver)
|
171
|
-
|
171
|
+
message = node.message
|
172
|
+
add_token(message.location, :method) unless message.is_a?(Symbol)
|
172
173
|
visit(node.arguments)
|
173
174
|
visit(node.block)
|
174
175
|
end
|
@@ -205,7 +206,7 @@ module RubyLsp
|
|
205
206
|
def visit_params(node)
|
206
207
|
return super unless visible?(node, @range)
|
207
208
|
|
208
|
-
node.keywords.each do |keyword
|
209
|
+
node.keywords.each do |keyword, *|
|
209
210
|
location = keyword.location
|
210
211
|
add_token(location_without_colon(location), :parameter)
|
211
212
|
end
|
@@ -215,7 +216,7 @@ module RubyLsp
|
|
215
216
|
end
|
216
217
|
|
217
218
|
rest = node.keyword_rest
|
218
|
-
if rest && !rest.is_a?(SyntaxTree::ArgsForward)
|
219
|
+
if rest && !rest.is_a?(SyntaxTree::ArgsForward) && !rest.is_a?(Symbol)
|
219
220
|
name = rest.name
|
220
221
|
add_token(name.location, :parameter) if name
|
221
222
|
end
|
@@ -238,9 +239,14 @@ module RubyLsp
|
|
238
239
|
|
239
240
|
value = node.value
|
240
241
|
|
241
|
-
|
242
|
+
case value
|
243
|
+
when SyntaxTree::Ident
|
242
244
|
type = type_for_local(value)
|
243
245
|
add_token(value.location, type)
|
246
|
+
when Symbol
|
247
|
+
# do nothing
|
248
|
+
else
|
249
|
+
visit(value)
|
244
250
|
end
|
245
251
|
|
246
252
|
super
|
@@ -256,6 +262,8 @@ module RubyLsp
|
|
256
262
|
when SyntaxTree::Ident
|
257
263
|
type = type_for_local(value)
|
258
264
|
add_token(value.location, type)
|
265
|
+
when Symbol
|
266
|
+
# do nothing
|
259
267
|
else
|
260
268
|
visit(value)
|
261
269
|
end
|
@@ -305,18 +313,21 @@ module RubyLsp
|
|
305
313
|
return unless node.operator == :=~
|
306
314
|
|
307
315
|
left = node.left
|
316
|
+
# The regexp needs to be on the left hand side of the =~ for local variable capture
|
317
|
+
return unless left.is_a?(SyntaxTree::RegexpLiteral)
|
318
|
+
|
308
319
|
parts = left.parts
|
320
|
+
return unless parts.one?
|
309
321
|
|
310
|
-
|
311
|
-
|
322
|
+
content = parts.first
|
323
|
+
return unless content.is_a?(SyntaxTree::TStringContent)
|
312
324
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
325
|
+
# For each capture name we find in the regexp, look for a local in the current_scope
|
326
|
+
Regexp.new(content.value, Regexp::FIXEDENCODING).names.each do |name|
|
327
|
+
local = current_scope.find_local(name)
|
328
|
+
next unless local
|
317
329
|
|
318
|
-
|
319
|
-
end
|
330
|
+
local.definitions.each { |definition| add_token(definition, :variable) }
|
320
331
|
end
|
321
332
|
end
|
322
333
|
|
@@ -325,7 +336,10 @@ module RubyLsp
|
|
325
336
|
return super unless visible?(node, @range)
|
326
337
|
|
327
338
|
add_token(node.constant.location, :class, [:declaration])
|
328
|
-
|
339
|
+
|
340
|
+
superclass = node.superclass
|
341
|
+
add_token(superclass.location, :class) if superclass
|
342
|
+
|
329
343
|
visit(node.bodystmt)
|
330
344
|
end
|
331
345
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
module Support
|
7
|
+
module Common
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(node: SyntaxTree::Node).returns(Interface::Range) }
|
11
|
+
def range_from_syntax_tree_node(node)
|
12
|
+
loc = node.location
|
13
|
+
|
14
|
+
Interface::Range.new(
|
15
|
+
start: Interface::Position.new(
|
16
|
+
line: loc.start_line - 1,
|
17
|
+
character: loc.start_column,
|
18
|
+
),
|
19
|
+
end: Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
sig do
|
24
|
+
params(node: T.any(SyntaxTree::ConstPathRef, SyntaxTree::ConstRef, SyntaxTree::TopConstRef)).returns(String)
|
25
|
+
end
|
26
|
+
def full_constant_name(node)
|
27
|
+
name = +node.constant.value
|
28
|
+
constant = T.let(node, SyntaxTree::Node)
|
29
|
+
|
30
|
+
while constant.is_a?(SyntaxTree::ConstPathRef)
|
31
|
+
constant = constant.parent
|
32
|
+
|
33
|
+
case constant
|
34
|
+
when SyntaxTree::ConstPathRef
|
35
|
+
name.prepend("#{constant.constant.value}::")
|
36
|
+
when SyntaxTree::VarRef
|
37
|
+
name.prepend("#{constant.value.value}::")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
name
|
42
|
+
end
|
43
|
+
|
44
|
+
sig { params(node: T.nilable(SyntaxTree::Node), range: T.nilable(T::Range[Integer])).returns(T::Boolean) }
|
45
|
+
def visible?(node, range)
|
46
|
+
return true if range.nil?
|
47
|
+
return false if node.nil?
|
48
|
+
|
49
|
+
loc = node.location
|
50
|
+
range.cover?(loc.start_line - 1) && range.cover?(loc.end_line - 1)
|
51
|
+
end
|
52
|
+
|
53
|
+
sig do
|
54
|
+
params(
|
55
|
+
node: SyntaxTree::Node,
|
56
|
+
title: String,
|
57
|
+
command_name: String,
|
58
|
+
path: String,
|
59
|
+
name: String,
|
60
|
+
test_command: String,
|
61
|
+
type: String,
|
62
|
+
).returns(Interface::CodeLens)
|
63
|
+
end
|
64
|
+
def create_code_lens(node, title:, command_name:, path:, name:, test_command:, type:)
|
65
|
+
range = range_from_syntax_tree_node(node)
|
66
|
+
arguments = [
|
67
|
+
path,
|
68
|
+
name,
|
69
|
+
test_command,
|
70
|
+
{
|
71
|
+
start_line: node.location.start_line - 1,
|
72
|
+
start_column: node.location.start_column,
|
73
|
+
end_line: node.location.end_line - 1,
|
74
|
+
end_column: node.location.end_column,
|
75
|
+
},
|
76
|
+
]
|
77
|
+
|
78
|
+
Interface::CodeLens.new(
|
79
|
+
range: range,
|
80
|
+
command: Interface::Command.new(
|
81
|
+
title: title,
|
82
|
+
command: command_name,
|
83
|
+
arguments: arguments,
|
84
|
+
),
|
85
|
+
data: { type: type },
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -7,8 +7,8 @@ module RubyLsp
|
|
7
7
|
class HighlightTarget
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
READ =
|
11
|
-
WRITE =
|
10
|
+
READ = Constant::DocumentHighlightKind::READ
|
11
|
+
WRITE = Constant::DocumentHighlightKind::WRITE
|
12
12
|
|
13
13
|
class HighlightMatch
|
14
14
|
extend T::Sig
|
@@ -84,10 +84,11 @@ module RubyLsp
|
|
84
84
|
SyntaxTree::KwRestParam, SyntaxTree::BlockArg
|
85
85
|
node.name&.value
|
86
86
|
when SyntaxTree::VarField, SyntaxTree::VarRef, SyntaxTree::VCall
|
87
|
-
node.value
|
87
|
+
value = node.value
|
88
|
+
value.value unless value.nil? || value.is_a?(Symbol)
|
88
89
|
when SyntaxTree::CallNode, SyntaxTree::Command, SyntaxTree::CommandCall
|
89
90
|
message = node.message
|
90
|
-
message
|
91
|
+
message.value unless message.is_a?(Symbol)
|
91
92
|
when SyntaxTree::ClassDeclaration, SyntaxTree::ModuleDeclaration
|
92
93
|
node.constant.constant.value
|
93
94
|
end
|