C14.11 r1: fingerprints carry the file's identity; stale disk reads never land
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1dc0d31615
commit
e2cb83ceaa
6 files changed
+86
-3
No files matched your search
@@ -53,6 +53,8 @@ pub struct Extra {
|
||||
pub pointing: bool,
|
||||
/// A kept tab's mode, place and text came back once.
|
||||
pub restored: bool,
|
||||
/// Disk reads started; only the newest lands.
|
||||
pub reads: u64,
|
||||
}
|
||||
|
||||
impl Extra {
|
||||
@@ -76,6 +78,7 @@ impl Default for Extra {
|
||||
pointed: None,
|
||||
pointing: false,
|
||||
restored: false,
|
||||
reads: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,13 +202,18 @@ impl Desk {
|
||||
|
||||
/// Changed: a clean tab follows, a dirty one asks.
|
||||
fn read_disk(&mut self, id: u64, path: PathBuf, cx: &mut Context<Self>) {
|
||||
let Some(tab) = self.tab_mut(id) else {
|
||||
return;
|
||||
};
|
||||
tab.extra.reads += 1;
|
||||
let number = tab.extra.reads;
|
||||
let reading = path.clone();
|
||||
cx.spawn(async move |desk, cx| {
|
||||
let read = cx
|
||||
.background_executor()
|
||||
.spawn(async move { read_still(&reading) })
|
||||
.await;
|
||||
desk.update(cx, |desk, cx| desk.disk_read(id, path, read, cx))
|
||||
desk.update(cx, |desk, cx| desk.disk_read(id, path, number, read, cx))
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
@@ -215,16 +223,25 @@ impl Desk {
|
||||
&mut self,
|
||||
id: u64,
|
||||
path: PathBuf,
|
||||
number: u64,
|
||||
read: io::Result<(Fingerprint, Source)>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(tab) = self.tab(id).filter(|tab| tab.session.path() == Some(&path)) else {
|
||||
return log::info!("mark: a read for a moved or closed tab was dropped");
|
||||
};
|
||||
if tab.extra.reads != number {
|
||||
return log::info!("mark: read {number} of tab {id} lapsed");
|
||||
}
|
||||
let (fingerprint, disk) = match read {
|
||||
Ok(read) => read,
|
||||
Err(error) => return self.set_outside(id, Outside::Unread(error.to_string()), cx),
|
||||
};
|
||||
// The disk moved on since the read: look again.
|
||||
if Fingerprint::of(&path).ok() != Some(fingerprint) {
|
||||
log::info!("mark: tab {id}'s file changed while read");
|
||||
return self.look(id, cx);
|
||||
}
|
||||
let current = tab.doc.lock().expect("the text lock").current.clone();
|
||||
let kept = disk.text == tab.extra.base;
|
||||
let dirty = tab.dirty(cx);
|
||||
|
||||
@@ -138,3 +138,45 @@ fn a_path_that_cannot_be_read_says_why(cx: &mut TestAppContext) {
|
||||
});
|
||||
assert!(unread);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_replace_that_keeps_the_time_still_reloads(cx: &mut TestAppContext) {
|
||||
let (desk, cx, id, path, _dirs) = opened("old text\n", cx);
|
||||
let modified = std::fs::metadata(&path)
|
||||
.expect("meta")
|
||||
.modified()
|
||||
.expect("a time");
|
||||
let next = path.with_extension("new");
|
||||
std::fs::write(&next, "new text\n").expect("a new file");
|
||||
let file = std::fs::File::options()
|
||||
.write(true)
|
||||
.open(&next)
|
||||
.expect("open");
|
||||
file.set_modified(modified).expect("the old time");
|
||||
drop(file);
|
||||
std::fs::rename(&next, &path).expect("a replace");
|
||||
look(&desk, id, cx);
|
||||
assert_eq!(shown(&desk, cx), "new text\n");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_stale_read_never_lands(cx: &mut TestAppContext) {
|
||||
let (desk, cx, id, path, _dirs) = opened("first\n", cx);
|
||||
std::fs::write(&path, "older\n").expect("an older write");
|
||||
let older = (
|
||||
ely_files::Fingerprint::of(&path).expect("its fingerprint"),
|
||||
crate::text::Source::decode(b"older\n".to_vec()).expect("reads"),
|
||||
);
|
||||
std::fs::write(&path, "newest disk\n").expect("a newer write");
|
||||
look(&desk, id, cx);
|
||||
assert_eq!(shown(&desk, cx), "newest disk\n");
|
||||
let reads = desk.read_with(cx, |desk, _| desk.tab(id).expect("open").extra.reads);
|
||||
for number in [reads - 1, reads] {
|
||||
let (path, older) = (path.clone(), (older.0, older.1.clone()));
|
||||
desk.update(cx, |desk, cx| {
|
||||
desk.disk_read(id, path, number, Ok(older), cx)
|
||||
});
|
||||
cx.run_until_parked();
|
||||
assert_eq!(shown(&desk, cx), "newest disk\n", "read {number}");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user