@@ -138,16 +138,13 @@ impl Default for LanguageConfig {
pub struct LanguageServerConfig {
pub disk_based_diagnostic_sources: HashSet<String>,
pub disk_based_diagnostics_progress_token: Option<String>,
- #[cfg(any(test, feature = "test-support"))]
- #[serde(skip)]
- fake_config: Option<FakeLanguageServerConfig>,
}
#[cfg(any(test, feature = "test-support"))]
-struct FakeLanguageServerConfig {
- servers_tx: mpsc::UnboundedSender<lsp::FakeLanguageServer>,
- capabilities: lsp::ServerCapabilities,
- initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
+pub struct FakeLspAdapter {
+ pub name: &'static str,
+ pub capabilities: lsp::ServerCapabilities,
+ pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
}
#[derive(Clone, Debug, Deserialize)]
@@ -162,6 +159,12 @@ pub struct Language {
pub(crate) config: LanguageConfig,
pub(crate) grammar: Option<Arc<Grammar>>,
pub(crate) adapter: Option<Arc<dyn LspAdapter>>,
+
+ #[cfg(any(test, feature = "test-support"))]
+ fake_adapter: Option<(
+ mpsc::UnboundedSender<lsp::FakeLanguageServer>,
+ Arc<FakeLspAdapter>,
+ )>,
}
pub struct Grammar {
@@ -262,26 +265,22 @@ impl LanguageRegistry {
cx: &mut MutableAppContext,
) -> Option<Task<Result<lsp::LanguageServer>>> {
#[cfg(any(test, feature = "test-support"))]
- if language.config.language_server.fake_config.is_some() {
+ if language.fake_adapter.is_some() {
let language = language.clone();
return Some(cx.spawn(|mut cx| async move {
- let fake_config = language
- .config
- .language_server
- .fake_config
- .as_ref()
- .unwrap();
+ let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
let (server, mut fake_server) = cx.update(|cx| {
lsp::LanguageServer::fake_with_capabilities(
- fake_config.capabilities.clone(),
+ fake_adapter.capabilities.clone(),
cx,
)
});
- if let Some(initializer) = &fake_config.initializer {
+
+ if let Some(initializer) = &fake_adapter.initializer {
initializer(&mut fake_server);
}
- let servers_tx = fake_config.servers_tx.clone();
+ let servers_tx = servers_tx.clone();
cx.background()
.spawn(async move {
fake_server
@@ -426,6 +425,9 @@ impl Language {
})
}),
adapter: None,
+
+ #[cfg(any(test, feature = "test-support"))]
+ fake_adapter: None,
}
}
@@ -478,6 +480,18 @@ impl Language {
self
}
+ #[cfg(any(test, feature = "test-support"))]
+ pub fn set_fake_lsp_adapter(
+ &mut self,
+ fake_lsp_adapter: FakeLspAdapter,
+ ) -> mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
+ let (servers_tx, servers_rx) = mpsc::unbounded();
+ let adapter = Arc::new(fake_lsp_adapter);
+ self.fake_adapter = Some((servers_tx, adapter.clone()));
+ self.adapter = Some(adapter);
+ servers_rx
+ }
+
pub fn name(&self) -> Arc<str> {
self.config.name.clone()
}
@@ -601,33 +615,42 @@ impl CodeLabel {
}
#[cfg(any(test, feature = "test-support"))]
-impl LanguageServerConfig {
- pub fn fake() -> (Self, mpsc::UnboundedReceiver<lsp::FakeLanguageServer>) {
- let (servers_tx, servers_rx) = mpsc::unbounded();
- (
- Self {
- fake_config: Some(FakeLanguageServerConfig {
- servers_tx,
- capabilities: lsp::LanguageServer::full_capabilities(),
- initializer: None,
- }),
- disk_based_diagnostics_progress_token: Some("fakeServer/check".to_string()),
- ..Default::default()
- },
- servers_rx,
- )
+impl Default for FakeLspAdapter {
+ fn default() -> Self {
+ Self {
+ name: "the-fake-language-server",
+ capabilities: lsp::LanguageServer::full_capabilities(),
+ initializer: None,
+ }
}
+}
- pub fn set_fake_capabilities(&mut self, capabilities: lsp::ServerCapabilities) {
- self.fake_config.as_mut().unwrap().capabilities = capabilities;
+impl LspAdapter for FakeLspAdapter {
+ fn name(&self) -> LanguageServerName {
+ LanguageServerName(self.name.into())
}
- pub fn set_fake_initializer(
- &mut self,
- initializer: impl 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer),
- ) {
- self.fake_config.as_mut().unwrap().initializer = Some(Box::new(initializer));
+ fn fetch_latest_server_version(
+ &self,
+ _: Arc<dyn HttpClient>,
+ ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>> {
+ unreachable!();
}
+
+ fn fetch_server_binary(
+ &self,
+ _: Box<dyn 'static + Send + Any>,
+ _: Arc<dyn HttpClient>,
+ _: PathBuf,
+ ) -> BoxFuture<'static, Result<PathBuf>> {
+ unreachable!();
+ }
+
+ fn cached_server_binary(&self, _: PathBuf) -> BoxFuture<'static, Option<PathBuf>> {
+ unreachable!();
+ }
+
+ fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
}
impl ToLspPosition for PointUtf16 {
@@ -4606,8 +4606,8 @@ mod tests {
use futures::StreamExt;
use gpui::test::subscribe;
use language::{
- tree_sitter_rust, Diagnostic, LanguageConfig, LanguageServerConfig, OffsetRangeExt, Point,
- ToPoint,
+ tree_sitter_rust, Diagnostic, FakeLspAdapter, LanguageConfig, LanguageServerConfig,
+ OffsetRangeExt, Point, ToPoint,
};
use lsp::Url;
use serde_json::json;
@@ -4683,41 +4683,44 @@ mod tests {
async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
- let (mut rust_lsp_config, mut fake_rust_servers) = LanguageServerConfig::fake();
- let (mut json_lsp_config, mut fake_json_servers) = LanguageServerConfig::fake();
- rust_lsp_config.set_fake_capabilities(lsp::ServerCapabilities {
- completion_provider: Some(lsp::CompletionOptions {
- trigger_characters: Some(vec![".".to_string(), "::".to_string()]),
- ..Default::default()
- }),
- ..Default::default()
- });
- json_lsp_config.set_fake_capabilities(lsp::ServerCapabilities {
- completion_provider: Some(lsp::CompletionOptions {
- trigger_characters: Some(vec![":".to_string()]),
- ..Default::default()
- }),
- ..Default::default()
- });
-
- let rust_language = Arc::new(Language::new(
+ let mut rust_language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: rust_lsp_config,
..Default::default()
},
Some(tree_sitter_rust::language()),
- ));
- let json_language = Arc::new(Language::new(
+ );
+ let mut json_language = Language::new(
LanguageConfig {
name: "JSON".into(),
path_suffixes: vec!["json".to_string()],
- language_server: json_lsp_config,
..Default::default()
},
None,
- ));
+ );
+ let mut fake_rust_servers = rust_language.set_fake_lsp_adapter(FakeLspAdapter {
+ name: "the-rust-language-server",
+ capabilities: lsp::ServerCapabilities {
+ completion_provider: Some(lsp::CompletionOptions {
+ trigger_characters: Some(vec![".".to_string(), "::".to_string()]),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ ..Default::default()
+ });
+ let mut fake_json_servers = json_language.set_fake_lsp_adapter(FakeLspAdapter {
+ name: "the-json-language-server",
+ capabilities: lsp::ServerCapabilities {
+ completion_provider: Some(lsp::CompletionOptions {
+ trigger_characters: Some(vec![":".to_string()]),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ ..Default::default()
+ });
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -4733,8 +4736,8 @@ mod tests {
let project = Project::test(fs, cx);
project.update(cx, |project, _| {
- project.languages.add(rust_language);
- project.languages.add(json_language);
+ project.languages.add(Arc::new(rust_language));
+ project.languages.add(Arc::new(json_language));
});
let worktree_id = project
@@ -4903,21 +4906,20 @@ mod tests {
async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
- let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
- let progress_token = language_server_config
- .disk_based_diagnostics_progress_token
- .clone()
- .unwrap();
-
- let language = Arc::new(Language::new(
+ let progress_token = "the-progress-token".to_string();
+ let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
+ language_server: LanguageServerConfig {
+ disk_based_diagnostics_progress_token: Some(progress_token.clone()),
+ ..Default::default()
+ },
..Default::default()
},
Some(tree_sitter_rust::language()),
- ));
+ );
+ let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -4930,7 +4932,7 @@ mod tests {
.await;
let project = Project::test(fs, cx);
- project.update(cx, |project, _| project.languages.add(language));
+ project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let (tree, _) = project
.update(cx, |project, cx| {
@@ -5022,19 +5024,20 @@ mod tests {
async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
- let (mut lsp_config, mut fake_servers) = LanguageServerConfig::fake();
- lsp_config
- .disk_based_diagnostic_sources
- .insert("disk".to_string());
- let language = Arc::new(Language::new(
+ // let (mut lsp_config, mut fake_servers) = LanguageServerConfig::fake();
+ let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: lsp_config,
+ language_server: LanguageServerConfig {
+ disk_based_diagnostic_sources: ["disk".to_string()].into_iter().collect(),
+ ..Default::default()
+ },
..Default::default()
},
Some(tree_sitter_rust::language()),
- ));
+ );
+ let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
let text = "
fn a() { A }
@@ -5047,7 +5050,7 @@ mod tests {
fs.insert_tree("/dir", json!({ "a.rs": text })).await;
let project = Project::test(fs, cx);
- project.update(cx, |project, _| project.languages.add(language));
+ project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let worktree_id = project
.update(cx, |project, cx| {
@@ -5396,16 +5399,15 @@ mod tests {
async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
- let (lsp_config, mut fake_servers) = LanguageServerConfig::fake();
- let language = Arc::new(Language::new(
+ let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: lsp_config,
..Default::default()
},
Some(tree_sitter_rust::language()),
- ));
+ );
+ let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
let text = "
fn a() {
@@ -5430,7 +5432,7 @@ mod tests {
.await;
let project = Project::test(fs, cx);
- project.update(cx, |project, _| project.languages.add(language));
+ project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let worktree_id = project
.update(cx, |project, cx| {
@@ -5746,16 +5748,15 @@ mod tests {
#[gpui::test]
async fn test_definition(cx: &mut gpui::TestAppContext) {
- let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
- let language = Arc::new(Language::new(
+ let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
..Default::default()
},
Some(tree_sitter_rust::language()),
- ));
+ );
+ let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -5768,9 +5769,7 @@ mod tests {
.await;
let project = Project::test(fs, cx);
- project.update(cx, |project, _| {
- Arc::get_mut(&mut project.languages).unwrap().add(language);
- });
+ project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let (tree, _) = project
.update(cx, |project, cx| {
@@ -6682,16 +6681,15 @@ mod tests {
async fn test_rename(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
- let (language_server_config, mut fake_servers) = LanguageServerConfig::fake();
- let language = Arc::new(Language::new(
+ let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
..Default::default()
},
Some(tree_sitter_rust::language()),
- ));
+ );
+ let mut fake_servers = language.set_fake_lsp_adapter(Default::default());
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -6704,9 +6702,7 @@ mod tests {
.await;
let project = Project::test(fs.clone(), cx);
- project.update(cx, |project, _| {
- Arc::get_mut(&mut project.languages).unwrap().add(language);
- });
+ project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let (tree, _) = project
.update(cx, |project, cx| {
@@ -1088,10 +1088,10 @@ mod tests {
};
use gpui::{executor, geometry::vector::vec2f, ModelHandle, TestAppContext, ViewHandle};
use language::{
- tree_sitter_rust, Diagnostic, DiagnosticEntry, Language, LanguageConfig, LanguageRegistry,
- LanguageServerConfig, OffsetRangeExt, Point, ToLspPosition,
+ tree_sitter_rust, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language, LanguageConfig,
+ LanguageRegistry, OffsetRangeExt, Point, ToLspPosition,
};
- use lsp;
+ use lsp::{self, FakeLanguageServer};
use parking_lot::Mutex;
use postage::barrier;
use project::{
@@ -2039,22 +2039,20 @@ mod tests {
cx_b: &mut TestAppContext,
) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -2261,29 +2259,29 @@ mod tests {
cx_b: &mut TestAppContext,
) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
// Set up a fake language server.
- let (mut language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- language_server_config.set_fake_capabilities(lsp::ServerCapabilities {
- completion_provider: Some(lsp::CompletionOptions {
- trigger_characters: Some(vec![".".to_string()]),
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
..Default::default()
- }),
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ completion_provider: Some(lsp::CompletionOptions {
+ trigger_characters: Some(vec![".".to_string()]),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
..Default::default()
});
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -2463,22 +2461,20 @@ mod tests {
#[gpui::test(iterations = 10)]
async fn test_formatting_buffer(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -2563,7 +2559,7 @@ mod tests {
#[gpui::test(iterations = 10)]
async fn test_definition(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
fs.insert_tree(
"/root-1",
@@ -2582,18 +2578,16 @@ mod tests {
.await;
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -2705,7 +2699,7 @@ mod tests {
#[gpui::test(iterations = 10)]
async fn test_references(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
fs.insert_tree(
"/root-1",
@@ -2725,18 +2719,16 @@ mod tests {
.await;
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -2967,16 +2959,16 @@ mod tests {
.await;
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- lang_registry.add(Arc::new(Language::new(
+ let mut language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
..Default::default()
},
Some(tree_sitter_rust::language()),
- )));
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -3092,7 +3084,7 @@ mod tests {
#[gpui::test(iterations = 10)]
async fn test_project_symbols(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
fs.insert_tree(
"/code",
@@ -3112,18 +3104,16 @@ mod tests {
.await;
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -3231,7 +3221,7 @@ mod tests {
mut rng: StdRng,
) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
fs.insert_tree(
"/root",
@@ -3244,19 +3234,16 @@ mod tests {
.await;
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
-
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -3337,23 +3324,21 @@ mod tests {
cx_b: &mut TestAppContext,
) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
cx_b.update(|cx| editor::init(cx));
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -3573,23 +3558,21 @@ mod tests {
#[gpui::test(iterations = 10)]
async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking();
- let mut lang_registry = Arc::new(LanguageRegistry::test());
+ let lang_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx_a.background());
cx_b.update(|cx| editor::init(cx));
// Set up a fake language server.
- let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
- Arc::get_mut(&mut lang_registry)
- .unwrap()
- .add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+ lang_registry.add(Arc::new(language));
// Connect to a server as 2 clients.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
@@ -4838,7 +4821,7 @@ mod tests {
let rng = Arc::new(Mutex::new(rng));
let guest_lang_registry = Arc::new(LanguageRegistry::test());
- let (language_server_config, _fake_language_servers) = LanguageServerConfig::fake();
+ let host_language_registry = Arc::new(LanguageRegistry::test());
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -4852,6 +4835,7 @@ mod tests {
let operations = Rc::new(Cell::new(0));
let mut server = TestServer::start(cx.foreground(), cx.background()).await;
let mut clients = Vec::new();
+ let files = Arc::new(Mutex::new(Vec::new()));
let mut next_entity_id = 100000;
let mut host_cx = TestAppContext::new(
@@ -4868,7 +4852,7 @@ mod tests {
Project::local(
host.client.clone(),
host.user_store.clone(),
- Arc::new(LanguageRegistry::test()),
+ host_language_registry.clone(),
fs.clone(),
cx,
)
@@ -4891,9 +4875,138 @@ mod tests {
.await
.unwrap();
+ // Set up fake language servers.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ None,
+ );
+ let _fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
+ name: "the-fake-language-server",
+ capabilities: lsp::LanguageServer::full_capabilities(),
+ initializer: Some(Box::new({
+ let rng = rng.clone();
+ let files = files.clone();
+ let project = host_project.downgrade();
+ move |fake_server: &mut FakeLanguageServer| {
+ fake_server.handle_request::<lsp::request::Completion, _, _>(
+ |_, _| async move {
+ Some(lsp::CompletionResponse::Array(vec![lsp::CompletionItem {
+ text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ range: lsp::Range::new(
+ lsp::Position::new(0, 0),
+ lsp::Position::new(0, 0),
+ ),
+ new_text: "the-new-text".to_string(),
+ })),
+ ..Default::default()
+ }]))
+ },
+ );
+
+ fake_server.handle_request::<lsp::request::CodeActionRequest, _, _>(
+ |_, _| async move {
+ Some(vec![lsp::CodeActionOrCommand::CodeAction(
+ lsp::CodeAction {
+ title: "the-code-action".to_string(),
+ ..Default::default()
+ },
+ )])
+ },
+ );
+
+ fake_server.handle_request::<lsp::request::PrepareRenameRequest, _, _>(
+ |params, _| async move {
+ Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
+ params.position,
+ params.position,
+ )))
+ },
+ );
+
+ fake_server.handle_request::<lsp::request::GotoDefinition, _, _>({
+ let files = files.clone();
+ let rng = rng.clone();
+ move |_, _| {
+ let files = files.clone();
+ let rng = rng.clone();
+ async move {
+ let files = files.lock();
+ let mut rng = rng.lock();
+ let count = rng.gen_range::<usize, _>(1..3);
+ let files = (0..count)
+ .map(|_| files.choose(&mut *rng).unwrap())
+ .collect::<Vec<_>>();
+ log::info!("LSP: Returning definitions in files {:?}", &files);
+ Some(lsp::GotoDefinitionResponse::Array(
+ files
+ .into_iter()
+ .map(|file| lsp::Location {
+ uri: lsp::Url::from_file_path(file).unwrap(),
+ range: Default::default(),
+ })
+ .collect(),
+ ))
+ }
+ }
+ });
+
+ fake_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>({
+ let rng = rng.clone();
+ let project = project.clone();
+ move |params, mut cx| {
+ let highlights = if let Some(project) = project.upgrade(&cx) {
+ project.update(&mut cx, |project, cx| {
+ let path = params
+ .text_document_position_params
+ .text_document
+ .uri
+ .to_file_path()
+ .unwrap();
+ let (worktree, relative_path) =
+ project.find_local_worktree(&path, cx)?;
+ let project_path =
+ ProjectPath::from((worktree.read(cx).id(), relative_path));
+ let buffer =
+ project.get_open_buffer(&project_path, cx)?.read(cx);
+
+ let mut highlights = Vec::new();
+ let highlight_count = rng.lock().gen_range(1..=5);
+ let mut prev_end = 0;
+ for _ in 0..highlight_count {
+ let range =
+ buffer.random_byte_range(prev_end, &mut *rng.lock());
+ let start = buffer
+ .offset_to_point_utf16(range.start)
+ .to_lsp_position();
+ let end = buffer
+ .offset_to_point_utf16(range.end)
+ .to_lsp_position();
+ highlights.push(lsp::DocumentHighlight {
+ range: lsp::Range::new(start, end),
+ kind: Some(lsp::DocumentHighlightKind::READ),
+ });
+ prev_end = range.end;
+ }
+ Some(highlights)
+ })
+ } else {
+ None
+ };
+ async move { highlights }
+ }
+ });
+ }
+ })),
+ });
+ host_language_registry.add(Arc::new(language));
+
clients.push(cx.foreground().spawn(host.simulate_host(
host_project,
- language_server_config,
+ files,
operations.clone(),
max_operations,
rng.clone(),
@@ -5324,264 +5437,128 @@ mod tests {
})
}
- fn simulate_host(
+ async fn simulate_host(
mut self,
project: ModelHandle<Project>,
- mut language_server_config: LanguageServerConfig,
+ files: Arc<Mutex<Vec<PathBuf>>>,
operations: Rc<Cell<usize>>,
max_operations: usize,
rng: Arc<Mutex<StdRng>>,
mut cx: TestAppContext,
- ) -> impl Future<Output = (Self, TestAppContext)> {
- let files: Arc<Mutex<Vec<PathBuf>>> = Default::default();
-
- // Set up a fake language server.
- language_server_config.set_fake_initializer({
- let rng = rng.clone();
- let files = files.clone();
- let project = project.downgrade();
- move |fake_server| {
- fake_server.handle_request::<lsp::request::Completion, _, _>(
- |_, _| async move {
- Some(lsp::CompletionResponse::Array(vec![lsp::CompletionItem {
- text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
- range: lsp::Range::new(
- lsp::Position::new(0, 0),
- lsp::Position::new(0, 0),
- ),
- new_text: "the-new-text".to_string(),
- })),
- ..Default::default()
- }]))
- },
- );
-
- fake_server.handle_request::<lsp::request::CodeActionRequest, _, _>(
- |_, _| async move {
- Some(vec![lsp::CodeActionOrCommand::CodeAction(
- lsp::CodeAction {
- title: "the-code-action".to_string(),
- ..Default::default()
- },
- )])
- },
- );
-
- fake_server.handle_request::<lsp::request::PrepareRenameRequest, _, _>(
- |params, _| async move {
- Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
- params.position,
- params.position,
- )))
- },
- );
+ ) -> (Self, TestAppContext) {
+ let fs = project.read_with(&cx, |project, _| project.fs().clone());
+ while operations.get() < max_operations {
+ operations.set(operations.get() + 1);
- fake_server.handle_request::<lsp::request::GotoDefinition, _, _>({
- let files = files.clone();
- let rng = rng.clone();
- move |_, _| {
- let files = files.clone();
- let rng = rng.clone();
- async move {
- let files = files.lock();
- let mut rng = rng.lock();
- let count = rng.gen_range::<usize, _>(1..3);
- let files = (0..count)
- .map(|_| files.choose(&mut *rng).unwrap())
- .collect::<Vec<_>>();
- log::info!("LSP: Returning definitions in files {:?}", &files);
- Some(lsp::GotoDefinitionResponse::Array(
- files
- .into_iter()
- .map(|file| lsp::Location {
- uri: lsp::Url::from_file_path(file).unwrap(),
- range: Default::default(),
- })
- .collect(),
- ))
+ let distribution = rng.lock().gen_range::<usize, _>(0..100);
+ match distribution {
+ 0..=20 if !files.lock().is_empty() => {
+ let path = files.lock().choose(&mut *rng.lock()).unwrap().clone();
+ let mut path = path.as_path();
+ while let Some(parent_path) = path.parent() {
+ path = parent_path;
+ if rng.lock().gen() {
+ break;
}
}
- });
- fake_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>({
- let rng = rng.clone();
- let project = project.clone();
- move |params, mut cx| {
- let highlights = if let Some(project) = project.upgrade(&cx) {
- project.update(&mut cx, |project, cx| {
- let path = params
- .text_document_position_params
- .text_document
- .uri
- .to_file_path()
- .unwrap();
- let (worktree, relative_path) =
- project.find_local_worktree(&path, cx)?;
- let project_path =
- ProjectPath::from((worktree.read(cx).id(), relative_path));
- let buffer =
- project.get_open_buffer(&project_path, cx)?.read(cx);
-
- let mut highlights = Vec::new();
- let highlight_count = rng.lock().gen_range(1..=5);
- let mut prev_end = 0;
- for _ in 0..highlight_count {
- let range =
- buffer.random_byte_range(prev_end, &mut *rng.lock());
- let start = buffer
- .offset_to_point_utf16(range.start)
- .to_lsp_position();
- let end = buffer
- .offset_to_point_utf16(range.end)
- .to_lsp_position();
- highlights.push(lsp::DocumentHighlight {
- range: lsp::Range::new(start, end),
- kind: Some(lsp::DocumentHighlightKind::READ),
- });
- prev_end = range.end;
- }
- Some(highlights)
- })
- } else {
- None
- };
- async move { highlights }
+ log::info!("Host: find/create local worktree {:?}", path);
+ let find_or_create_worktree = project.update(&mut cx, |project, cx| {
+ project.find_or_create_local_worktree(path, true, cx)
+ });
+ let find_or_create_worktree = async move {
+ find_or_create_worktree.await.unwrap();
+ };
+ if rng.lock().gen() {
+ cx.background().spawn(find_or_create_worktree).detach();
+ } else {
+ find_or_create_worktree.await;
}
- });
- }
- });
-
- project.update(&mut cx, |project, _| {
- project.languages().add(Arc::new(Language::new(
- LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- language_server: language_server_config,
- ..Default::default()
- },
- None,
- )));
- });
-
- async move {
- let fs = project.read_with(&cx, |project, _| project.fs().clone());
- while operations.get() < max_operations {
- operations.set(operations.get() + 1);
-
- let distribution = rng.lock().gen_range::<usize, _>(0..100);
- match distribution {
- 0..=20 if !files.lock().is_empty() => {
- let path = files.lock().choose(&mut *rng.lock()).unwrap().clone();
- let mut path = path.as_path();
- while let Some(parent_path) = path.parent() {
- path = parent_path;
- if rng.lock().gen() {
- break;
- }
- }
+ }
+ 10..=80 if !files.lock().is_empty() => {
+ let buffer = if self.buffers.is_empty() || rng.lock().gen() {
+ let file = files.lock().choose(&mut *rng.lock()).unwrap().clone();
+ let (worktree, path) = project
+ .update(&mut cx, |project, cx| {
+ project.find_or_create_local_worktree(file.clone(), true, cx)
+ })
+ .await
+ .unwrap();
+ let project_path =
+ worktree.read_with(&cx, |worktree, _| (worktree.id(), path));
+ log::info!(
+ "Host: opening path {:?}, worktree {}, relative_path {:?}",
+ file,
+ project_path.0,
+ project_path.1
+ );
+ let buffer = project
+ .update(&mut cx, |project, cx| {
+ project.open_buffer(project_path, cx)
+ })
+ .await
+ .unwrap();
+ self.buffers.insert(buffer.clone());
+ buffer
+ } else {
+ self.buffers
+ .iter()
+ .choose(&mut *rng.lock())
+ .unwrap()
+ .clone()
+ };
- log::info!("Host: find/create local worktree {:?}", path);
- let find_or_create_worktree = project.update(&mut cx, |project, cx| {
- project.find_or_create_local_worktree(path, true, cx)
+ if rng.lock().gen_bool(0.1) {
+ cx.update(|cx| {
+ log::info!(
+ "Host: dropping buffer {:?}",
+ buffer.read(cx).file().unwrap().full_path(cx)
+ );
+ self.buffers.remove(&buffer);
+ drop(buffer);
});
- let find_or_create_worktree = async move {
- find_or_create_worktree.await.unwrap();
- };
- if rng.lock().gen() {
- cx.background().spawn(find_or_create_worktree).detach();
- } else {
- find_or_create_worktree.await;
- }
- }
- 10..=80 if !files.lock().is_empty() => {
- let buffer = if self.buffers.is_empty() || rng.lock().gen() {
- let file = files.lock().choose(&mut *rng.lock()).unwrap().clone();
- let (worktree, path) = project
- .update(&mut cx, |project, cx| {
- project.find_or_create_local_worktree(
- file.clone(),
- true,
- cx,
- )
- })
- .await
- .unwrap();
- let project_path =
- worktree.read_with(&cx, |worktree, _| (worktree.id(), path));
+ } else {
+ buffer.update(&mut cx, |buffer, cx| {
log::info!(
- "Host: opening path {:?}, worktree {}, relative_path {:?}",
- file,
- project_path.0,
- project_path.1
+ "Host: updating buffer {:?} ({})",
+ buffer.file().unwrap().full_path(cx),
+ buffer.remote_id()
);
- let buffer = project
- .update(&mut cx, |project, cx| {
- project.open_buffer(project_path, cx)
- })
- .await
- .unwrap();
- self.buffers.insert(buffer.clone());
- buffer
- } else {
- self.buffers
- .iter()
- .choose(&mut *rng.lock())
- .unwrap()
- .clone()
- };
-
- if rng.lock().gen_bool(0.1) {
- cx.update(|cx| {
- log::info!(
- "Host: dropping buffer {:?}",
- buffer.read(cx).file().unwrap().full_path(cx)
- );
- self.buffers.remove(&buffer);
- drop(buffer);
- });
- } else {
- buffer.update(&mut cx, |buffer, cx| {
- log::info!(
- "Host: updating buffer {:?} ({})",
- buffer.file().unwrap().full_path(cx),
- buffer.remote_id()
- );
- buffer.randomly_edit(&mut *rng.lock(), 5, cx)
- });
- }
+ buffer.randomly_edit(&mut *rng.lock(), 5, cx)
+ });
}
- _ => loop {
- let path_component_count = rng.lock().gen_range::<usize, _>(1..=5);
- let mut path = PathBuf::new();
- path.push("/");
- for _ in 0..path_component_count {
- let letter = rng.lock().gen_range(b'a'..=b'z');
- path.push(std::str::from_utf8(&[letter]).unwrap());
- }
- path.set_extension("rs");
- let parent_path = path.parent().unwrap();
-
- log::info!("Host: creating file {:?}", path,);
-
- if fs.create_dir(&parent_path).await.is_ok()
- && fs.create_file(&path, Default::default()).await.is_ok()
- {
- files.lock().push(path);
- break;
- } else {
- log::info!("Host: cannot create file");
- }
- },
}
+ _ => loop {
+ let path_component_count = rng.lock().gen_range::<usize, _>(1..=5);
+ let mut path = PathBuf::new();
+ path.push("/");
+ for _ in 0..path_component_count {
+ let letter = rng.lock().gen_range(b'a'..=b'z');
+ path.push(std::str::from_utf8(&[letter]).unwrap());
+ }
+ path.set_extension("rs");
+ let parent_path = path.parent().unwrap();
- cx.background().simulate_random_delay().await;
- }
+ log::info!("Host: creating file {:?}", path,);
- log::info!("Host done");
+ if fs.create_dir(&parent_path).await.is_ok()
+ && fs.create_file(&path, Default::default()).await.is_ok()
+ {
+ files.lock().push(path);
+ break;
+ } else {
+ log::info!("Host: cannot create file");
+ }
+ },
+ }
- self.project = Some(project);
- (self, cx)
+ cx.background().simulate_random_delay().await;
}
+
+ log::info!("Host done");
+
+ self.project = Some(project);
+ (self, cx)
}
pub async fn simulate_guest(