From 72bec20a60258a93c806168d0f2df4b2ecec8077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Tue, 20 Oct 2026 02:23:17 -0400 Subject: [PATCH] R9.3, R9.4: AutoFilter without the header query (GitHub #4); paste on Windows Patch 0053: under LOK, Calc takes the first row as header instead of asking asynchronously; the worker closed the query and crashed. Patch 0049 includes doc.hxx (gcc on Linux did not build it). arboard read a missing HTML clipboard format as an error on Windows; the clipboard checks the format first, and paste errors show the whole chain. ElyTable tests compare CSV and selection text the platform's way (P3-09). --- Cargo.lock | 1 + agents.md | 1 + apps/ely-table/src/data.rs | 2 +- apps/ely-table/src/tests/data.rs | 8 ++--- apps/ely-table/src/tests/output.rs | 8 +++-- crates/ely-lok/src/client/tests/filter.rs | 27 ++++++++++++++ crates/ely-lok/src/view/clip.rs | 2 +- crates/ely-lok/src/view/tests/input.rs | 6 ++++ crates/ely-platform/Cargo.toml | 1 + crates/ely-platform/src/clipboard.rs | 18 ++++++++-- docs/compatibility.md | 2 +- packaging/linux/package.sh | 2 +- ...r-inline-objects-move-with-their-run.patch | 7 ++-- ...alc-autofilter-header-without-asking.patch | 36 +++++++++++++++++++ scripts/ci.sh | 4 +-- tasks/BUGS.md | 4 ++- tasks/TASKS.md | 5 +++ tasks/reviews/R9.3-r1.md | 3 ++ tasks/reviews/R9.3-r2.md | 1 + 19 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 patches/libreoffice/0053-lok-calc-autofilter-header-without-asking.patch create mode 100644 tasks/reviews/R9.3-r1.md create mode 100644 tasks/reviews/R9.3-r2.md diff --git a/Cargo.lock b/Cargo.lock index 9b4c00e..7293ce3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2254,6 +2254,7 @@ version = "0.1.8" dependencies = [ "anyhow", "arboard", + "clipboard-win", "core-foundation 0.10.0", "core-video", "directories", diff --git a/agents.md b/agents.md index 9a9d7ef..bfc92f8 100644 --- a/agents.md +++ b/agents.md @@ -324,3 +324,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely - 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。 +- 2026-10-20(GitHub #4,R9.3):整列看不出标题时 Calc 开自动筛选会弹异步询问,worker 当场关掉即在其回调里崩溃;补丁 `0053-lok-calc-autofilter-header-without-asking.patch`:LOK 下不问,首行作标题(同 Excel)。R9.4:arboard 在 Windows 把剪贴板上没有 HTML 读成错误,`ely_platform::clipboard` 先查格式;剪贴板错误的提示写出整条原因。补丁 0049 补上 `doc.hxx`(Linux 的 gcc 编不过;MSVC 与 clang 经别的头文件带入)。Gitea 上另发同名的过渡发布(用户定):0.1.8 及更早的应用在 Gitea 查更新,过渡发布的清单指向 GitHub 的下载,装上的 0.1.9 起从 GitHub 查;Gitea 只为此推上 main 与标签,不再是发布之处。 diff --git a/apps/ely-table/src/data.rs b/apps/ely-table/src/data.rs index 6e198c5..a360ea7 100644 --- a/apps/ely-table/src/data.rs +++ b/apps/ely-table/src/data.rs @@ -363,7 +363,7 @@ impl Book { Ok(Some(Clip::Html { html, .. })) => Some(html), Ok(_) => None, Err(error) => { - let text = Book::text(cx, "table.data.clipboard", &[("error", &error.to_string())]); + let text = Book::text(cx, "table.data.clipboard", &[("error", &format!("{error:#}"))]); return self.toast(text, Severity::Danger, cx); } }; diff --git a/apps/ely-table/src/tests/data.rs b/apps/ely-table/src/tests/data.rs index b606320..7959514 100644 --- a/apps/ely-table/src/tests/data.rs +++ b/apps/ely-table/src/tests/data.rs @@ -43,11 +43,9 @@ pub(super) fn cells(cx: &mut TestAppContext, book: &Entity, range: &str) - worker .run(&tab.doc, "cell.goto", &[range]) .expect("the range"); - tab.doc - .selection_text(&mut worker) - .expect("the text") - .trim() - .to_string() + let text = tab.doc.selection_text(&mut worker).expect("the text"); + // The Windows kernel ends rows with CRLF. + text.trim().lines().collect::>().join("\n") }) } diff --git a/apps/ely-table/src/tests/output.rs b/apps/ely-table/src/tests/output.rs index 769da9f..5cf73e8 100644 --- a/apps/ely-table/src/tests/output.rs +++ b/apps/ely-table/src/tests/output.rs @@ -113,15 +113,17 @@ fn exports_write_the_shown_sheet_as_text() { run(&mut cx, &book, "cell.goto", &["B1"]); run(&mut cx, &book, "cell.enter", &["a;b"]); let id = cx.update(|app| book.read(app).core.tabs[0].id); + // The kernel ends rows the system's way. + let end = if cfg!(windows) { "\r\n" } else { "\n" }; for (format, name, text) in [ - (Format::Csv, "out.csv", "3,a;b\n"), - (Format::Tsv, "out.tsv", "3\ta;b\n"), + (Format::Csv, "out.csv", "3,a;b"), + (Format::Tsv, "out.tsv", "3\ta;b"), ] { let path = dir.path().join(name); update(&mut cx, &book, |book, cx| book.export_to(id, path.clone(), format, cx)); settle(&cx, |_| path.exists()); quiet(&cx, &book); - assert_eq!(std::fs::read_to_string(&path).expect("reads"), text); + assert_eq!(std::fs::read_to_string(&path).expect("reads"), format!("{text}{end}")); } let pdf = dir.path().join("out.pdf"); update(&mut cx, &book, |book, cx| book.export_to(id, pdf.clone(), Format::Pdf, cx)); diff --git a/crates/ely-lok/src/client/tests/filter.rs b/crates/ely-lok/src/client/tests/filter.rs index 7280e5f..bb3a70a 100644 --- a/crates/ely-lok/src/client/tests/filter.rs +++ b/crates/ely-lok/src/client/tests/filter.rs @@ -152,3 +152,30 @@ fn one_cell_in_another_block_filters_that_block() { let entries: Vec = sheet::filter_values(&json).expect("parses").entries.into_iter().map(|e| e.text).collect(); assert_eq!(entries, ["9", "10"], "an AutoFilter from D1 is D's"); } + +/// A text-only column: no cell looks like a header. +const WORDS: &str = r#" + + + Name + a + b + +"#; + +#[test] +fn a_whole_column_without_a_clear_header_filters_from_its_first_row() { + if install().is_none() { + eprintln!("SKIP: no pinned LOK build"); + return; + } + let (_dir, mut worker, doc) = open_book(WORDS); + worker.run(&doc, "cell.goto", &["A:A"]).expect("marks the column"); + worker.run(&doc, "data.autofilter", &[]).expect("filters without asking"); + doc.paint_tile(&mut worker, (0, 0, 3840, 3840), (256, 256)) + .expect("the buttons paint"); + // The whole column holds blanks too. + assert_eq!(entries(&mut worker, &doc), ["", "a", "b"], "the first row heads"); +} diff --git a/crates/ely-lok/src/view/clip.rs b/crates/ely-lok/src/view/clip.rs index e14dcfa..97c3923 100644 --- a/crates/ely-lok/src/view/clip.rs +++ b/crates/ely-lok/src/view/clip.rs @@ -82,7 +82,7 @@ pub(super) fn mark_of(html: &str) -> Option<&str> { /// Pastes the system clipboard. pub(super) fn paste(worker: &mut Worker, doc: &Doc) -> io::Result<()> { - let Some(clip) = clipboard::read().map_err(io::Error::other)? else { + let Some(clip) = clipboard::read().map_err(|error| io::Error::other(format!("{error:#}")))? else { return Ok(()); }; let (mime, data) = flavor_of(clip); diff --git a/crates/ely-lok/src/view/tests/input.rs b/crates/ely-lok/src/view/tests/input.rs index 9e0a676..59922a0 100644 --- a/crates/ely-lok/src/view/tests/input.rs +++ b/crates/ely-lok/src/view/tests/input.rs @@ -247,6 +247,12 @@ fn the_clipboard_moves_html_tables_and_images() { text.contains(&"left".to_string()) && text.contains(&"right".to_string()), "{text:?}" ); + // Plain text from another app, with no HTML beside it. + clipboard::write(&Clip::Text("outside words".into())).expect("the text writes"); + cx.update(|app| view.update(app, |view, _| view.send(crate::view::input::Input::Paste))); + flush(&cx); + let text = saved(&view, &mut cx); + assert!(text.iter().any(|line| line.contains("outside words")), "{text:?}"); let mut png = Vec::new(); image::RgbaImage::from_pixel(4, 4, image::Rgba([255, 0, 0, 255])) diff --git a/crates/ely-platform/Cargo.toml b/crates/ely-platform/Cargo.toml index 8a2fdf5..e99036e 100644 --- a/crates/ely-platform/Cargo.toml +++ b/crates/ely-platform/Cargo.toml @@ -38,6 +38,7 @@ objc2.workspace = true security-framework.workspace = true [target.'cfg(windows)'.dependencies] +clipboard-win = "5.4" windows-sys.workspace = true windows.workspace = true diff --git a/crates/ely-platform/src/clipboard.rs b/crates/ely-platform/src/clipboard.rs index 1c9ff13..1e82d79 100644 --- a/crates/ely-platform/src/clipboard.rs +++ b/crates/ely-platform/src/clipboard.rs @@ -54,7 +54,7 @@ pub fn write(clip: &Clip) -> Result<()> { pub fn read() -> Result> { with_board(|board| { let text = absent_ok(board.get_text())?; - if let Some(html) = absent_ok(board.get().html())? { + if let Some(html) = html_of(board)? { let text = text.unwrap_or_default(); return Ok(Some(Clip::Html { html, text })); } @@ -76,7 +76,20 @@ pub fn read() -> Result> { /// The clipboard's HTML, if any; gpui's reads omit it. pub fn html() -> Result> { - with_board(|board| absent_ok(board.get().html())) + with_board(html_of) +} + +fn html_of(board: &mut Clipboard) -> Result> { + // arboard reads absent HTML on Windows as an error. + #[cfg(windows)] + { + let format = clipboard_win::register_format("HTML Format") + .context("the HTML clipboard format registers")?; + if !clipboard_win::is_format_avail(format.get()) { + return Ok(None); + } + } + absent_ok(board.get().html()) } /// Empty or other-format clipboards read as None. @@ -110,6 +123,7 @@ mod tests { let text = Clip::Text("plain 中文".into()); write(&text).expect("text writes"); assert_eq!(read().expect("text reads"), Some(text)); + assert_eq!(html().expect("no html reads"), None); let html = Clip::Html { html: "
a
".into(), text: "a".into(), diff --git a/docs/compatibility.md b/docs/compatibility.md index 639482a..05eef71 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–0052);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–0053);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/packaging/linux/package.sh b/packaging/linux/package.sh index 9390c27..737c321 100755 --- a/packaging/linux/package.sh +++ b/packaging/linux/package.sh @@ -18,7 +18,7 @@ row=$(awk -F'\t' -v slug="$slug" '$1 == slug { print $2 "\t" $3 }' "$root/packag } name=${row%%$'\t'*} categories=${row##*$'\t'} -# Ely's own code is MIT; a bundled engine keeps its licence. +# Ely is MIT; bundled engines keep their licences. case $slug in ely-doc | ely-table | ely-show) license="MIT AND MPL-2.0" ;; ely-pdf) license="MIT AND AGPL-3.0-or-later" ;; diff --git a/patches/libreoffice/0049-writer-inline-objects-move-with-their-run.patch b/patches/libreoffice/0049-writer-inline-objects-move-with-their-run.patch index 20752e2..0f08474 100644 --- a/patches/libreoffice/0049-writer-inline-objects-move-with-their-run.patch +++ b/patches/libreoffice/0049-writer-inline-objects-move-with-their-run.patch @@ -30,19 +30,20 @@ The w:position arithmetic moves into one helper both use. @param _ObjBoundHeight --- a/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx +++ b/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx -@@ -29,6 +29,11 @@ +@@ -29,6 +29,12 @@ #include #include #include +#include +#include ++#include +#include +#include +#include using namespace ::com::sun::star; -@@ -60,6 +65,23 @@ SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition( +@@ -60,6 +66,23 @@ SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition( SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition() {} @@ -66,7 +67,7 @@ The w:position arithmetic moves into one helper both use. /** method to cast to needed type */ const SwTextFrame& SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() const { -@@ -162,7 +184,8 @@ void SwAsCharAnchoredObjectPosition::CalcPosition() +@@ -162,7 +185,8 @@ void SwAsCharAnchoredObjectPosition::CalcPosition() const SwTwips nObjBoundHeight = ( mnFlags & AsCharFlags::Rotate ) ? aObjBoundRect.Width() : aObjBoundRect.Height(); diff --git a/patches/libreoffice/0053-lok-calc-autofilter-header-without-asking.patch b/patches/libreoffice/0053-lok-calc-autofilter-header-without-asking.patch new file mode 100644 index 0000000..c4aede4 --- /dev/null +++ b/patches/libreoffice/0053-lok-calc-autofilter-header-without-asking.patch @@ -0,0 +1,36 @@ +LOK: AutoFilter takes the first row as header without asking + +When Calc cannot tell a header from the data (a whole column of text, +an empty column), turning on AutoFilter asks whether the first row is +a header. Under LOK the client closes the box as soon as it opens, +inside the callback that announces it; the box's async handler then +applies the filter on a half-built dialog, and the next tile paint +crashes the process (GitHub ElyOffice #4). LOK asks no question here: +the first row heads the range, which is the box's default answer and +what Excel does. + +--- a/sc/source/ui/view/dbfunc.cxx ++++ b/sc/source/ui/view/dbfunc.cxx +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -340,7 +341,13 @@ + if ( !rDoc.IsBlockEmpty( aParam.nCol1, aParam.nRow1, + aParam.nCol2, aParam.nRow2, nTab ) ) + { +- if (!bHeader) ++ if (!bHeader && comphelper::LibreOfficeKit::isActive()) ++ { ++ // LOK asks nothing: the first row heads, the box's default. ++ pDBData->SetHeader( true ); ++ ApplyAutoFilter(*pDocSh, rViewData, pDBData, nRow, nTab, aParam); ++ } ++ else if (!bHeader) + { + std::shared_ptr xBox(Application::CreateMessageDialog(rViewData.GetDialogParent(), + VclMessageType::Question, diff --git a/scripts/ci.sh b/scripts/ci.sh index 981cf3a..0a468ed 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -93,7 +93,7 @@ for file in "$dist"/*; do fi names+=("$name") done -# Each asset's id and name, a page of 100 at a time; Windows Python writes CRLF. +# Asset ids and names, 100 per page; strip CRLF. have= for ((page = 1; ; page++)); do got=$(curl -fsS "${auth[@]}" "$api/releases/$id/assets?per_page=100&page=$page" | @@ -101,7 +101,7 @@ for ((page = 1; ; page++)); do [ -n "$got" ] || break have+=$got$'\n' done -# Rebuilt bytes replace a rerun's earlier upload; other platforms' files stay. +# A rerun replaces its own uploads, keeps others'. cd "$dist" for name in "${names[@]}"; do for old in $(awk -F'\t' -v name="$name" '$2 == name { print $1 }' <<<"$have"); do diff --git a/tasks/BUGS.md b/tasks/BUGS.md index 146231d..d357027 100644 --- a/tasks/BUGS.md +++ b/tasks/BUGS.md @@ -149,7 +149,7 @@ P0 次序:W-01、K-01、L-01、O-01、W-02、L-02、W-03、L-03、W-04、L-04 - [ ] P3-06 Windows:删不掉内核仍开着文件的标签工作目录(错误 32),写入失败无从模拟(`tests::more::a_kernel_write_failure_stays_visible`) - [ ] P3-07 Windows:测试以 `kill -9` 杀 worker,Git Bash 的 kill 不认 Windows 进程号,worker 不死(`view::tests::commands::a_dead_worker_reaches_apps_while_idle`) - [ ] P3-08 Windows(AMD):多个 worker 同时启动时内核的 OpenCL 探测卡在驱动的 `clCreateCommandQueue` 里数分钟(`openclwrapper::switchOpenCLDevice`);测试以 `SAL_DISABLE_OPENCL=1` 绕开;是否在 `ely.xcd` 关掉 `UseOpenCL` 待用户定 -- [ ] P3-09 Windows:内核给的选区文字与文本导出以 CRLF 换行,三个 ElyTable 单测按 LF 比对(`tests::data::sort_filter_duplicates_and_columns_run_from_their_dialogs`、`a_column_button_sorts_its_own_block_not_the_cursors`、`tests::output::exports_write_the_shown_sheet_as_text`);导出该用哪种换行待定 +- [x] P3-09 Windows:内核给的选区文字与文本导出以 CRLF 换行,三个 ElyTable 单测按 LF 比对(`tests::data::sort_filter_duplicates_and_columns_run_from_their_dialogs`、`a_column_button_sorts_its_own_block_not_the_cursors`、`tests::output::exports_write_the_shown_sheet_as_text`);导出该用哪种换行待定。2026-10-20:导出照内核随系统的换行(同 LibreOffice),测试按平台比对;选区文字的测试按行比对 - [ ] P3-10 Windows:`crates/ely-office/tests/restart.rs` 设 `HOME` 想用临时目录,但 Windows 上 `data_dir` 取已知文件夹(不看 `HOME`),测试在真实的 ElyDoc 配置里运行;中途被杀即留下挡路的 `lok-verify.fodt` 文件夹,真实 ElyDoc 的内核核对随之失败(2026-10-14 审查中出现,已手动删去) - [ ] P3-11 ElyShow:正编辑表格单元格时在幻灯片空白处右键,内核(Impress)只结束编辑、不发 `LOK_CALLBACK_CONTEXT_MENU`,再右键一次才有幻灯片菜单;Windows 实测,他端未核;修需内核补丁 - [ ] P3-12 Windows:`output::tests::targets_skip_hidden_slides_and_pad_numbers` 以 `/` 拼的路径比对,Windows 的 `join` 用 `\`,单测恒失败(代码无误) @@ -158,4 +158,6 @@ P0 次序:W-01、K-01、L-01、O-01、W-02、L-02、W-03、L-03、W-04、L-04 - [ ] P3-15 Windows:全量并行单测中偶有一个 LOK worker 读到的 BuildId 为 `development`(`desktop/source/app/app.cxx` 读不到 bootstrap 的 buildid 时的默认值),握手照规则拒绝;同一时刻别的 worker 读到正确的 8221e31,内核与 worker 都未重建,单独重跑即过(2026-10-14 ElyDoc `review::tests::one_unreadable_time_spares_the_other_notes`,三次重跑皆过)。疑为并发时读 `version.ini` 偶发失败,原因未查 - [ ] P3-16 发布:`ci.sh` 在三端各自调用 `packaging/source.sh` 并上传同名的源码包与上游源码包,发布里同名文件出现三份(Gitea 允许重名);上游源码包打的是各机的 `engines/mupdf-src`,含构建留下的文件,三份大小不同(v0.1.5:Linux 108 MB,macOS 161 MB)。v0.1.5 手动删去后到的两份,留 Linux 的一份。应只出一份,且上游包只含源码 - [ ] P3-17 ElyTable(Windows,0.1.5 安装版,2026-10-15 录视频时见):A1 选中后按两次 Ctrl+= 缩放到 150%,网格停在半滚动处:第 5 行被表头截去一半,第 1–4 行看不见,Ctrl+Home 也回不到 A1。应保持首行与首列在视图内(同 R2.7 的按键缩放) +- [ ] P3-18 Windows:`tests::menu::right_clicks_open_excel_rows_on_cells_and_headers` 第二次右键 A2(先 `cell.goto D9`)等不到菜单;不带 R9.3、R9.4 的源码同样失败,原因未查 +- [ ] P3-19 Windows:ElyTable 全量单测并行跑(默认线程数或 6)时,`output` 的测试与 worker 一起停在零 CPU、不再前进;逐个跑(`--test-threads=1`)不停,原因未查 diff --git a/tasks/TASKS.md b/tasks/TASKS.md index f1a4373..d2f4dac 100644 --- a/tasks/TASKS.md +++ b/tasks/TASKS.md @@ -317,3 +317,8 @@ - [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 随之合并 +- [x] R9.3 #4 ElyTable 开自动筛选即内核崩溃(§9,用户 2026-10-20 定:发 0.1.9 前修好):选中整列(点列标)而该列看不出标题(全是文字或全空)时,Calc 以异步询问框问“首行作标题吗”;worker 在宣告它的回调里当场关掉,询问框的回调在半建成的对话框上加上筛选,下一次画图块即访问违例(Windows 0xc0000005,macOS SIGSEGV)。单格、数据块、首行、有数字列的整列都不问,不崩。补丁 `0053-lok-calc-autofilter-header-without-asking.patch`:LOK 下不问,首行作标题(询问框的默认,同 Excel)。测试:`client/tests/filter.rs` 的 `a_whole_column_without_a_clear_header_filters_from_its_first_row`(整列文字开筛选、画图块、条目不含首行)在未打补丁的内核上开筛选即失败。 审查两轮(与 R9.4 同审):第 1 轮一处注释超过十字,已改;第 2 轮通过。同时查出补丁 0049 用 `GetDoc()` 却未含 `doc.hxx`,Linux 的 gcc 编不过(MSVC 与 clang 经别的头文件带入),补上;三端源码树都为 53 个补丁,macOS 与 Linux 内核随之重建。 +- [x] R9.4 Windows 上粘贴不可用(用户 2026-10-20 报,提示只写“the clipboard reads”):arboard 3.6.1 在 Windows 读 HTML 时不先查有无该格式,剪贴板只有纯文字(记事本、浏览器地址栏等)时报未知错误而不是“无此内容”,`clipboard::read` 先读 HTML,任何纯文字粘贴都失败;macOS 与 Linux 照报“无此内容”。`ely_platform::clipboard` 在 Windows 先以 `IsClipboardFormatAvailable` 查 “HTML Format”;粘贴失败的提示写出整条原因(`{:#}`,原先只有最外一层)。测试:`clipboard.rs` 的往返测试写纯文字后读回、无 HTML;`view/tests/input.rs` 把外来纯文字粘进文档(都要 `ELY_CLIPBOARD_TEST=1`,会覆盖剪贴板);去掉查验即两者都失败。 +- [ ] R9.5 发布 0.1.9(用户 2026-10-20 定:先修好粘贴与 #2、#4 再发):首批六个应用;版本号,打标签由发布流程三端建包、签名公证、上传,发布说明中英两段 +- [ ] R9.6 Gitea 上的过渡发布(用户 2026-10-20 定):0.1.8 及更早的应用在 Gitea 查更新,在 Gitea 推上 main 与 v0.1.9,发同名发布、同样的文件;其清单指向 GitHub 的下载,0.1.9 起从 GitHub 查 +- [ ] R9.7 更新日志:0.1.9 发好后在用户桌面写中英两段的更新说明 diff --git a/tasks/reviews/R9.3-r1.md b/tasks/reviews/R9.3-r1.md new file mode 100644 index 0000000..c3e7251 --- /dev/null +++ b/tasks/reviews/R9.3-r1.md @@ -0,0 +1,3 @@ +FAIL + +- crates/ely-lok/src/client/tests/filter.rs:156 — The new doc comment contains 11 words, exceeding agents.md's ten-word limit. Running `python tests/scripts/comments.py` reports this added line and exits with status 1. Shorten the comment to ten words or fewer. diff --git a/tasks/reviews/R9.3-r2.md b/tasks/reviews/R9.3-r2.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/R9.3-r2.md @@ -0,0 +1 @@ +PASS