C14.14 r3: formulas framed after outlining, a file per print job, no source selection in rendered modes (library 8234fcd)

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 11:18:07 -04:00
1 parent 8fc5ee2ab2
commit d9dadb3d0e
8 files changed
+27 -7

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=3bbbd05f381178b92fe7395eab9436647f69f9b4#3bbbd05f381178b92fe7395eab9436647f69f9b4"
source = "git+https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components?rev=8234fcdeb201c524deaf4bbf557e093495f5a5e3#8234fcdeb201c524deaf4bbf557e093495f5a5e3"
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 = "3bbbd05f381178b92fe7395eab9436647f69f9b4" }
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components", rev = "8234fcdeb201c524deaf4bbf557e093495f5a5e3" }
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"] }
+2 -2
View File
@@ -40,7 +40,7 @@ site/ 官网(Vite 8、pnpm、TypeScript,无框架;等轴 SVG 积木
## 组件映射
依赖 `ely-gpui-component`(pin 3bbbd05,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 8234fcd,gpui 为 crates.io 的 `gpui-pre` =0.3.8)。名字取自 `reference/Ely-GPUI-Components/src`。gpui 用法规则见该仓库 `AGENTS.md`。`tests/scripts/agents_md.py` 核对下表每个名字都是组件库公开项。
| 需要 | 用 |
| --- | --- |
@@ -283,4 +283,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
- 2026-10-11:Linux 包的实测(L1.6)。本机(Omarchy,Hyprland 0.56)装上六个 Arch 包与六个 AppImage,`linux-installed.sh` 两种都过;deb、rpm、Arch 包在 Ubuntu 26.04、Fedora 44、Arch 容器里装上、全部 ELF 找得到库;deb 与 rpm 的六个应用在各自容器的 Xvfb 下画出窗口(`linux-distros.sh`)。截图按窗口(`grim -T` 加 Hyprland 的 `stableId`):按区域截时用户切换工作区或别的窗口盖住即截错。ElyMark 的文件监视略去读取后不会自激:重读前先比指纹(长度与修改时间),不打开文件。
- 2026-10-11(用户定:替换 v0.1.3 的 Linux 包):v0.1.3 发布里原有的六个 AppImage(无头,打不开窗口)已删去,换成本机容器里建出的六个应用各四种包(共 24 个),出自 L1.7 的提交(晚于该标签);上传后逐个核对大小,ElyTree 的 AppImage 下载回来散列相同。`package.sh` 把每个 RUNPATH 按所在 ELF 解析(`$ORIGIN` 或 `${ORIGIN}` 开头,规范化后须在 AppDir 内),否则拒绝(如未修正的 cairo):CI 用的是别处建好的引擎,旧构建会在这里报错而不是带进包里。替换的 Linux 包对应的源码随之上传到同一发布(`source.sh`,文件名带构建提交号),发布说明写明 Linux 包出自哪个提交。
- 2026-10-11:`ci.sh` 用 `ELY_SHARE` 时,CI 克隆里的 `engines`、`reference` 须是指向共享克隆的链接(Windows 为目录联接,不查);是本克隆自建的目录或指向别处即报错,不混用。`.gitignore` 的 `/engines`、`/reference` 不带斜杠,链接也被忽略(`source.sh` 要求工作区干净)。
- 2026-10-11(用户定:ElyMark 不用 CEF,不用 Electron):ElyMark 改为原生。界面用组件库的 Markdown 组件(`documents::MarkdownEditor` 一族,缺的在组件库补并推到 Gitea),解析用 markdown-rs(`markdown` 1.0.0),公式用 RaTeX,Mermaid 用 mermaid-rs-renderer,PDF 用 MuPDF Story;CEF 随之删去,ElyMail 的正文也不用 CEF 与 Electron。进度在 `tasks/TASKS.md` 的 C14。组件库 fcad0ff 与 508cc55:`MarkdownRenderer`、`MarkdownEditor`、Markdown 着色、块范围与链接查找改读 markdown-rs 的语法树(GitHub 风格加公式),引用式链接与图片按定义解析,图片把所在段落分开,单行 `$$…$$` 为块公式,软换行(LF、CRLF、CR)读作空格,嵌套在引用与列表里的定义同样解析,强调与链接里的图片仍是图片(链接里的图片可按);`BlockEditor` 的导入导出不属 ElyMark,仍用 pulldown-cmark。markdown-rs 读嵌套图片时只留外层的说明。组件库 d5ecc5a:块公式经 `typography::Latex` 由 RaTeX 排出(字形为轮廓,按窗口缩放画),```` ```mermaid ```` 块经 `documents::Diagram` 由 mermaid-rs-renderer 画出(Mermaid 自己的深浅主题,底色与字色取 Ely 色板),都作为 gpui 资源在后台排版,RaTeX 或 Mermaid 对已解析的输入 panic 时显示为错误;`MarkdownRenderer::base` 给出文档所在文件夹,相对与 file 地址的图片从中读取并按自身大小、不超过栏宽显示,`data:` 地址解码,网络图片不载入(写明)。组件库 ab9a14c:每个公式、图与图片元素经 `primitives::held` 持有其资源,按资源计数持有者(8b9820b;画出的图存在共享的记录里,9036c92 起由最后离开的持有者释放,哪怕它自己还没收到图),最后一个持有者换了内容或离开窗口才从 gpui 资源缓存移除、在本帧之后从图集释放,共用同一内容的元素(含 gpui 缓存的视图)不受影响;公式按字形实际范围取画框,字形不被裁;公式失败显示原因、RaTeX 给的位置与原文,日志不含公式;`file:` 地址去掉查询与片段,`localhost` 为本机,Windows 上别的主机为共享路径,他处拒绝;Mermaid 的节点与饼图文字取 Ely 的前景色。组件库 2b6f551:`documents::MarkdownDocument` 是文件级的 Markdown 文档:全文与撤销在一个 `CodeEditor` 里(`CodeEditor::highlighter` 以 `markdown_highlights` 着色,无行号);可视以 gpui `list` 逐块画出文件的顶层块(链接定义、HTML、front matter 照原文显示,每个字节都在块里或块间),按下的块开成源码(`TextInput`),其键入即刻算作文档的文字,写回为一步撤销,上下键越过块边进入相邻块,Esc 写回;Cmd(他处 Ctrl)按下交给链接;预览只读;源码为编辑器本身;128 KiB 以内当场解析,更长的在后台解析,解析中按下块不打开(日志);新解析保留两端相同的块,滚动不跳。`CodeEditor` 的撤销历史最多留 64 MiB 文字,超出先丢最旧的步;`CodeEditor::reset` 换文字且撤销重新开始;`MarkdownMode` 加 `Preview`。组件库 fc181b4:一个插入点通用于各模式(编辑器的选区,写回的块移动它);`set_caret` 与 `set_top_line` 分别设插入点与视图,换模式保持顶行;按下的块在前一块写回后仍是所按的块(按偏移换算,结构变了即不开并记日志);块是 Tab 停靠点,Enter 或空格打开;预览不收按下、撤销与重做;撤销与重做每次记录、输入法组字、撤销、重做后都限在 64 MiB 内(先丢最旧的撤销,再丢最远的重做)。组件库 433c38f:只有对当下文字的解析才能打开块(解析的文字与编辑器相同),否则拒绝;要求的顶行在其文字解析后才落定:先到所在块,下一帧按块高的比例到块内位置,再有新的要求即接着放下一个;源码与列表之间切换保持顶行,可视与预览共用一个列表,切换不动滚动。组件库 abac8b4:顶行的要求带编号,迟到的帧回调只完成自己的那个;文字一换即按新文字重新放,放时按当下文字的行数夹住;`reveal` 是同样的要求(插入点设在该行,该行放到顶上),新文字解析后才落定。组件库 f59c9f7:文字超过读取上限(2 MiB)即丢掉旧的读取,大纲与块为空。ElyMark(C14.4):视图即一个 `MarkdownDocument`,文本即文件原文(BOM 与 CRLF 照 `text.rs` 存回),新建、打开、保存、另存、重命名经外壳照旧;视图在建成后的下一轮更新向外壳报一次载入(文档在 `new` 里当场解析,外壳此时还未订阅);文字超过 2 MiB 即只用源码并转去源码(随当前文字,不只看打开时);网页实现的查找替换、表格、附件、书写视图的应用、导出与打印Line truncated
- 2026-10-11(用户定:ElyMark 不用 CEF,不用 Electron):ElyMark 改为原生。界面用组件库的 Markdown 组件(`documents::MarkdownEditor` 一族,缺的在组件库补并推到 Gitea),解析用 markdown-rs(`markdown` 1.0.0),公式用 RaTeX,Mermaid 用 mermaid-rs-renderer,PDF 用 MuPDF Story;CEF 随之删去,ElyMail 的正文也不用 CEF 与 Electron。进度在 `tasks/TASKS.md` 的 C14。组件库 fcad0ff 与 508cc55:`MarkdownRenderer`、`MarkdownEditor`、Markdown 着色、块范围与链接查找改读 markdown-rs 的语法树(GitHub 风格加公式),引用式链接与图片按定义解析,图片把所在段落分开,单行 `$$…$$` 为块公式,软换行(LF、CRLF、CR)读作空格,嵌套在引用与列表里的定义同样解析,强调与链接里的图片仍是图片(链接里的图片可按);`BlockEditor` 的导入导出不属 ElyMark,仍用 pulldown-cmark。markdown-rs 读嵌套图片时只留外层的说明。组件库 d5ecc5a:块公式经 `typography::Latex` 由 RaTeX 排出(字形为轮廓,按窗口缩放画),```` ```mermaid ```` 块经 `documents::Diagram` 由 mermaid-rs-renderer 画出(Mermaid 自己的深浅主题,底色与字色取 Ely 色板),都作为 gpui 资源在后台排版,RaTeX 或 Mermaid 对已解析的输入 panic 时显示为错误;`MarkdownRenderer::base` 给出文档所在文件夹,相对与 file 地址的图片从中读取并按自身大小、不超过栏宽显示,`data:` 地址解码,网络图片不载入(写明)。组件库 ab9a14c:每个公式、图与图片元素经 `primitives::held` 持有其资源,按资源计数持有者(8b9820b;画出的图存在共享的记录里,9036c92 起由最后离开的持有者释放,哪怕它自己还没收到图),最后一个持有者换了内容或离开窗口才从 gpui 资源缓存移除、在本帧之后从图集释放,共用同一内容的元素(含 gpui 缓存的视图)不受影响;公式按字形实际范围取画框,字形不被裁;公式失败显示原因、RaTeX 给的位置与原文,日志不含公式;`file:` 地址去掉查询与片段,`localhost` 为本机,Windows 上别的主机为共享路径,他处拒绝;Mermaid 的节点与饼图文字取 Ely 的前景色。组件库 2b6f551:`documents::MarkdownDocument` 是文件级的 Markdown 文档:全文与撤销在一个 `CodeEditor` 里(`CodeEditor::highlighter` 以 `markdown_highlights` 着色,无行号);可视以 gpui `list` 逐块画出文件的顶层块(链接定义、HTML、front matter 照原文显示,每个字节都在块里或块间),按下的块开成源码(`TextInput`),其键入即刻算作文档的文字,写回为一步撤销,上下键越过块边进入相邻块,Esc 写回;Cmd(他处 Ctrl)按下交给链接;预览只读;源码为编辑器本身;128 KiB 以内当场解析,更长的在后台解析,解析中按下块不打开(日志);新解析保留两端相同的块,滚动不跳。`CodeEditor` 的撤销历史最多留 64 MiB 文字,超出先丢最旧的步;`CodeEditor::reset` 换文字且撤销重新开始;`MarkdownMode` 加 `Preview`。组件库 fc181b4:一个插入点通用于各模式(编辑器的选区,写回的块移动它);`set_caret` 与 `set_top_line` 分别设插入点与视图,换模式保持顶行;按下的块在前一块写回后仍是所按的块(按偏移换算,结构变了即不开并记日志);块是 Tab 停靠点,Enter 或空格打开;预览不收按下、撤销与重做;撤销与重做每次记录、输入法组字、撤销、重做后都限在 64 MiB 内(先丢最旧的撤销,再丢最远的重做)。组件库 433c38f:只有对当下文字的解析才能打开块(解析的文字与编辑器相同),否则拒绝;要求的顶行在其文字解析后才落定:先到所在块,下一帧按块高的比例到块内位置,再有新的要求即接着放下一个;源码与列表之间切换保持顶行,可视与预览共用一个列表,切换不动滚动。组件库 abac8b4:顶行的要求带编号,迟到的帧回调只完成自己的那个;文字一换即按新文字重新放,放时按当下文字的行数夹住;`reveal` 是同样的要求(插入点设在该行,该行放到顶上),新文字解析后才落定。组件库 f59c9f7:文字超过读取上限(2 MiB)即丢掉旧的读取,大纲与块为空。ElyMark(C14.4):视图即一个 `MarkdownDocument`,文本即文件原文(BOM 与 CRLF 照 `text.rs` 存回),新建、打开、保存、另存、重命名经外壳照旧;视图在建成后的下一轮更新向外壳报一次载入(文档在 `new` 里当场解析,外壳此时还未订阅);文字超过 2 MiB 即只用源码并转去源码(随当前文字,不只看打开时);网页实现的查找替换、表格、附件、书写视图的应用、导出与打印Line truncated
+8 -1
View File
@@ -249,7 +249,7 @@ impl Desk {
.and_then(|path| path.parent())
.map(PathBuf::from);
let (revision, work) = (source.session.revision(), source.work.clone());
let pdf = work.join("print.pdf");
let pdf = print_copy(&work);
log::info!("mark: prints tab {tab}");
cx.spawn(async move |desk, cx| {
let written = cx
@@ -310,5 +310,12 @@ impl Desk {
}
}
/// A file of its own for each print job.
fn print_copy(work: &std::path::Path) -> PathBuf {
static JOBS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let job = JOBS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
work.join(format!("print-{job}.pdf"))
}
#[cfg(test)]
mod tests;
+6
View File
@@ -86,3 +86,9 @@ fn rich_copy_takes_the_selection_as_html(cx: &mut TestAppContext) {
"{html}"
);
}
#[test]
fn each_print_job_writes_its_own_file() {
let work = std::path::Path::new("work");
assert_ne!(super::print_copy(work), super::print_copy(work));
}
+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 3bbbd05f381178b92fe7395eab9436647f69f9b4
fetch Ely-GPUI-Components https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components.git 8234fcdeb201c524deaf4bbf557e093495f5a5e3
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 \
+1 -1
View File
@@ -111,7 +111,7 @@
- [x] C14.11 外部修改(MARK-08,§14.4,QA-22):干净即重载并保持位置,有改动即比较,合并结果为一步撤销;改名、删除、读错照旧 — R1 FAIL 两项已修:保留修改时间的原子替换不被察觉(指纹加上文件身份);迟到的旧读取覆盖新版本(读盘编号,落定前核对磁盘)。R2 ok
- [~] C14.12 书写视图(MARK-09):专注模式、打字机滚动、正文宽度、字体、字号,存 `look.json`,不改 Markdown — R1 FAIL 已修:打开的块不随字号;首末块与首末行不能居中;缩放后不重新居中。R2 FAIL 已修:源码的上下内边距缩小了列表可见区,居中行以下不画,输入法与点按坐标错开半屏(改为列表首尾的空行);切换模式的定位覆盖居中。R3 FAIL 已修(三轮用尽,未再审):编辑器的居中记录只看行号,模式往返、再次跳到同一行、小幅缩放后不再居中(记录加上视图与行高,定位落定后清掉编辑器的记录)
- [x] C14.13 搜索(MARK-10):本文件与文件夹,结果跳到该行该处 — R1 FAIL 已修:查询整串转小写,原文逐字转小写,词尾 σ 对不上(两边逐字折叠,ς 同 σ)。R2 ok
- [ ] C14.14 输出(MARK-11):自包含 HTML、带资源文件夹的 HTML、纯文本(markdown-rs)、PDF(MuPDF Story,经 `ely-pdf-worker`)、打印、富文本复制;缺图、错公式、画不出的图随导出提示
- [~] C14.14 输出(MARK-11):自包含 HTML、带资源文件夹的 HTML、纯文本(markdown-rs)、PDF(MuPDF Story,经 `ely-pdf-worker`)、打印、富文本复制;缺图、错公式、画不出的图随导出提示 — R1 FAIL 十项已修:改由语法树逐节点写 HTML(各处行号、原地址、`data:` 图片、缺图留原地址或写替代文字);资源文件夹名编码;图片以 `create_new` 占名;每次 PDF 各自的暂存;图的缺字报错;纯文本的引用图片;富文本复制提示所缺。R2 FAIL 三项已修:链接按浏览器读法判协议;只删本次建成的文件夹;公式无轮廓的字以系统字体变路径或报错。R3 FAIL 三项已修(三轮用尽,未再审):公式先变路径再定边框;每次打印各自的文件;渲染模式无源码选区
- [ ] C14.15 会话恢复(MARK-12):标签、未保存内容、模式、插入点、滚动、视图设置
- [ ] C14.16 Git 配合与验收(MARK-13):状态栏 Git 状态与打开 ElyTree 照旧;三端构建,ElyMark 冒烟;逐条核对 MARK-01 至 14、QA-21、QA-22、PERF-07
+7
View File
@@ -0,0 +1,7 @@
FAIL
- reference/Ely-GPUI-Components/src/typography/math.rs:129 (3bbbd05) — Remaining SVG text is outlined after `svg(&formula)` has already computed the viewport; `flatten` keeps those old bounds even when the resolved font's ink extends outside them. On native Windows, exporting `$\text{𓀀}$` succeeds without a formula warning, but its 8 × 6.896 SVG contains ink spanning x=0.391..11.492 and y=-5.416..9.115. Rasterization retains only 1,377 ink pixels, versus 4,060 when framed around the complete outlines. `$\text{한글}$` also loses ink. Resolve and outline the text before computing the final frame, and verify that fallback glyphs fit completely. Evidence: `.work/C14.14-r3/windows-probe.log`.
- apps/ely-mark/src/export/mod.rs:252 — Every print job for a tab still writes the same `work/print.pdf`, although PDF conversion and panel dispatch run asynchronously. Press Print twice while conversion is pending, changing the text between requests: the second conversion can replace the first job's PDF before its panel reads it, and the first panel's cleanup can delete the second job's pending file. Windows and WSL worker/file-lifetime probes reproduce the first reader getting `Second print` and the second reader failing after the first cleanup. The separate conversion scratch directories do not protect this final file. Give each print job a distinct PDF retained through its own panel and cleanup. Evidence: `.work/C14.14-r3/windows-probe.log`, `linux-probe.log`; macOS panels were not run.
- reference/Ely-GPUI-Components/src/documents/document/place.rs:32 (3bbbd05) — `selected` returns the source editor's selection whenever no visual block is open, including in preview and visual modes where that selection is invisible. Select `First` in source, switch to preview or visual without opening a block, then choose Copy as Rich Text: `copy_rich` copies only `First` instead of the whole document required when there is no current selection. Both Windows and WSL GPUI probes retain `First` across these switches. Read the source selection only in source modes, and return no selection in rendered modes without an open editor; cover mode transitions in the copy tests. Evidence: `.work/C14.14-r3/windows-probe.log`, `linux-probe.log`.