Hosting moves to git.zacharyzhang.com: component dependency, site links, references; GitHub workflows removed

This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 15:58:26 -04:00
1 parent 383a1ea467
commit 623bc085f6
13 files changed
+29 -161

No files matched your search

-77
View File
@@ -1,77 +0,0 @@
# Builds the patched engines once; release.yml downloads them.
name: engines
on:
workflow_dispatch:
permissions:
contents: write
jobs:
macos:
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15
arch: arm64
- runner: macos-15-intel
arch: x86_64
runs-on: ${{ matrix.runner }}
timeout-minutes: 355
env:
GH_TOKEN: ${{ github.token }}
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_MAXSIZE: 6G
steps:
- uses: actions/checkout@v4
- name: Key
id: key
run: echo "key=$(scripts/engines-key.sh)" >> "$GITHUB_OUTPUT"
- name: Already built?
id: done
run: |
if gh release view "engines-${{ steps.key.outputs.key }}" --json assets \
--jq '.assets[].name' 2>/dev/null | grep -qx "engines-macos-${{ matrix.arch }}.tar.zst"; then
echo "built=true" >> "$GITHUB_OUTPUT"
fi
- name: Tools
if: steps.done.outputs.built != 'true'
run: brew install make gnu-sed bison flex gettext autoconf automake libtool ccache nasm zstd
- name: Compiler cache
if: steps.done.outputs.built != 'true'
uses: actions/cache/restore@v4
with:
path: .ccache
key: ccache-macos-${{ matrix.arch }}-${{ steps.key.outputs.key }}-${{ github.run_id }}
restore-keys: ccache-macos-${{ matrix.arch }}-
- name: Upstream sources
if: steps.done.outputs.built != 'true'
run: scripts/fetch-references.sh
- name: LibreOffice (patched)
if: steps.done.outputs.built != 'true'
run: scripts/build-libreoffice.sh
- name: MuPDF (patched), Git, git-lfs, OCR data, CEF
if: steps.done.outputs.built != 'true'
run: |
scripts/build-mupdf.sh
scripts/build-git.sh
scripts/fetch-git-lfs.sh
scripts/fetch-tessdata.sh
scripts/fetch-cef.sh
- name: Keep the compiler cache, even after a timeout
if: always() && steps.done.outputs.built != 'true'
uses: actions/cache/save@v4
with:
path: .ccache
key: ccache-macos-${{ matrix.arch }}-${{ steps.key.outputs.key }}-${{ github.run_id }}
- name: Publish
if: steps.done.outputs.built != 'true'
run: |
archive=engines-macos-${{ matrix.arch }}.tar.zst
tar -C engines -cf - lo-src/instdir mupdf-build mupdf-src git git-src/COPYING git-src/LGPL-2.1 cef tessdata |
zstd -19 -T0 -o "$archive"
tag=engines-${{ steps.key.outputs.key }}
gh release view "$tag" >/dev/null 2>&1 ||
gh release create "$tag" --prerelease --title "$tag" --notes "Pinned, patched engines; built by engines.yml."
gh release upload "$tag" "$archive" --clobber
-58
View File
@@ -1,58 +0,0 @@
# Builds macOS apps for a release tag and attaches them.
name: release
on:
workflow_dispatch:
inputs:
tag:
description: Release tag to attach the packages to, such as v0.1.0
required: true
permissions:
contents: write
jobs:
macos:
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15
arch: arm64
- runner: macos-15-intel
arch: x86_64
runs-on: ${{ matrix.runner }}
timeout-minutes: 120
env:
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Engines
run: |
brew install zstd
tag=engines-$(scripts/engines-key.sh)
gh release download "$tag" --pattern "engines-macos-${{ matrix.arch }}.tar.zst" ||
{ echo "::error::no $tag for ${{ matrix.arch }}; run the engines workflow first"; exit 1; }
mkdir -p engines
zstd -dc "engines-macos-${{ matrix.arch }}.tar.zst" | tar -C engines -xf -
- name: Upstream sources and ElyMark's page
run: |
scripts/fetch-references.sh
scripts/build-mark-content.sh
- name: Tests that need no window
run: |
tests/scripts/types.sh
tests/scripts/icons.sh
python3 tests/scripts/comments.py
- name: Packages
run: packaging/macos/release.sh 1
- name: Attach to the release
run: |
version=${{ inputs.tag }}
gh release view "$version" >/dev/null 2>&1 || gh release create "$version" --title "Ely Office $version" --notes "Built by release.yml."
gh release upload "$version" dist/*.dmg --clobber
if [ "${{ matrix.arch }}" = arm64 ]; then
gh release upload "$version" dist/ElyOffice-*-source.tar.gz dist/ElyOffice-*-upstream-source.tar.gz --clobber
fi
Generated
+2 -1
View File
@@ -1964,7 +1964,7 @@ dependencies = [
[[package]]
name = "ely-gpui-component"
version = "0.1.1"
source = "git+https://github.com/ZacharyZhang-NY/Ely-GPUI-Components?rev=f834f55c16b38d86fbc243b2d7719667503f4b01#f834f55c16b38d86fbc243b2d7719667503f4b01"
source = "git+https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components?rev=5d6efd46ec0c93b381ec7578561a1273c366025b#5d6efd46ec0c93b381ec7578561a1273c366025b"
dependencies = [
"alacritty_terminal",
"anyhow",
@@ -2207,6 +2207,7 @@ dependencies = [
"gpui-pre-platform",
"log",
"notify",
"semver",
"serde_json",
"tempfile",
]
+1 -1
View File
@@ -17,7 +17,7 @@ encoding_rs = "0.8"
jiff = "0.2"
anyhow = "1"
directories = "6"
ely-gpui-component = { git = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Components", rev = "f834f55c16b38d86fbc243b2d7719667503f4b01" }
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components", rev = "5d6efd46ec0c93b381ec7578561a1273c366025b" }
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"] }
+3 -3
View File
@@ -529,7 +529,7 @@ AI 或脚本修改文件与其他外部修改使用同一套处理规则。ElyMa
### 15.2 接入基线
后端以 Kigi CLI(https://github.com/ZacharyZhang-NY/Kigi-CLI,Rust)为基础,以 Rust 依赖直接嵌入,不用 ACP(用户 2026-10-05 定)。提供商登录(订阅账号或 API 密钥)、模型与端点配置沿用 Kigi 的实现,不另写一套。不解析终端装饰文本来伪造结构化事件。
后端以 Kigi CLI(https://git.zacharyzhang.com/ZacharyZhang-NY/Kigi-CLI,Rust)为基础,以 Rust 依赖直接嵌入,不用 ACP(用户 2026-10-05 定)。提供商登录(订阅账号或 API 密钥)、模型与端点配置沿用 Kigi 的实现,不另写一套。不解析终端装饰文本来伪造结构化事件。
会话恢复只在 Kigi 的会话存储支持并通过验证时启用。不能把本地历史回放当成后端会话已经恢复。
@@ -870,10 +870,10 @@ UI 自动测试、内核测试和手工交互测试互相补充。三端的输
核对日期:2026-10-01。来源用于确认接口、项目结构和许可条件,不证明 Ely 已完成接入。产品功能、默认设置与性能目标由本文定义。正式实现应记录所采用版本的固定提交和许可证,而不是只引用默认分支。
[S1] Ely GPUI Components,README,组件库使用方式、主题及许可证。
`https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/README.md`
`https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/README.md`
[S2] Ely GPUI Components,TASKS,组件分类与 host/prove 等状态定义。
`https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/TASKS.md`
`https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/TASKS.md`
[S3] LibreOfficeKit 官方文档,C/C++ 接口、分块渲染和输入回调。
`https://docs.libreoffice.org/libreofficekit.html`
+7 -5
View File
@@ -39,7 +39,7 @@ site/ 官网(Vite 8、pnpm、TypeScript,无框架;等轴 SVG 积木
## 组件映射
依赖 `ely-gpui-component`(pin f834f55,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 5d6efd4,gpui 为 crates.io 的 `gpui-pre` =0.3.8)。名字取自 `reference/Ely-GPUI-Components/src`。gpui 用法规则见该仓库 `AGENTS.md`。`tests/scripts/agents_md.py` 核对下表每个名字都是组件库公开项。
| 需要 | 用 |
| --- | --- |
@@ -160,6 +160,7 @@ tests/scripts/mark-tools.sh 真窗口 ElyMark:查找替换、正则、Tab
tests/scripts/comments-rules.sh comments.py 对长注释与跨行注释报错
tests/scripts/bad-settings.sh 通用设置读不出时 ElyDoc 照样启动,文件不被覆盖
tests/scripts/one-instance.sh 第二份 ElyDoc 被拒,第一份的工作目录不动
tests/scripts/update.sh 装好的 ElyTree 从本机服务的新版下载、替换、重新打开(需辅助功能权限)
tests/scripts/settings.sh 真窗口:ElyPDF 设置里选深色,ElyTree 即刻变深;作者名写入、不丢外观;ElyTree 拒绝非 Git 程序;设置文件读不出时提示且不覆盖;主窗口重开回到原处(需辅助功能与屏幕录制权限)
tests/scripts/privacy.sh 真窗口 ElyDoc:键入的文字不进日志;worker 的日志进应用日志;设置里的诊断先列出所含内容,导出的文件去掉家目录与姓名、不含正文(需辅助功能权限)
tests/scripts/panels.sh 真窗口 ElyDoc:左侧栏默认不宽于 230、拖动内侧边缘变宽、宽度存入设置、重启后照旧(需辅助功能权限)
@@ -186,8 +187,8 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
## 决策
- 2026-10-01:上游版本以 `scripts/fetch-references.sh` 为准。LibreOffice 26.2.6(8221e31)、MuPDF 1.28.5(8ad45e9)、gpui 为 `gpui-pre` =0.3.8 与 `gpui-pre-platform` =0.3.8(crates.io,2026-10-07 起,随组件库 K01)、组件库 f834f55(2026-10-09 起)。
- 2026-10-02:组件库 7380afb 起:对话框与面板的 Enter 提交改走字段的 key-down 动作(macOS IME 天然守卫,不再提前提交);面板族文案经组件 `i18n::text`(内建 en/zh-CN,应用目录可覆盖);核心控件带 role/aria;对话框带角色、名称与说明,Cancel/Close 与禁用说明本地化。同仓库 `~/Documents/GitHub/Ely-GPUI-Components` 修复并经 SSH 推送(本机 HTTPS keychain 令牌失效)。2026-10-04 组件库 b6cb94c:`NumberInput::on_commit` 只在 Enter、失焦、步进、拖动时触发,键入不触发;改文档的数值框用它,否则每个键入数字都成一条内核命令与一步撤销。同批带入上游的 Checkbox、Switch、Select 等 role/aria 与 RenderSurface。c0f17ee:`ToggleButton::disabled`(不可按、无 Tab 停靠、说明不可用,提示可写原因)。967d1e4:`ContextMenu::manual`(按属主编号的请求在某点打开,右键不开),供行在按下之后才到的菜单,如内核给的拼写建议。
- 2026-10-01:上游版本以 `scripts/fetch-references.sh` 为准。LibreOffice 26.2.6(8221e31)、MuPDF 1.28.5(8ad45e9)、gpui 为 `gpui-pre` =0.3.8 与 `gpui-pre-platform` =0.3.8(crates.io,2026-10-07 起,随组件库 K01)、组件库 5d6efd4(2026-10-09 起)。
- 2026-10-02:组件库 7380afb 起:对话框与面板的 Enter 提交改走字段的 key-down 动作(macOS IME 天然守卫,不再提前提交);面板族文案经组件 `i18n::text`(内建 en/zh-CN,应用目录可覆盖);核心控件带 role/aria;对话框带角色、名称与说明,Cancel/Close 与禁用说明本地化。同仓库 `~/Documents/GitHub/Ely-GPUI-Components` 修复并推送(2026-10-09 起推到 git.zacharyzhang.com,HTTPS,令牌在本机钥匙串)。2026-10-04 组件库 b6cb94c:`NumberInput::on_commit` 只在 Enter、失焦、步进、拖动时触发,键入不触发;改文档的数值框用它,否则每个键入数字都成一条内核命令与一步撤销。同批带入上游的 Checkbox、Switch、Select 等 role/aria 与 RenderSurface。c0f17ee:`ToggleButton::disabled`(不可按、无 Tab 停靠、说明不可用,提示可写原因)。967d1e4:`ContextMenu::manual`(按属主编号的请求在某点打开,右键不开),供行在按下之后才到的菜单,如内核给的拼写建议。
- 2026-10-06:审查者为探针复制的源码树须用自己的 `CARGO_TARGET_DIR`(`scripts/review.sh` 写明);写完结论前删掉这些副本与其构建目录(曾积到 /tmp 近 900 GB,磁盘写满、链接失败):曾编进本仓库 `target/`,ely-lok 里烘焙的源码路径指向已删的副本,单测找不到 worker。
- 2026-10-03:每条任务由 `scripts/review.sh` 在 herdr 分栏里交给 codex(gpt-6.1-sol,effort high;本机 `codex` 别名已带 `--yolo`,重复传参会报错)审查,最多三轮。此前各轮用 gpt-6-astra xhigh。
- 2026-10-01:macOS 的 LOK 用自建 LibreOffice 26.2.6.3 加 `patches/libreoffice/0001-lok-macos-tile-painting.patch`(已验证出图块)。2026-10-03 加 `0002-lok-dispatch-to-document-frame.patch`:`postUnoCommand` 原发往桌面的活动框架,另一文档关闭后命令落空或落到别的文档;改发本文档的框架。2026-10-04 加 `0003-lok-char-style-and-spacing-states.patch`:LOK 原不发当前字符样式与段前段后,属性栏无从同步;补发 `.uno:CharStyle`(界面名,无字符样式为空)与 `.uno:ULSpacing`(`上,下`,1/100 mm);混合选区的状态发 `{"commandName","dontcare":true}`,`ely_lok::MIXED` 表示,段落样式跨段不一致也算混合(原样报首段),字符样式带来的字体、字号、粗斜体等在选区内不一致也算混合(原样只看直接格式)。`.uno:ULSpacing` 缺的成员归零,故两值同发;属性栏记住已发未回显的两值状态(段距、页边距),连续编辑以它为底。同日加 `0004-lok-panel-states.patch`:补发页面尺寸、页面项(横向、版式、页码格式)、页边距、分栏、页眉页脚开关与版式、四种锚点与六种环绕(真假或禁用)、标题行重复;页面项缺的成员同样归零,故转向时页面项与尺寸都发。`0005-jsdialog-skip-disposed-dialogs.patch`:对话框守卫关闭对话框后,JSDialog 空闲任务仍为它生成整窗更新,读已释放窗口崩溃(实测崩溃报告),补丁让已释放的对话框不再生成消息。`0006-page-size-takes-the-page-item.patch`:`.uno:AttributePageSize` 也收页面项,转向是一次改动、一步撤销。`0007-lok-aqua-anyinput-without-peeking.patch`:worker 的请求经主 GCD 队列派发,而 Aqua 的 `AnyInput` 用 `nextEventMatchingMask` 窥探时会转动 run loop、在内核空闲任务中途执行请求(实测:表格删列与排版空闲任务交错,`SwLayIdle::DoIdleJob_` 段错误,约三成全量测试复现);补丁让 LOK 下的 `AnyInput` 改问客户端,worker 以 `registerAnyInputCallback` 报告是否有待处理请求,请求只在顶层让出时执行(补丁后连续十次全绿)。`0008-lok-toc-caption-formula-without-dialogs.patch`:目录、题注、公式在内核只有对话框入口;补丁给 `.uno:InsertMultiIndex` 加 `Title`(默认目录)、`.uno:InsertCaptionDialog` 加 `Category`(程序名)与 `Text`(照内核题注对话框的选项)、`.uno:InsertObjectStarMath` 加 `Formula`(文字转公式,选中公式时整体替换,一步撤销),并加 `getCommandValues(".uno:Formula")` 读选中公式。插入目录后光标落在目录内(内核原样)。`0009-lok-word-count-values.patch`:`getCommandValues(".uno:WordCount")` 给文档与选区的字数、字符数;内核的 `.uno:StateWordCount` 状态是英文串,只作重读的信号。构建加 `--with-myspell-dicts`,随包词典取自 LibreOffice 的 dictionaries 子模块(core 钉的 9925407,来源与许可见各目录 README 与 license),装在 `Resources/extensions`。构建后只留 `dict-en`(25 MB,英语拼写、断词、同义词):界面语言是英文与简体中文,中文无 Hunspell 词典;全部 65 个(473 MB)时 LOK 首启 5.4 秒、再启 2.3 秒,只留英文为 1.1 秒与 0.7 秒(PERF-01 要求 3 秒内可操作)。词典语种已由用户定:英文。`0010-lok-outline-values.patch`:`getCommandValues(".uno:Outline")` 给各标题的文字、级别、位置(twips)与是否当前(光标所在处按文档顺序之前最近的标题,`GetOutlinePos`;分栏时位置比不出先后),`.uno:Bookmarks` 的每项加位置(版面不显示的书签无位置);导航栏的跳转都按位置。`0011-lok-font-lists-present-when-a-member-is-used.patch`:LOK 把以 `;` 连写的字体列表整串当作字体名,列表中有字体已用上也报缺失(实测报出界面字体的回退列表);补丁让列表中任一成员用上即不算缺失,文档里写的列表全缺时照报。`0012-lok-calc-cursor-references-merge.patch`:Calc 在回调注册后补发单元格光标;`.uno:SheetReferences?sheet=N` 给引用某表的公式格数、命名区域数、第一个公式格,以及用 INDIRECT 的公式与名称数(这类引用运行时才知指向,删除说明里单独列出);合并带 `MoveContents` 时不弹对话框,并修上游“多个数据格的 API 合并什么也不做”。worker 以 `SAL_LOK_OPTIONS=sc_print_twips_msgs`(macOS 另加 `unipoll`)运行,Calc 的光标、选区与 `.uno:SheetGeometryData` 同为文档 twips;视图把可见区经 `setClientVisibleArea` 报给内核。`0013-lok-author-option.patch`:`lo_setOption("author", 名)` 设内核用户全名,新批注与修订以此署名。`0014-lok-calc-formula-entry-and-names.patch`:公式语法错误不弹询问、补全不切走编辑、提交清引用标记、名称的可撤销定Line truncated
@@ -202,8 +203,8 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
- 2026-10-01:MailCore 2 的子模块 libetpan 过旧,改钉 libetpan master `4d47862`。
- 2026-10-01:每个应用的全部数据在 `<本机数据目录>/ElyOffice/<slug>/`,路径由 `ely_platform::data_dir` 给出。卸载只动这里,且先问。用户文档永不碰。
- 2026-10-04(用户定):macOS 包标识前缀 `ely.zacharyzhang.office`(`packaging/macos/bundle.sh`);发布者 ZacharyZhang,网址 zacharyzhang.com(macOS `NSHumanReadableCopyright`,Windows 卸载项 `Publisher` 与 `URLInfoAbout`;Linux 桌面文件无此字段)。界面语言英文与简体中文,以后再加。拼写词典只随英文:LibreOffice 的词典库没有中文(中文不用 Hunspell 拼写)。内核界面语言固定英文,函数名照英文;ElyTable 把内核英文的选区统计(Sum、Average 等七个固定名)换成界面语言,数值照内核。批注与修订的作者取各用户的账户全名(无全名用登录名,与内核自身次序一致),由补丁 0013 的 `setOption("author")` 在 worker 启动时设定;作者设置页随设置任务接入。邮件合并字段写法 `«列名»` 由我定(用户交我决定)。
- 2026-10-01:更新清单是 JSON:`{"version", "assets": {"<os>-<arch>": {"url", "sha256"}}}`,只走 https(本机回环除外)。检查、下载、校验在 `ely_platform::update`,从不静默安装。包管理器安装的 Linux 版本不自更新。清单地址由设置给出,尚未配置。
- 2026-10-05(用户定):ElyAgent 的后端与内置模型的登录配置以 Kigi CLI(https://github.com/ZacharyZhang-NY/Kigi-CLI,Rust)为基础,以 Rust 依赖直接嵌入,不用 ACP;沿用其提供商登录(订阅账号或 API 密钥)与模型配置。
- 2026-10-01:更新清单是 JSON:`{"version", "assets": {"<os>-<arch>": {"url", "sha256"}}}`,只走 https(本机回环除外)。检查、下载、校验在 `ely_platform::update`,从不静默安装。包管理器安装的 Linux 版本不自更新。2026-10-09 起(用户定:0.1.2 加自动更新):每个应用一份清单,`<slug>.json`,随发布上传,应用经 git.zacharyzhang.com 的 API 读最新发布(`api/v1/repos/ZacharyZhang-NY/ElyOffice/releases/latest`),在其文件里找 `<slug>.json`(`ely_platform::release::asset_url`;Gitea 没有 `releases/latest/download` 路径;`ELY_UPDATE_MANIFEST` 直接给清单地址,测试用);只在从 `.app` 运行时可用(开发构建没有);照 PRD §4.2 自动检查默认关闭:设置“通用”的“启动时检查更新”(通用设置 `check_updates`)打开后启动时查一次、查不到只记日志,应用菜单的“检查更新…”随时手动查(已是最新或查不到都以提示写明);有新版即在窗口上方显示组件库的 `UpdateBanner`(文案进内建中英目录,组件库 5d6efd4):横幅在标题栏下方(`Shell` 的页眉里,`Updates` 自己是一个视图);下载(进度)、校验散列、“重新启动以更新”只走正常的退出流程(有未保存的照常询问;取消即什么也不装,按钮仍在);应用真正退出时(`on_app_quit`)以本程序的安装模式(`--ely-install-update dmg 包 进程号`,`ely_ui::run` 最先识别)起一个独立进程:等本进程结束,`ely_platform::install` 挂载 dmg、把同名 .app 拷到旁边再换掉原包(换上前失败即放回原包),无论成败都 `open` 该包;失败的原因写在数据目录 `updates/failed.txt`,重开的应用以提示写明。下载完成只归属于它下载的那个版本;下载中或已下载时再查不覆盖。`packaging/macos/release.sh` 为每个应用写出清单(版本、本机架构的 dmg 地址与 SHA-256),dmg 里另有指向“应用程序”的替身,可直接拖入。新包换上即为装好,旧副本删不掉只记警告。`tests/scripts/update.sh`:装好的 ElyMark 在默认设置下启动不发任何请求;按“检查更新…”后从本机服务的 9.9.9 下载;有未保存的文字时“重新启动以更新”先问,取消则原包不动,“不保存”后装上新版并重新打开(新版本身的进程在跑)。
- 2026-10-05(用户定):ElyAgent 的后端与内置模型的登录配置以 Kigi CLI(https://git.zacharyzhang.com/ZacharyZhang-NY/Kigi-CLI,Rust)为基础,以 Rust 依赖直接嵌入,不用 ACP;沿用其提供商登录(订阅账号或 API 密钥)与模型配置。
- 2026-10-05(用户定):八个应用都不许卡顿:键入、选择、滚动、文档渲染都要即时(GPUI 的 120 FPS 手感),树莓派 3 上也要流畅。输入延迟与帧时间是验收项,要实测;界面线程不等内核、不持 worker 锁做同步请求,空闲不做事。
- 2026-10-05:LOK 的输入与事件路径(实测后定)。原样:视图的事件监听长轮询 worker(持 worker 锁最多 50 毫秒,worker 读线程也随之阻塞最多 250 毫秒),按键排在锁后,键入锁等待中位 290 毫秒、最长 9 秒;输入队列在界面执行器上逐条跳回界面线程,每键约一帧,连续键入积压到 1 至 2 秒。现在:worker 有新事件即主动推送(`tag::EVENTS`,推送线程在输出锁下取批,批次即发送时状态),客户端读线程把回复与事件分开,事件存入 `client::Feed`,视图以异步方式等它(`Feed::next`,有新批次时唤醒,不占线程、不碰 worker 锁;原先每个打开的文档阻塞一个后台线程最多一秒,文档多于核数时会饿死输入与图块;监听任务归视图所有,视图释放即停);每个视图一条后台通道(`view/lane.rs`),输入优先、图块其次,连续执行,界面线程只收落地结果;文档尺寸与页框只在内核报尺寸变化时在后台读;批次弄脏的已显示图块即刻重绘,不等下一帧;视图的 `Reported` 事件只在内核回报或输入落地时发出,滚动与图块到达不触发应用的观察钩子;编辑与光标移动后应用要读的内核列表(ElyDoc 导航、字数、审阅,ElyTable 工作表与几何、单元格规则、格式面板)经 `ely_lok::read_off` 在后台读,一次一个,结果按发起者核对。实测(macOS,`tests/scripts/lag.sh`):按打字速度键入时输入落地 0 至 1 毫秒,图块 1 至 3 毫秒,按键到新图块 ElyDoc 中位 19 毫秒、ElyTable 3 毫秒;连续快速键入(脚本一次送出近百字)时,各次运行在 3 至 225 毫秒的中位之间摆动:新文档首次键入时内核有一次 150 至 230 毫秒的冷启动(首块图块与拼写等初始化),同一批字排在它之后;原为中位 1 秒、p95 1.9 秒。树莓派 3 未实测(本机无设备)。界面线程不碰 worker:应用对内核的读取、保存与另存为的导出、导出 PDF、比较、邮件合并都经 `Tabs::read_in`(或 `ely_lok::read_off`)在后台执行,回到窗口时按发起的标签与读取时的状态核对;保存导出期间标签状态为“正在保存”,同一标签的后续保存排队到它结束;另存为在写入前按文件身份再查一次目标是否已被别的标签持有;导出期间又有编辑时,“保存后关闭”不关闭,回到关闭询问;关闭标签时的撤销历史也在后台读;邮件合并预览与比较在发起时就保留自己的标签号与工作目录;读取失败不立即重试,等下一次状态变化;载入时一并在后台读版面与撤销历史(`ely_lok::layout`,`LokView::open` 接收版面)。窗口关闭回调先不放行,在后台逐个读标签的撤销历史并关闭(有改动的照常询问),最后一个标签关闭后移除窗口;内核文档的关闭也在后台(2026-10-06 起,原先同步读历史、在界面线程持 worker 锁关闭)。
- 2026-10-04(用户定):八个应用的内容区一律随系统深浅色:Doc 页面、Table 网格、Show 幻灯片、PDF 页面、邮件正文、Mark 编辑区、Agent 输出。自动颜色随之翻转,文件里写明的颜色照原样;打印与导出 PDF 仍为浅色。各引擎(LOK、MuPDF、CEF)接入应用主题,不留引擎默认色。LOK:`ely.xcd` 定义 `COLOR_SCHEME_ELY_DARK` 与 `COLOR_SCHEME_ELY_LIGHT`(文档底色、自动文字色、网格、链接等取 Ely 默认色板;内核自带的深色方案颜色留空、按应用外观取默认值,传方案名不改外观,所以不用它),`LokView` 在主题深浅变化时经有序队列发 `.uno:ChangeTheme`(不算编辑),页面底色深色取 `surface`、浅色取 `paper`;Omarchy 色板与这两套固定色可能略有差别。导出 PDF 实测仍为白底。图块作废时旧图仍显示,新图到达后替换,编辑与主题切换都不闪。
@@ -276,3 +277,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
- 2026-10-09:退出(缺陷清单 X-01)。Cmd+Q 与应用菜单的“退出”由应用级动作接收:主窗口的宿主在 `Closing::own_window` 里登记自己的退出流程(`ely_ui::commands::route_quit`),任何窗口(含设置窗口)发出的退出都经它逐个关闭标签、询问未保存的;宿主的窗口已不在时才直接退出;没有宿主的应用(ElyTree)直接退出。`Host::quitting` 在退出开始时运行(ElyMark 先记下打开的标签)。原先只有主窗口根上截退出,设置窗口在前时 Cmd+Q 不问即退,并把这次运行记为干净结束、删掉恢复点。
- 2026-10-09:作者名与读不出的设置(缺陷清单 X-02)。签名用的名字取启动时读入的通用设置(`ely_ui::settings::current`;文件读不出时为默认值,设置窗口另以 Banner 写明),`ely_platform::user::named(作者名)` 为空即用账户名;不再在引擎启动时重读文件(原先 `settings.json` 读不出时 Doc、Table、Show 以致命错误退出)。LOK worker 记下设定的作者名,引擎重启照用它。`tests/scripts/bad-settings.sh` 核对读不出的设置下 ElyDoc 照样启动、文件不被覆盖。
- 2026-10-09:每个应用只跑一份(缺陷清单 X-03)。`ely_ui::run` 在写日志之前取应用数据目录的 `instance.lock`(`ely_platform::instance::hold`;Unix 为 fcntl 记录锁,进程结束即放,被拒时以 `F_GETLK` 向系统问出持锁的进程号,不另存进程号文件,同时启动的几份也报得准;Windows 为 LockFileEx,不报进程号);已有一份在跑时第二份不启动,报“已在运行(进程号)”。原先第二份启动即清空第一份的工作目录、把它的恢复点当作干净结束删掉、改写崩溃锁。macOS 经访达打开文件本就交给运行中的那份;`open -n` 与 Linux 每文件一个进程时第二份被拒,文件须在已开的窗口里打开(未做转交)。`tests/scripts/one-instance.sh` 核对。
- 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 地址取。
+1 -1
View File
@@ -33,7 +33,7 @@ fetch() { # name url rev [sparse paths...]
echo "fetch $name $rev"
}
fetch Ely-GPUI-Components https://github.com/ZacharyZhang-NY/Ely-GPUI-Components.git f834f55c16b38d86fbc243b2d7719667503f4b01
fetch Ely-GPUI-Components https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components.git 5d6efd46ec0c93b381ec7578561a1273c366025b
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 \
+4 -4
View File
@@ -1,7 +1,7 @@
import { expect, test, type Page } from "@playwright/test";
import { TEXT, type Key, type Lang } from "../src/text.ts";
const REPO = "https://github.com/ZacharyZhang-NY/ElyOffice";
const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"];
const RELEASES = `${REPO}/releases/latest`;
@@ -78,13 +78,13 @@ test.describe("English locale", () => {
await expect(lang).toHaveText("中文");
});
test("downloads go to the GitHub release page, never to a file", async ({ page }) => {
test("downloads go to the release page, never to a file", async ({ page }) => {
await page.goto("/");
await expect(page.locator(".tour .get")).toHaveCount(APPS.length);
for (const i of APPS.keys()) await expect(page.locator(".tour .get").nth(i)).toHaveAttribute("href", RELEASES);
await expect(page.locator("#download a")).toHaveCount(1);
await expect(page.locator("#download [data-t=github]")).toHaveAttribute("href", RELEASES);
await expect(page.locator(".hero > a")).toHaveText("GitHub");
await expect(page.locator("#download [data-t=get]")).toHaveAttribute("href", RELEASES);
await expect(page.locator(".hero > a")).toHaveText("Source");
await expect(page.locator(".hero > a")).toHaveAttribute("href", REPO);
const files = await page.locator("a[href]").evaluateAll((as) =>
as.map((a) => (a as HTMLAnchorElement).href).filter((h) => /\.(dmg|tar\.gz|zip|exe|AppImage)$/.test(h)),
+6 -6
View File
@@ -10,7 +10,7 @@ import { film } from "./film.ts";
import { said, speak, type Lang } from "./text.ts";
import { RELEASES, VERSION } from "./release.ts";
const REPO = "https://github.com/ZacharyZhang-NY/ElyOffice";
const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
const app = document.querySelector<HTMLElement>("#app");
if (!app) throw new Error("index.html has no #app");
@@ -18,10 +18,10 @@ if (!app) throw new Error("index.html has no #app");
const hero = document.createElement("header");
const title = document.createElement("h1");
title.textContent = "Ely Office";
const github = document.createElement("a");
github.href = REPO;
github.textContent = "GitHub";
hero.append(title, said("p", "tagline"), said("p", "platforms"), github);
const source = document.createElement("a");
source.href = REPO;
source.textContent = "Source";
hero.append(title, said("p", "tagline"), said("p", "platforms"), source);
const { section, host, svg } = tour(hero);
rhythm(host, svg);
@@ -31,7 +31,7 @@ const footer = document.createElement("footer");
footer.id = "download";
const version = document.createElement("h2");
version.textContent = `Ely Office ${VERSION}`;
const get = said("a", "github");
const get = said("a", "get");
get.href = RELEASES;
footer.append(version, said("p", "platforms"), said("p", "needs"), said("p", "unsigned"), get);
+1 -1
View File
@@ -1,3 +1,3 @@
// The published release; downloads live on its GitHub page.
export const VERSION = "0.1.1";
export const RELEASES = "https://github.com/ZacharyZhang-NY/ElyOffice/releases/latest";
export const RELEASES = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice/releases/latest";
+2 -2
View File
@@ -16,7 +16,7 @@ const en = {
platforms: "Out now for macOS. Windows and Linux are coming soon.",
needs: "macOS 14 or later, Apple silicon.",
unsigned: "Not notarized. If macOS blocks the app, open System Settings › Privacy & Security and click Open Anyway.",
github: "Download from GitHub",
get: "Download",
other: "中文",
roads: "Drag a file down the road.",
fileDoc: "ElyDoc file",
@@ -52,7 +52,7 @@ const zh: typeof en = {
platforms: "macOS 版已发布。Windows 与 Linux 版即将推出。",
needs: "macOS 14 或更新,Apple 芯片。",
unsigned: "未经公证。macOS 拦下应用时,打开“系统设置 › 隐私与安全性”,点“仍要打开”。",
github: "前往 GitHub 下载",
get: "前往下载",
other: "English",
roads: "把文件沿着路拖过去。",
fileDoc: "ElyDoc 文件",
+1 -1
View File
@@ -71,7 +71,7 @@
<h1 data-text="title">Ely Office</h1>
<h1 data-text="name">Ely Office 0.1.0</h1>
<p class="version" data-text="version" data-soft>Out now for macOS · Windows and Linux soon macOS 现已推出 · Windows 与 Linux 即将推出</p>
<p class="url" data-text="url" data-soft>github.com/ZacharyZhang-NY/ElyOffice/releases</p>
<p class="url" data-text="url" data-soft>git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice/releases</p>
<div class="cap" data-text="offline"><p class="en">Works with the network off.</p><p class="zh">断网照常工作。</p></div>
<div class="cap" data-text="open"><p class="en">Open source, AGPL.</p><p class="zh">开源,AGPL 许可。</p></div>
<div class="cap" data-text="local"><p class="en">Your files stay in your folders.</p><p class="zh">文件留在你自己的文件夹里。</p></div>
+1 -1
View File
@@ -163,7 +163,7 @@ function end(ctx, t) {
const line = { x: left, align: "left", a };
text(ctx, { ...line, s: "macOS now · Windows and Linux soon", y, size: 34, color: "#c4c2c0" });
text(ctx, { ...line, s: "macOS 现已推出 · Windows 与 Linux 即将推出", y: y + 46, size: 28, color: "#acaaa8" });
const url = "github.com/ZacharyZhang-NY/ElyOffice";
const url = "git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
text(ctx, { ...line, s: url, y: y + 122, size: 30, color: "#f5f5f7", a: fade(t0 + BAR), weight: 400 });
}