Rerender tabs when buffers' file handles change
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
committed by
Max Brunsfeld
parent
9753e67410
commit
870925e2ac
+536
-443
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user