ruby-lsp 0.13.4 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -2
  3. data/VERSION +1 -1
  4. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +4 -8
  5. data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +5 -1
  6. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +4 -2
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +10 -5
  8. data/lib/ruby_indexer/test/classes_and_modules_test.rb +9 -0
  9. data/lib/ruby_indexer/test/index_test.rb +54 -3
  10. data/lib/ruby_lsp/addon.rb +21 -10
  11. data/lib/ruby_lsp/check_docs.rb +8 -8
  12. data/lib/ruby_lsp/executor.rb +28 -10
  13. data/lib/ruby_lsp/internal.rb +1 -1
  14. data/lib/ruby_lsp/listeners/code_lens.rb +54 -55
  15. data/lib/ruby_lsp/listeners/completion.rb +22 -18
  16. data/lib/ruby_lsp/listeners/definition.rb +31 -29
  17. data/lib/ruby_lsp/listeners/document_highlight.rb +6 -11
  18. data/lib/ruby_lsp/listeners/document_link.rb +6 -12
  19. data/lib/ruby_lsp/listeners/document_symbol.rb +194 -55
  20. data/lib/ruby_lsp/listeners/folding_ranges.rb +19 -23
  21. data/lib/ruby_lsp/listeners/hover.rb +36 -34
  22. data/lib/ruby_lsp/listeners/inlay_hints.rb +7 -13
  23. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -124
  24. data/lib/ruby_lsp/listeners/signature_help.rb +15 -14
  25. data/lib/ruby_lsp/requests/code_lens.rb +11 -19
  26. data/lib/ruby_lsp/requests/completion.rb +7 -9
  27. data/lib/ruby_lsp/requests/definition.rb +10 -22
  28. data/lib/ruby_lsp/requests/document_highlight.rb +7 -5
  29. data/lib/ruby_lsp/requests/document_link.rb +7 -6
  30. data/lib/ruby_lsp/requests/document_symbol.rb +5 -11
  31. data/lib/ruby_lsp/requests/folding_ranges.rb +11 -6
  32. data/lib/ruby_lsp/requests/hover.rb +18 -24
  33. data/lib/ruby_lsp/requests/inlay_hints.rb +7 -8
  34. data/lib/ruby_lsp/requests/on_type_formatting.rb +12 -2
  35. data/lib/ruby_lsp/requests/semantic_highlighting.rb +10 -8
  36. data/lib/ruby_lsp/requests/signature_help.rb +53 -18
  37. data/lib/ruby_lsp/requests/support/common.rb +38 -10
  38. data/lib/ruby_lsp/requests/support/dependency_detector.rb +5 -1
  39. data/lib/ruby_lsp/requests.rb +0 -1
  40. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +29 -0
  41. data/lib/ruby_lsp/response_builders/document_symbol.rb +57 -0
  42. data/lib/ruby_lsp/response_builders/hover.rb +49 -0
  43. data/lib/ruby_lsp/response_builders/response_builder.rb +16 -0
  44. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +199 -0
  45. data/lib/ruby_lsp/response_builders/signature_help.rb +28 -0
  46. data/lib/ruby_lsp/response_builders.rb +13 -0
  47. data/lib/ruby_lsp/server.rb +3 -3
  48. data/lib/ruby_lsp/setup_bundler.rb +64 -23
  49. data/lib/ruby_lsp/store.rb +4 -4
  50. metadata +14 -9
  51. data/lib/ruby_lsp/listener.rb +0 -33
  52. 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
@@ -58,7 +58,7 @@ module RubyLsp
58
58
 
59
59
  sig { void }
60
60
  def start
61
- warn("Starting Ruby LSP v#{VERSION}...")
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
- warn("Shutting down Ruby LSP...")
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
- warn("Shutdown complete with status #{status}")
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 setup a custom bundle if both `ruby-lsp` and `debug` are already in the Gemfile
61
- if @dependencies["ruby-lsp"] && @dependencies["debug"]
62
- warn("Ruby LSP> Skipping custom bundle setup since both `ruby-lsp` and `debug` are already in #{@gemfile}")
63
-
64
- # If the user decided to add the `ruby-lsp` and `debug` to their Gemfile after having already run the Ruby LSP,
65
- # then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle install` for the top level and
66
- # try to execute the Ruby LSP using the custom bundle, which will fail since the gems are not installed there
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
- warn("Ruby LSP> Skipping lockfile copies because there's no top level bundle")
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
- warn("Ruby LSP> Skipping custom bundle setup since #{@custom_lockfile} already exists and is up to date")
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 both `ruby-lsp` and `debug` are already in the Gemfile, then we shouldn't try to upgrade them or else we'll
182
- # produce undesired source control changes. If the custom bundle was just created and either `ruby-lsp` or `debug`
183
- # weren't a part of the Gemfile, then we need to run `bundle install` for the first time to generate the
184
- # Gemfile.lock with them included or else Bundler will complain that they're missing. We can only update if the
185
- # custom `.ruby-lsp/Gemfile.lock` already exists and includes both gems
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 version
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
- warn("Ruby LSP> Running bundle install for the custom bundle. This may take a while...")
212
- warn("Ruby LSP> Command: #{command}")
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 both `ruby-lsp` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it will produce
220
- # version control changes
221
- return false if @dependencies["ruby-lsp"] && @dependencies["debug"]
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
- # If the custom lockfile doesn't include either the `ruby-lsp` or `debug`, we need to run bundle install before
224
- # updating
225
- return false if custom_bundle_dependencies["ruby-lsp"].nil? || custom_bundle_dependencies["debug"].nil?
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
@@ -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.13.4
4
+ version: 0.14.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-01-12 00:00:00.000000000 Z
11
+ date: 2024-02-16 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.19.0
33
+ version: 0.22.0
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '0.20'
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.19.0
43
+ version: 0.22.0
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.20'
46
+ version: '0.25'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sorbet-runtime
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -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
@@ -169,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
174
  - !ruby/object:Gem::Version
170
175
  version: '0'
171
176
  requirements: []
172
- rubygems_version: 3.5.4
177
+ rubygems_version: 3.5.6
173
178
  signing_key:
174
179
  specification_version: 4
175
180
  summary: An opinionated language server for Ruby
@@ -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