ruby-lsp 0.21.0 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -81,8 +81,6 @@ module RubyLsp
81
81
  workspace_did_change_watched_files(message)
82
82
  when "workspace/symbol"
83
83
  workspace_symbol(message)
84
- when "window/showMessageRequest"
85
- window_show_message_request(message)
86
84
  when "rubyLsp/textDocument/showSyntaxTree"
87
85
  text_document_show_syntax_tree(message)
88
86
  when "rubyLsp/workspace/dependencies"
@@ -108,6 +106,8 @@ module RubyLsp
108
106
  )
109
107
  when "$/cancelRequest"
110
108
  @mutex.synchronize { @cancelled_requests << message[:params][:id] }
109
+ when nil
110
+ process_response(message) if message[:result]
111
111
  end
112
112
  rescue DelegateRequestError
113
113
  send_message(Error.new(id: message[:id], code: DelegateRequestError::CODE, message: "DELEGATE_REQUEST"))
@@ -140,6 +140,15 @@ module RubyLsp
140
140
  send_log_message("Error processing #{message[:method]}: #{e.full_message}", type: Constant::MessageType::ERROR)
141
141
  end
142
142
 
143
+ # Process responses to requests that were sent to the client
144
+ sig { params(message: T::Hash[Symbol, T.untyped]).void }
145
+ def process_response(message)
146
+ case message.dig(:result, :method)
147
+ when "window/showMessageRequest"
148
+ window_show_message_request(message)
149
+ end
150
+ end
151
+
143
152
  sig { params(include_project_addons: T::Boolean).void }
144
153
  def load_addons(include_project_addons: true)
145
154
  # If invoking Bundler.setup failed, then the load path will not be configured properly and trying to load add-ons
@@ -188,8 +197,6 @@ module RubyLsp
188
197
  client_name = options.dig(:clientInfo, :name)
189
198
  @store.client_name = client_name if client_name
190
199
 
191
- progress = options.dig(:capabilities, :window, :workDoneProgress)
192
- @store.supports_progress = progress.nil? ? true : progress
193
200
  configured_features = options.dig(:initializationOptions, :enabledFeatures)
194
201
 
195
202
  configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
@@ -209,6 +216,13 @@ module RubyLsp
209
216
  Hash.new(true)
210
217
  end
211
218
 
219
+ bundle_env_path = File.join(".ruby-lsp", "bundle_env")
220
+ bundle_env = if File.exist?(bundle_env_path)
221
+ env = File.readlines(bundle_env_path).to_h { |line| T.cast(line.chomp.split("=", 2), [String, String]) }
222
+ FileUtils.rm(bundle_env_path)
223
+ env
224
+ end
225
+
212
226
  document_symbol_provider = Requests::DocumentSymbol.provider if enabled_features["documentSymbols"]
213
227
  document_link_provider = Requests::DocumentLink.provider if enabled_features["documentLink"]
214
228
  code_lens_provider = Requests::CodeLens.provider if enabled_features["codeLens"]
@@ -262,6 +276,7 @@ module RubyLsp
262
276
  },
263
277
  formatter: @global_state.formatter,
264
278
  degraded_mode: !!(@install_error || @setup_error),
279
+ bundle_env: bundle_env,
265
280
  }
266
281
 
267
282
  send_message(Result.new(id: message[:id], response: response))
@@ -597,6 +612,11 @@ module RubyLsp
597
612
  # don't want to format it
598
613
  path = uri.to_standardized_path
599
614
  unless path.nil? || path.start_with?(@global_state.workspace_path)
615
+ send_log_message(<<~MESSAGE)
616
+ Ignoring formatting request for file outside of the workspace.
617
+ Workspace path was set by editor as #{@global_state.workspace_path}.
618
+ File path requested for formatting was #{path}
619
+ MESSAGE
600
620
  send_empty_response(message[:id])
601
621
  return
602
622
  end
@@ -1105,7 +1125,7 @@ module RubyLsp
1105
1125
 
1106
1126
  sig { params(id: String, title: String, percentage: Integer).void }
1107
1127
  def begin_progress(id, title, percentage: 0)
1108
- return unless @store.supports_progress
1128
+ return unless @global_state.client_capabilities.supports_progress
1109
1129
 
1110
1130
  send_message(Request.new(
1111
1131
  id: @current_request_id,
@@ -1113,52 +1133,21 @@ module RubyLsp
1113
1133
  params: Interface::WorkDoneProgressCreateParams.new(token: id),
1114
1134
  ))
1115
1135
 
1116
- send_message(Notification.new(
1117
- method: "$/progress",
1118
- params: Interface::ProgressParams.new(
1119
- token: id,
1120
- value: Interface::WorkDoneProgressBegin.new(
1121
- kind: "begin",
1122
- title: title,
1123
- percentage: percentage,
1124
- message: "#{percentage}% completed",
1125
- ),
1126
- ),
1127
- ))
1136
+ send_message(Notification.progress_begin(id, title, percentage: percentage, message: "#{percentage}% completed"))
1128
1137
  end
1129
1138
 
1130
1139
  sig { params(id: String, percentage: Integer).void }
1131
1140
  def progress(id, percentage)
1132
- return unless @store.supports_progress
1141
+ return unless @global_state.client_capabilities.supports_progress
1133
1142
 
1134
- send_message(
1135
- Notification.new(
1136
- method: "$/progress",
1137
- params: Interface::ProgressParams.new(
1138
- token: id,
1139
- value: Interface::WorkDoneProgressReport.new(
1140
- kind: "report",
1141
- percentage: percentage,
1142
- message: "#{percentage}% completed",
1143
- ),
1144
- ),
1145
- ),
1146
- )
1143
+ send_message(Notification.progress_report(id, percentage: percentage, message: "#{percentage}% completed"))
1147
1144
  end
1148
1145
 
1149
1146
  sig { params(id: String).void }
1150
1147
  def end_progress(id)
1151
- return unless @store.supports_progress
1148
+ return unless @global_state.client_capabilities.supports_progress
1152
1149
 
1153
- send_message(
1154
- Notification.new(
1155
- method: "$/progress",
1156
- params: Interface::ProgressParams.new(
1157
- token: id,
1158
- value: Interface::WorkDoneProgressEnd.new(kind: "end"),
1159
- ),
1160
- ),
1161
- )
1150
+ send_message(Notification.progress_end(id))
1162
1151
  rescue ClosedQueueError
1163
1152
  # If the server was killed and the message queue is already closed, there's no way to end the progress
1164
1153
  # notification
@@ -1226,11 +1215,14 @@ module RubyLsp
1226
1215
 
1227
1216
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
1228
1217
  def window_show_message_request(message)
1229
- addon_name = message[:addon_name]
1218
+ result = message[:result]
1219
+ return unless result
1220
+
1221
+ addon_name = result[:addon_name]
1230
1222
  addon = Addon.addons.find { |addon| addon.name == addon_name }
1231
1223
  return unless addon
1232
1224
 
1233
- addon.handle_window_show_message_response(message[:title])
1225
+ addon.handle_window_show_message_response(result[:title])
1234
1226
  end
1235
1227
  end
1236
1228
  end
@@ -12,7 +12,7 @@ require "digest"
12
12
  require "time"
13
13
  require "uri"
14
14
 
15
- # This file is a script that will configure a custom bundle for the Ruby LSP. The custom bundle allows developers to use
15
+ # This file is a script that will configure a composed bundle for the Ruby LSP. The composed bundle allows developers to use
16
16
  # the Ruby LSP without including the gem in their application's Gemfile while at the same time giving us access to the
17
17
  # exact locked versions of dependencies.
18
18
 
@@ -62,7 +62,7 @@ module RubyLsp
62
62
  @retry = T.let(false, T::Boolean)
63
63
  end
64
64
 
65
- # Sets up the custom bundle and returns the `BUNDLE_GEMFILE`, `BUNDLE_PATH` and `BUNDLE_APP_CONFIG` that should be
65
+ # Sets up the composed bundle and returns the `BUNDLE_GEMFILE`, `BUNDLE_PATH` and `BUNDLE_APP_CONFIG` that should be
66
66
  # used for running the server
67
67
  sig { returns(T::Hash[String, String]) }
68
68
  def setup!
@@ -73,12 +73,12 @@ module RubyLsp
73
73
  ignore_file = @custom_dir + ".gitignore"
74
74
  ignore_file.write("*") unless ignore_file.exist?
75
75
 
76
- # Do not set up a custom bundle if LSP dependencies are already in the Gemfile
76
+ # Do not set up a composed bundle if LSP dependencies are already in the Gemfile
77
77
  if @dependencies["ruby-lsp"] &&
78
78
  @dependencies["debug"] &&
79
79
  (@rails_app ? @dependencies["ruby-lsp-rails"] : true)
80
80
  $stderr.puts(
81
- "Ruby LSP> Skipping custom bundle setup since LSP dependencies are already in #{@gemfile}",
81
+ "Ruby LSP> Skipping composed bundle setup since LSP dependencies are already in #{@gemfile}",
82
82
  )
83
83
 
84
84
  return run_bundle_install
@@ -96,7 +96,7 @@ module RubyLsp
96
96
 
97
97
  if @custom_lockfile.exist? && @lockfile_hash_path.exist? && @lockfile_hash_path.read == current_lockfile_hash
98
98
  $stderr.puts(
99
- "Ruby LSP> Skipping custom bundle setup since #{@custom_lockfile} already exists and is up to date",
99
+ "Ruby LSP> Skipping composed bundle setup since #{@custom_lockfile} already exists and is up to date",
100
100
  )
101
101
  return run_bundle_install(@custom_gemfile)
102
102
  end
@@ -110,8 +110,8 @@ module RubyLsp
110
110
  private
111
111
 
112
112
  sig { returns(T::Hash[String, T.untyped]) }
113
- def custom_bundle_dependencies
114
- @custom_bundle_dependencies ||= T.let(
113
+ def composed_bundle_dependencies
114
+ @composed_bundle_dependencies ||= T.let(
115
115
  begin
116
116
  original_bundle_gemfile = ENV["BUNDLE_GEMFILE"]
117
117
 
@@ -136,8 +136,8 @@ module RubyLsp
136
136
  "",
137
137
  ]
138
138
 
139
- # If there's a top level Gemfile, we want to evaluate from the custom bundle. We get the source from the top level
140
- # Gemfile, so if there isn't one we need to add a default source
139
+ # If there's a top level Gemfile, we want to evaluate from the composed bundle. We get the source from the top
140
+ # level Gemfile, so if there isn't one we need to add a default source
141
141
  if @gemfile&.exist? && @lockfile&.exist?
142
142
  parts << "eval_gemfile(File.expand_path(\"../#{@gemfile_name}\", __dir__))"
143
143
  else
@@ -187,7 +187,7 @@ module RubyLsp
187
187
  env = bundler_settings_as_env
188
188
  env["BUNDLE_GEMFILE"] = bundle_gemfile.to_s
189
189
 
190
- # If the user has a custom bundle path configured, we need to ensure that we will use the absolute and not
190
+ # If the user has a composed bundle path configured, we need to ensure that we will use the absolute and not
191
191
  # relative version of it when running `bundle install`. This is necessary to avoid installing the gems under the
192
192
  # `.ruby-lsp` folder, which is not the user's intention. For example, if the path is configured as `vendor`, we
193
193
  # want to install it in the top level `vendor` and not `.ruby-lsp/vendor`
@@ -244,7 +244,7 @@ module RubyLsp
244
244
  base_bundle = base_bundle_command(env)
245
245
 
246
246
  # If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
247
- # to upgrade them or else we'll produce undesired source control changes. If the custom bundle was just created
247
+ # to upgrade them or else we'll produce undesired source control changes. If the composed bundle was just created
248
248
  # and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
249
249
  # install` for the first time to generate the Gemfile.lock with them included or else Bundler will complain that
250
250
  # they're missing. We can only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
@@ -274,16 +274,16 @@ module RubyLsp
274
274
  command << "1>&2"
275
275
 
276
276
  # Add bundle update
277
- $stderr.puts("Ruby LSP> Running bundle install for the custom bundle. This may take a while...")
277
+ $stderr.puts("Ruby LSP> Running bundle install for the composed bundle. This may take a while...")
278
278
  $stderr.puts("Ruby LSP> Command: #{command}")
279
279
 
280
- # Try to run the bundle install or update command. If that fails, it normally means that the custom lockfile is in
281
- # a bad state that no longer reflects the top level one. In that case, we can remove the whole directory, try
280
+ # Try to run the bundle install or update command. If that fails, it normally means that the composed lockfile is
281
+ # in a bad state that no longer reflects the top level one. In that case, we can remove the whole directory, try
282
282
  # another time and give up if it fails again
283
283
  if !system(env, command) && !@retry && @custom_gemfile.exist?
284
284
  @retry = true
285
285
  @custom_dir.rmtree
286
- $stderr.puts("Ruby LSP> Running bundle install failed. Trying to re-generate the custom bundle from scratch")
286
+ $stderr.puts("Ruby LSP> Running bundle install failed. Trying to re-generate the composed bundle from scratch")
287
287
  return setup!
288
288
  end
289
289
 
@@ -330,14 +330,14 @@ module RubyLsp
330
330
  if @rails_app
331
331
  return false if @dependencies.values_at("ruby-lsp", "ruby-lsp-rails", "debug").all?
332
332
 
333
- # If the custom lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle install
334
- # before updating
335
- return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug", "ruby-lsp-rails").any?(&:nil?)
333
+ # If the composed lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle
334
+ # install before updating
335
+ return false if composed_bundle_dependencies.values_at("ruby-lsp", "debug", "ruby-lsp-rails").any?(&:nil?)
336
336
  else
337
337
  return false if @dependencies.values_at("ruby-lsp", "debug").all?
338
338
 
339
- # If the custom lockfile doesn't include `ruby-lsp` or `debug`, we need to run bundle install before updating
340
- return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug").any?(&:nil?)
339
+ # If the composed lockfile doesn't include `ruby-lsp` or `debug`, we need to run bundle install before updating
340
+ return false if composed_bundle_dependencies.values_at("ruby-lsp", "debug").any?(&:nil?)
341
341
  end
342
342
 
343
343
  # If the last updated file doesn't exist or was updated more than 4 hours ago, we should update
@@ -359,6 +359,9 @@ module RubyLsp
359
359
  else
360
360
  match
361
361
  end
362
+ rescue URI::InvalidURIError, URI::InvalidComponentError
363
+ # If the path raises an invalid error, it might be a git ssh path, which indeed isn't a URI
364
+ match
362
365
  end
363
366
 
364
367
  @custom_lockfile.write(content)
@@ -7,9 +7,6 @@ module RubyLsp
7
7
 
8
8
  class NonExistingDocumentError < StandardError; end
9
9
 
10
- sig { returns(T::Boolean) }
11
- attr_accessor :supports_progress
12
-
13
10
  sig { returns(T::Hash[Symbol, RequestConfig]) }
14
11
  attr_accessor :features_configuration
15
12
 
@@ -19,7 +16,6 @@ module RubyLsp
19
16
  sig { void }
20
17
  def initialize
21
18
  @state = T.let({}, T::Hash[String, Document[T.untyped]])
22
- @supports_progress = T.let(true, T::Boolean)
23
19
  @features_configuration = T.let(
24
20
  {
25
21
  inlayHint: RequestConfig.new({
@@ -87,6 +87,61 @@ module RubyLsp
87
87
  params: data,
88
88
  )
89
89
  end
90
+
91
+ sig do
92
+ params(
93
+ id: String,
94
+ title: String,
95
+ percentage: T.nilable(Integer),
96
+ message: T.nilable(String),
97
+ ).returns(Notification)
98
+ end
99
+ def progress_begin(id, title, percentage: nil, message: nil)
100
+ new(
101
+ method: "$/progress",
102
+ params: Interface::ProgressParams.new(
103
+ token: id,
104
+ value: Interface::WorkDoneProgressBegin.new(
105
+ kind: "begin",
106
+ title: title,
107
+ percentage: percentage,
108
+ message: message,
109
+ ),
110
+ ),
111
+ )
112
+ end
113
+
114
+ sig do
115
+ params(
116
+ id: String,
117
+ percentage: T.nilable(Integer),
118
+ message: T.nilable(String),
119
+ ).returns(Notification)
120
+ end
121
+ def progress_report(id, percentage: nil, message: nil)
122
+ new(
123
+ method: "$/progress",
124
+ params: Interface::ProgressParams.new(
125
+ token: id,
126
+ value: Interface::WorkDoneProgressReport.new(
127
+ kind: "report",
128
+ percentage: percentage,
129
+ message: message,
130
+ ),
131
+ ),
132
+ )
133
+ end
134
+
135
+ sig { params(id: String).returns(Notification) }
136
+ def progress_end(id)
137
+ Notification.new(
138
+ method: "$/progress",
139
+ params: Interface::ProgressParams.new(
140
+ token: id,
141
+ value: Interface::WorkDoneProgressEnd.new(kind: "end"),
142
+ ),
143
+ )
144
+ end
90
145
  end
91
146
 
92
147
  extend T::Sig
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.21.0
4
+ version: 0.22.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-31 00:00:00.000000000 Z
11
+ date: 2024-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: language_server-protocol
@@ -217,7 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
217
  - !ruby/object:Gem::Version
218
218
  version: '0'
219
219
  requirements: []
220
- rubygems_version: 3.5.22
220
+ rubygems_version: 3.5.23
221
221
  signing_key:
222
222
  specification_version: 4
223
223
  summary: An opinionated language server for Ruby