ruby-lsp 0.4.2 → 0.5.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/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
|
-
# 
|
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
|
-
# 
|
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
|
-
# 
|
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
|
-
# 
|
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
|
-
# 
|
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
|
-
# 
|
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
|
-
# 
|
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
|
-
# 
|
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
|