Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use unique IDs for registering watchers #3144

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/ruby_lsp/internal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
require "rbs"
require "fileutils"
require "open3"
require "securerandom"

require "ruby-lsp"
require "ruby_lsp/base_server"
Expand Down
18 changes: 16 additions & 2 deletions lib/ruby_lsp/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,19 @@ def run_initialize(message)

# Not every client supports dynamic registration or file watching
if @global_state.client_capabilities.supports_watching_files
send_message(Request.register_watched_files(@current_request_id, "**/*.rb"))
send_message(Request.register_watched_files(
@current_request_id,
Interface::RelativePattern.new(base_uri: @global_state.workspace_uri.to_s, pattern: ".rubocop.yml"),
"**/*.rb",
registration_id: "workspace-watcher",
))

send_message(Request.register_watched_files(
@current_request_id,
Interface::RelativePattern.new(
base_uri: @global_state.workspace_uri.to_s,
pattern: "{.rubocop.yml,.rubocop}",
),
registration_id: "rubocop-watcher",
))
end

Expand Down Expand Up @@ -999,6 +1008,11 @@ def text_document_definition(message)
sig { params(message: T::Hash[Symbol, T.untyped]).void }
def workspace_did_change_watched_files(message)
changes = message.dig(:params, :changes)
# We allow add-ons to register for watching files and we have no restrictions for what they register for. If the
# same pattern is registered more than once, the LSP will receive duplicate change notifications. Receiving them
# is fine, but we shouldn't process the same file changes more than once
changes.uniq!

index = @global_state.index
changes.each do |change|
# File change events include folders, but we're only interested in files
Expand Down
14 changes: 11 additions & 3 deletions lib/ruby_lsp/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,27 @@ class Request < Message
class << self
extend T::Sig

sig { params(id: Integer, pattern: T.any(Interface::RelativePattern, String), kind: Integer).returns(Request) }
sig do
params(
id: Integer,
pattern: T.any(Interface::RelativePattern, String),
kind: Integer,
registration_id: T.nilable(String),
).returns(Request)
end
def register_watched_files(
id,
pattern,
kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE
kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
registration_id: nil
)
new(
id: id,
method: "client/registerCapability",
params: Interface::RegistrationParams.new(
registrations: [
Interface::Registration.new(
id: "workspace/didChangeWatchedFiles",
id: registration_id || SecureRandom.uuid,
method: "workspace/didChangeWatchedFiles",
register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new(
watchers: [
Expand Down
19 changes: 19 additions & 0 deletions test/server_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,25 @@ def test_did_change_watched_files_does_not_fail_for_non_existing_files
end
end

def test_did_change_watched_files_processes_unique_change_entries
@server.expects(:handle_rubocop_config_change).once
@server.process_message({
method: "workspace/didChangeWatchedFiles",
params: {
changes: [
{
uri: URI::Generic.from_path(path: File.join(Dir.pwd, ".rubocop.yml")).to_s,
type: RubyLsp::Constant::FileChangeType::CHANGED,
},
{
uri: URI::Generic.from_path(path: File.join(Dir.pwd, ".rubocop.yml")).to_s,
type: RubyLsp::Constant::FileChangeType::CHANGED,
},
],
},
})
end

def test_workspace_addons
create_test_addons
@server.load_addons
Expand Down