ElyMark: untitled copies pair by the tab made for them (M-07)

restore_shown takes its entry through Keeping::take; the test runs a
crashed session through start, untitled, made and take, the second
tab first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-10 11:42:29 -04:00
1 parent ad97f25ea4
commit 2c19d027a6
4 files changed
+48 -24

No files matched your search

+43 -23
View File
@@ -148,6 +148,16 @@ impl Keeping {
self.waiting[at].tab = Some(tab);
}
/// What tab `id` takes: its file or its copy.
fn take(&mut self, real: Option<&PathBuf>, id: u64) -> Option<Waiting> {
let at = self.waiting.iter().position(|waiting| match (&waiting.real, real) {
(Some(kept), Some(open)) => kept == open,
(None, None) => waiting.tab == Some(id),
_ => false,
})?;
Some(self.waiting.remove(at))
}
/// An end that never asked: the lock and points stay.
pub fn hold(&mut self) {
if self.crash.take().is_some() {
@@ -192,13 +202,6 @@ fn clear(dir: &Path) -> io::Result<()> {
}
/// What tab `id` restores: by file, or untitled by number.
fn waiting_for(waiting: &[Waiting], real: Option<&PathBuf>, id: u64) -> Option<usize> {
waiting.iter().position(|waiting| match (&waiting.real, real) {
(Some(kept), Some(open)) => kept == open,
(None, None) => waiting.tab == Some(id),
_ => false,
})
}
impl Desk {
/// A tab just shown takes its kept mode, place, text.
@@ -213,13 +216,12 @@ impl Desk {
.session
.path()
.and_then(|path| std::fs::canonicalize(path).ok());
let waiting = &mut self.keeping.waiting;
let Some(at) = waiting_for(waiting, real.as_ref(), id) else {
let Some(Waiting {
kept, text: back, ..
}) = self.keeping.take(real.as_ref(), id)
else {
return;
};
let Waiting {
kept, text: back, ..
} = waiting.remove(at);
let mode = Mode::parse(&kept.mode).unwrap_or(Mode::Visual);
log::info!("mark: restores tab {id} as {}", mode.name());
let tab = self.tab_mut(id).expect("open");
@@ -409,18 +411,36 @@ mod tests {
}
#[test]
fn an_untitled_copy_goes_to_the_tab_made_for_it() {
let untitled = |name: &str, tab: u64| super::Waiting {
kept: super::Kept { path: None, name: name.into(), mode: "visual".into(), place: None, slot: String::new() },
real: None,
text: None,
tab: Some(tab),
fn each_untitled_copy_goes_to_the_tab_made_for_it() {
let dir = tempfile::tempdir().expect("a temp dir");
let kept = |name: &str, mode: &str, slot: &str| super::Kept {
path: None,
name: name.into(),
mode: mode.into(),
place: Some(super::Place { line: slot.len() as u64, column: 1, scroll: 0.0 }),
slot: slot.into(),
};
let waiting = [untitled("Untitled1", 4), untitled("Untitled2", 5)];
// The second tab shows first: it still takes its own.
assert_eq!(super::waiting_for(&waiting, None, 5), Some(1));
assert_eq!(super::waiting_for(&waiting, None, 4), Some(0));
assert_eq!(super::waiting_for(&waiting, None, 9), None, "a new tab takes nothing");
let tabs = vec![kept("Untitled1", "visual", "a"), kept("Untitled2", "source", "bb")];
for (slot, text) in [("a", "first"), ("bb", "second")] {
let mut points = super::Recovery::new(super::recovery(dir.path(), slot));
points.write_once(text.as_bytes(), None, std::time::SystemTime::now()).expect("a point");
}
let saved = serde_json::to_vec(&super::Saved { tabs: tabs.clone() }).expect("a list");
std::fs::write(dir.path().join("session.json"), saved).expect("the list");
// A pid no process has: the last run crashed.
std::fs::write(dir.path().join("session.lock"), "open 4294967295").expect("a lock");
let (mut keeping, ..) = super::Keeping::start(dir.path()).expect("a session");
let made: Vec<_> = keeping.untitled();
assert_eq!(made, [(0, "Untitled1".to_string()), (1, "Untitled2".to_string())]);
for (at, _) in made {
keeping.made(at, 10 + at as u64);
}
assert!(keeping.take(None, 12).is_none(), "a new tab takes nothing");
// The second tab shows first: each still takes its own.
for (id, want, text) in [(11, &tabs[1], "second"), (10, &tabs[0], "first")] {
let got = keeping.take(None, id).expect("its copy");
assert_eq!((&got.kept, got.text.map(|(text, _)| text)), (want, Some(text.to_string())));
}
}
#[test]