Rerender tabs when buffers' file handles change

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Nathan Sobo
2021-04-26 14:16:35 -07:00
committed by Max Brunsfeld
parent 9753e67410
commit 870925e2ac
6 changed files with 615 additions and 473 deletions
File diff suppressed because it is too large Load Diff
+20 -9
View File
@@ -119,7 +119,7 @@ struct ClipboardSelection {
impl BufferView {
pub fn single_line(settings: watch::Receiver<Settings>, ctx: &mut ViewContext<Self>) -> Self {
let buffer = ctx.add_model(|_| Buffer::new(0, String::new()));
let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx));
let mut view = Self::for_buffer(buffer, settings, ctx);
view.single_line = true;
view
@@ -1316,6 +1316,7 @@ impl BufferView {
buffer::Event::Edited(_) => ctx.emit(Event::Edited),
buffer::Event::Dirtied => ctx.emit(Event::Dirtied),
buffer::Event::Saved => ctx.emit(Event::Saved),
buffer::Event::FileHandleChanged => ctx.emit(Event::FileHandleChanged),
}
}
}
@@ -1326,6 +1327,7 @@ pub enum Event {
Blurred,
Dirtied,
Saved,
FileHandleChanged,
}
impl Entity for BufferView {
@@ -1372,7 +1374,10 @@ impl workspace::ItemView for BufferView {
}
fn should_update_tab_on_event(event: &Self::Event) -> bool {
matches!(event, Event::Saved | Event::Dirtied)
matches!(
event,
Event::Saved | Event::Dirtied | Event::FileHandleChanged
)
}
fn title(&self, app: &AppContext) -> std::string::String {
@@ -1419,7 +1424,8 @@ mod tests {
#[test]
fn test_selection_with_mouse() {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n"));
let buffer =
app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
let settings = settings::channel(&app.font_cache()).unwrap().1;
let (_, buffer_view) =
app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
@@ -1533,7 +1539,7 @@ mod tests {
let layout_cache = TextLayoutCache::new(app.platform().fonts());
let font_cache = app.font_cache().clone();
let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
let settings = settings::channel(&font_cache).unwrap().1;
let (_, view) =
@@ -1550,7 +1556,7 @@ mod tests {
#[test]
fn test_fold() {
App::test((), |app| {
let buffer = app.add_model(|_| {
let buffer = app.add_model(|ctx| {
Buffer::new(
0,
"
@@ -1571,6 +1577,7 @@ mod tests {
}
"
.unindent(),
ctx,
)
});
let settings = settings::channel(&app.font_cache()).unwrap().1;
@@ -1644,7 +1651,7 @@ mod tests {
#[test]
fn test_move_cursor() -> Result<()> {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
let settings = settings::channel(&app.font_cache()).unwrap().1;
let (_, view) =
app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
@@ -1681,8 +1688,12 @@ mod tests {
#[test]
fn test_backspace() {
App::test((), |app| {
let buffer = app.add_model(|_| {
Buffer::new(0, "one two three\nfour five six\nseven eight nine\nten\n")
let buffer = app.add_model(|ctx| {
Buffer::new(
0,
"one two three\nfour five six\nseven eight nine\nten\n",
ctx,
)
});
let settings = settings::channel(&app.font_cache()).unwrap().1;
let (_, view) =
@@ -1714,7 +1725,7 @@ mod tests {
#[test]
fn test_clipboard() {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, "one two three four five six "));
let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx));
let settings = settings::channel(&app.font_cache()).unwrap().1;
let view = app
.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx))
+6 -6
View File
@@ -471,7 +471,7 @@ mod tests {
#[test]
fn test_basic_folds() {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6)));
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
map.fold(
@@ -522,7 +522,7 @@ mod tests {
#[test]
fn test_overlapping_folds() {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6)));
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
map.fold(
vec![
@@ -541,7 +541,7 @@ mod tests {
#[test]
fn test_merging_folds_via_edit() {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6)));
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
map.fold(
@@ -589,10 +589,10 @@ mod tests {
let mut rng = StdRng::seed_from_u64(seed);
App::test((), |app| {
let buffer = app.add_model(|_| {
let buffer = app.add_model(|ctx| {
let len = rng.gen_range(0..10);
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
Buffer::new(0, text)
Buffer::new(0, text, ctx)
});
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
@@ -664,7 +664,7 @@ mod tests {
fn test_buffer_rows() {
App::test((), |app| {
let text = sample_text(6, 6) + "\n";
let buffer = app.add_model(|_| Buffer::new(0, text));
let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
+2 -2
View File
@@ -298,7 +298,7 @@ mod tests {
fn test_chars_at() {
App::test((), |app| {
let text = sample_text(6, 6);
let buffer = app.add_model(|_| Buffer::new(0, text));
let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx));
buffer
.update(app, |buffer, ctx| {
@@ -365,7 +365,7 @@ mod tests {
#[test]
fn test_max_point() {
App::test((), |app| {
let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb"));
let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx));
let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx));
assert_eq!(
map.read(app).max_point(app.as_ref()),
+8 -6
View File
@@ -1,6 +1,6 @@
use super::{ItemView, ItemViewHandle};
use crate::{
editor::Buffer,
editor::{Buffer, History},
settings::Settings,
time::ReplicaId,
watch,
@@ -174,15 +174,17 @@ impl Workspace {
let replica_id = self.replica_id;
let file = worktree.file(path.clone(), ctx.as_ref())?;
let history = file.load_history(ctx.as_ref());
let buffer = async move { Ok(Buffer::from_history(replica_id, file, history.await?)) };
// let buffer = async move { Ok(Buffer::from_history(replica_id, file, history.await?)) };
let (mut tx, rx) = watch::channel(None);
self.items.insert(item_key, OpenedItem::Loading(rx));
ctx.spawn(
buffer,
move |me, buffer: anyhow::Result<Buffer>, ctx| match buffer {
Ok(buffer) => {
let handle = Box::new(ctx.add_model(|_| buffer)) as Box<dyn ItemHandle>;
history,
move |me, history: anyhow::Result<History>, ctx| match history {
Ok(history) => {
let handle = Box::new(
ctx.add_model(|ctx| Buffer::from_history(replica_id, file, history, ctx)),
) as Box<dyn ItemHandle>;
me.items
.insert(item_key, OpenedItem::Loaded(handle.clone()));
ctx.spawn(
+43 -7
View File
@@ -59,7 +59,7 @@ pub struct FileHandle {
state: Arc<Mutex<FileHandleState>>,
}
#[derive(Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
struct FileHandleState {
path: Arc<Path>,
is_deleted: bool,
@@ -403,6 +403,32 @@ impl FileHandle {
pub fn entry_id(&self) -> (usize, Arc<Path>) {
(self.worktree.id(), self.path())
}
pub fn observe_from_model<T: Entity>(
&self,
ctx: &mut ModelContext<T>,
mut callback: impl FnMut(&mut T, FileHandle, &mut ModelContext<T>) + 'static,
) {
let mut prev_state = self.state.lock().clone();
let cur_state = Arc::downgrade(&self.state);
ctx.observe(&self.worktree, move |observer, worktree, ctx| {
if let Some(cur_state) = cur_state.upgrade() {
let cur_state_unlocked = cur_state.lock();
if *cur_state_unlocked != prev_state {
prev_state = cur_state_unlocked.clone();
drop(cur_state_unlocked);
callback(
observer,
FileHandle {
worktree,
state: cur_state,
},
ctx,
);
}
}
});
}
}
#[derive(Clone, Debug)]
@@ -818,7 +844,12 @@ impl BackgroundScanner {
handles.retain(|handle_path, handle_state| {
if let Ok(path_suffix) = handle_path.strip_prefix(&old_path) {
let new_handle_path: Arc<Path> =
new_path.join(path_suffix).into();
if path_suffix.file_name().is_some() {
new_path.join(path_suffix)
} else {
new_path.to_path_buf()
}
.into();
if let Some(handle_state) = Weak::upgrade(&handle_state) {
handle_state.lock().path = new_handle_path.clone();
updated_handles
@@ -1266,20 +1297,24 @@ mod tests {
app.read(|ctx| tree.read(ctx).scan_complete()).await;
app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1));
let buffer = Buffer::new(1, "a line of text.\n".repeat(10 * 1024));
let buffer =
app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx));
let path = tree.update(&mut app, |tree, ctx| {
let path = tree.files(0).next().unwrap().path().clone();
assert_eq!(path.file_name().unwrap(), "file1");
smol::block_on(tree.save(&path, buffer.snapshot(), ctx.as_ref())).unwrap();
smol::block_on(tree.save(&path, buffer.read(ctx).snapshot(), ctx.as_ref()))
.unwrap();
path
});
let loaded_history = app
let history = app
.read(|ctx| tree.read(ctx).load_history(&path, ctx))
.await
.unwrap();
assert_eq!(loaded_history.base_text.as_ref(), buffer.text());
app.read(|ctx| {
assert_eq!(history.base_text.as_ref(), buffer.read(ctx).text());
});
});
}
@@ -1335,7 +1370,8 @@ mod tests {
"d/file4"
]
);
assert_eq!(file2.path().as_ref(), Path::new("a/file2.new"));
assert_eq!(file2.path().to_str().unwrap(), "a/file2.new");
assert_eq!(file4.path().as_ref(), Path::new("d/file4"));
assert_eq!(file5.path().as_ref(), Path::new("d/file5"));
assert!(!file2.is_deleted());