ruby-lsp 0.17.13 → 0.17.14
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/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
|