diff --git a/Cargo.lock b/Cargo.lock index 67de381..92af95e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,19 @@ dependencies = [ "ghash", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.5" @@ -324,6 +337,12 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + [[package]] name = "as-slice" version = "0.2.1" @@ -349,9 +368,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb8421aaa9644a5faf26735f258b669b15f063313ef8f8e2bdb28912a1a6f111" dependencies = [ "enumflags2", + "futures-channel", "futures-util", "getrandom 0.4.3", "serde", + "serde_repr", + "wayland-backend", + "wayland-client", + "wayland-protocols", "zbus", ] @@ -875,6 +899,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cbc" version = "0.1.2" @@ -1232,6 +1268,26 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + [[package]] name = "convert_case" version = "0.10.0" @@ -1847,6 +1903,12 @@ dependencies = [ "tendril", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "download-cef" version = "3.0.0" @@ -2479,6 +2541,17 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + [[package]] name = "filetime" version = "0.2.29" @@ -3117,17 +3190,23 @@ dependencies = [ "accesskit", "accesskit_unix", "anyhow", + "as-raw-xcb-connection", + "ashpd", "bytemuck", "calloop", + "calloop-wayland-source", + "filedescriptor", "futures", "gpui-pre", "gpui-pre-collections", "gpui-pre-http-client", "gpui-pre-util", + "gpui-pre-wgpu", "libc", "log", "notify-rust", "oo7", + "open", "parking_lot", "raw-window-handle", "smallvec", @@ -3135,6 +3214,16 @@ dependencies = [ "strum 0.28.0", "url", "uuid", + "wayland-backend", + "wayland-client", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-plasma", + "wayland-protocols-wlr", + "x11rb", + "xkbcommon", + "zed-scap", + "zed-xim", ] [[package]] @@ -3349,6 +3438,7 @@ dependencies = [ "unicode-segmentation", "web-sys", "wgpu", + "zed-font-kit", ] [[package]] @@ -3443,6 +3533,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.5" @@ -3853,6 +3949,25 @@ dependencies = [ "leaky-cow", ] +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -5255,6 +5370,16 @@ dependencies = [ "zvariant", ] +[[package]] +name = "open" +version = "5.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa576c76302b7b808eecc68061e67336c47833ef9d22caa74dda10fa9675eebc" +dependencies = [ + "is-wsl", + "libc", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -6385,6 +6510,12 @@ dependencies = [ "syn 3.0.6", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -7312,6 +7443,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tiny-skia" version = "0.11.4" @@ -7938,6 +8078,93 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-backend" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078" +dependencies = [ + "cc", + "downcast-rs", + "log", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" +dependencies = [ + "bitflags 2.13.2", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +dependencies = [ + "bitflags 2.13.2", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" +dependencies = [ + "bitflags 2.13.2", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" +dependencies = [ + "bitflags 2.13.2", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + [[package]] name = "wayland-sys" version = "0.31.11" @@ -8933,9 +9160,12 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ + "as-raw-xcb-connection", "gethostname", + "libc", "rustix", "x11rb-protocol", + "xcursor", ] [[package]] @@ -8966,6 +9196,48 @@ dependencies = [ "x11", ] +[[package]] +name = "xcursor" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23" + +[[package]] +name = "xim-ctext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac61a7062c40f3c37b6e82eeeef835d5cc7824b632a72784a89b3963c33284c" +dependencies = [ + "encoding_rs", +] + +[[package]] +name = "xim-parser" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcee45f89572d5a65180af3a84e7ddb24f5ea690a6d3aa9de231281544dd7b7" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "xkbcommon" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" +dependencies = [ + "as-raw-xcb-connection", + "libc", + "memmap2", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + [[package]] name = "xml-rs" version = "0.8.29" @@ -9177,6 +9449,20 @@ dependencies = [ "xcb", ] +[[package]] +name = "zed-xim" +version = "0.4.0-zed" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0b46ed118eba34d9ba53d94ddc0b665e0e06a2cf874cfa2dd5dec278148642" +dependencies = [ + "ahash", + "hashbrown 0.14.5", + "log", + "x11rb", + "xim-ctext", + "xim-parser", +] + [[package]] name = "zeno" version = "0.3.3" diff --git a/Cargo.toml b/Cargo.toml index f7f34de..de96025 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ dunce = "1" ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components", rev = "bd014707fd47cd9d0651a9af8c1db6033718a6ea" } 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"] } +gpui_platform = { package = "gpui-pre-platform", version = "=0.3.8", features = ["font-kit", "wayland", "x11"] } futures = "0.3" libc = "0.2" log = "0.4" diff --git a/agents.md b/agents.md index 21edecf..8fe1de0 100644 --- a/agents.md +++ b/agents.md @@ -131,6 +131,7 @@ scripts/review.sh ID 轮次 路径 审查一条任务 scripts/apply-lo-patches.sh engines/lo-src 找出源码已到补丁序列第几个,补上其余(构建脚本调用) tests/scripts/lo-patches.sh 补丁序列从中途接着打、再打一次为空操作 tests/scripts/media-targets.sh 媒体播放接口在 Linux、Windows 目标可编译(缺目标时 SKIP) +tests/scripts/linux-backends.sh Linux 构建带 Wayland 与 X11;Hyprland 上 ElyTree 在两者上都映射出窗口、画出页面与起始页文字(截窗口量色,tesseract 读字) cargo test -p ely-show --test compose 切换半程帧经 Metal 取像素(主线程,仅 macOS) tests/scripts/*.sh *.py 脚本测试(缺工具时报 SKIP) packaging/macos/bundle.sh ely-doc debug 出 dist/ElyDoc.app(带图标、文档类型与该应用的引擎) @@ -292,3 +293,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely - 2026-10-11(用户定:ElyTree 状态栏去掉 Git 的版本与路径那一项):所用 Git 的版本与路径只记日志。同时查出 Windows 上 `std::fs::canonicalize` 给出 `\\?\C:\…` 形式,仓库根、Git 目录、工作树与文件的真实路径一律改用 `dunce::canonicalize`(能写成普通路径即普通路径,同一文件仍是同一真实路径),状态栏的仓库路径随之为普通形式;ElyTree 的单测在 Windows 上由 44 个失败降到 8 个,余下 8 个改前同样失败(如写入 Windows 不许的文件名),未处理。 - 2026-10-11:ElyMark 的 AppImage(0.1.3 的 Linux 发布查出)。`linuxdeploy` 把可执行文件的 RUNPATH 改成 `$ORIGIN/../lib`,并把它找得到的 `libcef.so` 拷进 `usr/lib`:原先 `libcef.so` 与 CEF 的资料在 `usr/bin`,结果是两份 1.45 GB 的内核、程序载入 `usr/lib` 那份、CEF 在它旁边找不到 ICU 数据而退出(从未在 AppImage 里启动过)。现在 `appimage.sh` 把从 `engines/cef` 分装来的全部条目移进 `usr/lib`(按名字对照 CEF 文件夹,清单仍只在 `stage.sh`),以 `LD_LIBRARY_PATH=AppDir/usr/lib` 运行 `linuxdeploy`,`libcef.so` 只此一份、依赖照样带上,CEF 按所载 `libcef.so` 的文件夹取资料(`ely-web-content` 的 `open`)。ElyMark 的 AppImage 由 715 MB 降到 423 MB;WSL 里启动后 CEF 载入、窗口打开(WSL 里各应用都不出首帧,未在真桌面上验证)。 - 2026-10-09(用户定):代码与发布从 GitHub 搬到自建的 Gitea(git.zacharyzhang.com;GitHub 账号被封,推送与发布都被拒)。公开仓库 `ZacharyZhang-NY/ElyOffice`(原样推上 main、缺陷清单分支与 v0.1.0、v0.1.1 标签),组件库为同站的 `ZacharyZhang-NY/Ely-GPUI-Components`(Cargo 的 git 依赖与 `fetch-references.sh` 随之改址,钉的提交不变)。v0.1.1 的六个 dmg 与两个源码包重新发在 Gitea 的 v0.1.1 发布里。官网的下载与源码链接指向 Gitea(`releases/latest` 会跳到最新发布页)。`.github/workflows` 删去(它们靠 GitHub 的 macOS 机器与 `gh`,发布改在本机以 `packaging/macos/release.sh` 构建、经 Gitea API 上传)。发布视频里写的地址已在源文件改为 Gitea,已发布的成片仍是旧地址,重渲染后才更新。上游项目(LibreOffice、MuPDF、git-lfs、tessdata 等)照旧从它们自己的 GitHub 地址取。 +- 2026-10-11(用户报:Omarchy 上六个 AppImage 都打不开):`gpui-pre-platform` 对 `gpui-pre-linux` 关了默认特性,Wayland 与 X11 只经它自己的 `wayland`、`x11` 特性打开;工作区原只开 `font-kit`,Linux 上 gpui 退成无头平台,日志照写“window open”,合成器里从无窗口。工作区的 `gpui_platform` 加开两者;`tests/scripts/linux-backends.sh` 核对特性,在 Hyprland 上核对 Wayland 与 X11 两路都映射出窗口、截图里有均匀的深色页面,tesseract 读出起始页的 “Open a repository”(不交缓冲的窗口 Hyprland 不映射;不画字形时读不出)。 diff --git a/tasks/TASKS.md b/tasks/TASKS.md index 3c5faf4..a25ffec 100644 --- a/tasks/TASKS.md +++ b/tasks/TASKS.md @@ -198,3 +198,12 @@ - [x] R2.18 官网(用户定):下载一律指向 GitHub 的 v0.1.x 发布页,不直接链 DMG — R1 截图文案死代码(连同 screen() 与截图一并删去);R2 PASS;已上线 - [x] R2.19 发布 0.1.1:版本号、打包、GitHub Release、官网指向新发布页 — v0.1.1 已发布(六个 arm64 dmg 与两个源码包,releases/latest),官网显示 0.1.1;release-macos.sh 通过 - [x] R2.20 ElyShow:放映图层一次回复超过 64 MB 帧上限(大屏上 4 张以上图层的幻灯片报 “layers pass 67107840 bytes”,放映起不来) — R1 单层仍超帧上限、暂存不随文档释放;R2 测试只核长度;R3 PASS + +## L1 Linux 发布(用户 2026-10-11 报:Omarchy 上六个 AppImage 都打不开;要 deb、rpm、Arch、AppImage;在 ubuntu:26.04 容器里本机构建,替换 v0.1.3 的 Linux 包) + +- [x] L1.1 Linux 显示后端:`gpui_platform` 开 `wayland` 与 `x11`(原样无头,“window open”而合成器里没有窗口);Omarchy(Hyprland)上 ElyTree 在 Wayland 与 X11 上画出窗口(其余五个要引擎,随 L1.5 实测);`tests/scripts/linux-backends.sh` — R1 锁文件、目标目录、未证明交帧;R2 产物路径、字形未核;R3 语言、OCR 错误被吞;R4 PASS +- [ ] L1.2 Omarchy 主题同步:查清空闲时每秒数次重套主题的根因并修;Omarchy 换主题时应用跟随 +- [ ] L1.3 Linux 构建环境:`ubuntu:26.04` 容器里构建全部引擎与六个应用(glibc 不高于 2.43) +- [ ] L1.4 Linux 包:deb、rpm、Arch(pkg.tar.zst)、AppImage 出自同一份分装,装到 `/opt/ely-office/<应用>`,带桌面项、图标与文件类型 +- [ ] L1.5 本机出六个应用的四种包;Omarchy 上装 Arch 包与 AppImage 出窗口;deb、rpm 在各自发行版的容器里装上并冒烟 +- [ ] L1.6 v0.1.3:删去旧 AppImage,上传新包;`ci.sh` 的 Linux 产出四种包;agents.md 与官网随之 diff --git a/tasks/reviews/L1.1-r1.md b/tasks/reviews/L1.1-r1.md new file mode 100644 index 0000000..94306c4 --- /dev/null +++ b/tasks/reviews/L1.1-r1.md @@ -0,0 +1,7 @@ +FAIL + +Cargo.toml:25 — The new backend features require dependencies absent from the tracked Cargo.lock. In a clean copy, `cargo build --locked -p ely-tree` and locked metadata both exit 101 because the lockfile needs updating; the smoke script hides this by adding 26 packages during `cargo tree`. Commit the matching lockfile and verify a clean locked build. Evidence: `.work/l1.1-r1-locked.log`, `.work/l1.1-r1-backends.log`. + +tests/scripts/linux-backends.sh:30 — The executable path ignores Cargo's target directory. With a separate `CARGO_TARGET_DIR`, the probe successfully built ElyTree there, then failed because `$root/target/debug/ely-tree` did not exist. If that path contains an older binary, the script tests that binary instead of the build it just produced. Resolve and launch the actual Cargo build artifact. Evidence: `.work/l1.1-r1-custom-target.log`. + +tests/scripts/linux-backends.sh:32 — `ready ElyTree` does not establish that a frame was presented: its next-frame callback runs before presentation. In an isolated, rebuilt probe, replacing `platform_window.draw(...)` with a no-op still made this script exit 0 and claim both backends drew. Wayland tracing confirmed zero surface-buffer attachments, versus one with the original binary. Require successful presentation and compositor-visible rendered content before reporting success; a disabled presentation path must fail this test. Evidence: `.work/l1.1-r1-no-presentation.log`, `.work/l1.1-r1-presentation-evidence.log`. diff --git a/tasks/reviews/L1.1-r2.md b/tasks/reviews/L1.1-r2.md new file mode 100644 index 0000000..9a94894 --- /dev/null +++ b/tasks/reviews/L1.1-r2.md @@ -0,0 +1,5 @@ +FAIL + +tests/scripts/linux-backends.sh:36 — Executable selection still assumes Cargo's native output layout. With CARGO_BUILD_TARGET=x86_64-unknown-linux-gnu and a separate CARGO_TARGET_DIR, the locked build succeeds under /x86_64-unknown-linux-gnu/debug, then the script fails launching nonexistent /debug/ely-tree. An older native binary there would be tested instead. Launch the executable reported by Cargo's build-artifact JSON. Evidence: .work/l1.1-r2-explicit-target-build.log, .work/l1.1-r2-explicit-target.log. + +tests/scripts/linux-backends.sh:55 — The text assertion counts contrasting control fills and icons, so it passes without any text. In an isolated rebuilt probe, returning immediately from Window::paint_glyph still makes the script exit 0 on both Wayland and X11. The inspected window has no text, yet its ink count is 10578 against the 500 threshold. Check known rendered text in a region excluding control fills and icons, and verify that disabling glyph painting fails the assertion. Evidence: .work/l1.1-r2-no-glyphs.log, .work/l1.1-r2-glyph-evidence.log, .work/l1.1-r2-mutation.log. diff --git a/tasks/reviews/L1.1-r3.md b/tasks/reviews/L1.1-r3.md new file mode 100644 index 0000000..1250dfd --- /dev/null +++ b/tasks/reviews/L1.1-r3.md @@ -0,0 +1,5 @@ +FAIL + +tests/scripts/linux-backends.sh:60 — The OCR assertion always expects English while the application inherits its locale. Running with `ELY_LOCALE=zh-CN` maps and renders the window successfully, then fails because the supported Chinese interface contains no “Open a repository”. Pin `ELY_LOCALE=en` in the application's launch environment when asserting English text. Evidence: `.work/l1.1-r3-chinese.log`; forcing English passes both backends in `.work/l1.1-r3-fixed-locale.log`. + +tests/scripts/linux-backends.sh:59 — OCR failure diagnostics are discarded. With Tesseract installed but `TESSDATA_PREFIX` pointing to an existing empty directory, the script exits 1 with no output; the missing `eng.traineddata` and initialization errors disappear into `/dev/null`. Preserve Tesseract's stderr or include it in an explicit failure message. Evidence: `.work/l1.1-r3-missing-tessdata.log`, `.work/l1.1-r3-ocr-error-evidence.log`, `.work/l1.1-r3-verification.log`. diff --git a/tasks/reviews/L1.1-r4.md b/tasks/reviews/L1.1-r4.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/L1.1-r4.md @@ -0,0 +1 @@ +PASS diff --git a/tests/scripts/linux-backends.sh b/tests/scripts/linux-backends.sh new file mode 100755 index 0000000..77c55ca --- /dev/null +++ b/tests/scripts/linux-backends.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Linux builds carry Wayland and X11; ElyTree shows on each. +set -euo pipefail + +root=$(cd "$(dirname "$0")/../.." && pwd) +fail() { + echo "FAIL: $*" >&2 + exit 1 +} + +features=$(cargo tree --locked --manifest-path "$root/Cargo.toml" -p ely-tree -e features \ + -i gpui-pre-linux --target x86_64-unknown-linux-gnu) +for backend in wayland x11; do + grep -q "gpui-pre-linux feature \"$backend\"" <<<"$features" || fail "gpui is built without $backend" +done +[ "$(uname)" = Linux ] || { + echo "SKIP: windows show on Linux only" + exit 0 +} +for tool in hyprctl grim magick tesseract jq git; do + command -v "$tool" >/dev/null || { + echo "SKIP: no $tool; the window check reads Hyprland" + exit 0 + } +done +# The binary Cargo reports, wherever it builds. +app=$(cargo build -q --locked --message-format=json --manifest-path "$root/Cargo.toml" -p ely-tree --bin ely-tree | + jq -r 'select(.reason == "compiler-artifact" and .target.name == "ely-tree") | .executable // empty') +[ -x "$app" ] || fail "Cargo reported no ElyTree binary" +work=$(mktemp -d) +pid= +trap '[ -z "$pid" ] || kill "$pid" 2>/dev/null; rm -rf "$work"' EXIT + +show() { # backend, env args + local backend=$1 geometry= shot=$work/$1.png + shift + env "$@" ELY_GIT="$(command -v git)" ELY_SMOKE=hold ELY_APPEARANCE=dark ELY_OMARCHY_SYNC=0 ELY_LOCALE=en-US \ + HOME="$work" XDG_DATA_HOME="$work/data" "$app" 2>"$work/$backend.err" & + pid=$! + for _ in $(seq 120); do + geometry=$(hyprctl clients -j | jq -r --argjson pid "$pid" \ + '.[] | select(.pid == $pid and .mapped) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"') + [ -n "$geometry" ] && break + kill -0 "$pid" 2>/dev/null || fail "ElyTree quit on $backend: $(tail -n 5 "$work/$backend.err")" + sleep 0.5 + done + [ -n "$geometry" ] || fail "Hyprland never mapped ElyTree on $backend" + sleep 2 + grim -g "$geometry" "$shot" + kill "$pid" + wait "$pid" 2>/dev/null || true + pid= + # An even #252525 page and the start page's words. + local page words + page=$(magick "$shot" -gravity center -crop 60%x30%+0+25% +repage -format \ + '%[fx:max(abs(mean.r-0x25/255),max(abs(mean.g-0x25/255),abs(mean.b-0x25/255)))*255] %[fx:standard_deviation*255]' info:) + awk -v off="${page% *}" -v spread="${page#* }" 'BEGIN { exit !(off < 16 && spread < 6) }' || + fail "ElyTree on $backend shows no even page (off by, spread: $page)" + words=$(tesseract "$shot" - 2>"$work/ocr.err") || fail "tesseract failed: $(cat "$work/ocr.err")" + grep -q 'Open a repository' <<<"$words" || fail "ElyTree on $backend shows no 'Open a repository': $words" + echo "linux: ElyTree shows on $backend" +} +ran= +if [ -n "${WAYLAND_DISPLAY:-}" ]; then + show wayland + ran=1 +fi +if [ -n "${DISPLAY:-}" ]; then + show x11 -u WAYLAND_DISPLAY + ran=1 +fi +[ -n "$ran" ] || echo "SKIP: no WAYLAND_DISPLAY or DISPLAY"