From 1abaa5dc835251d0cbc720b7816cc9e413ae30b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 15 Oct 2026 03:18:41 -0400 Subject: [PATCH] R6.3 round 1 fix: restored tabs keep the recent list cleared A tab reopened from the session counts as already remembered, so clearing the list survives a restart; explicit opens still join it. Co-Authored-By: Claude Opus 5.5 (1M context) --- apps/ely-mark/src/desk.rs | 5 +++++ apps/ely-mark/src/restore/tests.rs | 36 ++++++++++++++++++++++++++++++ tasks/reviews/R6.2-r1.md | 7 ++++++ tasks/reviews/R6.3-r1.md | 3 +++ 4 files changed, 51 insertions(+) create mode 100644 tasks/reviews/R6.2-r1.md create mode 100644 tasks/reviews/R6.3-r1.md diff --git a/apps/ely-mark/src/desk.rs b/apps/ely-mark/src/desk.rs index 14291d2..69eeb2b 100644 --- a/apps/ely-mark/src/desk.rs +++ b/apps/ely-mark/src/desk.rs @@ -227,7 +227,12 @@ pub(crate) fn open_in( // Launch files stand alone; unsaved text still returns. if asked.is_empty() { for path in kept { + // A restored tab does not rejoin the recent list. + let (id, real) = (desk.core.next, dunce::canonicalize(&path).ok()); desk.open_path(path, cx); + if let Some(real) = real.filter(|_| desk.core.next > id) { + desk.remembered.insert(id, real); + } } } for (at, name) in desk.keeping.untitled() { diff --git a/apps/ely-mark/src/restore/tests.rs b/apps/ely-mark/src/restore/tests.rs index ce62242..9591ed4 100644 --- a/apps/ely-mark/src/restore/tests.rs +++ b/apps/ely-mark/src/restore/tests.rs @@ -441,4 +441,40 @@ mod window { "the session" ); } + + #[gpui::test] + fn a_cleared_recent_list_stays_cleared_with_tabs_restored( + first: &mut TestAppContext, + second: &mut TestAppContext, + ) { + let (data, files) = ( + tempfile::tempdir().expect("data"), + tempfile::tempdir().expect("files"), + ); + let (a, b) = (files.path().join("a.md"), files.path().join("b.md")); + std::fs::write(&a, "A +").expect("a"); + std::fs::write(&b, "B +").expect("b"); + let (desk, cx) = start(first, data.path()); + open(&desk, &a, cx); + let button = cx.debug_bounds("mark-clear-recent").expect("the button"); + cx.simulate_click(button.center(), gpui::Modifiers::none()); + cx.run_until_parked(); + desk.update(cx, |desk, cx| { + desk.leave(cx); + desk.keeping.close(); + }); + cx.run_until_parked(); + + let (desk, cx) = start(second, data.path()); + assert_eq!(names(&desk, cx), ["a.md"]); + assert!(desk.read_with(cx, |desk, _| desk.recent.is_empty())); + let list = data.path().join("recent.json"); + assert_eq!(std::fs::read_to_string(&list).expect("the list"), "[]"); + // An explicit open still joins the list. + open(&desk, &b, cx); + let real = dunce::canonicalize(&b).expect("real"); + assert_eq!(desk.read_with(cx, |desk, _| desk.recent.clone()), [real]); + } } diff --git a/tasks/reviews/R6.2-r1.md b/tasks/reviews/R6.2-r1.md new file mode 100644 index 0000000..8ac0c18 --- /dev/null +++ b/tasks/reviews/R6.2-r1.md @@ -0,0 +1,7 @@ +FAIL + +1. `../Ely-GPUI-Components/src/menus/draw.rs:251` (also `src/menus/aim.rs:70`) — [P2] Leaving a row does not invalidate its delayed action. The panel clears `over` only when its depth differs; moving outside every panel, onto padding, a separator, or a disabled row leaves the old `(depth, ix)` intact. Reproduction: hover Insert for 75 ms, move outside the menu, and wait another 150 ms: Insert still opens. Likewise, cross Delete inside the aim triangle and then leave the menu: after 300 ms, Delete replaces Insert despite no longer being hovered. Reentering the row also inherits the old deadline, and reopening the context menu elsewhere retains the pending action. In the isolated GPUI build, six corresponding probes failed; see `.work/R6.2-r1/probes.log`. Invalidate pending hover state on actual row exit and menu replacement, and verify the current hit target before applying a timer. Add regression tests for these transitions. The existing `cargo test --lib --features test-support menus::` suite passed all 43 tests, so it currently misses these failures. + +2. `../Ely-GPUI-Components/src/menus/draw.rs:198` — [P2] Icon-button rows bypass hover intent. Their move handler cancels the pending task and calls `mark` immediately, truncating the open submenu even inside the safe triangle. This arrangement exists in ElyMark's context menu: Copy as is followed by formatting buttons (`apps/ely-mark/src/view/menu.rs:125`, `:135`). Reproduction: open a submenu above an enabled icon row, then move diagonally across that row toward a lower submenu item. `review_aim_crossing_icon_row_keeps_submenu` first verifies that the crossing point satisfies `aim::toward`, then fails because the submenu disappears immediately. Route button-row targeting through the same aim protection, retaining its column, and cover reaching the submenu versus resting on the crossed button. Evidence: `.work/R6.2-r1/probes.log`. + +3. `../Ely-GPUI-Components/src/menus/aim.rs:17` — [P3] New comments violate this review's explicit ten-word limit: this line and line 58 contain 13 words; lines 1 and 80 contain 12. New comments at `src/menus/menu.rs:464` and `src/menus/tests/aim.rs:15`, `:41`, `:144` also exceed the limit. Counting whitespace-separated words reproduces the failures (`.work/R6.2-r1/comments.log`). Shorten or remove these added comments while keeping each comment on one line. diff --git a/tasks/reviews/R6.3-r1.md b/tasks/reviews/R6.3-r1.md new file mode 100644 index 0000000..d0c884f --- /dev/null +++ b/tasks/reviews/R6.3-r1.md @@ -0,0 +1,3 @@ +FAIL + +- apps/ely-mark/src/places.rs:112 — Clearing recent files does not survive restart when a document tab remains open. Open `private.md`, click **Clear Recent Files**, quit with that tab open, and relaunch. The click empties the sidebar and writes `[]`, but session restoration opens the saved tab with an empty `remembered` map; `Desk::observed` calls `track_recent`, restoring the cleared path to both the sidebar and `recent.json`. The restart probe reproduced this twice (`.work/R6.3-r1/probes-final.log`); all 99 ely-files and 140 ElyMark tests passed because the committed clear test stops before restart. Prevent automatic session restoration from re-adding cleared history while preserving recent-file updates for explicit opens, and add a regression that clears through the button, closes the session, and restarts with its saved tabs.