diff --git a/agents.md b/agents.md index 52f4575..cb0a8e8 100644 --- a/agents.md +++ b/agents.md @@ -323,3 +323,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely - 2026-10-19(用户定):ElyMail 的后端改为 Rust crate,取代 MailCore 2(其 Windows 构建是 VS 2013 工程加 2015 年前后的预编译依赖,POP 无 OAuth2):mail-send、mail-parser、mail-builder,在应用进程的后台任务里运行,不另起 worker;MailCore 2 与 libetpan 的取码、构建与探测随之删去。正文以 html5ever 解析、净化后按块的子集由 GPUI 绘制,不当作完整页面;写信用 Markdown 文档组件,发出纯文本与 HTML。Gmail 与 Microsoft 走 OAuth(授权码加 PKCE,本机回环),客户端 ID 在构建时注入:`ELY_GOOGLE_CLIENT_ID`、`ELY_GOOGLE_CLIENT_SECRET`、`ELY_MICROSOFT_CLIENT_ID`,本机写在项目根的 `oauth.env`(不入库),CI 为仓库机密;缺 ID 的构建里该登录写明不可用,不退回别的方式。iCloud 不给第三方 OAuth,走应用专用密码向导(`imap.mail.me.com:993`、`smtp.mail.me.com:587`,无 POP3)。注册由用户做(Google Desktop 客户端,Entra 公共客户端,委托权限 IMAP、POP、SMTP 与 offline_access)。POP3(C12.1 审查后)由引擎自写,不用 async-pop:它留着点填充、丢末尾 CRLF、吞掉登录后的连接错误、不答 XOAUTH2 的错误挑战、在 trace 日志里写出密码。IMAP(第 2 轮审查后)同样自写,以 imap-proto 解析回复,不用 async-imap:它的 LIST、FETCH 等流式命令不看结尾的 NO 与 BAD(拒绝成了空结果),登录与命令中途的 `* BYE` 被丢掉(只剩断线),trace 日志写出密码与邮件。SMTP 的事务(MAIL、RCPT、DATA)也由引擎自走:mail-send 不给首行的点加点;正文有 8 位字节即带 `BODY=8BITMIME`,服务器不支持即拒绝。读信按 MIME 树与所在容器(C12.2),嵌套(多部分与内嵌邮件都算)深于 64 层即报错,超深的解析结果以迭代拆开再丢(直接丢弃会递归、栈溢出);mail-parser 开 `full_encoding`;SMTPUTF8 按每一层的头块判定。本地存储(C12.3):rusqlite 自带的 SQLite,`mail.db` 加内容目录(原文按 SHA-256),FTS5(trigram)可由索引与原文重建;`user_version` 记结构版本,升级前备份,失败即只读;原文文件在删去或替换邮件的事务提交前删去,删不掉即回滚。只有 HTML 的邮件经 html5ever 的树构建器取文字入索引,元素深过 512 层即停读(树构建器的开放元素栈扫描随深度平方增长)。凭据(C12.4):密码与刷新令牌只进系统凭据库(keyring),被拒即只留在内存到退出;OAuth 换令牌与刷新经 ureq,回跳在 127.0.0.1 随机端口;Google 授权带 `access_type=offline` 与 `prompt=consent`(每次同意都发刷新令牌),Microsoft 另要 `profile`(无 `email` 时以 `preferred_username` 为地址),换码没有刷新令牌即报错;客户端 ID 由 `crates/ely-mail-engine/build.rs` 取环境变量或 `oauth.env`,该文件不存在即未配置,读不出或写错即构建失败。ureq 在 trace 级逐字节记下请求与回复(令牌、客户端密钥),`ely_platform::logging` 在任何 `ELY_LOG` 下都不记 `ureq`、`ureq_proto` 低于 info 的日志。账号(C12.5):`ely_mail_engine::Account` 存在 accounts 表的 settings 列(JSON),凭据库名 `account:地址`;删账号先删凭据再删本地数据,本地删除失败即放回凭据,凭据库删不掉时内存里的凭据照留,不动服务端;地址在库里唯一,不分 ASCII 大小写(`Error::Taken`)。应用的库读写在后台、锁后进行,网络任务在应用自带的两线程 tokio 运行时上,结果交回 gpui。iCloud 收发都以完整地址为用户名。删去原文先改名为 `.散列.gone` 留在原处,事务提交后才删,失败即改回;打开库时按库里是否仍有邮件指向它放回或删去(C12.5 第 1 轮后)。对话框的请求(检查、登录、保存)在整个窗口里编号,回来时只作用于仍在等它的那个对话框;保存的结果照样更新账号列表,失败而对话框已换即以提示写明。端口记下上次自动填入的值,与之不同的即为键入,换安全方式不覆盖。IMAP 同步(C12.6):文件夹按 LIST 存为邮箱(角色按 RFC 6154,INBOX 按名、库里不分大小写;有 LIST-EXTENDED 与 SPECIAL-USE 即以 `RETURN (SPECIAL-USE)` 取角色),不再列出的连同邮件删去;EXAMINE 缺 UIDVALIDITY 或 EXISTS 即报错;UIDVALIDITY 变了即清空重建;同一 UID 的 FETCH 回复合并;邮件头全取,正文只取 90 天内(`sync::BODY_DAYS`):先读 BODYSTRUCTURE,无附件即取整封,有附件只取头与正文部分、按原结构重组,附件内容为空、部分号记在 `missing`,附件按需(C12.17),处置为 attachment 的多部分整个按需,related 里不看处置(RFC 2387);新列由结构 v2 升级加上,UIDVALIDITY 不同于所记时只删别的 UIDVALIDITY 下的邮件;`start` 指向多部分(BODYSTRUCTURE 无其 Content-ID)时各多部分子项照正文读;任何一步失败即停,成功才记同步时间;打开窗口与添加账号后各同步一次;本机 TLS 初始化失败记为该账号的同步失败。POP3 收取(C12.7):`Protocol::Pop { keep }`,一个 INBOX,按 UIDL 整封取一次,不保留副本时存下之后才 DELE,服务端删去的本地照留。同步控制(C12.8):窗口开着时每 10 分钟同步全部账号,“立即同步”可手动;暂停中止进行中的同步、手动与定时都不再同步,恢复即同步全部;暂停只在内存里,不跨重启;邮箱的 `offline`(结构 v3)打开时该文件夹不限 90 天取每封的整封(连同附件),同步进行中打开的在该次结束后再同步一次;每次同步有全窗口唯一的序号(账号条目删去重建也不重来),迟到的结束不碰更新的同步。 - 2026-10-19(用户定):代码与发布从 Gitea 搬到 GitHub 组织 ELY-Open-Source(`ELY-Open-Source/ElyOffice`;组件库 `ELY-Open-Source/Ely-GPUI-Components`,Cargo 的 git 依赖与 `fetch-references.sh` 随之改址,钉的提交不变;Kigi CLI 同在此组织)。历史、标签与发布已迁过,Gitea 停用,GitHub 是唯一的家。发布由 `.github/workflows/release.yml` 在推送 `v*` 标签时运行(只此一种触发,拉取请求到不了自托管机器):macOS 在 `[self-hosted, macos-signing]`(Mac mini 的图形会话,Developer ID 签名并公证),Windows 与 Linux(WSL)在 `[self-hosted, ely-windows]`;各机的常驻克隆 `$HOME/ely-ci/ElyOffice` 从 GitHub 拉取。`scripts/ci.sh` 经 GitHub API 按标签取发布、没有就建(`GITHUB_TOKEN`,`contents: write`),同名文件先删再传:重跑只换本平台的文件。更新检查读 `api.github.com/repos/ELY-Open-Source/ElyOffice/releases/latest` 的 `.json`,清单的下载地址为 `github.com/ELY-Open-Source/ElyOffice/releases/download/v<版本>/<文件>`;0.1.8 及以前装好的应用仍查 Gitea,需手动装一次新版。官网 worker 读 GitHub API(可选机密 `GITHUB_TOKEN` 避开共享出口地址的限流),下载与源码链接指向 GitHub(GitHub 标志);macOS 版已公证,去掉“未经公证”的提示。发布视频的源文件与成片里仍是 Gitea 地址,未改未重渲染。 - 2026-10-19(用户定):自有代码由 AGPL-3.0-or-later 改为 MIT(`LICENSE`,Copyright (c) 2026 Yang Zhang;工作区 `Cargo.toml`、Linux 包的许可字段、`docs/licenses.md`、官网)。第三方照旧:LibreOffice 与 `patches/libreoffice` 为 MPL-2.0 等,Git 为 GPL-2.0,MuPDF 为 AGPL-3.0;ElyPDF 链接 MuPDF,其发行包整体仍须按 AGPL 履行,Linux 包的许可字段据此写为 `MIT AND <引擎许可>`。 +- 2026-10-19(GitHub #2,R9.1):Impress 在母版视图里 `getParts` 数母版、`getPartName` 给母版名,`getPartInfo` 却读同一序号的幻灯片,母版多于幻灯片时信息里没有 `visible`,ElyShow 每次重读部件都报错;补丁 `0052-lok-impress-master-view-part-info.patch` 让母版视图里取母版页(`client/tests/show.rs` 核对)。`ELY_SHARE` 下发布流程不重建内核:新补丁须先在三台机器的共享引擎上各自重建。GitHub PR #1(R9.2,用户定合并):选区画在图块之上,不透明的选区色盖住文字,`LokView` 画选区时不透明度至多 0.3。 diff --git a/crates/ely-lok/src/client/tests/show.rs b/crates/ely-lok/src/client/tests/show.rs index 5de560f..8de3371 100644 --- a/crates/ely-lok/src/client/tests/show.rs +++ b/crates/ely-lok/src/client/tests/show.rs @@ -103,6 +103,24 @@ fn size_layout_master_and_theme_change_in_one_step() { ); } +/// Issue #2: more masters than slides, a slide hidden. +#[test] +fn the_master_view_lists_its_masters() { + if install().is_none() { + eprintln!("SKIP: no pinned LOK build"); + return; + } + let (_dir, mut worker, doc) = open_deck(); + worker.run(&doc, "slide.hide", &[]).expect("hides One"); + worker.run(&doc, "master.edit", &[]).expect("the master view"); + worker.run(&doc, "master.insert", &[]).expect("a master"); + worker.run(&doc, "master.insert", &[]).expect("another"); + let masters = design(&mut worker, &doc).masters; + assert_eq!(masters.len(), 3, "more masters than slides"); + let shown: Vec<(String, bool)> = masters.into_iter().map(|name| (name, true)).collect(); + assert_eq!(slides(&mut worker, &doc), shown, "masters, all shown"); +} + #[test] fn a_master_edit_shows_on_its_slides() { if install().is_none() { diff --git a/docs/compatibility.md b/docs/compatibility.md index aa0c4a0..639482a 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -3,7 +3,7 @@ 随发行说明发布,每个版本一份。支持某格式不等于支持它的全部功能;下表只写已验证的内容、已知限制与保存行为。 版本:Ely Office 0.1.8(首版六个应用:ElyDoc、ElyTable、ElyShow、ElyPDF、ElyTree、ElyMark)。日期 2026-10-19。 -内核:LibreOffice 26.2.6.3(8221e31,加 `patches/libreoffice` 0001–0051);MuPDF 1.28.5(8ad45e9,加 `patches/mupdf` 0001–0005);Git 2.56.0(a018953)与 git-lfs 3.8.0。 +内核:LibreOffice 26.2.6.3(8221e31,加 `patches/libreoffice` 0001–0052);MuPDF 1.28.5(8ad45e9,加 `patches/mupdf` 0001–0005);Git 2.56.0(a018953)与 git-lfs 3.8.0。 验证机:macOS 27.0 arm64。Windows 与 Linux 未验证。本机没有 Microsoft Office:与 Office 的交叉检查未做(待做)。 ## 往返验证 diff --git a/patches/libreoffice/0052-lok-impress-master-view-part-info.patch b/patches/libreoffice/0052-lok-impress-master-view-part-info.patch new file mode 100644 index 0000000..0ea7112 --- /dev/null +++ b/patches/libreoffice/0052-lok-impress-master-view-part-info.patch @@ -0,0 +1,23 @@ +LOK: in the master view, a part's info is its master + +In the master view getParts counts the masters and getPartName names +them, but getPartInfo still read the slide at the same index. With +more masters than slides the last parts had no page, so the info had +no "visible" and clients could not list the parts; below that, each +master carried its slide's visibility and size. Read the master page +in the master view, as getPartName does. + +--- a/sd/source/ui/unoidl/unomodel.cxx ++++ b/sd/source/ui/unoidl/unomodel.cxx +@@ -4583,7 +4583,10 @@ + if (!pViewSh) + return OUString(); + +- SdPage* pSdPage = mpDoc->GetSdPage(nPart, pViewSh->GetPageKind()); ++ // In the master view, parts are masters, as getParts counts. ++ SdPage* pSdPage = isMasterViewMode() ++ ? mpDoc->GetMasterSdPage(nPart, PageKind::Standard) ++ : mpDoc->GetSdPage(nPart, pViewSh->GetPageKind()); + const sal_Int16 nMasterPageCount= pViewSh->GetDoc()->GetMasterSdPageCount(pViewSh->GetPageKind()); + + ::tools::JsonWriter jsonWriter; diff --git a/tasks/TASKS.md b/tasks/TASKS.md index 498f06d..bb3c935 100644 --- a/tasks/TASKS.md +++ b/tasks/TASKS.md @@ -312,3 +312,8 @@ - [x] R8.4 ElyMark 公式(§14):行内公式排版(原只显示着色的 TeX 原文);`\(…\)` 读作行内公式,`\[…\]` 读作块公式(组件库 dceca9f、e095f06、a20e712、5fba7b3、de961eb;`tex/tests.rs`、`math_text.rs` 与 ElyMark `visual.rs` 测试 — 第 1 轮:折行处的公式画错行、相邻公式合并、链接地址与 `` 被换、`\$` 被拒、跨块成对、行内错误不显示、注释超长;第 2 轮:段首空格的块公式、嵌套 ``、注释超长;第 3 轮:交叉闭合的标签,修后以测试核对,不再审查) - [x] R8.5 发布 0.1.8(用户 2026-10-18 定,要快):版本号,打标签由发布流程三端建包、签名公证、上传(Windows 任务重跑通过;macOS 原在 LaunchDaemon 运行器上找不到签名证书,改到 `macos-signing`,本次在其会话里手动跑 `ci.sh`,公证并上传;发布说明中英两段) - [x] R8.6 答复 #8、#9,写已修于 0.1.8,修好的关闭;`agents.md` 随之(两条已答复并关闭;`agents.md` 记下签名运行器) + +## R9 GitHub #2 与 PR #1(用户 2026-10-19 定:发 0.1.9 前修好) + +- [x] R9.1 #2 ElyShow 点“编辑母版”即反复报“no visibility”(§10):根因在内核:母版视图里 `getParts` 数母版、`getPartName` 给母版名,`getPartInfo` 却按同一序号读幻灯片;母版多于幻灯片时末几个序号无页,信息里没有 `visible`,`Doc::sheets` 照规则报错,每次重读都报;序号在幻灯片数以内时母版带着同号幻灯片的隐藏与尺寸。补丁 `0052-lok-impress-master-view-part-info.patch`:母版视图里按 `getPartName` 的读法取母版页。测试:`client/tests/show.rs` 的 `the_master_view_lists_its_masters`(隐藏一张幻灯片,进母版视图、加两个母版,三个母版都列出且都显示)在未打补丁的内核上报同一句“no visibility”,打上后通过;show 与 slides 的内核测试全过,`lo-patches.sh` 照样从中途接着打。Windows 内核已重建。未验证:macOS(报告所在的平台)与 Linux 的内核尚未重建,发布前在各自的共享引擎上重建 +- [x] R9.2 合并 PR #1(用户定):选区画在已画好的图块之上,Omarchy 等主题的选区色不透明时盖住所选文字;画选区时不透明度至多 0.3,更低的照用(`view/render.rs`)。合并前在 Windows 上跑其测试 `selection_keeps_document_text_readable_across_themes` 通过,去掉上限即以对比度 1:1 失败;在 GitHub 以合并提交并入(bddf765),本地 main 随之合并 diff --git a/tasks/reviews/R9.1-r1.md b/tasks/reviews/R9.1-r1.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/R9.1-r1.md @@ -0,0 +1 @@ +PASS