ruby-lsp 0.17.13 → 0.17.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp +2 -0
- data/lib/ruby_lsp/document.rb +9 -114
- data/lib/ruby_lsp/erb_document.rb +16 -2
- data/lib/ruby_lsp/global_state.rb +1 -1
- data/lib/ruby_lsp/internal.rb +1 -0
- data/lib/ruby_lsp/rbs_document.rb +41 -0
- data/lib/ruby_lsp/requests/code_action_resolve.rb +34 -18
- data/lib/ruby_lsp/requests/code_actions.rb +1 -1
- data/lib/ruby_lsp/requests/completion.rb +2 -2
- data/lib/ruby_lsp/requests/definition.rb +1 -1
- data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
- data/lib/ruby_lsp/requests/formatting.rb +1 -1
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
- data/lib/ruby_lsp/requests/on_type_formatting.rb +1 -1
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/selection_ranges.rb +2 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -1
- data/lib/ruby_lsp/requests/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/support/formatter.rb +2 -2
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +2 -2
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +2 -2
- data/lib/ruby_lsp/ruby_document.rb +119 -1
- data/lib/ruby_lsp/server.rb +93 -5
- data/lib/ruby_lsp/setup_bundler.rb +15 -4
- data/lib/ruby_lsp/store.rb +10 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17c576dbc88c8c4012eb777b15df7df630a827d7692f6bceec06b68178b25357
|
4
|
+
data.tar.gz: f023f22a818616b1c8c6fb1de77d0637e7bdae37b60b46e941b297aaa95729a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0848d63fef1677ccf276182cdea5a8304e4a1e04a7ec4936f8f083c27bc62f575fe3f0a207f75805cf3c8eb106e43d5d1afe2df366028980cb5eee6ed97c14b
|
7
|
+
data.tar.gz: d57869c1ee7dcec65becd9ee4fc225c91e946e697c3aab8a42d2453c1a85bcc91cd8e0a6364d810f8109c2b97102f101d24bf8986d2e4b3905b56368e260b0d3
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.17.
|
1
|
+
0.17.14
|
data/exe/ruby-lsp
CHANGED
@@ -81,6 +81,8 @@ require "ruby_lsp/load_sorbet"
|
|
81
81
|
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
82
82
|
require "ruby_lsp/internal"
|
83
83
|
|
84
|
+
T::Utils.run_all_sig_blocks
|
85
|
+
|
84
86
|
if options[:debug]
|
85
87
|
if ["x64-mingw-ucrt", "x64-mingw32"].include?(RUBY_PLATFORM)
|
86
88
|
$stderr.puts "Debugging is not supported on Windows"
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -7,15 +7,19 @@ module RubyLsp
|
|
7
7
|
enums do
|
8
8
|
Ruby = new("ruby")
|
9
9
|
ERB = new("erb")
|
10
|
+
RBS = new("rbs")
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
14
|
extend T::Sig
|
14
15
|
extend T::Helpers
|
16
|
+
extend T::Generic
|
17
|
+
|
18
|
+
ParseResultType = type_member
|
15
19
|
|
16
20
|
abstract!
|
17
21
|
|
18
|
-
sig { returns(
|
22
|
+
sig { returns(ParseResultType) }
|
19
23
|
attr_reader :parse_result
|
20
24
|
|
21
25
|
sig { returns(String) }
|
@@ -38,10 +42,10 @@ module RubyLsp
|
|
38
42
|
@version = T.let(version, Integer)
|
39
43
|
@uri = T.let(uri, URI::Generic)
|
40
44
|
@needs_parsing = T.let(true, T::Boolean)
|
41
|
-
@parse_result = T.let(parse,
|
45
|
+
@parse_result = T.let(parse, ParseResultType)
|
42
46
|
end
|
43
47
|
|
44
|
-
sig { params(other: Document).returns(T::Boolean) }
|
48
|
+
sig { params(other: Document[T.untyped]).returns(T::Boolean) }
|
45
49
|
def ==(other)
|
46
50
|
self.class == other.class && uri == other.uri && @source == other.source
|
47
51
|
end
|
@@ -54,7 +58,7 @@ module RubyLsp
|
|
54
58
|
type_parameters(:T)
|
55
59
|
.params(
|
56
60
|
request_name: String,
|
57
|
-
block: T.proc.params(document: Document).returns(T.type_parameter(:T)),
|
61
|
+
block: T.proc.params(document: Document[ParseResultType]).returns(T.type_parameter(:T)),
|
58
62
|
).returns(T.type_parameter(:T))
|
59
63
|
end
|
60
64
|
def cache_fetch(request_name, &block)
|
@@ -93,7 +97,7 @@ module RubyLsp
|
|
93
97
|
@cache.clear
|
94
98
|
end
|
95
99
|
|
96
|
-
sig { abstract.returns(
|
100
|
+
sig { abstract.returns(ParseResultType) }
|
97
101
|
def parse; end
|
98
102
|
|
99
103
|
sig { abstract.returns(T::Boolean) }
|
@@ -104,115 +108,6 @@ module RubyLsp
|
|
104
108
|
Scanner.new(@source, @encoding)
|
105
109
|
end
|
106
110
|
|
107
|
-
sig do
|
108
|
-
params(
|
109
|
-
position: T::Hash[Symbol, T.untyped],
|
110
|
-
node_types: T::Array[T.class_of(Prism::Node)],
|
111
|
-
).returns(NodeContext)
|
112
|
-
end
|
113
|
-
def locate_node(position, node_types: [])
|
114
|
-
locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
|
115
|
-
end
|
116
|
-
|
117
|
-
sig do
|
118
|
-
params(
|
119
|
-
node: Prism::Node,
|
120
|
-
char_position: Integer,
|
121
|
-
node_types: T::Array[T.class_of(Prism::Node)],
|
122
|
-
).returns(NodeContext)
|
123
|
-
end
|
124
|
-
def locate(node, char_position, node_types: [])
|
125
|
-
queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
|
126
|
-
closest = node
|
127
|
-
parent = T.let(nil, T.nilable(Prism::Node))
|
128
|
-
nesting_nodes = T.let(
|
129
|
-
[],
|
130
|
-
T::Array[T.any(
|
131
|
-
Prism::ClassNode,
|
132
|
-
Prism::ModuleNode,
|
133
|
-
Prism::SingletonClassNode,
|
134
|
-
Prism::DefNode,
|
135
|
-
Prism::BlockNode,
|
136
|
-
Prism::LambdaNode,
|
137
|
-
Prism::ProgramNode,
|
138
|
-
)],
|
139
|
-
)
|
140
|
-
|
141
|
-
nesting_nodes << node if node.is_a?(Prism::ProgramNode)
|
142
|
-
call_node = T.let(nil, T.nilable(Prism::CallNode))
|
143
|
-
|
144
|
-
until queue.empty?
|
145
|
-
candidate = queue.shift
|
146
|
-
|
147
|
-
# Skip nil child nodes
|
148
|
-
next if candidate.nil?
|
149
|
-
|
150
|
-
# Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
|
151
|
-
# same order as the visiting mechanism, which means searching the child nodes before moving on to the next
|
152
|
-
# sibling
|
153
|
-
T.unsafe(queue).unshift(*candidate.child_nodes)
|
154
|
-
|
155
|
-
# Skip if the current node doesn't cover the desired position
|
156
|
-
loc = candidate.location
|
157
|
-
next unless (loc.start_offset...loc.end_offset).cover?(char_position)
|
158
|
-
|
159
|
-
# If the node's start character is already past the position, then we should've found the closest node
|
160
|
-
# already
|
161
|
-
break if char_position < loc.start_offset
|
162
|
-
|
163
|
-
# If the candidate starts after the end of the previous nesting level, then we've exited that nesting level and
|
164
|
-
# need to pop the stack
|
165
|
-
previous_level = nesting_nodes.last
|
166
|
-
nesting_nodes.pop if previous_level && loc.start_offset > previous_level.location.end_offset
|
167
|
-
|
168
|
-
# Keep track of the nesting where we found the target. This is used to determine the fully qualified name of the
|
169
|
-
# target when it is a constant
|
170
|
-
case candidate
|
171
|
-
when Prism::ClassNode, Prism::ModuleNode, Prism::SingletonClassNode, Prism::DefNode, Prism::BlockNode,
|
172
|
-
Prism::LambdaNode
|
173
|
-
nesting_nodes << candidate
|
174
|
-
end
|
175
|
-
|
176
|
-
if candidate.is_a?(Prism::CallNode)
|
177
|
-
arg_loc = candidate.arguments&.location
|
178
|
-
blk_loc = candidate.block&.location
|
179
|
-
if (arg_loc && (arg_loc.start_offset...arg_loc.end_offset).cover?(char_position)) ||
|
180
|
-
(blk_loc && (blk_loc.start_offset...blk_loc.end_offset).cover?(char_position))
|
181
|
-
call_node = candidate
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
# If there are node types to filter by, and the current node is not one of those types, then skip it
|
186
|
-
next if node_types.any? && node_types.none? { |type| candidate.class == type }
|
187
|
-
|
188
|
-
# If the current node is narrower than or equal to the previous closest node, then it is more precise
|
189
|
-
closest_loc = closest.location
|
190
|
-
if loc.end_offset - loc.start_offset <= closest_loc.end_offset - closest_loc.start_offset
|
191
|
-
parent = closest
|
192
|
-
closest = candidate
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
# When targeting the constant part of a class/module definition, we do not want the nesting to be duplicated. That
|
197
|
-
# is, when targeting Bar in the following example:
|
198
|
-
#
|
199
|
-
# ```ruby
|
200
|
-
# class Foo::Bar; end
|
201
|
-
# ```
|
202
|
-
# The correct target is `Foo::Bar` with an empty nesting. `Foo::Bar` should not appear in the nesting stack, even
|
203
|
-
# though the class/module node does indeed enclose the target, because it would lead to incorrect behavior
|
204
|
-
if closest.is_a?(Prism::ConstantReadNode) || closest.is_a?(Prism::ConstantPathNode)
|
205
|
-
last_level = nesting_nodes.last
|
206
|
-
|
207
|
-
if (last_level.is_a?(Prism::ModuleNode) || last_level.is_a?(Prism::ClassNode)) &&
|
208
|
-
last_level.constant_path == closest
|
209
|
-
nesting_nodes.pop
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
NodeContext.new(closest, parent, nesting_nodes, call_node)
|
214
|
-
end
|
215
|
-
|
216
111
|
class Scanner
|
217
112
|
extend T::Sig
|
218
113
|
|
@@ -4,15 +4,19 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
class ERBDocument < Document
|
6
6
|
extend T::Sig
|
7
|
+
extend T::Generic
|
7
8
|
|
8
|
-
|
9
|
+
ParseResultType = type_member { { fixed: Prism::ParseResult } }
|
10
|
+
|
11
|
+
sig { override.returns(ParseResultType) }
|
9
12
|
def parse
|
10
13
|
return @parse_result unless @needs_parsing
|
11
14
|
|
12
15
|
@needs_parsing = false
|
13
16
|
scanner = ERBScanner.new(@source)
|
14
17
|
scanner.scan
|
15
|
-
|
18
|
+
# assigning empty scopes to turn Prism into eval mode
|
19
|
+
@parse_result = Prism.parse(scanner.ruby, scopes: [[]])
|
16
20
|
end
|
17
21
|
|
18
22
|
sig { override.returns(T::Boolean) }
|
@@ -25,6 +29,16 @@ module RubyLsp
|
|
25
29
|
LanguageId::ERB
|
26
30
|
end
|
27
31
|
|
32
|
+
sig do
|
33
|
+
params(
|
34
|
+
position: T::Hash[Symbol, T.untyped],
|
35
|
+
node_types: T::Array[T.class_of(Prism::Node)],
|
36
|
+
).returns(NodeContext)
|
37
|
+
end
|
38
|
+
def locate_node(position, node_types: [])
|
39
|
+
RubyDocument.locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
|
40
|
+
end
|
41
|
+
|
28
42
|
class ERBScanner
|
29
43
|
extend T::Sig
|
30
44
|
|
@@ -93,7 +93,7 @@ module RubyLsp
|
|
93
93
|
@test_library = detect_test_library(direct_dependencies)
|
94
94
|
notifications << Notification.window_log_message("Detected test library: #{@test_library}")
|
95
95
|
|
96
|
-
@has_type_checker = detect_typechecker(
|
96
|
+
@has_type_checker = detect_typechecker(all_dependencies)
|
97
97
|
if @has_type_checker
|
98
98
|
notifications << Notification.window_log_message(
|
99
99
|
"Ruby LSP detected this is a Sorbet project and will defer to the Sorbet LSP for some functionality",
|
data/lib/ruby_lsp/internal.rb
CHANGED
@@ -36,6 +36,7 @@ require "ruby_lsp/node_context"
|
|
36
36
|
require "ruby_lsp/document"
|
37
37
|
require "ruby_lsp/ruby_document"
|
38
38
|
require "ruby_lsp/erb_document"
|
39
|
+
require "ruby_lsp/rbs_document"
|
39
40
|
require "ruby_lsp/store"
|
40
41
|
require "ruby_lsp/addon"
|
41
42
|
require "ruby_lsp/requests/support/rubocop_runner"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
class RBSDocument < Document
|
6
|
+
extend T::Sig
|
7
|
+
extend T::Generic
|
8
|
+
|
9
|
+
ParseResultType = type_member { { fixed: T::Array[RBS::AST::Declarations::Base] } }
|
10
|
+
|
11
|
+
sig { params(source: String, version: Integer, uri: URI::Generic, encoding: Encoding).void }
|
12
|
+
def initialize(source:, version:, uri:, encoding: Encoding::UTF_8)
|
13
|
+
@syntax_error = T.let(false, T::Boolean)
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { override.returns(ParseResultType) }
|
18
|
+
def parse
|
19
|
+
return @parse_result unless @needs_parsing
|
20
|
+
|
21
|
+
@needs_parsing = false
|
22
|
+
|
23
|
+
_, _, declarations = RBS::Parser.parse_signature(@source)
|
24
|
+
@syntax_error = false
|
25
|
+
@parse_result = declarations
|
26
|
+
rescue RBS::ParsingError
|
27
|
+
@syntax_error = true
|
28
|
+
@parse_result
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { override.returns(T::Boolean) }
|
32
|
+
def syntax_error?
|
33
|
+
@syntax_error
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { override.returns(LanguageId) }
|
37
|
+
def language_id
|
38
|
+
LanguageId::RBS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -112,7 +112,7 @@ module RubyLsp
|
|
112
112
|
extracted_source = T.must(@document.source[start_index...end_index])
|
113
113
|
|
114
114
|
# Find the closest statements node, so that we place the refactor in a valid position
|
115
|
-
node_context =
|
115
|
+
node_context = RubyDocument
|
116
116
|
.locate(@document.parse_result.value, start_index, node_types: [Prism::StatementsNode, Prism::BlockNode])
|
117
117
|
|
118
118
|
closest_statements = node_context.node
|
@@ -206,28 +206,44 @@ module RubyLsp
|
|
206
206
|
extracted_source = T.must(@document.source[start_index...end_index])
|
207
207
|
|
208
208
|
# Find the closest method declaration node, so that we place the refactor in a valid position
|
209
|
-
node_context =
|
210
|
-
|
211
|
-
return Error::InvalidTargetRange
|
209
|
+
node_context = RubyDocument.locate(@document.parse_result.value, start_index, node_types: [Prism::DefNode])
|
210
|
+
closest_node = node_context.node
|
211
|
+
return Error::InvalidTargetRange unless closest_node
|
212
212
|
|
213
|
-
|
214
|
-
|
213
|
+
target_range = if closest_node.is_a?(Prism::DefNode)
|
214
|
+
end_keyword_loc = closest_node.end_keyword_loc
|
215
|
+
return Error::InvalidTargetRange unless end_keyword_loc
|
215
216
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
target_range = {
|
220
|
-
start: { line: end_line, character: character },
|
221
|
-
end: { line: end_line, character: character },
|
222
|
-
}
|
217
|
+
end_line = end_keyword_loc.end_line - 1
|
218
|
+
character = end_keyword_loc.end_column
|
219
|
+
indentation = " " * end_keyword_loc.start_column
|
223
220
|
|
224
|
-
|
221
|
+
new_method_source = <<~RUBY.chomp
|
225
222
|
|
226
223
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
224
|
+
#{indentation}def #{NEW_METHOD_NAME}
|
225
|
+
#{indentation} #{extracted_source}
|
226
|
+
#{indentation}end
|
227
|
+
RUBY
|
228
|
+
|
229
|
+
{
|
230
|
+
start: { line: end_line, character: character },
|
231
|
+
end: { line: end_line, character: character },
|
232
|
+
}
|
233
|
+
else
|
234
|
+
new_method_source = <<~RUBY
|
235
|
+
#{indentation}def #{NEW_METHOD_NAME}
|
236
|
+
#{indentation} #{extracted_source.gsub("\n", "\n ")}
|
237
|
+
#{indentation}end
|
238
|
+
|
239
|
+
RUBY
|
240
|
+
|
241
|
+
line = [0, source_range.dig(:start, :line) - 1].max
|
242
|
+
{
|
243
|
+
start: { line: line, character: source_range.dig(:start, :character) },
|
244
|
+
end: { line: line, character: source_range.dig(:start, :character) },
|
245
|
+
}
|
246
|
+
end
|
231
247
|
|
232
248
|
Interface::CodeAction.new(
|
233
249
|
title: CodeActions::EXTRACT_TO_METHOD_TITLE,
|
@@ -46,7 +46,7 @@ module RubyLsp
|
|
46
46
|
|
47
47
|
sig do
|
48
48
|
params(
|
49
|
-
document:
|
49
|
+
document: T.any(RubyDocument, ERBDocument),
|
50
50
|
global_state: GlobalState,
|
51
51
|
params: T::Hash[Symbol, T.untyped],
|
52
52
|
sorbet_level: RubyDocument::SorbetLevel,
|
@@ -60,7 +60,7 @@ module RubyLsp
|
|
60
60
|
# Completion always receives the position immediately after the character that was just typed. Here we adjust it
|
61
61
|
# back by 1, so that we find the right node
|
62
62
|
char_position = document.create_scanner.find_char_position(params[:position]) - 1
|
63
|
-
node_context =
|
63
|
+
node_context = RubyDocument.locate(
|
64
64
|
document.parse_result.value,
|
65
65
|
char_position,
|
66
66
|
node_types: [
|
@@ -32,7 +32,7 @@ module RubyLsp
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
sig { params(global_state: GlobalState, document:
|
35
|
+
sig { params(global_state: GlobalState, document: RubyDocument).void }
|
36
36
|
def initialize(global_state, document)
|
37
37
|
super()
|
38
38
|
@active_linters = T.let(global_state.active_linters, T::Array[Support::Formatter])
|
@@ -23,7 +23,8 @@ module RubyLsp
|
|
23
23
|
class SelectionRanges < Request
|
24
24
|
extend T::Sig
|
25
25
|
include Support::Common
|
26
|
-
|
26
|
+
|
27
|
+
sig { params(document: T.any(RubyDocument, ERBDocument)).void }
|
27
28
|
def initialize(document)
|
28
29
|
super()
|
29
30
|
@document = document
|
@@ -20,7 +20,7 @@ module RubyLsp
|
|
20
20
|
class ShowSyntaxTree < Request
|
21
21
|
extend T::Sig
|
22
22
|
|
23
|
-
sig { params(document:
|
23
|
+
sig { params(document: RubyDocument, range: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
24
24
|
def initialize(document, range)
|
25
25
|
super()
|
26
26
|
@document = document
|
@@ -10,13 +10,13 @@ module RubyLsp
|
|
10
10
|
|
11
11
|
interface!
|
12
12
|
|
13
|
-
sig { abstract.params(uri: URI::Generic, document:
|
13
|
+
sig { abstract.params(uri: URI::Generic, document: RubyDocument).returns(T.nilable(String)) }
|
14
14
|
def run_formatting(uri, document); end
|
15
15
|
|
16
16
|
sig do
|
17
17
|
abstract.params(
|
18
18
|
uri: URI::Generic,
|
19
|
-
document:
|
19
|
+
document: RubyDocument,
|
20
20
|
).returns(T.nilable(T::Array[Interface::Diagnostic]))
|
21
21
|
end
|
22
22
|
def run_diagnostic(uri, document); end
|
@@ -31,7 +31,7 @@ module RubyLsp
|
|
31
31
|
|
32
32
|
# TODO: avoid passing document once we have alternative ways to get at
|
33
33
|
# encoding and file source
|
34
|
-
sig { params(document:
|
34
|
+
sig { params(document: RubyDocument, offense: RuboCop::Cop::Offense, uri: URI::Generic).void }
|
35
35
|
def initialize(document, offense, uri)
|
36
36
|
@document = document
|
37
37
|
@offense = offense
|
@@ -17,7 +17,7 @@ module RubyLsp
|
|
17
17
|
@format_runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
|
18
18
|
end
|
19
19
|
|
20
|
-
sig { override.params(uri: URI::Generic, document:
|
20
|
+
sig { override.params(uri: URI::Generic, document: RubyDocument).returns(T.nilable(String)) }
|
21
21
|
def run_formatting(uri, document)
|
22
22
|
filename = T.must(uri.to_standardized_path || uri.opaque)
|
23
23
|
|
@@ -29,7 +29,7 @@ module RubyLsp
|
|
29
29
|
sig do
|
30
30
|
override.params(
|
31
31
|
uri: URI::Generic,
|
32
|
-
document:
|
32
|
+
document: RubyDocument,
|
33
33
|
).returns(T.nilable(T::Array[Interface::Diagnostic]))
|
34
34
|
end
|
35
35
|
def run_diagnostic(uri, document)
|
@@ -29,7 +29,7 @@ module RubyLsp
|
|
29
29
|
)
|
30
30
|
end
|
31
31
|
|
32
|
-
sig { override.params(uri: URI::Generic, document:
|
32
|
+
sig { override.params(uri: URI::Generic, document: RubyDocument).returns(T.nilable(String)) }
|
33
33
|
def run_formatting(uri, document)
|
34
34
|
path = uri.to_standardized_path
|
35
35
|
return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
|
@@ -40,7 +40,7 @@ module RubyLsp
|
|
40
40
|
sig do
|
41
41
|
override.params(
|
42
42
|
uri: URI::Generic,
|
43
|
-
document:
|
43
|
+
document: RubyDocument,
|
44
44
|
).returns(T.nilable(T::Array[Interface::Diagnostic]))
|
45
45
|
end
|
46
46
|
def run_diagnostic(uri, document)
|
@@ -3,6 +3,11 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
class RubyDocument < Document
|
6
|
+
extend T::Sig
|
7
|
+
extend T::Generic
|
8
|
+
|
9
|
+
ParseResultType = type_member { { fixed: Prism::ParseResult } }
|
10
|
+
|
6
11
|
class SorbetLevel < T::Enum
|
7
12
|
enums do
|
8
13
|
None = new("none")
|
@@ -13,7 +18,110 @@ module RubyLsp
|
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
16
|
-
|
21
|
+
class << self
|
22
|
+
extend T::Sig
|
23
|
+
|
24
|
+
sig do
|
25
|
+
params(
|
26
|
+
node: Prism::Node,
|
27
|
+
char_position: Integer,
|
28
|
+
node_types: T::Array[T.class_of(Prism::Node)],
|
29
|
+
).returns(NodeContext)
|
30
|
+
end
|
31
|
+
def locate(node, char_position, node_types: [])
|
32
|
+
queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
|
33
|
+
closest = node
|
34
|
+
parent = T.let(nil, T.nilable(Prism::Node))
|
35
|
+
nesting_nodes = T.let(
|
36
|
+
[],
|
37
|
+
T::Array[T.any(
|
38
|
+
Prism::ClassNode,
|
39
|
+
Prism::ModuleNode,
|
40
|
+
Prism::SingletonClassNode,
|
41
|
+
Prism::DefNode,
|
42
|
+
Prism::BlockNode,
|
43
|
+
Prism::LambdaNode,
|
44
|
+
Prism::ProgramNode,
|
45
|
+
)],
|
46
|
+
)
|
47
|
+
|
48
|
+
nesting_nodes << node if node.is_a?(Prism::ProgramNode)
|
49
|
+
call_node = T.let(nil, T.nilable(Prism::CallNode))
|
50
|
+
|
51
|
+
until queue.empty?
|
52
|
+
candidate = queue.shift
|
53
|
+
|
54
|
+
# Skip nil child nodes
|
55
|
+
next if candidate.nil?
|
56
|
+
|
57
|
+
# Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
|
58
|
+
# same order as the visiting mechanism, which means searching the child nodes before moving on to the next
|
59
|
+
# sibling
|
60
|
+
T.unsafe(queue).unshift(*candidate.child_nodes)
|
61
|
+
|
62
|
+
# Skip if the current node doesn't cover the desired position
|
63
|
+
loc = candidate.location
|
64
|
+
next unless (loc.start_offset...loc.end_offset).cover?(char_position)
|
65
|
+
|
66
|
+
# If the node's start character is already past the position, then we should've found the closest node
|
67
|
+
# already
|
68
|
+
break if char_position < loc.start_offset
|
69
|
+
|
70
|
+
# If the candidate starts after the end of the previous nesting level, then we've exited that nesting level
|
71
|
+
# and need to pop the stack
|
72
|
+
previous_level = nesting_nodes.last
|
73
|
+
nesting_nodes.pop if previous_level && loc.start_offset > previous_level.location.end_offset
|
74
|
+
|
75
|
+
# Keep track of the nesting where we found the target. This is used to determine the fully qualified name of
|
76
|
+
# the target when it is a constant
|
77
|
+
case candidate
|
78
|
+
when Prism::ClassNode, Prism::ModuleNode, Prism::SingletonClassNode, Prism::DefNode, Prism::BlockNode,
|
79
|
+
Prism::LambdaNode
|
80
|
+
nesting_nodes << candidate
|
81
|
+
end
|
82
|
+
|
83
|
+
if candidate.is_a?(Prism::CallNode)
|
84
|
+
arg_loc = candidate.arguments&.location
|
85
|
+
blk_loc = candidate.block&.location
|
86
|
+
if (arg_loc && (arg_loc.start_offset...arg_loc.end_offset).cover?(char_position)) ||
|
87
|
+
(blk_loc && (blk_loc.start_offset...blk_loc.end_offset).cover?(char_position))
|
88
|
+
call_node = candidate
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# If there are node types to filter by, and the current node is not one of those types, then skip it
|
93
|
+
next if node_types.any? && node_types.none? { |type| candidate.class == type }
|
94
|
+
|
95
|
+
# If the current node is narrower than or equal to the previous closest node, then it is more precise
|
96
|
+
closest_loc = closest.location
|
97
|
+
if loc.end_offset - loc.start_offset <= closest_loc.end_offset - closest_loc.start_offset
|
98
|
+
parent = closest
|
99
|
+
closest = candidate
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# When targeting the constant part of a class/module definition, we do not want the nesting to be duplicated.
|
104
|
+
# That is, when targeting Bar in the following example:
|
105
|
+
#
|
106
|
+
# ```ruby
|
107
|
+
# class Foo::Bar; end
|
108
|
+
# ```
|
109
|
+
# The correct target is `Foo::Bar` with an empty nesting. `Foo::Bar` should not appear in the nesting stack,
|
110
|
+
# even though the class/module node does indeed enclose the target, because it would lead to incorrect behavior
|
111
|
+
if closest.is_a?(Prism::ConstantReadNode) || closest.is_a?(Prism::ConstantPathNode)
|
112
|
+
last_level = nesting_nodes.last
|
113
|
+
|
114
|
+
if (last_level.is_a?(Prism::ModuleNode) || last_level.is_a?(Prism::ClassNode)) &&
|
115
|
+
last_level.constant_path == closest
|
116
|
+
nesting_nodes.pop
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
NodeContext.new(closest, parent, nesting_nodes, call_node)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
sig { override.returns(ParseResultType) }
|
17
125
|
def parse
|
18
126
|
return @parse_result unless @needs_parsing
|
19
127
|
|
@@ -84,5 +192,15 @@ module RubyLsp
|
|
84
192
|
end
|
85
193
|
end
|
86
194
|
end
|
195
|
+
|
196
|
+
sig do
|
197
|
+
params(
|
198
|
+
position: T::Hash[Symbol, T.untyped],
|
199
|
+
node_types: T::Array[T.class_of(Prism::Node)],
|
200
|
+
).returns(NodeContext)
|
201
|
+
end
|
202
|
+
def locate_node(position, node_types: [])
|
203
|
+
RubyDocument.locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
|
204
|
+
end
|
87
205
|
end
|
88
206
|
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -298,9 +298,12 @@ module RubyLsp
|
|
298
298
|
language_id = case text_document[:languageId]
|
299
299
|
when "erb", "eruby"
|
300
300
|
Document::LanguageId::ERB
|
301
|
+
when "rbs"
|
302
|
+
Document::LanguageId::RBS
|
301
303
|
else
|
302
304
|
Document::LanguageId::Ruby
|
303
305
|
end
|
306
|
+
|
304
307
|
@store.set(
|
305
308
|
uri: text_document[:uri],
|
306
309
|
source: text_document[:text],
|
@@ -341,7 +344,12 @@ module RubyLsp
|
|
341
344
|
def text_document_selection_range(message)
|
342
345
|
uri = message.dig(:params, :textDocument, :uri)
|
343
346
|
ranges = @store.cache_fetch(uri, "textDocument/selectionRange") do |document|
|
344
|
-
|
347
|
+
case document
|
348
|
+
when RubyDocument, ERBDocument
|
349
|
+
Requests::SelectionRanges.new(document).perform
|
350
|
+
else
|
351
|
+
[]
|
352
|
+
end
|
345
353
|
end
|
346
354
|
|
347
355
|
# Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
|
@@ -363,6 +371,11 @@ module RubyLsp
|
|
363
371
|
uri = URI(message.dig(:params, :textDocument, :uri))
|
364
372
|
document = @store.get(uri)
|
365
373
|
|
374
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
375
|
+
send_empty_response(message[:id])
|
376
|
+
return
|
377
|
+
end
|
378
|
+
|
366
379
|
# If the response has already been cached by another request, return it
|
367
380
|
cached_response = document.cache_get(message[:method])
|
368
381
|
if cached_response
|
@@ -407,6 +420,12 @@ module RubyLsp
|
|
407
420
|
range = params[:range]
|
408
421
|
uri = params.dig(:textDocument, :uri)
|
409
422
|
document = @store.get(uri)
|
423
|
+
|
424
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
425
|
+
send_empty_response(message[:id])
|
426
|
+
return
|
427
|
+
end
|
428
|
+
|
410
429
|
start_line = range.dig(:start, :line)
|
411
430
|
end_line = range.dig(:end, :line)
|
412
431
|
|
@@ -436,6 +455,10 @@ module RubyLsp
|
|
436
455
|
end
|
437
456
|
|
438
457
|
document = @store.get(uri)
|
458
|
+
unless document.is_a?(RubyDocument)
|
459
|
+
send_empty_response(message[:id])
|
460
|
+
return
|
461
|
+
end
|
439
462
|
|
440
463
|
response = Requests::Formatting.new(@global_state, document).perform
|
441
464
|
send_message(Result.new(id: message[:id], response: response))
|
@@ -452,6 +475,12 @@ module RubyLsp
|
|
452
475
|
params = message[:params]
|
453
476
|
dispatcher = Prism::Dispatcher.new
|
454
477
|
document = @store.get(params.dig(:textDocument, :uri))
|
478
|
+
|
479
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
480
|
+
send_empty_response(message[:id])
|
481
|
+
return
|
482
|
+
end
|
483
|
+
|
455
484
|
request = Requests::DocumentHighlight.new(document, params[:position], dispatcher)
|
456
485
|
dispatcher.dispatch(document.parse_result.value)
|
457
486
|
send_message(Result.new(id: message[:id], response: request.perform))
|
@@ -462,6 +491,11 @@ module RubyLsp
|
|
462
491
|
params = message[:params]
|
463
492
|
document = @store.get(params.dig(:textDocument, :uri))
|
464
493
|
|
494
|
+
unless document.is_a?(RubyDocument)
|
495
|
+
send_empty_response(message[:id])
|
496
|
+
return
|
497
|
+
end
|
498
|
+
|
465
499
|
send_message(
|
466
500
|
Result.new(
|
467
501
|
id: message[:id],
|
@@ -481,6 +515,11 @@ module RubyLsp
|
|
481
515
|
dispatcher = Prism::Dispatcher.new
|
482
516
|
document = @store.get(params.dig(:textDocument, :uri))
|
483
517
|
|
518
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
519
|
+
send_empty_response(message[:id])
|
520
|
+
return
|
521
|
+
end
|
522
|
+
|
484
523
|
send_message(
|
485
524
|
Result.new(
|
486
525
|
id: message[:id],
|
@@ -495,7 +534,7 @@ module RubyLsp
|
|
495
534
|
)
|
496
535
|
end
|
497
536
|
|
498
|
-
sig { params(document: Document).returns(RubyDocument::SorbetLevel) }
|
537
|
+
sig { params(document: Document[T.untyped]).returns(RubyDocument::SorbetLevel) }
|
499
538
|
def sorbet_level(document)
|
500
539
|
return RubyDocument::SorbetLevel::Ignore unless @global_state.has_type_checker
|
501
540
|
return RubyDocument::SorbetLevel::Ignore unless document.is_a?(RubyDocument)
|
@@ -509,6 +548,12 @@ module RubyLsp
|
|
509
548
|
hints_configurations = T.must(@store.features_configuration.dig(:inlayHint))
|
510
549
|
dispatcher = Prism::Dispatcher.new
|
511
550
|
document = @store.get(params.dig(:textDocument, :uri))
|
551
|
+
|
552
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
553
|
+
send_empty_response(message[:id])
|
554
|
+
return
|
555
|
+
end
|
556
|
+
|
512
557
|
request = Requests::InlayHints.new(document, params[:range], hints_configurations, dispatcher)
|
513
558
|
dispatcher.visit(document.parse_result.value)
|
514
559
|
send_message(Result.new(id: message[:id], response: request.perform))
|
@@ -519,6 +564,11 @@ module RubyLsp
|
|
519
564
|
params = message[:params]
|
520
565
|
document = @store.get(params.dig(:textDocument, :uri))
|
521
566
|
|
567
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
568
|
+
send_empty_response(message[:id])
|
569
|
+
return
|
570
|
+
end
|
571
|
+
|
522
572
|
send_message(
|
523
573
|
Result.new(
|
524
574
|
id: message[:id],
|
@@ -581,7 +631,10 @@ module RubyLsp
|
|
581
631
|
document = @store.get(uri)
|
582
632
|
|
583
633
|
response = document.cache_fetch("textDocument/diagnostic") do |document|
|
584
|
-
|
634
|
+
case document
|
635
|
+
when RubyDocument
|
636
|
+
Requests::Diagnostics.new(@global_state, document).perform
|
637
|
+
end
|
585
638
|
end
|
586
639
|
|
587
640
|
send_message(
|
@@ -604,6 +657,11 @@ module RubyLsp
|
|
604
657
|
dispatcher = Prism::Dispatcher.new
|
605
658
|
document = @store.get(params.dig(:textDocument, :uri))
|
606
659
|
|
660
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
661
|
+
send_empty_response(message[:id])
|
662
|
+
return
|
663
|
+
end
|
664
|
+
|
607
665
|
send_message(
|
608
666
|
Result.new(
|
609
667
|
id: message[:id],
|
@@ -632,6 +690,11 @@ module RubyLsp
|
|
632
690
|
dispatcher = Prism::Dispatcher.new
|
633
691
|
document = @store.get(params.dig(:textDocument, :uri))
|
634
692
|
|
693
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
694
|
+
send_empty_response(message[:id])
|
695
|
+
return
|
696
|
+
end
|
697
|
+
|
635
698
|
send_message(
|
636
699
|
Result.new(
|
637
700
|
id: message[:id],
|
@@ -653,6 +716,11 @@ module RubyLsp
|
|
653
716
|
dispatcher = Prism::Dispatcher.new
|
654
717
|
document = @store.get(params.dig(:textDocument, :uri))
|
655
718
|
|
719
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
720
|
+
send_empty_response(message[:id])
|
721
|
+
return
|
722
|
+
end
|
723
|
+
|
656
724
|
send_message(
|
657
725
|
Result.new(
|
658
726
|
id: message[:id],
|
@@ -710,9 +778,16 @@ module RubyLsp
|
|
710
778
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
711
779
|
def text_document_show_syntax_tree(message)
|
712
780
|
params = message[:params]
|
781
|
+
document = @store.get(params.dig(:textDocument, :uri))
|
782
|
+
|
783
|
+
unless document.is_a?(RubyDocument)
|
784
|
+
send_empty_response(message[:id])
|
785
|
+
return
|
786
|
+
end
|
787
|
+
|
713
788
|
response = {
|
714
789
|
ast: Requests::ShowSyntaxTree.new(
|
715
|
-
|
790
|
+
document,
|
716
791
|
params[:range],
|
717
792
|
).perform,
|
718
793
|
}
|
@@ -722,11 +797,19 @@ module RubyLsp
|
|
722
797
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
723
798
|
def text_document_prepare_type_hierarchy(message)
|
724
799
|
params = message[:params]
|
800
|
+
document = @store.get(params.dig(:textDocument, :uri))
|
801
|
+
|
802
|
+
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
803
|
+
send_empty_response(message[:id])
|
804
|
+
return
|
805
|
+
end
|
806
|
+
|
725
807
|
response = Requests::PrepareTypeHierarchy.new(
|
726
|
-
|
808
|
+
document,
|
727
809
|
@global_state.index,
|
728
810
|
params[:position],
|
729
811
|
).perform
|
812
|
+
|
730
813
|
send_message(Result.new(id: message[:id], response: response))
|
731
814
|
end
|
732
815
|
|
@@ -793,6 +876,11 @@ module RubyLsp
|
|
793
876
|
send_message(Notification.window_show_error("Error while indexing: #{error.message}"))
|
794
877
|
end
|
795
878
|
|
879
|
+
# Indexing produces a high number of short lived object allocations. That might lead to some fragmentation and
|
880
|
+
# an unnecessarily expanded heap. Compacting ensures that the heap is as small as possible and that future
|
881
|
+
# allocations and garbage collections are faster
|
882
|
+
GC.compact
|
883
|
+
|
796
884
|
# Always end the progress notification even if indexing failed or else it never goes away and the user has no
|
797
885
|
# way of dismissing it
|
798
886
|
end_progress("indexing-progress")
|
@@ -50,6 +50,7 @@ module RubyLsp
|
|
50
50
|
@last_updated_path = T.let(@custom_dir + "last_updated", Pathname)
|
51
51
|
|
52
52
|
@dependencies = T.let(load_dependencies, T::Hash[String, T.untyped])
|
53
|
+
@rails_app = T.let(rails_app?, T::Boolean)
|
53
54
|
@retry = T.let(false, T::Boolean)
|
54
55
|
end
|
55
56
|
|
@@ -62,7 +63,7 @@ module RubyLsp
|
|
62
63
|
# Do not set up a custom bundle if LSP dependencies are already in the Gemfile
|
63
64
|
if @dependencies["ruby-lsp"] &&
|
64
65
|
@dependencies["debug"] &&
|
65
|
-
(@
|
66
|
+
(@rails_app ? @dependencies["ruby-lsp-rails"] : true)
|
66
67
|
$stderr.puts(
|
67
68
|
"Ruby LSP> Skipping custom bundle setup since LSP dependencies are already in #{@gemfile}",
|
68
69
|
)
|
@@ -148,7 +149,7 @@ module RubyLsp
|
|
148
149
|
parts << 'gem "debug", require: false, group: :development, platforms: :mri'
|
149
150
|
end
|
150
151
|
|
151
|
-
if @
|
152
|
+
if @rails_app && !@dependencies["ruby-lsp-rails"]
|
152
153
|
parts << 'gem "ruby-lsp-rails", require: false, group: :development'
|
153
154
|
end
|
154
155
|
|
@@ -209,7 +210,7 @@ module RubyLsp
|
|
209
210
|
command << " && bundle update "
|
210
211
|
command << "ruby-lsp " unless @dependencies["ruby-lsp"]
|
211
212
|
command << "debug " unless @dependencies["debug"]
|
212
|
-
command << "ruby-lsp-rails " if @
|
213
|
+
command << "ruby-lsp-rails " if @rails_app && !@dependencies["ruby-lsp-rails"]
|
213
214
|
command << "--pre" if @experimental
|
214
215
|
command.delete_suffix!(" ")
|
215
216
|
command << ")"
|
@@ -244,7 +245,7 @@ module RubyLsp
|
|
244
245
|
def should_bundle_update?
|
245
246
|
# If `ruby-lsp`, `ruby-lsp-rails` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it
|
246
247
|
# will produce version control changes
|
247
|
-
if @
|
248
|
+
if @rails_app
|
248
249
|
return false if @dependencies.values_at("ruby-lsp", "ruby-lsp-rails", "debug").all?
|
249
250
|
|
250
251
|
# If the custom lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle install
|
@@ -280,5 +281,15 @@ module RubyLsp
|
|
280
281
|
|
281
282
|
@custom_lockfile.write(content)
|
282
283
|
end
|
284
|
+
|
285
|
+
# Detects if the project is a Rails app by looking if the superclass of the main class is `Rails::Application`
|
286
|
+
sig { returns(T::Boolean) }
|
287
|
+
def rails_app?
|
288
|
+
config = Pathname.new("config/application.rb").expand_path
|
289
|
+
application_contents = config.read if config.exist?
|
290
|
+
return false unless application_contents
|
291
|
+
|
292
|
+
/class .* < (::)?Rails::Application/.match?(application_contents)
|
293
|
+
end
|
283
294
|
end
|
284
295
|
end
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -18,7 +18,7 @@ module RubyLsp
|
|
18
18
|
|
19
19
|
sig { void }
|
20
20
|
def initialize
|
21
|
-
@state = T.let({}, T::Hash[String, Document])
|
21
|
+
@state = T.let({}, T::Hash[String, Document[T.untyped]])
|
22
22
|
@supports_progress = T.let(true, T::Boolean)
|
23
23
|
@features_configuration = T.let(
|
24
24
|
{
|
@@ -33,7 +33,7 @@ module RubyLsp
|
|
33
33
|
@client_name = T.let("Unknown", String)
|
34
34
|
end
|
35
35
|
|
36
|
-
sig { params(uri: URI::Generic).returns(Document) }
|
36
|
+
sig { params(uri: URI::Generic).returns(Document[T.untyped]) }
|
37
37
|
def get(uri)
|
38
38
|
document = @state[uri.to_s]
|
39
39
|
return document unless document.nil?
|
@@ -44,8 +44,11 @@ module RubyLsp
|
|
44
44
|
raise NonExistingDocumentError, uri.to_s unless path
|
45
45
|
|
46
46
|
ext = File.extname(path)
|
47
|
-
language_id =
|
47
|
+
language_id = case ext
|
48
|
+
when ".erb", ".rhtml"
|
48
49
|
Document::LanguageId::ERB
|
50
|
+
when ".rbs"
|
51
|
+
Document::LanguageId::RBS
|
49
52
|
else
|
50
53
|
Document::LanguageId::Ruby
|
51
54
|
end
|
@@ -66,13 +69,14 @@ module RubyLsp
|
|
66
69
|
).void
|
67
70
|
end
|
68
71
|
def set(uri:, source:, version:, language_id:, encoding: Encoding::UTF_8)
|
69
|
-
|
72
|
+
@state[uri.to_s] = case language_id
|
70
73
|
when Document::LanguageId::ERB
|
71
74
|
ERBDocument.new(source: source, version: version, uri: uri, encoding: encoding)
|
75
|
+
when Document::LanguageId::RBS
|
76
|
+
RBSDocument.new(source: source, version: version, uri: uri, encoding: encoding)
|
72
77
|
else
|
73
78
|
RubyDocument.new(source: source, version: version, uri: uri, encoding: encoding)
|
74
79
|
end
|
75
|
-
@state[uri.to_s] = document
|
76
80
|
end
|
77
81
|
|
78
82
|
sig { params(uri: URI::Generic, edits: T::Array[T::Hash[Symbol, T.untyped]], version: Integer).void }
|
@@ -100,7 +104,7 @@ module RubyLsp
|
|
100
104
|
.params(
|
101
105
|
uri: URI::Generic,
|
102
106
|
request_name: String,
|
103
|
-
block: T.proc.params(document: Document).returns(T.type_parameter(:T)),
|
107
|
+
block: T.proc.params(document: Document[T.untyped]).returns(T.type_parameter(:T)),
|
104
108
|
).returns(T.type_parameter(:T))
|
105
109
|
end
|
106
110
|
def cache_fetch(uri, request_name, &block)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.17.
|
4
|
+
version: 0.17.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- lib/ruby_lsp/load_sorbet.rb
|
138
138
|
- lib/ruby_lsp/node_context.rb
|
139
139
|
- lib/ruby_lsp/parameter_scope.rb
|
140
|
+
- lib/ruby_lsp/rbs_document.rb
|
140
141
|
- lib/ruby_lsp/requests.rb
|
141
142
|
- lib/ruby_lsp/requests/code_action_resolve.rb
|
142
143
|
- lib/ruby_lsp/requests/code_actions.rb
|