ruby-lsp 0.19.1 → 0.20.1
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 +7 -1
- data/lib/core_ext/uri.rb +2 -2
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +63 -12
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +85 -36
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +5 -1
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +39 -98
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +12 -19
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +22 -0
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -7
- data/lib/ruby_indexer/test/enhancements_test.rb +5 -7
- data/lib/ruby_indexer/test/global_variable_test.rb +49 -0
- data/lib/ruby_indexer/test/index_test.rb +89 -0
- data/lib/ruby_lsp/erb_document.rb +15 -2
- data/lib/ruby_lsp/listeners/definition.rb +20 -0
- data/lib/ruby_lsp/listeners/folding_ranges.rb +3 -3
- data/lib/ruby_lsp/requests/code_action_resolve.rb +8 -2
- data/lib/ruby_lsp/requests/completion.rb +1 -1
- data/lib/ruby_lsp/requests/definition.rb +2 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +5 -1
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/range_formatting.rb +4 -2
- data/lib/ruby_lsp/requests/references.rb +3 -1
- data/lib/ruby_lsp/requests/rename.rb +3 -1
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -6
- data/lib/ruby_lsp/response_builders/document_symbol.rb +2 -2
- data/lib/ruby_lsp/response_builders/hover.rb +2 -2
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +14 -8
- data/lib/ruby_lsp/response_builders/signature_help.rb +2 -2
- data/lib/ruby_lsp/ruby_document.rb +33 -12
- data/lib/ruby_lsp/setup_bundler.rb +30 -8
- data/lib/ruby_lsp/type_inferrer.rb +1 -1
- metadata +6 -5
@@ -39,6 +39,7 @@ module RubyLsp
|
|
39
39
|
:on_block_argument_node_enter,
|
40
40
|
:on_constant_read_node_enter,
|
41
41
|
:on_constant_path_node_enter,
|
42
|
+
:on_global_variable_read_node_enter,
|
42
43
|
:on_instance_variable_read_node_enter,
|
43
44
|
:on_instance_variable_write_node_enter,
|
44
45
|
:on_instance_variable_and_write_node_enter,
|
@@ -120,6 +121,25 @@ module RubyLsp
|
|
120
121
|
find_in_index(name)
|
121
122
|
end
|
122
123
|
|
124
|
+
sig { params(node: Prism::GlobalVariableReadNode).void }
|
125
|
+
def on_global_variable_read_node_enter(node)
|
126
|
+
entries = @index[node.name.to_s]
|
127
|
+
|
128
|
+
return unless entries
|
129
|
+
|
130
|
+
entries.each do |entry|
|
131
|
+
location = entry.location
|
132
|
+
|
133
|
+
@response_builder << Interface::Location.new(
|
134
|
+
uri: URI::Generic.from_path(path: entry.file_path).to_s,
|
135
|
+
range: Interface::Range.new(
|
136
|
+
start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
|
137
|
+
end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
|
138
|
+
),
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
123
143
|
sig { params(node: Prism::InstanceVariableReadNode).void }
|
124
144
|
def on_instance_variable_read_node_enter(node)
|
125
145
|
handle_instance_variable_definition(node.name.to_s)
|
@@ -239,10 +239,10 @@ module RubyLsp
|
|
239
239
|
statements = node.statements
|
240
240
|
return unless statements
|
241
241
|
|
242
|
-
|
243
|
-
return
|
242
|
+
statement = statements.body.last
|
243
|
+
return unless statement
|
244
244
|
|
245
|
-
add_lines_range(node.location.start_line,
|
245
|
+
add_lines_range(node.location.start_line, statement.location.end_line)
|
246
246
|
end
|
247
247
|
|
248
248
|
sig { params(node: Prism::Node).void }
|
@@ -99,7 +99,13 @@ module RubyLsp
|
|
99
99
|
|
100
100
|
# Find the closest statements node, so that we place the refactor in a valid position
|
101
101
|
node_context = RubyDocument
|
102
|
-
.locate(@document.parse_result.value,
|
102
|
+
.locate(@document.parse_result.value,
|
103
|
+
start_index,
|
104
|
+
node_types: [
|
105
|
+
Prism::StatementsNode,
|
106
|
+
Prism::BlockNode,
|
107
|
+
],
|
108
|
+
code_units_cache: @document.code_units_cache)
|
103
109
|
|
104
110
|
closest_statements = node_context.node
|
105
111
|
parent_statements = node_context.parent
|
@@ -196,7 +202,7 @@ module RubyLsp
|
|
196
202
|
@document.parse_result.value,
|
197
203
|
start_index,
|
198
204
|
node_types: [Prism::DefNode],
|
199
|
-
|
205
|
+
code_units_cache: @document.code_units_cache,
|
200
206
|
)
|
201
207
|
closest_node = node_context.node
|
202
208
|
return Error::InvalidTargetRange unless closest_node
|
@@ -57,7 +57,7 @@ module RubyLsp
|
|
57
57
|
Prism::InstanceVariableTargetNode,
|
58
58
|
Prism::InstanceVariableWriteNode,
|
59
59
|
],
|
60
|
-
|
60
|
+
code_units_cache: document.code_units_cache,
|
61
61
|
)
|
62
62
|
@response_builder = T.let(
|
63
63
|
ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem].new,
|
@@ -46,6 +46,7 @@ module RubyLsp
|
|
46
46
|
Prism::ConstantReadNode,
|
47
47
|
Prism::ConstantPathNode,
|
48
48
|
Prism::BlockArgumentNode,
|
49
|
+
Prism::GlobalVariableReadNode,
|
49
50
|
Prism::InstanceVariableReadNode,
|
50
51
|
Prism::InstanceVariableAndWriteNode,
|
51
52
|
Prism::InstanceVariableOperatorWriteNode,
|
@@ -57,7 +58,7 @@ module RubyLsp
|
|
57
58
|
Prism::SuperNode,
|
58
59
|
Prism::ForwardingSuperNode,
|
59
60
|
],
|
60
|
-
|
61
|
+
code_units_cache: document.code_units_cache,
|
61
62
|
)
|
62
63
|
|
63
64
|
target = node_context.node
|
@@ -28,7 +28,11 @@ module RubyLsp
|
|
28
28
|
char_position = document.create_scanner.find_char_position(position)
|
29
29
|
delegate_request_if_needed!(global_state, document, char_position)
|
30
30
|
|
31
|
-
node_context = RubyDocument.locate(
|
31
|
+
node_context = RubyDocument.locate(
|
32
|
+
document.parse_result.value,
|
33
|
+
char_position,
|
34
|
+
code_units_cache: document.code_units_cache,
|
35
|
+
)
|
32
36
|
|
33
37
|
@response_builder = T.let(
|
34
38
|
ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight].new,
|
@@ -41,7 +41,7 @@ module RubyLsp
|
|
41
41
|
document.parse_result.value,
|
42
42
|
char_position,
|
43
43
|
node_types: Listeners::Hover::ALLOWED_TARGETS,
|
44
|
-
|
44
|
+
code_units_cache: document.code_units_cache,
|
45
45
|
)
|
46
46
|
target = node_context.node
|
47
47
|
parent = node_context.parent
|
@@ -34,16 +34,18 @@ module RubyLsp
|
|
34
34
|
)
|
35
35
|
return unless formatted_text
|
36
36
|
|
37
|
+
code_units_cache = @document.code_units_cache
|
38
|
+
|
37
39
|
[
|
38
40
|
Interface::TextEdit.new(
|
39
41
|
range: Interface::Range.new(
|
40
42
|
start: Interface::Position.new(
|
41
43
|
line: location.start_line - 1,
|
42
|
-
character: location.
|
44
|
+
character: location.cached_start_code_units_column(code_units_cache),
|
43
45
|
),
|
44
46
|
end: Interface::Position.new(
|
45
47
|
line: location.end_line - 1,
|
46
|
-
character: location.
|
48
|
+
character: location.cached_end_code_units_column(code_units_cache),
|
47
49
|
),
|
48
50
|
),
|
49
51
|
new_text: formatted_text.strip,
|
@@ -42,7 +42,7 @@ module RubyLsp
|
|
42
42
|
Prism::CallNode,
|
43
43
|
Prism::DefNode,
|
44
44
|
],
|
45
|
-
|
45
|
+
code_units_cache: @document.code_units_cache,
|
46
46
|
)
|
47
47
|
target = node_context.node
|
48
48
|
parent = node_context.parent
|
@@ -78,6 +78,8 @@ module RubyLsp
|
|
78
78
|
|
79
79
|
parse_result = Prism.parse_file(path)
|
80
80
|
collect_references(reference_target, parse_result, uri)
|
81
|
+
rescue Errno::EISDIR, Errno::ENOENT
|
82
|
+
# If `path` is a directory, just ignore it and continue. If the file doesn't exist, then we also ignore it.
|
81
83
|
end
|
82
84
|
|
83
85
|
@store.each do |_uri, document|
|
@@ -37,7 +37,7 @@ module RubyLsp
|
|
37
37
|
@document.parse_result.value,
|
38
38
|
char_position,
|
39
39
|
node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
|
40
|
-
|
40
|
+
code_units_cache: @document.code_units_cache,
|
41
41
|
)
|
42
42
|
target = node_context.node
|
43
43
|
parent = node_context.parent
|
@@ -147,6 +147,8 @@ module RubyLsp
|
|
147
147
|
parse_result = Prism.parse_file(path)
|
148
148
|
edits = collect_changes(target, parse_result, name, uri)
|
149
149
|
changes[uri.to_s] = edits unless edits.empty?
|
150
|
+
rescue Errno::EISDIR, Errno::ENOENT
|
151
|
+
# If `path` is a directory, just ignore it and continue. If the file doesn't exist, then we also ignore it.
|
150
152
|
end
|
151
153
|
|
152
154
|
@store.each do |uri, document|
|
@@ -101,7 +101,7 @@ module RubyLsp
|
|
101
101
|
@range = range
|
102
102
|
@result_id = T.let(SemanticHighlighting.next_result_id.to_s, String)
|
103
103
|
@response_builder = T.let(
|
104
|
-
ResponseBuilders::SemanticHighlighting.new(
|
104
|
+
ResponseBuilders::SemanticHighlighting.new(document.code_units_cache),
|
105
105
|
ResponseBuilders::SemanticHighlighting,
|
106
106
|
)
|
107
107
|
Listeners::SemanticHighlighting.new(dispatcher, @response_builder)
|
@@ -43,7 +43,7 @@ module RubyLsp
|
|
43
43
|
document.parse_result.value,
|
44
44
|
char_position,
|
45
45
|
node_types: [Prism::CallNode],
|
46
|
-
|
46
|
+
code_units_cache: document.code_units_cache,
|
47
47
|
)
|
48
48
|
|
49
49
|
target = adjust_for_nested_target(node_context.node, node_context.parent, position)
|
@@ -159,7 +159,7 @@ module RubyLsp
|
|
159
159
|
def namespace_constant_name(node)
|
160
160
|
path = node.constant_path
|
161
161
|
case path
|
162
|
-
when Prism::ConstantPathNode, Prism::ConstantReadNode
|
162
|
+
when Prism::ConstantPathNode, Prism::ConstantReadNode
|
163
163
|
constant_name(path)
|
164
164
|
end
|
165
165
|
end
|
@@ -47,12 +47,6 @@ module RubyLsp
|
|
47
47
|
|
48
48
|
class ConfigurationError < StandardError; end
|
49
49
|
|
50
|
-
sig { returns(T::Array[RuboCop::Cop::Offense]) }
|
51
|
-
attr_reader :offenses
|
52
|
-
|
53
|
-
sig { returns(::RuboCop::Config) }
|
54
|
-
attr_reader :config_for_working_directory
|
55
|
-
|
56
50
|
DEFAULT_ARGS = T.let(
|
57
51
|
[
|
58
52
|
"--stderr", # Print any output to stderr so that our stdout does not get polluted
|
@@ -63,6 +57,12 @@ module RubyLsp
|
|
63
57
|
T::Array[String],
|
64
58
|
)
|
65
59
|
|
60
|
+
sig { returns(T::Array[RuboCop::Cop::Offense]) }
|
61
|
+
attr_reader :offenses
|
62
|
+
|
63
|
+
sig { returns(::RuboCop::Config) }
|
64
|
+
attr_reader :config_for_working_directory
|
65
|
+
|
66
66
|
begin
|
67
67
|
RuboCop::Options.new.parse(["--raise-cop-error"])
|
68
68
|
DEFAULT_ARGS << "--raise-cop-error"
|
@@ -4,6 +4,8 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
module ResponseBuilders
|
6
6
|
class DocumentSymbol < ResponseBuilder
|
7
|
+
extend T::Sig
|
8
|
+
|
7
9
|
ResponseType = type_member { { fixed: T::Array[Interface::DocumentSymbol] } }
|
8
10
|
|
9
11
|
class SymbolHierarchyRoot
|
@@ -18,8 +20,6 @@ module RubyLsp
|
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
extend T::Sig
|
22
|
-
|
23
23
|
sig { void }
|
24
24
|
def initialize
|
25
25
|
super
|
@@ -4,11 +4,11 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
module ResponseBuilders
|
6
6
|
class Hover < ResponseBuilder
|
7
|
-
ResponseType = type_member { { fixed: String } }
|
8
|
-
|
9
7
|
extend T::Sig
|
10
8
|
extend T::Generic
|
11
9
|
|
10
|
+
ResponseType = type_member { { fixed: String } }
|
11
|
+
|
12
12
|
sig { void }
|
13
13
|
def initialize
|
14
14
|
super
|
@@ -6,6 +6,8 @@ module RubyLsp
|
|
6
6
|
class SemanticHighlighting < ResponseBuilder
|
7
7
|
class UndefinedTokenType < StandardError; end
|
8
8
|
|
9
|
+
extend T::Sig
|
10
|
+
|
9
11
|
TOKEN_TYPES = T.let(
|
10
12
|
{
|
11
13
|
namespace: 0,
|
@@ -51,25 +53,29 @@ module RubyLsp
|
|
51
53
|
T::Hash[Symbol, Integer],
|
52
54
|
)
|
53
55
|
|
54
|
-
extend T::Sig
|
55
|
-
|
56
56
|
ResponseType = type_member { { fixed: Interface::SemanticTokens } }
|
57
57
|
|
58
|
-
sig
|
59
|
-
|
58
|
+
sig do
|
59
|
+
params(code_units_cache: T.any(
|
60
|
+
T.proc.params(arg0: Integer).returns(Integer),
|
61
|
+
Prism::CodeUnitsCache,
|
62
|
+
)).void
|
63
|
+
end
|
64
|
+
def initialize(code_units_cache)
|
60
65
|
super()
|
61
|
-
@
|
66
|
+
@code_units_cache = code_units_cache
|
62
67
|
@stack = T.let([], T::Array[SemanticToken])
|
63
68
|
end
|
64
69
|
|
65
70
|
sig { params(location: Prism::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
|
66
71
|
def add_token(location, type, modifiers = [])
|
67
|
-
|
72
|
+
end_code_unit = location.cached_end_code_units_offset(@code_units_cache)
|
73
|
+
length = end_code_unit - location.cached_start_code_units_offset(@code_units_cache)
|
68
74
|
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
69
75
|
@stack.push(
|
70
76
|
SemanticToken.new(
|
71
77
|
start_line: location.start_line,
|
72
|
-
start_code_unit_column: location.
|
78
|
+
start_code_unit_column: location.cached_start_code_units_column(@code_units_cache),
|
73
79
|
length: length,
|
74
80
|
type: T.must(TOKEN_TYPES[type]),
|
75
81
|
modifier: modifiers_indices,
|
@@ -83,7 +89,7 @@ module RubyLsp
|
|
83
89
|
return false unless token
|
84
90
|
|
85
91
|
token.start_line == location.start_line &&
|
86
|
-
token.start_code_unit_column == location.
|
92
|
+
token.start_code_unit_column == location.cached_start_code_units_column(@code_units_cache)
|
87
93
|
end
|
88
94
|
|
89
95
|
sig { returns(T.nilable(SemanticToken)) }
|
@@ -4,10 +4,10 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
module ResponseBuilders
|
6
6
|
class SignatureHelp < ResponseBuilder
|
7
|
-
ResponseType = type_member { { fixed: T.nilable(Interface::SignatureHelp) } }
|
8
|
-
|
9
7
|
extend T::Sig
|
10
8
|
|
9
|
+
ResponseType = type_member { { fixed: T.nilable(Interface::SignatureHelp) } }
|
10
|
+
|
11
11
|
sig { void }
|
12
12
|
def initialize
|
13
13
|
super
|
@@ -25,11 +25,14 @@ module RubyLsp
|
|
25
25
|
params(
|
26
26
|
node: Prism::Node,
|
27
27
|
char_position: Integer,
|
28
|
+
code_units_cache: T.any(
|
29
|
+
T.proc.params(arg0: Integer).returns(Integer),
|
30
|
+
Prism::CodeUnitsCache,
|
31
|
+
),
|
28
32
|
node_types: T::Array[T.class_of(Prism::Node)],
|
29
|
-
encoding: Encoding,
|
30
33
|
).returns(NodeContext)
|
31
34
|
end
|
32
|
-
def locate(node, char_position, node_types: []
|
35
|
+
def locate(node, char_position, code_units_cache:, node_types: [])
|
33
36
|
queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
|
34
37
|
closest = node
|
35
38
|
parent = T.let(nil, T.nilable(Prism::Node))
|
@@ -62,8 +65,8 @@ module RubyLsp
|
|
62
65
|
|
63
66
|
# Skip if the current node doesn't cover the desired position
|
64
67
|
loc = candidate.location
|
65
|
-
loc_start_offset = loc.
|
66
|
-
loc_end_offset = loc.
|
68
|
+
loc_start_offset = loc.cached_start_code_units_offset(code_units_cache)
|
69
|
+
loc_end_offset = loc.cached_end_code_units_offset(code_units_cache)
|
67
70
|
next unless (loc_start_offset...loc_end_offset).cover?(char_position)
|
68
71
|
|
69
72
|
# If the node's start character is already past the position, then we should've found the closest node
|
@@ -74,7 +77,7 @@ module RubyLsp
|
|
74
77
|
# and need to pop the stack
|
75
78
|
previous_level = nesting_nodes.last
|
76
79
|
if previous_level &&
|
77
|
-
(loc_start_offset > previous_level.location.
|
80
|
+
(loc_start_offset > previous_level.location.cached_end_code_units_offset(code_units_cache))
|
78
81
|
nesting_nodes.pop
|
79
82
|
end
|
80
83
|
|
@@ -89,10 +92,10 @@ module RubyLsp
|
|
89
92
|
if candidate.is_a?(Prism::CallNode)
|
90
93
|
arg_loc = candidate.arguments&.location
|
91
94
|
blk_loc = candidate.block&.location
|
92
|
-
if (arg_loc && (arg_loc.
|
93
|
-
arg_loc.
|
94
|
-
(blk_loc && (blk_loc.
|
95
|
-
blk_loc.
|
95
|
+
if (arg_loc && (arg_loc.cached_start_code_units_offset(code_units_cache)...
|
96
|
+
arg_loc.cached_end_code_units_offset(code_units_cache)).cover?(char_position)) ||
|
97
|
+
(blk_loc && (blk_loc.cached_start_code_units_offset(code_units_cache)...
|
98
|
+
blk_loc.cached_end_code_units_offset(code_units_cache)).cover?(char_position))
|
96
99
|
call_node = candidate
|
97
100
|
end
|
98
101
|
end
|
@@ -102,8 +105,8 @@ module RubyLsp
|
|
102
105
|
|
103
106
|
# If the current node is narrower than or equal to the previous closest node, then it is more precise
|
104
107
|
closest_loc = closest.location
|
105
|
-
closest_node_start_offset = closest_loc.
|
106
|
-
closest_node_end_offset = closest_loc.
|
108
|
+
closest_node_start_offset = closest_loc.cached_start_code_units_offset(code_units_cache)
|
109
|
+
closest_node_end_offset = closest_loc.cached_end_code_units_offset(code_units_cache)
|
107
110
|
if loc_end_offset - loc_start_offset <= closest_node_end_offset - closest_node_start_offset
|
108
111
|
parent = closest
|
109
112
|
closest = candidate
|
@@ -131,12 +134,30 @@ module RubyLsp
|
|
131
134
|
end
|
132
135
|
end
|
133
136
|
|
137
|
+
sig do
|
138
|
+
returns(T.any(
|
139
|
+
T.proc.params(arg0: Integer).returns(Integer),
|
140
|
+
Prism::CodeUnitsCache,
|
141
|
+
))
|
142
|
+
end
|
143
|
+
attr_reader :code_units_cache
|
144
|
+
|
145
|
+
sig { params(source: String, version: Integer, uri: URI::Generic, encoding: Encoding).void }
|
146
|
+
def initialize(source:, version:, uri:, encoding: Encoding::UTF_8)
|
147
|
+
super
|
148
|
+
@code_units_cache = T.let(@parse_result.code_units_cache(@encoding), T.any(
|
149
|
+
T.proc.params(arg0: Integer).returns(Integer),
|
150
|
+
Prism::CodeUnitsCache,
|
151
|
+
))
|
152
|
+
end
|
153
|
+
|
134
154
|
sig { override.returns(T::Boolean) }
|
135
155
|
def parse!
|
136
156
|
return false unless @needs_parsing
|
137
157
|
|
138
158
|
@needs_parsing = false
|
139
159
|
@parse_result = Prism.parse(@source)
|
160
|
+
@code_units_cache = @parse_result.code_units_cache(@encoding)
|
140
161
|
true
|
141
162
|
end
|
142
163
|
|
@@ -214,8 +235,8 @@ module RubyLsp
|
|
214
235
|
RubyDocument.locate(
|
215
236
|
@parse_result.value,
|
216
237
|
create_scanner.find_char_position(position),
|
238
|
+
code_units_cache: @code_units_cache,
|
217
239
|
node_types: node_types,
|
218
|
-
encoding: @encoding,
|
219
240
|
)
|
220
241
|
end
|
221
242
|
end
|
@@ -48,7 +48,9 @@ module RubyLsp
|
|
48
48
|
@lockfile_hash_path = T.let(@custom_dir + "main_lockfile_hash", Pathname)
|
49
49
|
@last_updated_path = T.let(@custom_dir + "last_updated", Pathname)
|
50
50
|
|
51
|
-
|
51
|
+
dependencies, bundler_version = load_dependencies
|
52
|
+
@dependencies = T.let(dependencies, T::Hash[String, T.untyped])
|
53
|
+
@bundler_version = T.let(bundler_version, T.nilable(Gem::Version))
|
52
54
|
@rails_app = T.let(rails_app?, T::Boolean)
|
53
55
|
@retry = T.let(false, T::Boolean)
|
54
56
|
end
|
@@ -156,14 +158,15 @@ module RubyLsp
|
|
156
158
|
@custom_gemfile.write(content) unless @custom_gemfile.exist? && @custom_gemfile.read == content
|
157
159
|
end
|
158
160
|
|
159
|
-
sig { returns(T::Hash[String, T.untyped]) }
|
161
|
+
sig { returns([T::Hash[String, T.untyped], T.nilable(Gem::Version)]) }
|
160
162
|
def load_dependencies
|
161
|
-
return {} unless @lockfile&.exist?
|
163
|
+
return [{}, nil] unless @lockfile&.exist?
|
162
164
|
|
163
165
|
# We need to parse the Gemfile.lock manually here. If we try to do `bundler/setup` to use something more
|
164
166
|
# convenient, we may end up with issues when the globally installed `ruby-lsp` version mismatches the one included
|
165
167
|
# in the `Gemfile`
|
166
|
-
|
168
|
+
lockfile_parser = Bundler::LockfileParser.new(@lockfile.read)
|
169
|
+
dependencies = lockfile_parser.dependencies
|
167
170
|
|
168
171
|
# When working on a gem, the `ruby-lsp` might be listed as a dependency in the gemspec. We need to make sure we
|
169
172
|
# check those as well or else we may get version mismatch errors. Notice that bundler allows more than one
|
@@ -172,7 +175,7 @@ module RubyLsp
|
|
172
175
|
dependencies.merge!(Bundler.load_gemspec(path).dependencies.to_h { |dep| [dep.name, dep] })
|
173
176
|
end
|
174
177
|
|
175
|
-
dependencies
|
178
|
+
[dependencies, lockfile_parser.bundler_version]
|
176
179
|
end
|
177
180
|
|
178
181
|
sig { params(bundle_gemfile: T.nilable(Pathname)).returns(T::Hash[String, String]) }
|
@@ -188,6 +191,16 @@ module RubyLsp
|
|
188
191
|
env["BUNDLE_PATH"] = File.expand_path(env["BUNDLE_PATH"], @project_path)
|
189
192
|
end
|
190
193
|
|
194
|
+
# If there's a Bundler version locked, then we need to use that one to run bundle commands, so that the composed
|
195
|
+
# lockfile is also locked to the same version. This avoids Bundler restarts on version mismatches
|
196
|
+
base_bundle = if @bundler_version
|
197
|
+
env["BUNDLER_VERSION"] = @bundler_version.to_s
|
198
|
+
install_bundler_if_needed
|
199
|
+
"bundle _#{@bundler_version}_"
|
200
|
+
else
|
201
|
+
"bundle"
|
202
|
+
end
|
203
|
+
|
191
204
|
# If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
|
192
205
|
# to upgrade them or else we'll produce undesired source control changes. If the custom bundle was just created
|
193
206
|
# and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
|
@@ -196,13 +209,13 @@ module RubyLsp
|
|
196
209
|
|
197
210
|
# When not updating, we run `(bundle check || bundle install)`
|
198
211
|
# When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
|
199
|
-
command = +"(
|
212
|
+
command = +"(#{base_bundle} check"
|
200
213
|
|
201
214
|
if should_bundle_update?
|
202
215
|
# If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
|
203
216
|
# version
|
204
217
|
command.prepend("(")
|
205
|
-
command << " &&
|
218
|
+
command << " && #{base_bundle} update "
|
206
219
|
command << "ruby-lsp " unless @dependencies["ruby-lsp"]
|
207
220
|
command << "debug " unless @dependencies["debug"]
|
208
221
|
command << "ruby-lsp-rails " if @rails_app && !@dependencies["ruby-lsp-rails"]
|
@@ -212,7 +225,7 @@ module RubyLsp
|
|
212
225
|
@last_updated_path.write(Time.now.iso8601)
|
213
226
|
end
|
214
227
|
|
215
|
-
command << " ||
|
228
|
+
command << " || #{base_bundle} install) "
|
216
229
|
|
217
230
|
# Redirect stdout to stderr to prevent going into an infinite loop. The extension might confuse stdout output with
|
218
231
|
# responses
|
@@ -259,6 +272,15 @@ module RubyLsp
|
|
259
272
|
end
|
260
273
|
end
|
261
274
|
|
275
|
+
sig { void }
|
276
|
+
def install_bundler_if_needed
|
277
|
+
# Try to find the bundler version specified in the lockfile in installed gems. If not found, install it
|
278
|
+
requirement = Gem::Requirement.new(@bundler_version.to_s)
|
279
|
+
return if Gem::Specification.any? { |s| s.name == "bundler" && requirement =~ s.version }
|
280
|
+
|
281
|
+
Gem.install("bundler", @bundler_version.to_s)
|
282
|
+
end
|
283
|
+
|
262
284
|
sig { returns(T::Boolean) }
|
263
285
|
def should_bundle_update?
|
264
286
|
# If `ruby-lsp`, `ruby-lsp-rails` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it
|
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.
|
4
|
+
version: 0.20.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.2'
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '2.0'
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: '1.
|
43
|
+
version: '1.2'
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '2.0'
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/ruby_indexer/test/configuration_test.rb
|
112
112
|
- lib/ruby_indexer/test/constant_test.rb
|
113
113
|
- lib/ruby_indexer/test/enhancements_test.rb
|
114
|
+
- lib/ruby_indexer/test/global_variable_test.rb
|
114
115
|
- lib/ruby_indexer/test/index_test.rb
|
115
116
|
- lib/ruby_indexer/test/instance_variables_test.rb
|
116
117
|
- lib/ruby_indexer/test/method_test.rb
|
@@ -211,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
212
|
- !ruby/object:Gem::Version
|
212
213
|
version: '0'
|
213
214
|
requirements: []
|
214
|
-
rubygems_version: 3.5.
|
215
|
+
rubygems_version: 3.5.21
|
215
216
|
signing_key:
|
216
217
|
specification_version: 4
|
217
218
|
summary: An opinionated language server for Ruby
|