@@ -2,10 +2,9 @@ use std::sync::Arc;
use std::time::Duration;
use crate::Editor;
-use collections::HashMap;
+use collections::{HashMap, HashSet};
use gpui::AsyncApp;
use gpui::{App, Entity, Task};
-use itertools::Itertools;
use language::Buffer;
use language::Language;
use lsp::LanguageServerId;
@@ -33,22 +32,34 @@ where
F: Fn(&Language) -> bool,
{
let project = editor.project.clone()?;
+ let multi_buffer = editor.buffer();
+ let mut seen_buffer_ids = HashSet::default();
editor
.selections
.disjoint_anchors_arc()
.iter()
- .filter_map(|selection| Some((selection.head(), selection.head().text_anchor.buffer_id?)))
- .unique_by(|(_, buffer_id)| *buffer_id)
- .find_map(|(trigger_anchor, buffer_id)| {
- let buffer = editor.buffer().read(cx).buffer(buffer_id)?;
- let language = buffer.read(cx).language_at(trigger_anchor.text_anchor)?;
+ .find_map(|selection| {
+ let multi_buffer = multi_buffer.read(cx);
+ let (position, buffer) = multi_buffer
+ .buffer_for_anchor(selection.head(), cx)
+ .map(|buffer| (selection.head(), buffer))
+ .or_else(|| {
+ multi_buffer
+ .buffer_for_anchor(selection.tail(), cx)
+ .map(|buffer| (selection.tail(), buffer))
+ })?;
+ if !seen_buffer_ids.insert(buffer.read(cx).remote_id()) {
+ return None;
+ }
+
+ let language = buffer.read(cx).language_at(position.text_anchor)?;
if filter_language(&language) {
let server_id = buffer.update(cx, |buffer, cx| {
project
.read(cx)
.language_server_id_for_name(buffer, &language_server_name, cx)
})?;
- Some((trigger_anchor, language, server_id, buffer))
+ Some((position, language, server_id, buffer))
} else {
None
}
@@ -173,3 +184,100 @@ pub fn lsp_tasks(
.await
})
}
+
+#[cfg(test)]
+mod tests {
+ use std::sync::Arc;
+
+ use futures::StreamExt as _;
+ use gpui::{AppContext as _, Entity, TestAppContext};
+ use language::{FakeLspAdapter, Language};
+ use languages::rust_lang;
+ use lsp::{LanguageServerId, LanguageServerName};
+ use multi_buffer::{Anchor, MultiBuffer};
+ use project::{FakeFs, Project};
+ use util::path;
+
+ use crate::{MoveToEnd, editor_tests::init_test, test::build_editor_with_project};
+
+ use super::find_specific_language_server_in_selection;
+
+ #[gpui::test]
+ async fn test_find_language_server_at_end_of_file(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_file(path!("/file.rs"), "fn main() {}".into())
+ .await;
+
+ let project = Project::test(fs, [path!("/file.rs").as_ref()], cx).await;
+ let language_registry = project.read_with(cx, |project, _| project.languages().clone());
+ language_registry.add(rust_lang());
+ let mut fake_servers =
+ language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
+
+ let underlying_buffer = project
+ .update(cx, |project, cx| {
+ project.open_local_buffer(path!("/file.rs"), cx)
+ })
+ .await
+ .unwrap();
+
+ let buffer = cx.new(|cx| MultiBuffer::singleton(underlying_buffer.clone(), cx));
+ let (editor, cx) = cx.add_window_view(|window, cx| {
+ build_editor_with_project(project.clone(), buffer, window, cx)
+ });
+
+ let fake_server = fake_servers.next().await.unwrap();
+ cx.executor().run_until_parked();
+
+ let expected_server_id = fake_server.server.server_id();
+ let language_server_name = LanguageServerName::new_static("the-fake-language-server");
+ let filter = |language: &Language| language.name().as_ref() == "Rust";
+
+ let assert_result = |result: Option<(
+ Anchor,
+ Arc<Language>,
+ LanguageServerId,
+ Entity<language::Buffer>,
+ )>,
+ message: &str| {
+ let (_, language, server_id, buffer) = result.expect(message);
+ assert_eq!(
+ language.name().as_ref(),
+ "Rust",
+ "{message}: wrong language"
+ );
+ assert_eq!(server_id, expected_server_id, "{message}: wrong server ID");
+ assert_eq!(buffer, underlying_buffer, "{message}: wrong buffer");
+ };
+
+ editor.update(cx, |editor, cx| {
+ assert_result(
+ find_specific_language_server_in_selection(
+ editor,
+ cx,
+ filter,
+ language_server_name.clone(),
+ ),
+ "should find correct language server at beginning of file",
+ );
+ });
+
+ editor.update_in(cx, |editor, window, cx| {
+ editor.move_to_end(&MoveToEnd, window, cx);
+ });
+
+ editor.update(cx, |editor, cx| {
+ assert_result(
+ find_specific_language_server_in_selection(
+ editor,
+ cx,
+ filter,
+ language_server_name.clone(),
+ ),
+ "should find correct language server at end of file",
+ );
+ });
+ }
+}