ruby-lsp 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp-check +1 -1
- data/lib/core_ext/uri.rb +2 -2
- 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 +46 -98
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +7 -6
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +22 -0
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +20 -5
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +76 -14
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +12 -0
- 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 +3 -0
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +14 -0
- data/lib/ruby_indexer/test/reference_finder_test.rb +162 -6
- data/lib/ruby_lsp/erb_document.rb +20 -2
- data/lib/ruby_lsp/internal.rb +3 -1
- 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 +16 -4
- data/lib/ruby_lsp/requests/completion.rb +1 -0
- data/lib/ruby_lsp/requests/definition.rb +2 -0
- data/lib/ruby_lsp/requests/document_highlight.rb +5 -1
- data/lib/ruby_lsp/requests/hover.rb +1 -0
- data/lib/ruby_lsp/requests/range_formatting.rb +57 -0
- data/lib/ruby_lsp/requests/references.rb +146 -0
- data/lib/ruby_lsp/requests/rename.rb +16 -9
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/signature_help.rb +6 -1
- data/lib/ruby_lsp/requests/support/common.rb +1 -1
- data/lib/ruby_lsp/requests/support/formatter.rb +3 -0
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +6 -0
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -6
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +8 -0
- 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 +44 -8
- data/lib/ruby_lsp/server.rb +63 -2
- data/lib/ruby_lsp/type_inferrer.rb +1 -1
- metadata +8 -5
@@ -25,10 +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
33
|
).returns(NodeContext)
|
30
34
|
end
|
31
|
-
def locate(node, char_position, node_types: [])
|
35
|
+
def locate(node, char_position, code_units_cache:, node_types: [])
|
32
36
|
queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
|
33
37
|
closest = node
|
34
38
|
parent = T.let(nil, T.nilable(Prism::Node))
|
@@ -61,16 +65,21 @@ module RubyLsp
|
|
61
65
|
|
62
66
|
# Skip if the current node doesn't cover the desired position
|
63
67
|
loc = candidate.location
|
64
|
-
|
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)
|
70
|
+
next unless (loc_start_offset...loc_end_offset).cover?(char_position)
|
65
71
|
|
66
72
|
# If the node's start character is already past the position, then we should've found the closest node
|
67
73
|
# already
|
68
|
-
break if char_position <
|
74
|
+
break if char_position < loc_start_offset
|
69
75
|
|
70
76
|
# If the candidate starts after the end of the previous nesting level, then we've exited that nesting level
|
71
77
|
# and need to pop the stack
|
72
78
|
previous_level = nesting_nodes.last
|
73
|
-
|
79
|
+
if previous_level &&
|
80
|
+
(loc_start_offset > previous_level.location.cached_end_code_units_offset(code_units_cache))
|
81
|
+
nesting_nodes.pop
|
82
|
+
end
|
74
83
|
|
75
84
|
# Keep track of the nesting where we found the target. This is used to determine the fully qualified name of
|
76
85
|
# the target when it is a constant
|
@@ -83,8 +92,10 @@ module RubyLsp
|
|
83
92
|
if candidate.is_a?(Prism::CallNode)
|
84
93
|
arg_loc = candidate.arguments&.location
|
85
94
|
blk_loc = candidate.block&.location
|
86
|
-
if (arg_loc && (arg_loc.
|
87
|
-
|
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))
|
88
99
|
call_node = candidate
|
89
100
|
end
|
90
101
|
end
|
@@ -94,7 +105,9 @@ module RubyLsp
|
|
94
105
|
|
95
106
|
# If the current node is narrower than or equal to the previous closest node, then it is more precise
|
96
107
|
closest_loc = closest.location
|
97
|
-
|
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)
|
110
|
+
if loc_end_offset - loc_start_offset <= closest_node_end_offset - closest_node_start_offset
|
98
111
|
parent = closest
|
99
112
|
closest = candidate
|
100
113
|
end
|
@@ -121,12 +134,30 @@ module RubyLsp
|
|
121
134
|
end
|
122
135
|
end
|
123
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
|
+
|
124
154
|
sig { override.returns(T::Boolean) }
|
125
155
|
def parse!
|
126
156
|
return false unless @needs_parsing
|
127
157
|
|
128
158
|
@needs_parsing = false
|
129
159
|
@parse_result = Prism.parse(@source)
|
160
|
+
@code_units_cache = @parse_result.code_units_cache(@encoding)
|
130
161
|
true
|
131
162
|
end
|
132
163
|
|
@@ -201,7 +232,12 @@ module RubyLsp
|
|
201
232
|
).returns(NodeContext)
|
202
233
|
end
|
203
234
|
def locate_node(position, node_types: [])
|
204
|
-
RubyDocument.locate(
|
235
|
+
RubyDocument.locate(
|
236
|
+
@parse_result.value,
|
237
|
+
create_scanner.find_char_position(position),
|
238
|
+
code_units_cache: @code_units_cache,
|
239
|
+
node_types: node_types,
|
240
|
+
)
|
205
241
|
end
|
206
242
|
end
|
207
243
|
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -43,6 +43,8 @@ module RubyLsp
|
|
43
43
|
text_document_semantic_tokens_range(message)
|
44
44
|
when "textDocument/formatting"
|
45
45
|
text_document_formatting(message)
|
46
|
+
when "textDocument/rangeFormatting"
|
47
|
+
text_document_range_formatting(message)
|
46
48
|
when "textDocument/documentHighlight"
|
47
49
|
text_document_document_highlight(message)
|
48
50
|
when "textDocument/onTypeFormatting"
|
@@ -69,6 +71,8 @@ module RubyLsp
|
|
69
71
|
text_document_prepare_type_hierarchy(message)
|
70
72
|
when "textDocument/rename"
|
71
73
|
text_document_rename(message)
|
74
|
+
when "textDocument/references"
|
75
|
+
text_document_references(message)
|
72
76
|
when "typeHierarchy/supertypes"
|
73
77
|
type_hierarchy_supertypes(message)
|
74
78
|
when "typeHierarchy/subtypes"
|
@@ -87,7 +91,16 @@ module RubyLsp
|
|
87
91
|
id: message[:id],
|
88
92
|
response:
|
89
93
|
Addon.addons.map do |addon|
|
90
|
-
|
94
|
+
version_method = addon.method(:version)
|
95
|
+
|
96
|
+
# If the add-on doesn't define a `version` method, we'd be calling the abstract method defined by
|
97
|
+
# Sorbet, which would raise an error.
|
98
|
+
# Therefore, we only call the method if it's defined by the add-on itself
|
99
|
+
if version_method.owner != Addon
|
100
|
+
version = addon.version
|
101
|
+
end
|
102
|
+
|
103
|
+
{ name: addon.name, version: version, errored: addon.error? }
|
91
104
|
end,
|
92
105
|
),
|
93
106
|
)
|
@@ -230,6 +243,8 @@ module RubyLsp
|
|
230
243
|
signature_help_provider: signature_help_provider,
|
231
244
|
type_hierarchy_provider: type_hierarchy_provider,
|
232
245
|
rename_provider: !@global_state.has_type_checker,
|
246
|
+
references_provider: !@global_state.has_type_checker,
|
247
|
+
document_range_formatting_provider: true,
|
233
248
|
experimental: {
|
234
249
|
addon_detection: true,
|
235
250
|
},
|
@@ -513,6 +528,34 @@ module RubyLsp
|
|
513
528
|
send_message(Result.new(id: message[:id], response: request.perform))
|
514
529
|
end
|
515
530
|
|
531
|
+
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
532
|
+
def text_document_range_formatting(message)
|
533
|
+
# If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
|
534
|
+
if @global_state.formatter == "none"
|
535
|
+
send_empty_response(message[:id])
|
536
|
+
return
|
537
|
+
end
|
538
|
+
|
539
|
+
params = message[:params]
|
540
|
+
uri = params.dig(:textDocument, :uri)
|
541
|
+
# Do not format files outside of the workspace. For example, if someone is looking at a gem's source code, we
|
542
|
+
# don't want to format it
|
543
|
+
path = uri.to_standardized_path
|
544
|
+
unless path.nil? || path.start_with?(@global_state.workspace_path)
|
545
|
+
send_empty_response(message[:id])
|
546
|
+
return
|
547
|
+
end
|
548
|
+
|
549
|
+
document = @store.get(uri)
|
550
|
+
unless document.is_a?(RubyDocument)
|
551
|
+
send_empty_response(message[:id])
|
552
|
+
return
|
553
|
+
end
|
554
|
+
|
555
|
+
response = Requests::RangeFormatting.new(@global_state, document, params).perform
|
556
|
+
send_message(Result.new(id: message[:id], response: response))
|
557
|
+
end
|
558
|
+
|
516
559
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
517
560
|
def text_document_formatting(message)
|
518
561
|
# If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
|
@@ -636,6 +679,24 @@ module RubyLsp
|
|
636
679
|
send_message(Error.new(id: message[:id], code: Constant::ErrorCodes::REQUEST_FAILED, message: e.message))
|
637
680
|
end
|
638
681
|
|
682
|
+
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
683
|
+
def text_document_references(message)
|
684
|
+
params = message[:params]
|
685
|
+
document = @store.get(params.dig(:textDocument, :uri))
|
686
|
+
|
687
|
+
unless document.is_a?(RubyDocument)
|
688
|
+
send_empty_response(message[:id])
|
689
|
+
return
|
690
|
+
end
|
691
|
+
|
692
|
+
send_message(
|
693
|
+
Result.new(
|
694
|
+
id: message[:id],
|
695
|
+
response: Requests::References.new(@global_state, @store, document, params).perform,
|
696
|
+
),
|
697
|
+
)
|
698
|
+
end
|
699
|
+
|
639
700
|
sig { params(document: Document[T.untyped]).returns(RubyDocument::SorbetLevel) }
|
640
701
|
def sorbet_level(document)
|
641
702
|
return RubyDocument::SorbetLevel::Ignore unless @global_state.has_type_checker
|
@@ -711,7 +772,7 @@ module RubyLsp
|
|
711
772
|
return
|
712
773
|
end
|
713
774
|
|
714
|
-
result = Requests::CodeActionResolve.new(document, params).perform
|
775
|
+
result = Requests::CodeActionResolve.new(document, @global_state, params).perform
|
715
776
|
|
716
777
|
case result
|
717
778
|
when Requests::CodeActionResolve::Error::EmptySelection
|
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.0
|
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-11 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
|
@@ -154,6 +155,8 @@ files:
|
|
154
155
|
- lib/ruby_lsp/requests/inlay_hints.rb
|
155
156
|
- lib/ruby_lsp/requests/on_type_formatting.rb
|
156
157
|
- lib/ruby_lsp/requests/prepare_type_hierarchy.rb
|
158
|
+
- lib/ruby_lsp/requests/range_formatting.rb
|
159
|
+
- lib/ruby_lsp/requests/references.rb
|
157
160
|
- lib/ruby_lsp/requests/rename.rb
|
158
161
|
- lib/ruby_lsp/requests/request.rb
|
159
162
|
- lib/ruby_lsp/requests/selection_ranges.rb
|
@@ -209,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
212
|
- !ruby/object:Gem::Version
|
210
213
|
version: '0'
|
211
214
|
requirements: []
|
212
|
-
rubygems_version: 3.5.
|
215
|
+
rubygems_version: 3.5.21
|
213
216
|
signing_key:
|
214
217
|
specification_version: 4
|
215
218
|
summary: An opinionated language server for Ruby
|