diff --git a/apps/ely-mark/src/desk.rs b/apps/ely-mark/src/desk.rs index 83c6c47..266cf6d 100644 --- a/apps/ely-mark/src/desk.rs +++ b/apps/ely-mark/src/desk.rs @@ -257,7 +257,7 @@ pub fn open(app: AppId, window: &mut Window, cx: &mut App) -> Entity { cx.on_app_quit(|desk, cx| { // A system end skips asking: unsaved tabs keep points. if desk.core.tabs.iter().any(|tab| tab.dirty(cx)) { - log::warn!("mark: quit with unsaved tabs; points stay"); + desk.keeping.hold(); } else { desk.keeping.close(); } diff --git a/apps/ely-mark/src/restore.rs b/apps/ely-mark/src/restore.rs index 908ab4f..acead37 100644 --- a/apps/ely-mark/src/restore.rs +++ b/apps/ely-mark/src/restore.rs @@ -148,6 +148,13 @@ impl Keeping { self.waiting[at].tab = Some(tab); } + /// An end that never asked: the lock and points stay. + pub fn hold(&mut self) { + if self.crash.take().is_some() { + log::warn!("mark: the session ends unasked; its points stay"); + } + } + /// A clean end: no crash next time, no stale points. pub fn close(&mut self) { let Some(crash) = self.crash.take() else { @@ -415,4 +422,23 @@ mod tests { assert_eq!(super::waiting_for(&waiting, None, 4), Some(0)); assert_eq!(super::waiting_for(&waiting, None, 9), None, "a new tab takes nothing"); } + + #[test] + fn an_unasked_end_keeps_the_lock_and_points_past_release() { + let dir = tempfile::tempdir().expect("a temp dir"); + let point = dir.path().join("recovery/s/point"); + let (lock, slot) = (dir.path().join("session.lock"), point.parent().expect("a slot")); + let (mut held, ..) = super::Keeping::start(dir.path()).expect("a session"); + std::fs::create_dir_all(slot).expect("a slot"); + std::fs::write(&point, "unsaved").expect("a point"); + held.hold(); + held.close(); + assert!(lock.exists() && point.exists(), "release after quit wiped them"); + drop(held); + let (mut clean, ..) = super::Keeping::start(dir.path()).expect("a session"); + std::fs::create_dir_all(slot).expect("a slot"); + std::fs::write(&point, "unsaved").expect("a point"); + clean.close(); + assert!(!lock.exists() && !point.exists(), "a clean end clears"); + } } diff --git a/tasks/BUGS.md b/tasks/BUGS.md index 40c2e2c..e5a3469 100644 --- a/tasks/BUGS.md +++ b/tasks/BUGS.md @@ -66,7 +66,7 @@ - [x] M-03 干净标签接过磁盘文字后关闭仍问“是否保存” — 接过磁盘文字的各路(同文、干净重载、合并)都经 adopt_disk,标签与视图的保存基线同设;R1 合并采用未同步视图基线;R2 注释超长;R3 PASS - [x] M-04 第二次打印或导出 PDF 悄悄取消第一次,没有文件也没有错误 — 每份打印与导出各有编号与文件,作业按编号保留、互不取消;每份作业完成时记下编号与结果;R1 窗口测试只数日志;R2 PASS(窗口测试只在 macOS,本机未运行) - [x] M-05 点页面里的链接什么也不发生 — 页面拦下链接单击,地址取链接标记原文,预览单击、可视 Cmd/Ctrl 单击交应用(审查 4 轮) -- [ ] M-06 `on_app_quit` 无条件删恢复点与崩溃锁,AppKit 直接终止时丢未保存内容 +- [x] M-06 `on_app_quit` 无条件删恢复点与崩溃锁,AppKit 直接终止时丢未保存内容 — 未保存时退出只放下锁、不清点,窗口释放时不再删(审查 1 轮) - [ ] M-07 崩溃恢复的未命名副本按“第一个显示的未命名标签”配对,内容可能落错标签 - [ ] M-08 页面重载后悬着的渲染回调永不完成,导出既不成功也不报错 - [ ] M-09 导出的保存面板出错被当作取消 diff --git a/tasks/reviews/M-06-r1.md b/tasks/reviews/M-06-r1.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/M-06-r1.md @@ -0,0 +1 @@ +PASS