ruby-lsp 0.12.2 → 0.13.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/README.md +1 -0
- data/VERSION +1 -1
- data/exe/ruby-lsp-check +20 -4
- data/exe/ruby-lsp-doctor +2 -2
- data/lib/ruby_indexer/lib/ruby_indexer/{visitor.rb → collector.rb} +144 -61
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +9 -4
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +89 -12
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +22 -4
- data/lib/ruby_indexer/ruby_indexer.rb +1 -1
- data/lib/ruby_indexer/test/configuration_test.rb +10 -0
- data/lib/ruby_indexer/test/index_test.rb +64 -0
- data/lib/ruby_indexer/test/method_test.rb +80 -0
- data/lib/ruby_lsp/addon.rb +9 -13
- data/lib/ruby_lsp/document.rb +7 -9
- data/lib/ruby_lsp/executor.rb +54 -51
- data/lib/ruby_lsp/internal.rb +4 -0
- data/lib/ruby_lsp/listener.rb +4 -5
- data/lib/ruby_lsp/requests/code_action_resolve.rb +8 -4
- data/lib/ruby_lsp/requests/code_lens.rb +16 -7
- data/lib/ruby_lsp/requests/completion.rb +60 -8
- data/lib/ruby_lsp/requests/definition.rb +55 -29
- data/lib/ruby_lsp/requests/diagnostics.rb +0 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +20 -11
- data/lib/ruby_lsp/requests/document_link.rb +2 -3
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/folding_ranges.rb +12 -15
- data/lib/ruby_lsp/requests/formatting.rb +0 -5
- data/lib/ruby_lsp/requests/hover.rb +23 -4
- data/lib/ruby_lsp/requests/inlay_hints.rb +42 -4
- data/lib/ruby_lsp/requests/on_type_formatting.rb +18 -4
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +41 -16
- data/lib/ruby_lsp/requests/support/common.rb +22 -2
- data/lib/ruby_lsp/requests/support/dependency_detector.rb +0 -1
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +3 -8
- data/lib/ruby_lsp/requests/workspace_symbol.rb +6 -11
- data/lib/ruby_lsp/ruby_document.rb +14 -0
- data/lib/ruby_lsp/setup_bundler.rb +2 -0
- data/lib/ruby_lsp/store.rb +5 -3
- data/lib/ruby_lsp/utils.rb +8 -3
- metadata +8 -7
@@ -107,20 +107,15 @@ module RubyLsp
|
|
107
107
|
sig { override.returns(ResponseType) }
|
108
108
|
attr_reader :_response
|
109
109
|
|
110
|
-
sig
|
111
|
-
|
112
|
-
|
113
|
-
message_queue: Thread::Queue,
|
114
|
-
range: T.nilable(T::Range[Integer]),
|
115
|
-
).void
|
116
|
-
end
|
117
|
-
def initialize(dispatcher, message_queue, range: nil)
|
118
|
-
super(dispatcher, message_queue)
|
110
|
+
sig { params(dispatcher: Prism::Dispatcher, range: T.nilable(T::Range[Integer])).void }
|
111
|
+
def initialize(dispatcher, range: nil)
|
112
|
+
super(dispatcher)
|
119
113
|
|
120
114
|
@_response = T.let([], ResponseType)
|
121
115
|
@range = range
|
122
116
|
@special_methods = T.let(nil, T.nilable(T::Array[String]))
|
123
117
|
@current_scope = T.let(ParameterScope.new, ParameterScope)
|
118
|
+
@inside_regex_capture = T.let(false, T::Boolean)
|
124
119
|
|
125
120
|
dispatcher.register(
|
126
121
|
self,
|
@@ -135,7 +130,8 @@ module RubyLsp
|
|
135
130
|
:on_local_variable_write_node_enter,
|
136
131
|
:on_local_variable_read_node_enter,
|
137
132
|
:on_block_parameter_node_enter,
|
138
|
-
:
|
133
|
+
:on_required_keyword_parameter_node_enter,
|
134
|
+
:on_optional_keyword_parameter_node_enter,
|
139
135
|
:on_keyword_rest_parameter_node_enter,
|
140
136
|
:on_optional_parameter_node_enter,
|
141
137
|
:on_required_parameter_node_enter,
|
@@ -151,6 +147,8 @@ module RubyLsp
|
|
151
147
|
:on_local_variable_or_write_node_enter,
|
152
148
|
:on_local_variable_target_node_enter,
|
153
149
|
:on_block_local_variable_node_enter,
|
150
|
+
:on_match_write_node_enter,
|
151
|
+
:on_match_write_node_leave,
|
154
152
|
)
|
155
153
|
end
|
156
154
|
|
@@ -164,14 +162,28 @@ module RubyLsp
|
|
164
162
|
# We can't push a semantic token for [] and []= because the argument inside the brackets is a part of
|
165
163
|
# the message_loc
|
166
164
|
return if message.start_with?("[") && (message.end_with?("]") || message.end_with?("]="))
|
167
|
-
|
168
|
-
return process_regexp_locals(node) if message == "=~"
|
165
|
+
return if message == "=~"
|
169
166
|
return if special_method?(message)
|
170
167
|
|
171
168
|
type = Support::Sorbet.annotation?(node) ? :type : :method
|
172
169
|
add_token(T.must(node.message_loc), type)
|
173
170
|
end
|
174
171
|
|
172
|
+
sig { params(node: Prism::MatchWriteNode).void }
|
173
|
+
def on_match_write_node_enter(node)
|
174
|
+
call = node.call
|
175
|
+
|
176
|
+
if call.message == "=~"
|
177
|
+
@inside_regex_capture = true
|
178
|
+
process_regexp_locals(call)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
sig { params(node: Prism::MatchWriteNode).void }
|
183
|
+
def on_match_write_node_leave(node)
|
184
|
+
@inside_regex_capture = true if node.call.message == "=~"
|
185
|
+
end
|
186
|
+
|
175
187
|
sig { params(node: Prism::ConstantReadNode).void }
|
176
188
|
def on_constant_read_node_enter(node)
|
177
189
|
return unless visible?(node, @range)
|
@@ -252,11 +264,18 @@ module RubyLsp
|
|
252
264
|
@current_scope << name.to_sym if name
|
253
265
|
end
|
254
266
|
|
255
|
-
sig { params(node: Prism::
|
256
|
-
def
|
257
|
-
|
258
|
-
|
267
|
+
sig { params(node: Prism::RequiredKeywordParameterNode).void }
|
268
|
+
def on_required_keyword_parameter_node_enter(node)
|
269
|
+
@current_scope << node.name
|
270
|
+
return unless visible?(node, @range)
|
271
|
+
|
272
|
+
location = node.name_loc
|
273
|
+
add_token(location.copy(length: location.length - 1), :parameter)
|
274
|
+
end
|
259
275
|
|
276
|
+
sig { params(node: Prism::OptionalKeywordParameterNode).void }
|
277
|
+
def on_optional_keyword_parameter_node_enter(node)
|
278
|
+
@current_scope << node.name
|
260
279
|
return unless visible?(node, @range)
|
261
280
|
|
262
281
|
location = node.name_loc
|
@@ -351,6 +370,12 @@ module RubyLsp
|
|
351
370
|
|
352
371
|
sig { params(node: Prism::LocalVariableTargetNode).void }
|
353
372
|
def on_local_variable_target_node_enter(node)
|
373
|
+
# If we're inside a regex capture, Prism will add LocalVariableTarget nodes for each captured variable.
|
374
|
+
# Unfortunately, if the regex contains a backslash, the location will be incorrect and we'll end up highlighting
|
375
|
+
# the entire regex as a local variable. We process these captures in process_regexp_locals instead and then
|
376
|
+
# prevent pushing local variable target tokens. See https://github.com/ruby/prism/issues/1912
|
377
|
+
return if @inside_regex_capture
|
378
|
+
|
354
379
|
return unless visible?(node, @range)
|
355
380
|
|
356
381
|
add_token(node.location, @current_scope.type_for(node.name))
|
@@ -9,6 +9,9 @@ module RubyLsp
|
|
9
9
|
# https://github.com/Shopify/ruby-lsp-rails, or addons by created by developers outside of Shopify, so be
|
10
10
|
# cautious of changing anything.
|
11
11
|
extend T::Sig
|
12
|
+
extend T::Helpers
|
13
|
+
|
14
|
+
requires_ancestor { Kernel }
|
12
15
|
|
13
16
|
sig { params(node: Prism::Node).returns(Interface::Range) }
|
14
17
|
def range_from_node(node)
|
@@ -66,12 +69,29 @@ module RubyLsp
|
|
66
69
|
)
|
67
70
|
end
|
68
71
|
|
69
|
-
sig { params(
|
72
|
+
sig { params(file_path: String).returns(T.nilable(T::Boolean)) }
|
73
|
+
def defined_in_gem?(file_path)
|
74
|
+
DependencyDetector.instance.typechecker && BUNDLE_PATH && !file_path.start_with?(T.must(BUNDLE_PATH)) &&
|
75
|
+
!file_path.start_with?(RbConfig::CONFIG["rubylibdir"])
|
76
|
+
end
|
77
|
+
|
78
|
+
sig { params(node: Prism::CallNode).returns(T::Boolean) }
|
79
|
+
def self_receiver?(node)
|
80
|
+
receiver = node.receiver
|
81
|
+
receiver.nil? || receiver.is_a?(Prism::SelfNode)
|
82
|
+
end
|
83
|
+
|
84
|
+
sig do
|
85
|
+
params(
|
86
|
+
title: String,
|
87
|
+
entries: T.any(T::Array[RubyIndexer::Entry], RubyIndexer::Entry),
|
88
|
+
).returns(Interface::MarkupContent)
|
89
|
+
end
|
70
90
|
def markdown_from_index_entries(title, entries)
|
71
91
|
markdown_title = "```ruby\n#{title}\n```"
|
72
92
|
definitions = []
|
73
93
|
content = +""
|
74
|
-
entries.each do |entry|
|
94
|
+
Array(entries).each do |entry|
|
75
95
|
loc = entry.location
|
76
96
|
|
77
97
|
# We always handle locations as zero based. However, for file links in Markdown we need them to be one
|
@@ -66,7 +66,6 @@ module RubyLsp
|
|
66
66
|
|
67
67
|
sig { returns(T::Array[String]) }
|
68
68
|
def dependencies
|
69
|
-
# NOTE: If changing this behaviour, it's likely that the VS Code extension will also need changed.
|
70
69
|
@dependencies ||= T.let(
|
71
70
|
begin
|
72
71
|
Bundler.with_original_env { Bundler.default_gemfile }
|
@@ -34,15 +34,10 @@ module RubyLsp
|
|
34
34
|
|
35
35
|
sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
|
36
36
|
def run(uri, document)
|
37
|
-
|
38
|
-
|
39
|
-
return if @options.ignore_files.any? { |pattern| File.fnmatch(pattern, relative_path) }
|
37
|
+
path = uri.to_standardized_path
|
38
|
+
return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
|
40
39
|
|
41
|
-
SyntaxTree.format(
|
42
|
-
document.source,
|
43
|
-
@options.print_width,
|
44
|
-
options: @options.formatter_options,
|
45
|
-
)
|
40
|
+
SyntaxTree.format(document.source, @options.print_width, options: @options.formatter_options)
|
46
41
|
end
|
47
42
|
end
|
48
43
|
end
|
@@ -20,6 +20,7 @@ module RubyLsp
|
|
20
20
|
#
|
21
21
|
class WorkspaceSymbol
|
22
22
|
extend T::Sig
|
23
|
+
include Support::Common
|
23
24
|
|
24
25
|
sig { params(query: T.nilable(String), index: RubyIndexer::Index).void }
|
25
26
|
def initialize(query, index)
|
@@ -29,21 +30,11 @@ module RubyLsp
|
|
29
30
|
|
30
31
|
sig { returns(T::Array[Interface::WorkspaceSymbol]) }
|
31
32
|
def run
|
32
|
-
bundle_path = begin
|
33
|
-
Bundler.bundle_path.to_s
|
34
|
-
rescue Bundler::GemfileNotFound
|
35
|
-
nil
|
36
|
-
end
|
37
|
-
|
38
33
|
@index.fuzzy_search(@query).filter_map do |entry|
|
39
34
|
# If the project is using Sorbet, we let Sorbet handle symbols defined inside the project itself and RBIs, but
|
40
35
|
# we still return entries defined in gems to allow developers to jump directly to the source
|
41
36
|
file_path = entry.file_path
|
42
|
-
if
|
43
|
-
!file_path.start_with?(RbConfig::CONFIG["rubylibdir"])
|
44
|
-
|
45
|
-
next
|
46
|
-
end
|
37
|
+
next if defined_in_gem?(file_path)
|
47
38
|
|
48
39
|
# We should never show private symbols when searching the entire workspace
|
49
40
|
next if entry.visibility == :private
|
@@ -82,6 +73,10 @@ module RubyLsp
|
|
82
73
|
Constant::SymbolKind::NAMESPACE
|
83
74
|
when RubyIndexer::Entry::Constant
|
84
75
|
Constant::SymbolKind::CONSTANT
|
76
|
+
when RubyIndexer::Entry::Method
|
77
|
+
entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
|
78
|
+
when RubyIndexer::Entry::Accessor
|
79
|
+
Constant::SymbolKind::PROPERTY
|
85
80
|
end
|
86
81
|
end
|
87
82
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
class RubyDocument < Document
|
6
|
+
sig { override.returns(Prism::ParseResult) }
|
7
|
+
def parse
|
8
|
+
return @parse_result unless @needs_parsing
|
9
|
+
|
10
|
+
@needs_parsing = false
|
11
|
+
@parse_result = Prism.parse(@source)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -12,6 +12,8 @@ require "time"
|
|
12
12
|
# the Ruby LSP without including the gem in their application's Gemfile while at the same time giving us access to the
|
13
13
|
# exact locked versions of dependencies.
|
14
14
|
|
15
|
+
Bundler.ui.level = :silent
|
16
|
+
|
15
17
|
module RubyLsp
|
16
18
|
class SetupBundler
|
17
19
|
extend T::Sig
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "ruby_lsp/document"
|
5
|
-
|
6
4
|
module RubyLsp
|
7
5
|
class Store
|
8
6
|
extend T::Sig
|
@@ -19,6 +17,9 @@ module RubyLsp
|
|
19
17
|
sig { returns(T::Boolean) }
|
20
18
|
attr_accessor :experimental_features
|
21
19
|
|
20
|
+
sig { returns(URI::Generic) }
|
21
|
+
attr_accessor :workspace_uri
|
22
|
+
|
22
23
|
sig { void }
|
23
24
|
def initialize
|
24
25
|
@state = T.let({}, T::Hash[String, Document])
|
@@ -26,6 +27,7 @@ module RubyLsp
|
|
26
27
|
@formatter = T.let("auto", String)
|
27
28
|
@supports_progress = T.let(true, T::Boolean)
|
28
29
|
@experimental_features = T.let(false, T::Boolean)
|
30
|
+
@workspace_uri = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
|
29
31
|
end
|
30
32
|
|
31
33
|
sig { params(uri: URI::Generic).returns(Document) }
|
@@ -40,7 +42,7 @@ module RubyLsp
|
|
40
42
|
|
41
43
|
sig { params(uri: URI::Generic, source: String, version: Integer).void }
|
42
44
|
def set(uri:, source:, version:)
|
43
|
-
document =
|
45
|
+
document = RubyDocument.new(source: source, version: version, uri: uri, encoding: @encoding)
|
44
46
|
@state[uri.to_s] = document
|
45
47
|
end
|
46
48
|
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -4,9 +4,14 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
# Used to indicate that a request shouldn't return a response
|
6
6
|
VOID = T.let(Object.new.freeze, Object)
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
BUNDLE_PATH = T.let(
|
8
|
+
begin
|
9
|
+
Bundler.bundle_path.to_s
|
10
|
+
rescue Bundler::GemfileNotFound
|
11
|
+
nil
|
12
|
+
end,
|
13
|
+
T.nilable(String),
|
14
|
+
)
|
10
15
|
|
11
16
|
# A notification to be sent to the client
|
12
17
|
class Message
|
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.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -30,20 +30,20 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.18.0
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: '0.
|
36
|
+
version: '0.19'
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.
|
43
|
+
version: 0.18.0
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '0.
|
46
|
+
version: '0.19'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: sorbet-runtime
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,12 +78,12 @@ files:
|
|
78
78
|
- lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb
|
79
79
|
- lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb
|
80
80
|
- lib/ruby-lsp.rb
|
81
|
+
- lib/ruby_indexer/lib/ruby_indexer/collector.rb
|
81
82
|
- lib/ruby_indexer/lib/ruby_indexer/configuration.rb
|
82
83
|
- lib/ruby_indexer/lib/ruby_indexer/entry.rb
|
83
84
|
- lib/ruby_indexer/lib/ruby_indexer/index.rb
|
84
85
|
- lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb
|
85
86
|
- lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
|
86
|
-
- lib/ruby_indexer/lib/ruby_indexer/visitor.rb
|
87
87
|
- lib/ruby_indexer/ruby_indexer.rb
|
88
88
|
- lib/ruby_indexer/test/classes_and_modules_test.rb
|
89
89
|
- lib/ruby_indexer/test/configuration_test.rb
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- lib/ruby_lsp/requests/support/source_uri.rb
|
133
133
|
- lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb
|
134
134
|
- lib/ruby_lsp/requests/workspace_symbol.rb
|
135
|
+
- lib/ruby_lsp/ruby_document.rb
|
135
136
|
- lib/ruby_lsp/server.rb
|
136
137
|
- lib/ruby_lsp/setup_bundler.rb
|
137
138
|
- lib/ruby_lsp/store.rb
|