ElyMark: outside changes tested through the window; a reload keeps its place (C14.11)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-12 07:51:44 -04:00
1 parent 7529d39d5a
commit ea5f47d74e
7 files changed
+178 -28

No files matched your search

Generated
+1 -1
View File
@@ -1922,7 +1922,7 @@ dependencies = [
[[package]]
name = "ely-gpui-component"
version = "0.1.1"
source = "git+https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components?rev=d126a7e7f7977dddae598486dd99aba79ce1f5f0#d126a7e7f7977dddae598486dd99aba79ce1f5f0"
source = "git+https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components?rev=e89fb32f43b51c0cd03f6be383dc58796bac19e1#e89fb32f43b51c0cd03f6be383dc58796bac19e1"
dependencies = [
"alacritty_terminal",
"anyhow",
+1 -1
View File
@@ -19,7 +19,7 @@ jiff = "0.2"
anyhow = "1"
directories = "6"
dunce = "1"
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components", rev = "d126a7e7f7977dddae598486dd99aba79ce1f5f0" }
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components", rev = "e89fb32f43b51c0cd03f6be383dc58796bac19e1" }
env_logger = "0.11"
gpui = { package = "gpui-pre", version = "=0.3.8", default-features = false, features = ["stacker"] }
gpui_platform = { package = "gpui-pre-platform", version = "=0.3.8", features = ["font-kit", "wayland", "x11"] }
+1 -1
View File
@@ -40,7 +40,7 @@ site/ 官网(Vite 8、pnpm、TypeScript,无框架;等轴 SVG 积木
## 组件映射
依赖 `ely-gpui-component`(pin d126a7e,gpui 为 crates.io 的 `gpui-pre` =0.3.8)。名字取自 `reference/Ely-GPUI-Components/src`。gpui 用法规则见该仓库 `AGENTS.md`。`tests/scripts/agents_md.py` 核对下表每个名字都是组件库公开项。
依赖 `ely-gpui-component`(pin e89fb32,gpui 为 crates.io 的 `gpui-pre` =0.3.8)。名字取自 `reference/Ely-GPUI-Components/src`。gpui 用法规则见该仓库 `AGENTS.md`。`tests/scripts/agents_md.py` 核对下表每个名字都是组件库公开项。
| 需要 | 用 |
| --- | --- |
+33
View File
@@ -190,3 +190,36 @@ enum Choice {
Mine,
Merged,
}
#[cfg(test)]
mod tests {
use gpui::TestAppContext;
use super::Choice;
use crate::outside::tests::{look, opened, shown};
#[gpui::test]
fn a_merge_lands_as_one_undo_step(cx: &mut TestAppContext) {
let (desk, cx, id, path, _dirs) = opened("a\n\nb\n", cx);
let view = desk.read_with(cx, |desk, _| desk.active_view().expect("a tab"));
view.update(cx, |view, cx| view.adopt("a\n\nb\n\nmine\n".into(), cx));
cx.run_until_parked();
std::fs::write(&path, "theirs\n\na\n\nb\n").expect("an outside write");
look(&desk, id, cx);
desk.update(cx, |desk, cx| desk.compare(id, cx));
desk.update_in(cx, |desk, window, cx| {
desk.settle(Choice::Merged, window, cx)
});
cx.run_until_parked();
assert_eq!(shown(&desk, cx), "theirs\n\na\n\nb\n\nmine\n");
let focus = view.read_with(cx, |view, _| view.focus.clone());
cx.update(|window, cx| window.focus(&focus, cx));
cx.run_until_parked();
cx.simulate_keystrokes("secondary-z");
assert_eq!(
shown(&desk, cx),
"a\n\nb\n\nmine\n",
"one undo takes the merge back"
);
}
}
+1 -24
View File
@@ -403,27 +403,4 @@ fn watch(dirs: &[PathBuf], cx: &mut Context<Desk>) -> notify::Result<Recommended
}
#[cfg(test)]
mod tests {
use std::time::{Duration, Instant};
use ely_files::Action;
use super::Extra;
#[test]
fn a_restarted_autosave_saves_the_next_edit() {
let mut extra = Extra::default();
extra.policy.set_has_path();
extra.policy.edit(Instant::now());
// A write was in flight when the disk changed.
extra.writing = Some(1);
extra.restart_autosave();
// As autosave settles a heard write, then edits.
if let Some(revision) = extra.writing.take() {
extra.policy.save_finished(revision, true);
}
let now = Instant::now();
extra.policy.edit(now);
assert!(matches!(extra.policy.tick(now + Duration::from_secs(5)), Action::SaveDue(_)));
}
}
pub(crate) mod tests;
+140
View File
@@ -0,0 +1,140 @@
use std::{
path::PathBuf,
time::{Duration, Instant},
};
use ely_files::Action;
use ely_office::prelude::*;
use gpui::{Entity, TestAppContext, VisualTestContext};
use super::{Extra, GAP, Outside};
use crate::desk::{
Desk,
tests::{open, start},
};
#[test]
fn a_restarted_autosave_saves_the_next_edit() {
let mut extra = Extra::default();
extra.policy.set_has_path();
extra.policy.edit(Instant::now());
// A write was in flight when the disk changed.
extra.writing = Some(1);
extra.restart_autosave();
// As autosave settles a heard write, then edits.
if let Some(revision) = extra.writing.take() {
extra.policy.save_finished(revision, true);
}
let now = Instant::now();
extra.policy.edit(now);
assert!(matches!(
extra.policy.tick(now + Duration::from_secs(5)),
Action::SaveDue(_)
));
}
/// A saved file open: its desk, tab and path.
pub(crate) fn opened(
text: &str,
cx: &mut TestAppContext,
) -> (
Entity<Desk>,
&'static mut VisualTestContext,
u64,
PathBuf,
[tempfile::TempDir; 2],
) {
let (data, files) = (
tempfile::tempdir().expect("data"),
tempfile::tempdir().expect("files"),
);
let path = files.path().join("a.md");
std::fs::write(&path, text).expect("a file");
let (desk, cx) = start(cx, data.path());
open(&desk, &path, cx);
let id = desk.read_with(cx, |desk, _| desk.core.active.expect("a tab"));
(desk, cx, id, path, [data, files])
}
/// The desk looks at the file, as the watcher would.
pub(crate) fn look(desk: &Entity<Desk>, id: u64, cx: &mut VisualTestContext) {
desk.update(cx, |desk, cx| desk.look(id, cx));
cx.run_until_parked();
cx.executor().advance_clock(GAP * 2);
cx.run_until_parked();
}
pub(crate) fn shown(desk: &Entity<Desk>, cx: &mut VisualTestContext) -> String {
desk.read_with(cx, |desk, cx| {
let view = desk.active_view().expect("a tab");
view.read(cx).document().read(cx).text(cx)
})
}
#[gpui::test]
fn a_clean_tab_takes_the_disk_and_keeps_its_place(cx: &mut TestAppContext) {
let (desk, cx, id, path, _dirs) = opened("one\n\ntwo\n\nthree\n", cx);
let view = desk.read_with(cx, |desk, _| desk.active_view().expect("a tab"));
let document = view.read_with(cx, |view, _| view.document().clone());
document.update(cx, |document, cx| document.set_caret(4, 2, cx));
std::fs::write(&path, "uno\n\ndos\n\ntres, longer\n").expect("an outside write");
look(&desk, id, cx);
assert_eq!(shown(&desk, cx), "uno\n\ndos\n\ntres, longer\n");
assert!(!view.read_with(cx, |view, _| view.modified()));
assert_eq!(
document.read_with(cx, |document, cx| document.caret(cx)),
(4, 2)
);
let focus = view.read_with(cx, |view, _| view.focus.clone());
cx.update(|window, cx| window.focus(&focus, cx));
cx.run_until_parked();
cx.simulate_keystrokes("secondary-z");
assert_eq!(
shown(&desk, cx),
"uno\n\ndos\n\ntres, longer\n",
"undo stops at the disk"
);
}
#[gpui::test]
fn a_deleted_file_keeps_its_text_and_says_so(cx: &mut TestAppContext) {
let (desk, cx, id, path, _dirs) = opened("kept\n", cx);
std::fs::remove_file(&path).expect("deleted");
look(&desk, id, cx);
let deleted = desk.read_with(cx, |desk, _| {
matches!(desk.tab(id).expect("open").extra.outside, Outside::Deleted)
});
assert!(deleted);
assert_eq!(shown(&desk, cx), "kept\n");
}
#[gpui::test]
fn a_renamed_file_is_followed(cx: &mut TestAppContext) {
let (desk, cx, id, path, _dirs) = opened("moved\n", cx);
let to = path.with_file_name("b.md");
std::fs::rename(&path, &to).expect("renamed");
look(&desk, id, cx);
let now = desk.read_with(cx, |desk, _| {
desk.tab(id)
.and_then(|tab| tab.session.path().map(PathBuf::from))
});
assert_eq!(
now.map(|path| path.file_name().map(ToOwned::to_owned)),
Some(Some("b.md".into()))
);
}
#[gpui::test]
fn a_path_that_cannot_be_read_says_why(cx: &mut TestAppContext) {
let (desk, cx, id, path, _dirs) = opened("text\n", cx);
std::fs::remove_file(&path).expect("removed");
std::fs::create_dir(&path).expect("a folder in its place");
look(&desk, id, cx);
let unread = desk.read_with(cx, |desk, _| {
matches!(
desk.tab(id).expect("open").extra.outside,
Outside::Unread(_)
)
});
assert!(unread);
}
+1 -1
View File
@@ -36,7 +36,7 @@ fetch() { # name url rev [sparse paths...]
echo "fetch $name $rev"
}
fetch Ely-GPUI-Components https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components.git d126a7e7f7977dddae598486dd99aba79ce1f5f0
fetch Ely-GPUI-Components https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components.git e89fb32f43b51c0cd03f6be383dc58796bac19e1
fetch zed https://github.com/zed-industries/zed.git 1a28cff4b409169bac058bca40dfbfeb7621d19b
fetch libreoffice-core https://github.com/LibreOffice/core.git 8221e31b3ac356a1623c672912a3d2b492f7e3d1 \
include/LibreOfficeKit libreofficekit desktop/source/lib desktop/inc \