mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 13:24:19 +00:00
Merge pull request #1819 from zed-industries/remote-renames
Assign a new language when remote buffer is renamed
This commit is contained in:
commit
cf2ec99a4d
2 changed files with 91 additions and 61 deletions
|
@ -34,8 +34,7 @@ use live_kit_client::MacOSDisplay;
|
||||||
use lsp::{self, FakeLanguageServer};
|
use lsp::{self, FakeLanguageServer};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::{
|
use project::{
|
||||||
search::SearchQuery, worktree::WorktreeHandle, DiagnosticSummary, Project, ProjectPath,
|
search::SearchQuery, DiagnosticSummary, Project, ProjectPath, ProjectStore, WorktreeId,
|
||||||
ProjectStore, WorktreeId,
|
|
||||||
};
|
};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
@ -1228,26 +1227,49 @@ async fn test_room_location(
|
||||||
|
|
||||||
#[gpui::test(iterations = 10)]
|
#[gpui::test(iterations = 10)]
|
||||||
async fn test_propagate_saves_and_fs_changes(
|
async fn test_propagate_saves_and_fs_changes(
|
||||||
|
deterministic: Arc<Deterministic>,
|
||||||
cx_a: &mut TestAppContext,
|
cx_a: &mut TestAppContext,
|
||||||
cx_b: &mut TestAppContext,
|
cx_b: &mut TestAppContext,
|
||||||
cx_c: &mut TestAppContext,
|
cx_c: &mut TestAppContext,
|
||||||
) {
|
) {
|
||||||
cx_a.foreground().forbid_parking();
|
deterministic.forbid_parking();
|
||||||
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
|
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
let client_c = server.create_client(cx_c, "user_c").await;
|
let client_c = server.create_client(cx_c, "user_c").await;
|
||||||
|
|
||||||
server
|
server
|
||||||
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
|
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
|
||||||
.await;
|
.await;
|
||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
|
let rust = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
name: "Rust".into(),
|
||||||
|
path_suffixes: vec!["rs".to_string()],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Some(tree_sitter_rust::language()),
|
||||||
|
));
|
||||||
|
let javascript = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
name: "JavaScript".into(),
|
||||||
|
path_suffixes: vec!["js".to_string()],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Some(tree_sitter_rust::language()),
|
||||||
|
));
|
||||||
|
for client in [&client_a, &client_b, &client_c] {
|
||||||
|
client.language_registry.add(rust.clone());
|
||||||
|
client.language_registry.add(javascript.clone());
|
||||||
|
}
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
"file1": "",
|
"file1.rs": "",
|
||||||
"file2": ""
|
"file2": ""
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -1267,19 +1289,25 @@ async fn test_propagate_saves_and_fs_changes(
|
||||||
|
|
||||||
// Open and edit a buffer as both guests B and C.
|
// Open and edit a buffer as both guests B and C.
|
||||||
let buffer_b = project_b
|
let buffer_b = project_b
|
||||||
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
|
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let buffer_c = project_c
|
let buffer_c = project_c
|
||||||
.update(cx_c, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
|
.update(cx_c, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
buffer_b.read_with(cx_b, |buffer, _| {
|
||||||
|
assert_eq!(&*buffer.language().unwrap().name(), "Rust");
|
||||||
|
});
|
||||||
|
buffer_c.read_with(cx_c, |buffer, _| {
|
||||||
|
assert_eq!(&*buffer.language().unwrap().name(), "Rust");
|
||||||
|
});
|
||||||
buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "i-am-b, ")], None, cx));
|
buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "i-am-b, ")], None, cx));
|
||||||
buffer_c.update(cx_c, |buf, cx| buf.edit([(0..0, "i-am-c, ")], None, cx));
|
buffer_c.update(cx_c, |buf, cx| buf.edit([(0..0, "i-am-c, ")], None, cx));
|
||||||
|
|
||||||
// Open and edit that buffer as the host.
|
// Open and edit that buffer as the host.
|
||||||
let buffer_a = project_a
|
let buffer_a = project_a
|
||||||
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "file1"), cx))
|
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -1290,90 +1318,87 @@ async fn test_propagate_saves_and_fs_changes(
|
||||||
buf.edit([(buf.len()..buf.len(), "i-am-a")], None, cx)
|
buf.edit([(buf.len()..buf.len(), "i-am-a")], None, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for edits to propagate
|
deterministic.run_until_parked();
|
||||||
buffer_a
|
buffer_a.read_with(cx_a, |buf, _| {
|
||||||
.condition(cx_a, |buf, _| buf.text() == "i-am-c, i-am-b, i-am-a")
|
assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
|
||||||
.await;
|
});
|
||||||
buffer_b
|
buffer_b.read_with(cx_b, |buf, _| {
|
||||||
.condition(cx_b, |buf, _| buf.text() == "i-am-c, i-am-b, i-am-a")
|
assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
|
||||||
.await;
|
});
|
||||||
buffer_c
|
buffer_c.read_with(cx_c, |buf, _| {
|
||||||
.condition(cx_c, |buf, _| buf.text() == "i-am-c, i-am-b, i-am-a")
|
assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
|
||||||
.await;
|
});
|
||||||
|
|
||||||
// Edit the buffer as the host and concurrently save as guest B.
|
// Edit the buffer as the host and concurrently save as guest B.
|
||||||
let save_b = buffer_b.update(cx_b, |buf, cx| buf.save(cx));
|
let save_b = buffer_b.update(cx_b, |buf, cx| buf.save(cx));
|
||||||
buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "hi-a, ")], None, cx));
|
buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "hi-a, ")], None, cx));
|
||||||
save_b.await.unwrap();
|
save_b.await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client_a.fs.load("/a/file1".as_ref()).await.unwrap(),
|
client_a.fs.load("/a/file1.rs".as_ref()).await.unwrap(),
|
||||||
"hi-a, i-am-c, i-am-b, i-am-a"
|
"hi-a, i-am-c, i-am-b, i-am-a"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
deterministic.run_until_parked();
|
||||||
buffer_a.read_with(cx_a, |buf, _| assert!(!buf.is_dirty()));
|
buffer_a.read_with(cx_a, |buf, _| assert!(!buf.is_dirty()));
|
||||||
buffer_b.read_with(cx_b, |buf, _| assert!(!buf.is_dirty()));
|
buffer_b.read_with(cx_b, |buf, _| assert!(!buf.is_dirty()));
|
||||||
buffer_c.condition(cx_c, |buf, _| !buf.is_dirty()).await;
|
buffer_c.read_with(cx_c, |buf, _| assert!(!buf.is_dirty()));
|
||||||
|
|
||||||
worktree_a.flush_fs_events(cx_a).await;
|
|
||||||
|
|
||||||
// Make changes on host's file system, see those changes on guest worktrees.
|
// Make changes on host's file system, see those changes on guest worktrees.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs
|
||||||
.rename(
|
.rename(
|
||||||
"/a/file1".as_ref(),
|
"/a/file1.rs".as_ref(),
|
||||||
"/a/file1-renamed".as_ref(),
|
"/a/file1.js".as_ref(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs
|
||||||
.rename("/a/file2".as_ref(), "/a/file3".as_ref(), Default::default())
|
.rename("/a/file2".as_ref(), "/a/file3".as_ref(), Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_a.fs.insert_file("/a/file4", "4".into()).await;
|
client_a.fs.insert_file("/a/file4", "4".into()).await;
|
||||||
|
deterministic.run_until_parked();
|
||||||
|
|
||||||
worktree_a
|
worktree_a.read_with(cx_a, |tree, _| {
|
||||||
.condition(cx_a, |tree, _| {
|
assert_eq!(
|
||||||
tree.paths()
|
tree.paths()
|
||||||
.map(|p| p.to_string_lossy())
|
.map(|p| p.to_string_lossy())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>(),
|
||||||
== ["file1-renamed", "file3", "file4"]
|
["file1.js", "file3", "file4"]
|
||||||
})
|
)
|
||||||
.await;
|
});
|
||||||
worktree_b
|
worktree_b.read_with(cx_b, |tree, _| {
|
||||||
.condition(cx_b, |tree, _| {
|
assert_eq!(
|
||||||
tree.paths()
|
tree.paths()
|
||||||
.map(|p| p.to_string_lossy())
|
.map(|p| p.to_string_lossy())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>(),
|
||||||
== ["file1-renamed", "file3", "file4"]
|
["file1.js", "file3", "file4"]
|
||||||
})
|
)
|
||||||
.await;
|
});
|
||||||
worktree_c
|
worktree_c.read_with(cx_c, |tree, _| {
|
||||||
.condition(cx_c, |tree, _| {
|
assert_eq!(
|
||||||
tree.paths()
|
tree.paths()
|
||||||
.map(|p| p.to_string_lossy())
|
.map(|p| p.to_string_lossy())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>(),
|
||||||
== ["file1-renamed", "file3", "file4"]
|
["file1.js", "file3", "file4"]
|
||||||
})
|
)
|
||||||
.await;
|
});
|
||||||
|
|
||||||
// Ensure buffer files are updated as well.
|
// Ensure buffer files are updated as well.
|
||||||
buffer_a
|
buffer_a.read_with(cx_a, |buffer, _| {
|
||||||
.condition(cx_a, |buf, _| {
|
assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
|
||||||
buf.file().unwrap().path().to_str() == Some("file1-renamed")
|
assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
|
||||||
})
|
});
|
||||||
.await;
|
buffer_b.read_with(cx_b, |buffer, _| {
|
||||||
buffer_b
|
assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
|
||||||
.condition(cx_b, |buf, _| {
|
assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
|
||||||
buf.file().unwrap().path().to_str() == Some("file1-renamed")
|
});
|
||||||
})
|
buffer_c.read_with(cx_c, |buffer, _| {
|
||||||
.await;
|
assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
|
||||||
buffer_c
|
assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
|
||||||
.condition(cx_c, |buf, _| {
|
});
|
||||||
buf.file().unwrap().path().to_str() == Some("file1-renamed")
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test(iterations = 10)]
|
#[gpui::test(iterations = 10)]
|
||||||
|
|
|
@ -1780,17 +1780,21 @@ impl Project {
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
// If the buffer has a language, set it and start the language server if we haven't already.
|
// If the buffer has a language, set it and start the language server if we haven't already.
|
||||||
let full_path = buffer.read(cx).file()?.full_path(cx);
|
let full_path = buffer.read(cx).file()?.full_path(cx);
|
||||||
let language = self.languages.select_language(&full_path)?;
|
let new_language = self.languages.select_language(&full_path)?;
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.set_language_registry(self.languages.clone());
|
if buffer.language().map_or(true, |old_language| {
|
||||||
buffer.set_language(Some(language.clone()), cx);
|
!Arc::ptr_eq(old_language, &new_language)
|
||||||
|
}) {
|
||||||
|
buffer.set_language_registry(self.languages.clone());
|
||||||
|
buffer.set_language(Some(new_language.clone()), cx);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let file = File::from_dyn(buffer.read(cx).file())?;
|
let file = File::from_dyn(buffer.read(cx).file())?;
|
||||||
let worktree = file.worktree.read(cx).as_local()?;
|
let worktree = file.worktree.read(cx).as_local()?;
|
||||||
let worktree_id = worktree.id();
|
let worktree_id = worktree.id();
|
||||||
let worktree_abs_path = worktree.abs_path().clone();
|
let worktree_abs_path = worktree.abs_path().clone();
|
||||||
self.start_language_server(worktree_id, worktree_abs_path, language, cx);
|
self.start_language_server(worktree_id, worktree_abs_path, new_language, cx);
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -4992,6 +4996,7 @@ impl Project {
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.file_updated(Arc::new(file), cx).detach();
|
buffer.file_updated(Arc::new(file), cx).detach();
|
||||||
});
|
});
|
||||||
|
this.assign_language_to_buffer(&buffer, cx);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue