ruby-lsp 0.13.3 → 0.14.2
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 +6 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp-doctor +2 -0
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +4 -8
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +5 -1
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +4 -2
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +10 -5
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +9 -0
- data/lib/ruby_indexer/test/index_test.rb +54 -3
- data/lib/ruby_lsp/addon.rb +34 -17
- data/lib/ruby_lsp/check_docs.rb +8 -8
- data/lib/ruby_lsp/executor.rb +28 -10
- data/lib/ruby_lsp/internal.rb +8 -6
- data/lib/ruby_lsp/listeners/code_lens.rb +54 -55
- data/lib/ruby_lsp/listeners/completion.rb +22 -18
- data/lib/ruby_lsp/listeners/definition.rb +31 -29
- data/lib/ruby_lsp/listeners/document_highlight.rb +6 -11
- data/lib/ruby_lsp/listeners/document_link.rb +6 -12
- data/lib/ruby_lsp/listeners/document_symbol.rb +194 -55
- data/lib/ruby_lsp/listeners/folding_ranges.rb +19 -23
- data/lib/ruby_lsp/listeners/hover.rb +36 -34
- data/lib/ruby_lsp/listeners/inlay_hints.rb +7 -13
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -124
- data/lib/ruby_lsp/listeners/signature_help.rb +15 -14
- data/lib/ruby_lsp/requests/code_lens.rb +11 -19
- data/lib/ruby_lsp/requests/completion.rb +7 -9
- data/lib/ruby_lsp/requests/definition.rb +10 -22
- data/lib/ruby_lsp/requests/document_highlight.rb +7 -5
- data/lib/ruby_lsp/requests/document_link.rb +7 -6
- data/lib/ruby_lsp/requests/document_symbol.rb +5 -11
- data/lib/ruby_lsp/requests/folding_ranges.rb +11 -6
- data/lib/ruby_lsp/requests/hover.rb +18 -24
- data/lib/ruby_lsp/requests/inlay_hints.rb +7 -8
- data/lib/ruby_lsp/requests/on_type_formatting.rb +12 -2
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +10 -8
- data/lib/ruby_lsp/requests/signature_help.rb +53 -18
- data/lib/ruby_lsp/requests/support/common.rb +38 -10
- data/lib/ruby_lsp/requests/support/dependency_detector.rb +5 -1
- data/lib/ruby_lsp/requests.rb +0 -1
- data/lib/ruby_lsp/response_builders/collection_response_builder.rb +29 -0
- data/lib/ruby_lsp/response_builders/document_symbol.rb +57 -0
- data/lib/ruby_lsp/response_builders/hover.rb +49 -0
- data/lib/ruby_lsp/response_builders/response_builder.rb +16 -0
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +199 -0
- data/lib/ruby_lsp/response_builders/signature_help.rb +28 -0
- data/lib/ruby_lsp/response_builders.rb +13 -0
- data/lib/ruby_lsp/server.rb +3 -3
- data/lib/ruby_lsp/setup_bundler.rb +64 -23
- data/lib/ruby_lsp/store.rb +4 -4
- metadata +17 -11
- data/lib/ruby_lsp/listener.rb +0 -33
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +0 -73
@@ -0,0 +1,199 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module ResponseBuilders
|
6
|
+
class SemanticHighlighting < ResponseBuilder
|
7
|
+
class UndefinedTokenType < StandardError; end
|
8
|
+
|
9
|
+
TOKEN_TYPES = T.let(
|
10
|
+
{
|
11
|
+
namespace: 0,
|
12
|
+
type: 1,
|
13
|
+
class: 2,
|
14
|
+
enum: 3,
|
15
|
+
interface: 4,
|
16
|
+
struct: 5,
|
17
|
+
typeParameter: 6,
|
18
|
+
parameter: 7,
|
19
|
+
variable: 8,
|
20
|
+
property: 9,
|
21
|
+
enumMember: 10,
|
22
|
+
event: 11,
|
23
|
+
function: 12,
|
24
|
+
method: 13,
|
25
|
+
macro: 14,
|
26
|
+
keyword: 15,
|
27
|
+
modifier: 16,
|
28
|
+
comment: 17,
|
29
|
+
string: 18,
|
30
|
+
number: 19,
|
31
|
+
regexp: 20,
|
32
|
+
operator: 21,
|
33
|
+
decorator: 22,
|
34
|
+
}.freeze,
|
35
|
+
T::Hash[Symbol, Integer],
|
36
|
+
)
|
37
|
+
|
38
|
+
TOKEN_MODIFIERS = T.let(
|
39
|
+
{
|
40
|
+
declaration: 0,
|
41
|
+
definition: 1,
|
42
|
+
readonly: 2,
|
43
|
+
static: 3,
|
44
|
+
deprecated: 4,
|
45
|
+
abstract: 5,
|
46
|
+
async: 6,
|
47
|
+
modification: 7,
|
48
|
+
documentation: 8,
|
49
|
+
default_library: 9,
|
50
|
+
}.freeze,
|
51
|
+
T::Hash[Symbol, Integer],
|
52
|
+
)
|
53
|
+
|
54
|
+
extend T::Sig
|
55
|
+
|
56
|
+
ResponseType = type_member { { fixed: Interface::SemanticTokens } }
|
57
|
+
|
58
|
+
sig { void }
|
59
|
+
def initialize
|
60
|
+
super
|
61
|
+
@stack = T.let([], T::Array[SemanticToken])
|
62
|
+
end
|
63
|
+
|
64
|
+
sig { params(location: Prism::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
|
65
|
+
def add_token(location, type, modifiers = [])
|
66
|
+
length = location.end_offset - location.start_offset
|
67
|
+
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
68
|
+
@stack.push(
|
69
|
+
SemanticToken.new(
|
70
|
+
location: location,
|
71
|
+
length: length,
|
72
|
+
type: T.must(TOKEN_TYPES[type]),
|
73
|
+
modifier: modifiers_indices,
|
74
|
+
),
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
sig { returns(T.nilable(SemanticToken)) }
|
79
|
+
def last
|
80
|
+
@stack.last
|
81
|
+
end
|
82
|
+
|
83
|
+
sig { override.returns(Interface::SemanticTokens) }
|
84
|
+
def response
|
85
|
+
SemanticTokenEncoder.new.encode(@stack)
|
86
|
+
end
|
87
|
+
|
88
|
+
class SemanticToken
|
89
|
+
extend T::Sig
|
90
|
+
|
91
|
+
sig { returns(Prism::Location) }
|
92
|
+
attr_reader :location
|
93
|
+
|
94
|
+
sig { returns(Integer) }
|
95
|
+
attr_reader :length
|
96
|
+
|
97
|
+
sig { returns(Integer) }
|
98
|
+
attr_reader :type
|
99
|
+
|
100
|
+
sig { returns(T::Array[Integer]) }
|
101
|
+
attr_reader :modifier
|
102
|
+
|
103
|
+
sig { params(location: Prism::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
|
104
|
+
def initialize(location:, length:, type:, modifier:)
|
105
|
+
@location = location
|
106
|
+
@length = length
|
107
|
+
@type = type
|
108
|
+
@modifier = modifier
|
109
|
+
end
|
110
|
+
|
111
|
+
sig { params(type_symbol: Symbol).void }
|
112
|
+
def replace_type(type_symbol)
|
113
|
+
type_int = TOKEN_TYPES[type_symbol]
|
114
|
+
raise UndefinedTokenType, "Undefined token type: #{type_symbol}" unless type_int
|
115
|
+
|
116
|
+
@type = type_int
|
117
|
+
end
|
118
|
+
|
119
|
+
sig { params(modifier_symbols: T::Array[Symbol]).void }
|
120
|
+
def replace_modifier(modifier_symbols)
|
121
|
+
@modifier = modifier_symbols.filter_map do |modifier_symbol|
|
122
|
+
modifier_index = TOKEN_MODIFIERS[modifier_symbol]
|
123
|
+
raise UndefinedTokenType, "Undefined token modifier: #{modifier_symbol}" unless modifier_index
|
124
|
+
|
125
|
+
modifier_index
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class SemanticTokenEncoder
|
131
|
+
extend T::Sig
|
132
|
+
|
133
|
+
sig { void }
|
134
|
+
def initialize
|
135
|
+
@current_row = T.let(0, Integer)
|
136
|
+
@current_column = T.let(0, Integer)
|
137
|
+
end
|
138
|
+
|
139
|
+
sig do
|
140
|
+
params(
|
141
|
+
tokens: T::Array[SemanticToken],
|
142
|
+
).returns(Interface::SemanticTokens)
|
143
|
+
end
|
144
|
+
def encode(tokens)
|
145
|
+
sorted_tokens = tokens.sort_by.with_index do |token, index|
|
146
|
+
# Enumerable#sort_by is not deterministic when the compared values are equal.
|
147
|
+
# When that happens, we need to use the index as a tie breaker to ensure
|
148
|
+
# that the order of the tokens is always the same.
|
149
|
+
[token.location.start_line, token.location.start_column, index]
|
150
|
+
end
|
151
|
+
|
152
|
+
delta = sorted_tokens.flat_map do |token|
|
153
|
+
compute_delta(token)
|
154
|
+
end
|
155
|
+
|
156
|
+
Interface::SemanticTokens.new(data: delta)
|
157
|
+
end
|
158
|
+
|
159
|
+
# The delta array is computed according to the LSP specification:
|
160
|
+
# > The protocol for the token format relative uses relative
|
161
|
+
# > positions, because most tokens remain stable relative to
|
162
|
+
# > each other when edits are made in a file. This simplifies
|
163
|
+
# > the computation of a delta if a server supports it. So each
|
164
|
+
# > token is represented using 5 integers.
|
165
|
+
|
166
|
+
# For more information on how each number is calculated, read:
|
167
|
+
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
|
168
|
+
sig { params(token: SemanticToken).returns(T::Array[Integer]) }
|
169
|
+
def compute_delta(token)
|
170
|
+
row = token.location.start_line - 1
|
171
|
+
column = token.location.start_column
|
172
|
+
|
173
|
+
begin
|
174
|
+
delta_line = row - @current_row
|
175
|
+
|
176
|
+
delta_column = column
|
177
|
+
delta_column -= @current_column if delta_line == 0
|
178
|
+
|
179
|
+
[delta_line, delta_column, token.length, token.type, encode_modifiers(token.modifier)]
|
180
|
+
ensure
|
181
|
+
@current_row = row
|
182
|
+
@current_column = column
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Encode an array of modifiers to positions onto a bit flag
|
187
|
+
# For example, [:default_library] will be encoded as
|
188
|
+
# 0b1000000000, as :default_library is the 10th bit according
|
189
|
+
# to the token modifiers index map.
|
190
|
+
sig { params(modifiers: T::Array[Integer]).returns(Integer) }
|
191
|
+
def encode_modifiers(modifiers)
|
192
|
+
modifiers.inject(0) do |encoded_modifiers, modifier|
|
193
|
+
encoded_modifiers | (1 << modifier)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module ResponseBuilders
|
6
|
+
class SignatureHelp < ResponseBuilder
|
7
|
+
ResponseType = type_member { { fixed: T.nilable(Interface::SignatureHelp) } }
|
8
|
+
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { void }
|
12
|
+
def initialize
|
13
|
+
super
|
14
|
+
@signature_help = T.let(nil, ResponseType)
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { params(signature_help: ResponseType).void }
|
18
|
+
def replace(signature_help)
|
19
|
+
@signature_help = signature_help
|
20
|
+
end
|
21
|
+
|
22
|
+
sig { override.returns(ResponseType) }
|
23
|
+
def response
|
24
|
+
@signature_help
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module ResponseBuilders
|
6
|
+
autoload :CollectionResponseBuilder, "ruby_lsp/response_builders/collection_response_builder"
|
7
|
+
autoload :DocumentSymbol, "ruby_lsp/response_builders/document_symbol"
|
8
|
+
autoload :Hover, "ruby_lsp/response_builders/hover"
|
9
|
+
autoload :ResponseBuilder, "ruby_lsp/response_builders/response_builder"
|
10
|
+
autoload :SemanticHighlighting, "ruby_lsp/response_builders/semantic_highlighting"
|
11
|
+
autoload :SignatureHelp, "ruby_lsp/response_builders/signature_help"
|
12
|
+
end
|
13
|
+
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -58,7 +58,7 @@ module RubyLsp
|
|
58
58
|
|
59
59
|
sig { void }
|
60
60
|
def start
|
61
|
-
|
61
|
+
$stderr.puts("Starting Ruby LSP v#{VERSION}...")
|
62
62
|
|
63
63
|
# Requests that have to be executed sequentially or in the main process are implemented here. All other requests
|
64
64
|
# fall under the else branch which just pushes requests to the queue
|
@@ -73,7 +73,7 @@ module RubyLsp
|
|
73
73
|
when "$/setTrace"
|
74
74
|
VOID
|
75
75
|
when "shutdown"
|
76
|
-
|
76
|
+
$stderr.puts("Shutting down Ruby LSP...")
|
77
77
|
|
78
78
|
@message_queue.close
|
79
79
|
# Close the queue so that we can no longer receive items
|
@@ -92,7 +92,7 @@ module RubyLsp
|
|
92
92
|
# We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
|
93
93
|
# https://microsoft.github.io/language-server-protocol/specification/#exit
|
94
94
|
status = @store.empty? ? 0 : 1
|
95
|
-
|
95
|
+
$stderr.puts("Shutdown complete with status #{status}")
|
96
96
|
exit(status)
|
97
97
|
else
|
98
98
|
# Default case: push the request to the queue to be executed by the worker
|
@@ -57,13 +57,18 @@ module RubyLsp
|
|
57
57
|
def setup!
|
58
58
|
raise BundleNotLocked if @gemfile&.exist? && !@lockfile&.exist?
|
59
59
|
|
60
|
-
# Do not
|
61
|
-
if @dependencies["ruby-lsp"] &&
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
60
|
+
# Do not set up a custom bundle if LSP dependencies are already in the Gemfile
|
61
|
+
if @dependencies["ruby-lsp"] &&
|
62
|
+
@dependencies["debug"] &&
|
63
|
+
(@dependencies["rails"] ? @dependencies["ruby-lsp-rails"] : true)
|
64
|
+
$stderr.puts(
|
65
|
+
"Ruby LSP> Skipping custom bundle setup since LSP dependencies are already in #{@gemfile}",
|
66
|
+
)
|
67
|
+
|
68
|
+
# If the user decided to add `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) to their Gemfile after
|
69
|
+
# having already run the Ruby LSP, then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle
|
70
|
+
# install` for the top level and try to execute the Ruby LSP using the custom bundle, which will fail since the
|
71
|
+
# gems are not installed there
|
67
72
|
@custom_dir.rmtree if @custom_dir.exist?
|
68
73
|
return run_bundle_install
|
69
74
|
end
|
@@ -76,7 +81,7 @@ module RubyLsp
|
|
76
81
|
write_custom_gemfile
|
77
82
|
|
78
83
|
unless @gemfile&.exist? && @lockfile&.exist?
|
79
|
-
|
84
|
+
$stderr.puts("Ruby LSP> Skipping lockfile copies because there's no top level bundle")
|
80
85
|
return run_bundle_install(@custom_gemfile)
|
81
86
|
end
|
82
87
|
|
@@ -84,11 +89,14 @@ module RubyLsp
|
|
84
89
|
current_lockfile_hash = Digest::SHA256.hexdigest(lockfile_contents)
|
85
90
|
|
86
91
|
if @custom_lockfile.exist? && @lockfile_hash_path.exist? && @lockfile_hash_path.read == current_lockfile_hash
|
87
|
-
|
92
|
+
$stderr.puts(
|
93
|
+
"Ruby LSP> Skipping custom bundle setup since #{@custom_lockfile} already exists and is up to date",
|
94
|
+
)
|
88
95
|
return run_bundle_install(@custom_gemfile)
|
89
96
|
end
|
90
97
|
|
91
98
|
FileUtils.cp(@lockfile.to_s, @custom_lockfile.to_s)
|
99
|
+
correct_relative_remote_paths
|
92
100
|
@lockfile_hash_path.write(current_lockfile_hash)
|
93
101
|
run_bundle_install(@custom_gemfile)
|
94
102
|
end
|
@@ -138,6 +146,10 @@ module RubyLsp
|
|
138
146
|
parts << 'gem "debug", require: false, group: :development, platforms: :mri'
|
139
147
|
end
|
140
148
|
|
149
|
+
if @dependencies["rails"] && !@dependencies["ruby-lsp-rails"]
|
150
|
+
parts << 'gem "ruby-lsp-rails", require: false, group: :development'
|
151
|
+
end
|
152
|
+
|
141
153
|
content = parts.join("\n")
|
142
154
|
@custom_gemfile.write(content) unless @custom_gemfile.exist? && @custom_gemfile.read == content
|
143
155
|
end
|
@@ -178,22 +190,24 @@ module RubyLsp
|
|
178
190
|
local_config_path = File.join(Dir.pwd, ".bundle")
|
179
191
|
env["BUNDLE_APP_CONFIG"] = local_config_path if Dir.exist?(local_config_path)
|
180
192
|
|
181
|
-
# If
|
182
|
-
# produce undesired source control changes. If the custom bundle was just created
|
183
|
-
# weren't a part of the Gemfile, then we need to run `bundle
|
184
|
-
# Gemfile.lock with them included or else Bundler will complain that
|
185
|
-
# custom `.ruby-lsp/Gemfile.lock` already exists and includes
|
193
|
+
# If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
|
194
|
+
# to upgrade them or else we'll produce undesired source control changes. If the custom bundle was just created
|
195
|
+
# and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
|
196
|
+
# install` for the first time to generate the Gemfile.lock with them included or else Bundler will complain that
|
197
|
+
# they're missing. We can only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
|
186
198
|
|
187
199
|
# When not updating, we run `(bundle check || bundle install)`
|
188
200
|
# When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
|
189
201
|
command = +"(bundle check"
|
190
202
|
|
191
203
|
if should_bundle_update?
|
192
|
-
# If ruby-lsp or debug are not in the Gemfile, try to update them to the latest
|
204
|
+
# If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
|
205
|
+
# version
|
193
206
|
command.prepend("(")
|
194
207
|
command << " && bundle update "
|
195
208
|
command << "ruby-lsp " unless @dependencies["ruby-lsp"]
|
196
209
|
command << "debug " unless @dependencies["debug"]
|
210
|
+
command << "ruby-lsp-rails " if @dependencies["rails"] && !@dependencies["ruby-lsp-rails"]
|
197
211
|
command << "--pre" if @experimental
|
198
212
|
command.delete_suffix!(" ")
|
199
213
|
command << ")"
|
@@ -208,24 +222,51 @@ module RubyLsp
|
|
208
222
|
command << "1>&2"
|
209
223
|
|
210
224
|
# Add bundle update
|
211
|
-
|
212
|
-
|
225
|
+
$stderr.puts("Ruby LSP> Running bundle install for the custom bundle. This may take a while...")
|
226
|
+
$stderr.puts("Ruby LSP> Command: #{command}")
|
213
227
|
system(env, command)
|
214
228
|
[bundle_gemfile.to_s, expanded_path, env["BUNDLE_APP_CONFIG"]]
|
215
229
|
end
|
216
230
|
|
217
231
|
sig { returns(T::Boolean) }
|
218
232
|
def should_bundle_update?
|
219
|
-
# If
|
220
|
-
# version control changes
|
221
|
-
|
233
|
+
# If `ruby-lsp`, `ruby-lsp-rails` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it
|
234
|
+
# will produce version control changes
|
235
|
+
if @dependencies["rails"]
|
236
|
+
return false if @dependencies.values_at("ruby-lsp", "ruby-lsp-rails", "debug").all?
|
237
|
+
|
238
|
+
# If the custom lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle install
|
239
|
+
# before updating
|
240
|
+
return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug", "ruby-lsp-rails").any?(&:nil?)
|
241
|
+
else
|
242
|
+
return false if @dependencies.values_at("ruby-lsp", "debug").all?
|
222
243
|
|
223
|
-
|
224
|
-
|
225
|
-
|
244
|
+
# If the custom lockfile doesn't include `ruby-lsp` or `debug`, we need to run bundle install before updating
|
245
|
+
return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug").any?(&:nil?)
|
246
|
+
end
|
226
247
|
|
227
248
|
# If the last updated file doesn't exist or was updated more than 4 hours ago, we should update
|
228
249
|
!@last_updated_path.exist? || Time.parse(@last_updated_path.read) < (Time.now - FOUR_HOURS)
|
229
250
|
end
|
251
|
+
|
252
|
+
# When a lockfile has remote references based on relative file paths, we need to ensure that they are pointing to
|
253
|
+
# the correct place since after copying the relative path is no longer valid
|
254
|
+
sig { void }
|
255
|
+
def correct_relative_remote_paths
|
256
|
+
content = @custom_lockfile.read
|
257
|
+
content.gsub!(/remote: (.*)/) do |match|
|
258
|
+
path = T.must(Regexp.last_match)[1]
|
259
|
+
|
260
|
+
# We should only apply the correction if the remote is a relative path. It might also be a URI, like
|
261
|
+
# `https://rubygems.org` or an absolute path, in which case we shouldn't do anything
|
262
|
+
if path&.start_with?(".")
|
263
|
+
"remote: #{File.expand_path(path, T.must(@gemfile).dirname)}"
|
264
|
+
else
|
265
|
+
match
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
@custom_lockfile.write(content)
|
270
|
+
end
|
230
271
|
end
|
231
272
|
end
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -23,6 +23,9 @@ module RubyLsp
|
|
23
23
|
sig { returns(T::Hash[Symbol, RequestConfig]) }
|
24
24
|
attr_accessor :features_configuration
|
25
25
|
|
26
|
+
sig { returns(String) }
|
27
|
+
attr_accessor :client_name
|
28
|
+
|
26
29
|
sig { void }
|
27
30
|
def initialize
|
28
31
|
@state = T.let({}, T::Hash[String, Document])
|
@@ -33,10 +36,6 @@ module RubyLsp
|
|
33
36
|
@workspace_uri = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
|
34
37
|
@features_configuration = T.let(
|
35
38
|
{
|
36
|
-
codeLens: RequestConfig.new({
|
37
|
-
enableAll: false,
|
38
|
-
gemfileLinks: true,
|
39
|
-
}),
|
40
39
|
inlayHint: RequestConfig.new({
|
41
40
|
enableAll: false,
|
42
41
|
implicitRescue: false,
|
@@ -45,6 +44,7 @@ module RubyLsp
|
|
45
44
|
},
|
46
45
|
T::Hash[Symbol, RequestConfig],
|
47
46
|
)
|
47
|
+
@client_name = T.let("Unknown", String)
|
48
48
|
end
|
49
49
|
|
50
50
|
sig { params(uri: URI::Generic).returns(Document) }
|
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.14.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -30,34 +30,34 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.22.0
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: '0.
|
36
|
+
version: '0.25'
|
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.22.0
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '0.
|
46
|
+
version: '0.25'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: sorbet-runtime
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.5.
|
53
|
+
version: 0.5.10782
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.5.
|
60
|
+
version: 0.5.10782
|
61
61
|
description: An opinionated language server for Ruby
|
62
62
|
email:
|
63
63
|
- ruby@shopify.com
|
@@ -97,7 +97,6 @@ files:
|
|
97
97
|
- lib/ruby_lsp/document.rb
|
98
98
|
- lib/ruby_lsp/executor.rb
|
99
99
|
- lib/ruby_lsp/internal.rb
|
100
|
-
- lib/ruby_lsp/listener.rb
|
101
100
|
- lib/ruby_lsp/listeners/code_lens.rb
|
102
101
|
- lib/ruby_lsp/listeners/completion.rb
|
103
102
|
- lib/ruby_lsp/listeners/definition.rb
|
@@ -139,11 +138,17 @@ files:
|
|
139
138
|
- lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb
|
140
139
|
- lib/ruby_lsp/requests/support/rubocop_runner.rb
|
141
140
|
- lib/ruby_lsp/requests/support/selection_range.rb
|
142
|
-
- lib/ruby_lsp/requests/support/semantic_token_encoder.rb
|
143
141
|
- lib/ruby_lsp/requests/support/sorbet.rb
|
144
142
|
- lib/ruby_lsp/requests/support/source_uri.rb
|
145
143
|
- lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb
|
146
144
|
- lib/ruby_lsp/requests/workspace_symbol.rb
|
145
|
+
- lib/ruby_lsp/response_builders.rb
|
146
|
+
- lib/ruby_lsp/response_builders/collection_response_builder.rb
|
147
|
+
- lib/ruby_lsp/response_builders/document_symbol.rb
|
148
|
+
- lib/ruby_lsp/response_builders/hover.rb
|
149
|
+
- lib/ruby_lsp/response_builders/response_builder.rb
|
150
|
+
- lib/ruby_lsp/response_builders/semantic_highlighting.rb
|
151
|
+
- lib/ruby_lsp/response_builders/signature_help.rb
|
147
152
|
- lib/ruby_lsp/ruby_document.rb
|
148
153
|
- lib/ruby_lsp/server.rb
|
149
154
|
- lib/ruby_lsp/setup_bundler.rb
|
@@ -154,6 +159,7 @@ licenses:
|
|
154
159
|
- MIT
|
155
160
|
metadata:
|
156
161
|
allowed_push_host: https://rubygems.org
|
162
|
+
documentation_uri: https://shopify.github.io/ruby-lsp/
|
157
163
|
post_install_message:
|
158
164
|
rdoc_options: []
|
159
165
|
require_paths:
|
@@ -169,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
175
|
- !ruby/object:Gem::Version
|
170
176
|
version: '0'
|
171
177
|
requirements: []
|
172
|
-
rubygems_version: 3.5.
|
178
|
+
rubygems_version: 3.5.6
|
173
179
|
signing_key:
|
174
180
|
specification_version: 4
|
175
181
|
summary: An opinionated language server for Ruby
|
data/lib/ruby_lsp/listener.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyLsp
|
5
|
-
# Listener is an abstract class to be used by requests for listening to events emitted when visiting an AST using the
|
6
|
-
# Prism::Dispatcher.
|
7
|
-
class Listener
|
8
|
-
extend T::Sig
|
9
|
-
extend T::Helpers
|
10
|
-
extend T::Generic
|
11
|
-
include Requests::Support::Common
|
12
|
-
|
13
|
-
ResponseType = type_member
|
14
|
-
|
15
|
-
abstract!
|
16
|
-
|
17
|
-
sig { params(dispatcher: Prism::Dispatcher).void }
|
18
|
-
def initialize(dispatcher)
|
19
|
-
super()
|
20
|
-
@dispatcher = dispatcher
|
21
|
-
end
|
22
|
-
|
23
|
-
sig { returns(ResponseType) }
|
24
|
-
def response
|
25
|
-
_response
|
26
|
-
end
|
27
|
-
|
28
|
-
# Override this method with an attr_reader that returns the response of your listener. The listener should
|
29
|
-
# accumulate results in a @response variable and then provide the reader so that it is accessible
|
30
|
-
sig { abstract.returns(ResponseType) }
|
31
|
-
def _response; end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyLsp
|
5
|
-
module Requests
|
6
|
-
module Support
|
7
|
-
class SemanticTokenEncoder
|
8
|
-
extend T::Sig
|
9
|
-
|
10
|
-
sig { void }
|
11
|
-
def initialize
|
12
|
-
@current_row = T.let(0, Integer)
|
13
|
-
@current_column = T.let(0, Integer)
|
14
|
-
end
|
15
|
-
|
16
|
-
sig do
|
17
|
-
params(
|
18
|
-
tokens: T::Array[Listeners::SemanticHighlighting::SemanticToken],
|
19
|
-
).returns(Interface::SemanticTokens)
|
20
|
-
end
|
21
|
-
def encode(tokens)
|
22
|
-
delta = tokens
|
23
|
-
.sort_by do |token|
|
24
|
-
[token.location.start_line, token.location.start_column]
|
25
|
-
end
|
26
|
-
.flat_map do |token|
|
27
|
-
compute_delta(token)
|
28
|
-
end
|
29
|
-
|
30
|
-
Interface::SemanticTokens.new(data: delta)
|
31
|
-
end
|
32
|
-
|
33
|
-
# The delta array is computed according to the LSP specification:
|
34
|
-
# > The protocol for the token format relative uses relative
|
35
|
-
# > positions, because most tokens remain stable relative to
|
36
|
-
# > each other when edits are made in a file. This simplifies
|
37
|
-
# > the computation of a delta if a server supports it. So each
|
38
|
-
# > token is represented using 5 integers.
|
39
|
-
|
40
|
-
# For more information on how each number is calculated, read:
|
41
|
-
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
|
42
|
-
sig { params(token: Listeners::SemanticHighlighting::SemanticToken).returns(T::Array[Integer]) }
|
43
|
-
def compute_delta(token)
|
44
|
-
row = token.location.start_line - 1
|
45
|
-
column = token.location.start_column
|
46
|
-
|
47
|
-
begin
|
48
|
-
delta_line = row - @current_row
|
49
|
-
|
50
|
-
delta_column = column
|
51
|
-
delta_column -= @current_column if delta_line == 0
|
52
|
-
|
53
|
-
[delta_line, delta_column, token.length, token.type, encode_modifiers(token.modifier)]
|
54
|
-
ensure
|
55
|
-
@current_row = row
|
56
|
-
@current_column = column
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Encode an array of modifiers to positions onto a bit flag
|
61
|
-
# For example, [:default_library] will be encoded as
|
62
|
-
# 0b1000000000, as :default_library is the 10th bit according
|
63
|
-
# to the token modifiers index map.
|
64
|
-
sig { params(modifiers: T::Array[Integer]).returns(Integer) }
|
65
|
-
def encode_modifiers(modifiers)
|
66
|
-
modifiers.inject(0) do |encoded_modifiers, modifier|
|
67
|
-
encoded_modifiers | (1 << modifier)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|