Notify all language servers only when a buffer is saved
Other notifications such as opening, closing or changing a document are still tied to the buffer's language.
This commit is contained in:
parent
4cb4b99c56
commit
0a9595b5fa
2 changed files with 129 additions and 198 deletions
|
@ -225,7 +225,9 @@ impl LspCommand for PerformRename {
|
||||||
if let Some(edit) = message {
|
if let Some(edit) = message {
|
||||||
let language_server = project
|
let language_server = project
|
||||||
.read_with(&cx, |project, cx| {
|
.read_with(&cx, |project, cx| {
|
||||||
project.language_server_for_buffer(&buffer, cx).cloned()
|
project
|
||||||
|
.language_server_for_buffer(buffer.read(cx), cx)
|
||||||
|
.cloned()
|
||||||
})
|
})
|
||||||
.ok_or_else(|| anyhow!("no language server found for buffer"))?;
|
.ok_or_else(|| anyhow!("no language server found for buffer"))?;
|
||||||
let language = buffer
|
let language = buffer
|
||||||
|
@ -343,7 +345,9 @@ impl LspCommand for GetDefinition {
|
||||||
let mut definitions = Vec::new();
|
let mut definitions = Vec::new();
|
||||||
let language_server = project
|
let language_server = project
|
||||||
.read_with(&cx, |project, cx| {
|
.read_with(&cx, |project, cx| {
|
||||||
project.language_server_for_buffer(&buffer, cx).cloned()
|
project
|
||||||
|
.language_server_for_buffer(buffer.read(cx), cx)
|
||||||
|
.cloned()
|
||||||
})
|
})
|
||||||
.ok_or_else(|| anyhow!("no language server found for buffer"))?;
|
.ok_or_else(|| anyhow!("no language server found for buffer"))?;
|
||||||
let language = buffer
|
let language = buffer
|
||||||
|
@ -519,7 +523,9 @@ impl LspCommand for GetReferences {
|
||||||
let mut references = Vec::new();
|
let mut references = Vec::new();
|
||||||
let language_server = project
|
let language_server = project
|
||||||
.read_with(&cx, |project, cx| {
|
.read_with(&cx, |project, cx| {
|
||||||
project.language_server_for_buffer(&buffer, cx).cloned()
|
project
|
||||||
|
.language_server_for_buffer(buffer.read(cx), cx)
|
||||||
|
.cloned()
|
||||||
})
|
})
|
||||||
.ok_or_else(|| anyhow!("no language server found for buffer"))?;
|
.ok_or_else(|| anyhow!("no language server found for buffer"))?;
|
||||||
let language = buffer
|
let language = buffer
|
||||||
|
|
|
@ -889,7 +889,7 @@ impl Project {
|
||||||
.await?;
|
.await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.assign_language_to_buffer(&buffer, cx);
|
this.assign_language_to_buffer(&buffer, cx);
|
||||||
this.register_buffer_with_language_servers(&buffer, cx);
|
this.register_buffer_with_language_server(&buffer, cx);
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -948,35 +948,23 @@ impl Project {
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
self.assign_language_to_buffer(buffer, cx);
|
self.assign_language_to_buffer(buffer, cx);
|
||||||
self.register_buffer_with_language_servers(buffer, cx);
|
self.register_buffer_with_language_server(buffer, cx);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_buffer_with_language_servers(
|
fn register_buffer_with_language_server(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer_handle: &ModelHandle<Buffer>,
|
buffer_handle: &ModelHandle<Buffer>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let buffer_language_name = buffer.language().map(|l| l.name().clone());
|
let buffer_id = buffer.remote_id();
|
||||||
if let Some(file) = File::from_dyn(buffer.file()) {
|
if let Some(file) = File::from_dyn(buffer.file()) {
|
||||||
let worktree_id = file.worktree_id(cx);
|
|
||||||
if file.is_local() {
|
if file.is_local() {
|
||||||
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
||||||
let initial_snapshot = buffer.as_text_snapshot();
|
let initial_snapshot = buffer.text_snapshot();
|
||||||
self.buffer_snapshots
|
let language_server = self.language_server_for_buffer(buffer, cx).cloned();
|
||||||
.insert(buffer.remote_id(), vec![(0, initial_snapshot.clone())]);
|
|
||||||
|
|
||||||
let mut notifications = Vec::new();
|
|
||||||
let did_open_text_document = lsp::DidOpenTextDocumentParams {
|
|
||||||
text_document: lsp::TextDocumentItem::new(
|
|
||||||
uri,
|
|
||||||
Default::default(),
|
|
||||||
0,
|
|
||||||
initial_snapshot.text(),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(local_worktree) = file.worktree.read(cx).as_local() {
|
if let Some(local_worktree) = file.worktree.read(cx).as_local() {
|
||||||
if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
|
if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
|
||||||
|
@ -985,12 +973,20 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (language_name, server) in self.language_servers_for_worktree(worktree_id) {
|
if let Some(server) = language_server {
|
||||||
notifications.push(server.notify::<lsp::notification::DidOpenTextDocument>(
|
server
|
||||||
did_open_text_document.clone(),
|
.notify::<lsp::notification::DidOpenTextDocument>(
|
||||||
));
|
lsp::DidOpenTextDocumentParams {
|
||||||
|
text_document: lsp::TextDocumentItem::new(
|
||||||
if Some(language_name) == buffer_language_name.as_deref() {
|
uri,
|
||||||
|
Default::default(),
|
||||||
|
0,
|
||||||
|
initial_snapshot.text(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
.log_err();
|
||||||
buffer_handle.update(cx, |buffer, cx| {
|
buffer_handle.update(cx, |buffer, cx| {
|
||||||
buffer.set_completion_triggers(
|
buffer.set_completion_triggers(
|
||||||
server
|
server
|
||||||
|
@ -1002,15 +998,15 @@ impl Project {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
self.buffer_snapshots
|
||||||
|
.insert(buffer_id, vec![(0, initial_snapshot)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.observe_release(buffer_handle, |this, buffer, cx| {
|
cx.observe_release(buffer_handle, |this, buffer, cx| {
|
||||||
if let Some(file) = File::from_dyn(buffer.file()) {
|
if let Some(file) = File::from_dyn(buffer.file()) {
|
||||||
let worktree_id = file.worktree_id(cx);
|
|
||||||
if file.is_local() {
|
if file.is_local() {
|
||||||
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
||||||
for (_, server) in this.language_servers_for_worktree(worktree_id) {
|
if let Some(server) = this.language_server_for_buffer(buffer, cx) {
|
||||||
server
|
server
|
||||||
.notify::<lsp::notification::DidCloseTextDocument>(
|
.notify::<lsp::notification::DidCloseTextDocument>(
|
||||||
lsp::DidCloseTextDocumentParams {
|
lsp::DidCloseTextDocumentParams {
|
||||||
|
@ -1046,9 +1042,11 @@ impl Project {
|
||||||
cx.background().spawn(request).detach_and_log_err(cx);
|
cx.background().spawn(request).detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
BufferEvent::Edited => {
|
BufferEvent::Edited => {
|
||||||
|
let language_server = self
|
||||||
|
.language_server_for_buffer(buffer.read(cx), cx)?
|
||||||
|
.clone();
|
||||||
let buffer = buffer.read(cx);
|
let buffer = buffer.read(cx);
|
||||||
let file = File::from_dyn(buffer.file())?;
|
let file = File::from_dyn(buffer.file())?;
|
||||||
let worktree_id = file.worktree_id(cx);
|
|
||||||
let abs_path = file.as_local()?.abs_path(cx);
|
let abs_path = file.as_local()?.abs_path(cx);
|
||||||
let uri = lsp::Url::from_file_path(abs_path).unwrap();
|
let uri = lsp::Url::from_file_path(abs_path).unwrap();
|
||||||
let buffer_snapshots = self.buffer_snapshots.entry(buffer.remote_id()).or_default();
|
let buffer_snapshots = self.buffer_snapshots.entry(buffer.remote_id()).or_default();
|
||||||
|
@ -1075,19 +1073,20 @@ impl Project {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let changes = lsp::DidChangeTextDocumentParams {
|
|
||||||
text_document: lsp::VersionedTextDocumentIdentifier::new(uri, next_version),
|
|
||||||
content_changes,
|
|
||||||
};
|
|
||||||
|
|
||||||
buffer_snapshots.push((next_version, next_snapshot));
|
buffer_snapshots.push((next_version, next_snapshot));
|
||||||
|
|
||||||
for (_, server) in self.language_servers_for_worktree(worktree_id) {
|
language_server
|
||||||
server
|
.notify::<lsp::notification::DidChangeTextDocument>(
|
||||||
.notify::<lsp::notification::DidChangeTextDocument>(changes.clone())
|
lsp::DidChangeTextDocumentParams {
|
||||||
|
text_document: lsp::VersionedTextDocumentIdentifier::new(
|
||||||
|
uri,
|
||||||
|
next_version,
|
||||||
|
),
|
||||||
|
content_changes,
|
||||||
|
},
|
||||||
|
)
|
||||||
.log_err();
|
.log_err();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
BufferEvent::Saved => {
|
BufferEvent::Saved => {
|
||||||
let file = File::from_dyn(buffer.read(cx).file())?;
|
let file = File::from_dyn(buffer.read(cx).file())?;
|
||||||
let worktree_id = file.worktree_id(cx);
|
let worktree_id = file.worktree_id(cx);
|
||||||
|
@ -1177,17 +1176,27 @@ impl Project {
|
||||||
let language_server = language_server?.await.log_err()?;
|
let language_server = language_server?.await.log_err()?;
|
||||||
let this = this.upgrade(&cx)?;
|
let this = this.upgrade(&cx)?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.language_servers.insert(key, language_server.clone());
|
this.language_servers
|
||||||
|
.insert(key.clone(), language_server.clone());
|
||||||
|
|
||||||
|
// Tell the language server about every open buffer in the worktree that matches the language.
|
||||||
for buffer in this.opened_buffers.values() {
|
for buffer in this.opened_buffers.values() {
|
||||||
if let Some(buffer_handle) = buffer.upgrade(cx) {
|
if let Some(buffer_handle) = buffer.upgrade(cx) {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let file = File::from_dyn(buffer.file())?;
|
let file = if let Some(file) = File::from_dyn(buffer.file()) {
|
||||||
if file.worktree.read(cx).id() != worktree_id {
|
file
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let language = if let Some(language) = buffer.language() {
|
||||||
|
language
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if (file.worktree.read(cx).id(), language.name()) != key {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the language server about every open buffer in the worktree.
|
|
||||||
let file = file.as_local()?;
|
let file = file.as_local()?;
|
||||||
let versions = this
|
let versions = this
|
||||||
.buffer_snapshots
|
.buffer_snapshots
|
||||||
|
@ -1207,12 +1216,6 @@ impl Project {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.log_err()?;
|
.log_err()?;
|
||||||
|
|
||||||
// Update the language buffers
|
|
||||||
if buffer
|
|
||||||
.language()
|
|
||||||
.map_or(false, |l| l.name() == language.name())
|
|
||||||
{
|
|
||||||
buffer_handle.update(cx, |buffer, cx| {
|
buffer_handle.update(cx, |buffer, cx| {
|
||||||
buffer.set_completion_triggers(
|
buffer.set_completion_triggers(
|
||||||
language_server
|
language_server
|
||||||
|
@ -1228,7 +1231,6 @@ impl Project {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
});
|
});
|
||||||
|
@ -1584,25 +1586,11 @@ impl Project {
|
||||||
let mut remote_buffers = None;
|
let mut remote_buffers = None;
|
||||||
for buffer_handle in buffers {
|
for buffer_handle in buffers {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let worktree;
|
|
||||||
if let Some(file) = File::from_dyn(buffer.file()) {
|
if let Some(file) = File::from_dyn(buffer.file()) {
|
||||||
worktree = file.worktree.clone();
|
|
||||||
if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
|
if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
|
||||||
let lang_server;
|
if let Some(server) = self.language_server_for_buffer(buffer, cx) {
|
||||||
if let Some(lang) = buffer.language() {
|
local_buffers.push((buffer_handle, buffer_abs_path, server.clone()));
|
||||||
if let Some(server) = self
|
|
||||||
.language_servers
|
|
||||||
.get(&(worktree.read(cx).id(), lang.name()))
|
|
||||||
{
|
|
||||||
lang_server = server.clone();
|
|
||||||
} else {
|
|
||||||
return Task::ready(Ok(Default::default()));
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return Task::ready(Ok(Default::default()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local_buffers.push((buffer_handle, buffer_abs_path, lang_server));
|
|
||||||
} else {
|
} else {
|
||||||
remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
|
remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
|
||||||
}
|
}
|
||||||
|
@ -1918,7 +1906,7 @@ impl Project {
|
||||||
if worktree.read(cx).as_local().is_some() {
|
if worktree.read(cx).as_local().is_some() {
|
||||||
let buffer_abs_path = buffer_abs_path.unwrap();
|
let buffer_abs_path = buffer_abs_path.unwrap();
|
||||||
let lang_server =
|
let lang_server =
|
||||||
if let Some(server) = self.language_server_for_buffer(&source_buffer_handle, cx) {
|
if let Some(server) = self.language_server_for_buffer(source_buffer, cx) {
|
||||||
server.clone()
|
server.clone()
|
||||||
} else {
|
} else {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
|
@ -2029,8 +2017,7 @@ impl Project {
|
||||||
let buffer_id = buffer.remote_id();
|
let buffer_id = buffer.remote_id();
|
||||||
|
|
||||||
if self.is_local() {
|
if self.is_local() {
|
||||||
let lang_server =
|
let lang_server = if let Some(server) = self.language_server_for_buffer(buffer, cx) {
|
||||||
if let Some(server) = self.language_server_for_buffer(&buffer_handle, cx) {
|
|
||||||
server.clone()
|
server.clone()
|
||||||
} else {
|
} else {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
|
@ -2121,21 +2108,11 @@ impl Project {
|
||||||
|
|
||||||
if worktree.read(cx).as_local().is_some() {
|
if worktree.read(cx).as_local().is_some() {
|
||||||
let buffer_abs_path = buffer_abs_path.unwrap();
|
let buffer_abs_path = buffer_abs_path.unwrap();
|
||||||
let lang_name;
|
let lang_server = if let Some(server) = self.language_server_for_buffer(buffer, cx) {
|
||||||
let lang_server;
|
server.clone()
|
||||||
if let Some(lang) = buffer.language() {
|
|
||||||
lang_name = lang.name();
|
|
||||||
if let Some(server) = self
|
|
||||||
.language_servers
|
|
||||||
.get(&(worktree.read(cx).id(), lang_name.clone()))
|
|
||||||
{
|
|
||||||
lang_server = server.clone();
|
|
||||||
} else {
|
} else {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
return Task::ready(Ok(Default::default()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let lsp_range = lsp::Range::new(
|
let lsp_range = lsp::Range::new(
|
||||||
range.start.to_point_utf16(buffer).to_lsp_position(),
|
range.start.to_point_utf16(buffer).to_lsp_position(),
|
||||||
|
@ -2223,8 +2200,7 @@ impl Project {
|
||||||
} else {
|
} else {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
};
|
};
|
||||||
let lang_server =
|
let lang_server = if let Some(server) = self.language_server_for_buffer(buffer, cx) {
|
||||||
if let Some(server) = self.language_server_for_buffer(&buffer_handle, cx) {
|
|
||||||
server.clone()
|
server.clone()
|
||||||
} else {
|
} else {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
|
@ -2674,7 +2650,7 @@ impl Project {
|
||||||
if self.is_local() {
|
if self.is_local() {
|
||||||
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
||||||
if let Some((file, language_server)) =
|
if let Some((file, language_server)) =
|
||||||
file.zip(self.language_server_for_buffer(&buffer_handle, cx).cloned())
|
file.zip(self.language_server_for_buffer(buffer, cx).cloned())
|
||||||
{
|
{
|
||||||
let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
|
let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
|
||||||
return cx.spawn(|this, cx| async move {
|
return cx.spawn(|this, cx| async move {
|
||||||
|
@ -3934,16 +3910,15 @@ impl Project {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok((**buffer.read(cx)).clone())
|
Ok((buffer.read(cx)).text_snapshot())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn language_server_for_buffer(
|
fn language_server_for_buffer(
|
||||||
&self,
|
&self,
|
||||||
buffer: &ModelHandle<Buffer>,
|
buffer: &Buffer,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> Option<&Arc<LanguageServer>> {
|
) -> Option<&Arc<LanguageServer>> {
|
||||||
let buffer = buffer.read(cx);
|
|
||||||
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
|
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
|
||||||
let worktree_id = file.worktree_id(cx);
|
let worktree_id = file.worktree_id(cx);
|
||||||
self.language_servers.get(&(worktree_id, language.name()))
|
self.language_servers.get(&(worktree_id, language.name()))
|
||||||
|
@ -4339,20 +4314,8 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// A server is started up, and it is notified about both open buffers.
|
// A server is started up, and it is notified about Rust files.
|
||||||
let mut fake_rust_server = fake_rust_servers.next().await.unwrap();
|
let mut fake_rust_server = fake_rust_servers.next().await.unwrap();
|
||||||
assert_eq!(
|
|
||||||
fake_rust_server
|
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
|
||||||
.await
|
|
||||||
.text_document,
|
|
||||||
lsp::TextDocumentItem {
|
|
||||||
uri: lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap(),
|
|
||||||
version: 0,
|
|
||||||
text: "a = 1".to_string(),
|
|
||||||
language_id: Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fake_rust_server
|
fake_rust_server
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
@ -4401,18 +4364,6 @@ mod tests {
|
||||||
// Another language server is started up, and it is notified about
|
// Another language server is started up, and it is notified about
|
||||||
// all three open buffers.
|
// all three open buffers.
|
||||||
let mut fake_json_server = fake_json_servers.next().await.unwrap();
|
let mut fake_json_server = fake_json_servers.next().await.unwrap();
|
||||||
assert_eq!(
|
|
||||||
fake_json_server
|
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
|
||||||
.await
|
|
||||||
.text_document,
|
|
||||||
lsp::TextDocumentItem {
|
|
||||||
uri: lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap(),
|
|
||||||
version: 0,
|
|
||||||
text: "a = 1".to_string(),
|
|
||||||
language_id: Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fake_json_server
|
fake_json_server
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
@ -4425,18 +4376,6 @@ mod tests {
|
||||||
language_id: Default::default()
|
language_id: Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
fake_json_server
|
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
|
||||||
.await
|
|
||||||
.text_document,
|
|
||||||
lsp::TextDocumentItem {
|
|
||||||
uri: lsp::Url::from_file_path("/the-root/test.rs").unwrap(),
|
|
||||||
version: 1,
|
|
||||||
text: "const A: i32 = 12;".to_string(),
|
|
||||||
language_id: Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// This buffer is configured based on the second language server's
|
// This buffer is configured based on the second language server's
|
||||||
// capabilities.
|
// capabilities.
|
||||||
|
@ -4444,20 +4383,6 @@ mod tests {
|
||||||
assert_eq!(buffer.completion_triggers(), &[":".to_string()]);
|
assert_eq!(buffer.completion_triggers(), &[":".to_string()]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// The first language server is also notified about the new open buffer.
|
|
||||||
assert_eq!(
|
|
||||||
fake_rust_server
|
|
||||||
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
|
||||||
.await
|
|
||||||
.text_document,
|
|
||||||
lsp::TextDocumentItem {
|
|
||||||
uri: lsp::Url::from_file_path("/the-root/package.json").unwrap(),
|
|
||||||
version: 0,
|
|
||||||
text: "{\"a\": 1}".to_string(),
|
|
||||||
language_id: Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// When opening another buffer whose language server is already running,
|
// When opening another buffer whose language server is already running,
|
||||||
// it is also configured based on the existing language server's capabilities.
|
// it is also configured based on the existing language server's capabilities.
|
||||||
let rust_buffer2 = project
|
let rust_buffer2 = project
|
||||||
|
@ -4473,39 +4398,45 @@ mod tests {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Edit a buffer. The changes are reported to both the language servers.
|
// Changes are reported only to servers matching the buffer's language.
|
||||||
toml_buffer.update(cx, |buffer, cx| buffer.edit([5..5], "23", cx));
|
toml_buffer.update(cx, |buffer, cx| buffer.edit([5..5], "23", cx));
|
||||||
|
rust_buffer2.update(cx, |buffer, cx| buffer.edit([0..0], "let x = 1;", cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fake_rust_server
|
fake_rust_server
|
||||||
.receive_notification::<lsp::notification::DidChangeTextDocument>()
|
.receive_notification::<lsp::notification::DidChangeTextDocument>()
|
||||||
.await
|
.await
|
||||||
.text_document,
|
.text_document,
|
||||||
lsp::VersionedTextDocumentIdentifier::new(
|
lsp::VersionedTextDocumentIdentifier::new(
|
||||||
lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap(),
|
lsp::Url::from_file_path("/the-root/test2.rs").unwrap(),
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Save notifications are reported to all servers.
|
||||||
|
toml_buffer
|
||||||
|
.update(cx, |buffer, cx| buffer.save(cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fake_rust_server
|
||||||
|
.receive_notification::<lsp::notification::DidSaveTextDocument>()
|
||||||
|
.await
|
||||||
|
.text_document,
|
||||||
|
lsp::TextDocumentIdentifier::new(
|
||||||
|
lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fake_json_server
|
fake_json_server
|
||||||
.receive_notification::<lsp::notification::DidChangeTextDocument>()
|
.receive_notification::<lsp::notification::DidSaveTextDocument>()
|
||||||
.await,
|
.await
|
||||||
lsp::DidChangeTextDocumentParams {
|
.text_document,
|
||||||
text_document: lsp::VersionedTextDocumentIdentifier::new(
|
lsp::TextDocumentIdentifier::new(
|
||||||
lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap(),
|
lsp::Url::from_file_path("/the-root/Cargo.toml").unwrap()
|
||||||
1
|
)
|
||||||
),
|
|
||||||
content_changes: vec![lsp::TextDocumentContentChangeEvent {
|
|
||||||
range: Some(lsp::Range::new(
|
|
||||||
lsp::Position::new(0, 5),
|
|
||||||
lsp::Position::new(0, 5)
|
|
||||||
)),
|
|
||||||
range_length: None,
|
|
||||||
text: "23".to_string(),
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Close a buffer. Both language servers are notified.
|
// Close notifications are reported only to servers matching the buffer's language.
|
||||||
cx.update(|_| drop(json_buffer));
|
cx.update(|_| drop(json_buffer));
|
||||||
let close_message = lsp::DidCloseTextDocumentParams {
|
let close_message = lsp::DidCloseTextDocumentParams {
|
||||||
text_document: lsp::TextDocumentIdentifier::new(
|
text_document: lsp::TextDocumentIdentifier::new(
|
||||||
|
@ -4518,12 +4449,6 @@ mod tests {
|
||||||
.await,
|
.await,
|
||||||
close_message,
|
close_message,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
fake_rust_server
|
|
||||||
.receive_notification::<lsp::notification::DidCloseTextDocument>()
|
|
||||||
.await,
|
|
||||||
close_message,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue