ruby-lsp 0.19.1 → 0.20.1
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 +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
|