Implement the `did_change_watched_files` event in LSP to recompile project on manifest change.
This is a follow on from #7079
At the moment we are spawning a tokio thread to watch for changes to the projects Forc.toml file. This isn't very effecient, we should be taking advantage of the LSP did_change_watched_files event. This works by registering the file types you would like the client to watch for you and then trigger an event when they are created, modified or deleted. See below for how we can do this.
/// Registers a file system watcher for Forc.toml files with the client.
pub async fn register_forc_toml_watcher(&self) {
let client = self
.client
.as_ref()
.expect("Client is guaranteed to be set by the time this is called");
let watchers = vec![FileSystemWatcher {
glob_pattern: GlobPattern::String("**/Forc.toml".to_string()),
kind: Some(WatchKind::Create | WatchKind::Change),
}];
let registration_options = DidChangeWatchedFilesRegistrationOptions { watchers };
let registration = Registration {
id: "forc-toml-watcher".to_string(),
method: "workspace/didChangeWatchedFiles".to_string(),
register_options: Some(
serde_json::to_value(registration_options)
.expect("Failed to serialize registration options"),
),
};
if let Err(err) = client.register_capability(vec![registration]).await {
tracing::error!("Failed to register Forc.toml file watcher: {}", err);
} else {
tracing::info!("Successfully registered Forc.toml file watcher");
}
}
Then in the handle_did_change_watched_files function we can trigger a recompilation of the project if we detect that the manifest has been modified.
To be safe for now, we probably want to perform GC on the relevant program that had the manifest edits before recompiling.
let _ = session.garbage_collect_program(&mut session.engines.write());
Finally, once this is implemented we should remove the custom tokio thread monitoring in the sync module as it will no longer be required.