Add channel to notify project when languages are added

This commit is contained in:
Isaac Clayton 2022-07-08 14:37:27 +02:00
parent 5cb59dfdab
commit 73620dad06
4 changed files with 80 additions and 4 deletions

View file

@ -125,6 +125,7 @@ pub struct Project {
buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
nonce: u128,
initialized_persistent_state: bool,
_maintain_buffer_languages: Task<()>,
}
#[derive(Error, Debug)]
@ -472,6 +473,7 @@ impl Project {
opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
client_subscriptions: Vec::new(),
_subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
active_entry: None,
languages,
client,
@ -549,6 +551,7 @@ impl Project {
loading_local_worktrees: Default::default(),
active_entry: None,
collaborators: Default::default(),
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
languages,
user_store: user_store.clone(),
project_store,
@ -2019,6 +2022,34 @@ impl Project {
})
}
fn maintain_buffer_languages(
languages: &LanguageRegistry,
cx: &mut ModelContext<Project>,
) -> Task<()> {
let mut subscription = languages.subscribe();
cx.spawn_weak(|project, mut cx| async move {
while let Some(_) = subscription.next().await {
if let Some(project) = project.upgrade(&cx) {
project.update(&mut cx, |project, cx| {
let mut buffers_without_language = Vec::new();
for buffer in project.opened_buffers.values() {
if let Some(buffer) = buffer.upgrade(cx) {
if buffer.read(cx).language().is_none() {
buffers_without_language.push(buffer);
}
}
}
for buffer in buffers_without_language {
project.assign_language_to_buffer(&buffer, cx);
project.register_buffer_with_language_server(&buffer, cx);
}
});
}
}
})
}
fn assign_language_to_buffer(
&mut self,
buffer: &ModelHandle<Buffer>,
@ -2089,9 +2120,10 @@ impl Project {
move |params, mut cx| {
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.on_lsp_diagnostics_published(
// TODO(isaac): remove block on
smol::block_on(this.on_lsp_diagnostics_published(
server_id, params, &adapter, cx,
);
));
});
}
}

View file

@ -122,11 +122,46 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
.await;
let project = Project::test(fs.clone(), ["/the-root".as_ref()], cx).await;
project.update(cx, |project, _| {
project.languages.add(Arc::new(rust_language));
// Open a buffer before languages have been added
let json_buffer = project
.update(cx, |project, cx| {
project.open_local_buffer("/the-root/package.json", cx)
})
.await
.unwrap();
// Assert that this buffer does not have a language
assert!(json_buffer.read_with(cx, |buffer, _| { buffer.language().is_none() }));
// Now we add the languages to the project, and subscribe to the watcher
project.update(cx, |project, cx| {
// Get a handle to the channel and clear out default item
let mut recv = project.languages.subscribe();
recv.blocking_recv();
// Add, then wait to be notified that JSON has been added
project.languages.add(Arc::new(json_language));
recv.blocking_recv();
// Add, then wait to be notified that Rust has been added
project.languages.add(Arc::new(rust_language));
recv.blocking_recv();
// Uncommenting this would cause the thread to block indefinitely:
// recv.blocking_recv();
// Force the assignment, we know the watcher has been notified
// but have no way to wait for the watcher to assign to the project
project.assign_language_to_buffer(&json_buffer, cx);
});
// Assert that the opened buffer does have a language, and that it is JSON
let name = json_buffer.read_with(cx, |buffer, _| buffer.language().map(|l| l.name()));
assert_eq!(name, Some("JSON".into()));
// Close the JSON buffer we opened
cx.update(|_| drop(json_buffer));
// Open a buffer without an associated language server.
let toml_buffer = project
.update(cx, |project, cx| {