Add channel to notify project when languages are added
This commit is contained in:
parent
5cb59dfdab
commit
73620dad06
4 changed files with 80 additions and 4 deletions
|
@ -18,6 +18,7 @@ use gpui::{MutableAppContext, Task};
|
||||||
use highlight_map::HighlightMap;
|
use highlight_map::HighlightMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
use postage::watch;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{de, Deserialize, Deserializer};
|
use serde::{de, Deserialize, Deserializer};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
@ -316,6 +317,7 @@ pub struct LanguageRegistry {
|
||||||
Shared<BoxFuture<'static, Result<PathBuf, Arc<anyhow::Error>>>>,
|
Shared<BoxFuture<'static, Result<PathBuf, Arc<anyhow::Error>>>>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
|
subscription: RwLock<(watch::Sender<()>, watch::Receiver<()>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageRegistry {
|
impl LanguageRegistry {
|
||||||
|
@ -328,6 +330,7 @@ impl LanguageRegistry {
|
||||||
lsp_binary_statuses_rx,
|
lsp_binary_statuses_rx,
|
||||||
login_shell_env_loaded: login_shell_env_loaded.shared(),
|
login_shell_env_loaded: login_shell_env_loaded.shared(),
|
||||||
lsp_binary_paths: Default::default(),
|
lsp_binary_paths: Default::default(),
|
||||||
|
subscription: RwLock::new(watch::channel()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +341,11 @@ impl LanguageRegistry {
|
||||||
|
|
||||||
pub fn add(&self, language: Arc<Language>) {
|
pub fn add(&self, language: Arc<Language>) {
|
||||||
self.languages.write().push(language.clone());
|
self.languages.write().push(language.clone());
|
||||||
|
*self.subscription.write().0.borrow_mut() = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe(&self) -> watch::Receiver<()> {
|
||||||
|
self.subscription.read().1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_theme(&self, theme: &SyntaxTheme) {
|
pub fn set_theme(&self, theme: &SyntaxTheme) {
|
||||||
|
|
|
@ -125,6 +125,7 @@ pub struct Project {
|
||||||
buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
|
buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
|
||||||
nonce: u128,
|
nonce: u128,
|
||||||
initialized_persistent_state: bool,
|
initialized_persistent_state: bool,
|
||||||
|
_maintain_buffer_languages: Task<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -472,6 +473,7 @@ impl Project {
|
||||||
opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
|
opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
|
||||||
client_subscriptions: Vec::new(),
|
client_subscriptions: Vec::new(),
|
||||||
_subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
|
_subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
|
||||||
|
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
languages,
|
languages,
|
||||||
client,
|
client,
|
||||||
|
@ -549,6 +551,7 @@ impl Project {
|
||||||
loading_local_worktrees: Default::default(),
|
loading_local_worktrees: Default::default(),
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
collaborators: Default::default(),
|
collaborators: Default::default(),
|
||||||
|
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
|
||||||
languages,
|
languages,
|
||||||
user_store: user_store.clone(),
|
user_store: user_store.clone(),
|
||||||
project_store,
|
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(
|
fn assign_language_to_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &ModelHandle<Buffer>,
|
buffer: &ModelHandle<Buffer>,
|
||||||
|
@ -2089,9 +2120,10 @@ impl Project {
|
||||||
move |params, mut cx| {
|
move |params, mut cx| {
|
||||||
if let Some(this) = this.upgrade(&cx) {
|
if let Some(this) = this.upgrade(&cx) {
|
||||||
this.update(&mut cx, |this, 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,
|
server_id, params, &adapter, cx,
|
||||||
);
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,11 +122,46 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let project = Project::test(fs.clone(), ["/the-root".as_ref()], cx).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));
|
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.
|
// Open a buffer without an associated language server.
|
||||||
let toml_buffer = project
|
let toml_buffer = project
|
||||||
.update(cx, |project, cx| {
|
.update(cx, |project, cx| {
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub async fn new_json(executor: Arc<Background>) -> Result<PluginLspAdapter> {
|
||||||
include_bytes!("../../../../plugins/bin/json_language.wasm.pre"),
|
include_bytes!("../../../../plugins/bin/json_language.wasm.pre"),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
// smol::Timer::after(std::time::Duration::from_secs(5)).await;
|
||||||
PluginLspAdapter::new(plugin, executor).await
|
PluginLspAdapter::new(plugin, executor).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue