R4.11: real-window acceptance; shifted keys bind their characters

A real keyboard reports Shift plus punctuation as the character on every
platform, so the Windows key-name bindings never fired. Windows also
keeps Ctrl+Shift+0 for Chinese input; Actual Size adds Ctrl+Shift+9.

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-14 22:30:44 -04:00
1 parent 65514599fe
commit 4460fd35a6
8 files changed
+72 -34

No files matched your search

+1 -1
View File
@@ -478,7 +478,7 @@ Git 托管、PR 审核平台、Issue 系统、CI 平台和远程开发环境不
参考 MarkText 的 Markdown 编辑行为、ColaMD 的本地文件同步和内容保留规则、Markion 的 GPUI 原生 Markdown 编辑,不复制其整个应用窗口。不用 Electron,不用 CEF 或其他网页内容宿主。[S17][S18]
解析、渲染、编辑命令与右键菜单以 Typora 1.14.10 的默认设置为对照,不输于它;可视模式仍是按下的块以原文编辑,不改为所见即所得的行内编辑(用户 2026-10-13 定)。[S25]
解析、渲染、编辑命令与右键菜单以 Typora 1.14.10 的默认设置为对照,不输于它;可视模式仍是按下的块以原文编辑,不改为所见即所得的行内编辑(用户 2026-10-13 定)。Typora 是参照,不求一一相同:验收看每项功能可用,缺 Typora 的某项、次序或措辞不同不算缺陷(用户 2026-10-14 定)。[S25]
### 14.2 功能要求
+1 -1
View File
@@ -292,7 +292,7 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
- 2026-10-14(用户要求核对 ElyTable 与 ElyShow):ElyTable 的右键(R5.5)。菜单机制移入 `ely_office::menu`(取内核这次给的菜单、开在所点之处、剪贴板图标行、子菜单可否随其中各项),ElyDoc 与 ElyTable 共用;`ely_lok::menu` 的目标另有单元格(有 `.uno:InsertCell`)与 Writer 之外的绘图对象(有 `.uno:ArrangeMenu`)。网格照 Excel:插入 ▸、删除 ▸、清除内容(`.uno:ClearContents`,同 Delete 键,不弹内核的删除内容对话框)、合并、拆分、设置单元格格式(打开格式面板);对象为置于顶层、置于底层;编辑单元格时只有剪贴板行。行列表头由 Ely 自画,内核不给菜单:右键先选中该行或列(已选的整行整列含它即不动,同 Excel)。选中对象或正编辑图形里的文字时,绘图外壳取代了单元格外壳,`.uno:SelectRow`/`.uno:SelectColumn` 原无处执行而被丢弃;补丁 `0046-lok-calc-headers-leave-drawings.patch` 让 LOK 下视图外壳接下这两条:先结束图形编辑(键入的文字留下)并取消选中,再选行列,同 Calc 自己的表头(`DrawDeselectAll`),菜单为插入、删除、清除内容、行高或列宽、隐藏、显示。ElyTable 每一项的可否都取自内核对它所发的那条命令此刻的状态(内核的菜单只定目标):补丁 `0045-lok-command-states.patch` 加 `getCommandValues(".uno:CommandStates?commands=…")`,先冲出调度器、再逐条问调度器(同菜单栏),未知的命令即报错(`ely_lok::menu::runs`);LOK 推送的状态只有固定的一组,且在空闲时才更新。因此受保护而许插入行列的工作表照样可插;行高、列宽只在文档只读时禁用(内核的规则),受保护时由内核拒绝并报出其错误。ElyTable 无批注界面,不列批注。
- 2026-10-14:ElyShow 的右键(R5.6)。画布右键照 PowerPoint 按目标出 Ely 的菜单(`apps/ely-show/src/menu.rs`,共用 `ely_office::menu`);`ely_lok::menu` 的目标另有幻灯片(有 `.uno:SlideLayoutMenu`)与 Writer 之外的图片(有 `.uno:ChangePicture`)。幻灯片为版式 ▸、新建批注;编辑文字为项目符号、编号、新建批注;图形与文本框为组合 ▸、置于顶层 ▸、置于底层 ▸、新建批注;图片另有替换…、裁剪;表格为插入 ▸、删除 ▸、合并单元格、新建批注;剪贴板同为图标行。每项可否取自内核对其命令此刻的状态(补丁 0045):整表选中时可插入行列,删除与合并要光标进单元格(内核的规则)。Impress 的 `LOK_CALLBACK_TABLE_SELECTED` 由 boost 属性树写出,数值与真假都是文字,空列表是空串,`table::read` 照收;拖动表格边线走 R5.3 的同一路径(`.uno:TableChangeCurrentBorderPosition`,偏移为 twips,内核换算)。补丁 `0047-lok-impress-table-edges.patch`:Impress 原只给内侧边线的上下限,行的下限是布局器写死的 600(上游待办),参考线与落点不符;补丁让两轴都带首尾边线的上下限(`leftMin`、`leftMax`、`rightMin`、`rightMax`,列只限从左到右),内侧行线取行自身的最小高度,`table::Lines::ends` 收下,有则按它夹住(内侧线也直接用内核的上限),Writer 不给时照旧留 40 twips;已在界外的线从不逆着拖动方向移动,原地按下松开不发命令;最左列边线原什么也不做却记一步撤销(上游待办),LOK 下改为改首列宽并随边线移动表格,同一步撤销,桌面的拖动手柄不变。正编辑的单元格按编辑器量最小高度,略大于内核真正允许的(约 2 像素),新表的行因此不能再缩,参考线与落点仍一致。正编辑表格单元格时在幻灯片空白处右键,内核只结束编辑、不给菜单,再按一次才有(BUGS P3-11)。
- 2026-10-14(Gitea #1,Linux Wayland 报):ElyShow 左侧缩略图条滚轮不滚。根因:列表包在 `ContextMenu` 宿主里,宿主无尺寸,列表随内容长高、从不溢出,滚轮无处可滚(右栏正常);宿主改为 `size_full`(同 ElyPDF 的三处),`tests/strip.rs` 以 24 张幻灯片核对滚轮滚到最后一张。各应用其余 `ContextMenu` 宿主已核:ElyPDF 三处本有尺寸,ElyTable 的工作表标签条与下拉选项不是滚动列表。
- 2026-10-14:ElyMark 的菜单与快捷键(R4.9,MARK-15)。项与键取自 Typora 1.14.10 主进程字节码的字符串表(`.work/typora-main-menus.txt`)与其 `zh-Hans.lproj/Menu.json`;实际大小在字节码里有 Ctrl+Shift+9 与 Ctrl+Shift+0 两串,照用户所定用 Ctrl+Shift+0,R4.11 在真窗口核对。表格是“段落”的子菜单(照 Typora),顶层不再有“表格”。原 Ctrl+1/2/3 切模式、Ctrl+=/-/0 字号、Ctrl+Shift+F 专注让给 Typora 的键;可视、源码、预览留在“视图”菜单,无键。Ctrl+/ 另绑在 `ElyEditor` 上(gpui 同深度后绑者胜),盖过代码编辑器的 `//` 注释切换(Markdown 没有这种注释);`MarkdownDocument` 的键上下文只在可视模式有。带 Shift 的标点:Windows 写键名(`ctrl-shift-[`),macOS 与 Linux 写字符(`cmd-{`),见 `blocks::shifted`。Ctrl+Enter 在打开的块里原是输入框的 Submit(文档不处理),改绑为下方插入行。拒绝一律成信息提示:当场的由 `Desk::edit` 说,后台读出的经 `DocumentEvent::EditRefused`、`view::Refused` 到宿主。菜单打开时,打开的块把焦点借给菜单,块与选区都留着,菜单命令照样作用于所选(组件 6d90351)。复制为 Markdown 与粘贴为纯文本只作用于文档:焦点在文档外的输入框(查找框、对话框)时交给该框自己的复制、粘贴。表格子菜单末项为删除表格(组件 `TableEdit::Delete`,一步撤销,插入点不在表格里即拒绝;在打开的块里删除后焦点回到文档,撤销键照用,组件 6c2d28c)。Typora 有而组件库暂缺的不进菜单:行内公式、上下标、注释、提示块子菜单、任务状态、列表缩进 Ctrl+[/]、代码工具。
- 2026-10-14:ElyMark 的菜单与快捷键(R4.9,MARK-15)。项与键取自 Typora 1.14.10 主进程字节码的字符串表(`.work/typora-main-menus.txt`)与其 `zh-Hans.lproj/Menu.json`;实际大小在字节码里有 Ctrl+Shift+9 与 Ctrl+Shift+0 两串,照用户所定用 Ctrl+Shift+0;R4.11 真窗口查出 Windows 的中文输入法把 Ctrl+Shift+0 留作热键(注册表 `HKCU\Control Panel\Input Method\Hot Keys\00000104`),应用收不到,Windows 另绑 Ctrl+Shift+9(菜单显示它)。表格是“段落”的子菜单(照 Typora),顶层不再有“表格”。原 Ctrl+1/2/3 切模式、Ctrl+=/-/0 字号、Ctrl+Shift+F 专注让给 Typora 的键;可视、源码、预览留在“视图”菜单,无键。Ctrl+/ 另绑在 `ElyEditor` 上(gpui 同深度后绑者胜),盖过代码编辑器的 `//` 注释切换(Markdown 没有这种注释);`MarkdownDocument` 的键上下文只在可视模式有。带 Shift 的标点与数字一律写所出的字符(`secondary-{`、`secondary-+`、`alt-%`):三端的 gpui 都把 Shift 加该键报成字符并去掉 Shift(Windows 见 `gpui-pre-windows` 的 `get_keystroke_key`);R4.9 原在 Windows 写键名,真键盘按不出(R4.11 真窗口查出)。Ctrl+Enter 在打开的块里原是输入框的 Submit(文档不处理),改绑为下方插入行。拒绝一律成信息提示:当场的由 `Desk::edit` 说,后台读出的经 `DocumentEvent::EditRefused`、`view::Refused` 到宿主。菜单打开时,打开的块把焦点借给菜单,块与选区都留着,菜单命令照样作用于所选(组件 6d90351)。复制为 Markdown 与粘贴为纯文本只作用于文档:焦点在文档外的输入框(查找框、对话框)时交给该框自己的复制、粘贴。表格子菜单末项为删除表格(组件 `TableEdit::Delete`,一步撤销,插入点不在表格里即拒绝;在打开的块里删除后焦点回到文档,撤销键照用,组件 6c2d28c)。Typora 有而组件库暂缺的不进菜单:行内公式、上下标、注释、提示块子菜单、任务状态、列表缩进 Ctrl+[/]、代码工具。
- 2026-10-14:ElyMark 的右键菜单(R4.10)。项、次序与显隐规则取自 Typora 1.14.10 的 `resources/window.html`(`#context-menu` 与其子菜单)与 `frame.js` 的显隐函数,记在 `.work/R4.10/typora-context-menu.txt`。菜单在 `view/menu.rs`,`MarkView` 自持(`ely_office::menu::Offer` 与 `ContextMenu::manual`):可视模式由组件的 `DocumentEvent::Pointed` 开在指针处,源码与预览由视图自己的右键开。剪切、复制、粘贴、删除所选范围为图标行,按下即把其键交回菜单打开前的焦点(`dispatch_keystroke`),与键盘同一路径;无选区时剪切、复制、删除灰显。其余项经各自的动作,显示所绑的键。组件 013f142、1b5fb07:文本框与代码编辑器右键落在选区里时保留选区,否则把插入点移到所点处;可视模式打开的块右键不写回、不关闭,目标在后台按全文读出(块外的引用定义照样解析);`MarkdownDocument::delete_image`(删除图片,一步撤销,无图片即 `EditRefusal::NoImage`);可视无块时 Ctrl+V 粘贴文字(原只收图片,文字被丢弃)。复制为 HTML 代码的图片照原地址(`Pictures::Written`,同 Typora),复制为富文本照旧内嵌。“编辑”菜单的复制项照 Typora 次序:纯文本、Markdown、HTML 代码、富文本。Typora 有而不做的:缩进与减少缩进行(可视只在打开的块里有)、复制表格、代码自动缩进、图片上传、缩放、移动与语法切换、拼写、表情复制、检查元素。gpui 的测试只发按下,菜单在 Enter 松开时选中,测试另发松开(`blocks/context.rs` 的 `choose`)。第 1 轮后:右键的目标按所点的字节读(组件 79e94f7),保留的选区只供剪贴板,删除图片删所点的那张;三种“复制为”在后台转换,界面线程只写剪贴板,新的复制取代未完成的旧复制(`Desk::copying`);`ely_office::menu::Offer` 只在首次绘制时把请求交给宿主(宿主按元素存的“已开”记录随标签切走而丢,切回会重开),ElyDoc、ElyTable、ElyShow 同受其益。第 2 轮后:转换完成时剪贴板已不是开始时的内容(此后有任何复制,含编辑器自己的 Ctrl+C)即丢弃这次结果,同内容的再次写入分不出;打开的块里只认最后一次右键(组件 2b8bd9f),所点字节对回所画字节的读法逐段只对齐一次(原逐字重读,8000 字的段落要近 2 秒)。第 3 轮后:剪贴板的比对另含其 HTML(gpui 读剪贴板不含 HTML,纯文字相同而富文本不同的后来复制原被盖掉;`ely_platform::clipboard::html`);组件的计时测试改用 `web_time::Instant`(组件 e07fd34)。
- 2026-10-14(用户报:整个软件中文显示问题很多):中文显示(R4.13)。Windows 上 gpui 以用户区域(本机为 en-US)排版全部文字,DirectWrite 按日文为汉字选回退字体,日文字体缺的简体字再落到另一字体,同一个词里字形与粗细不一(ElyTree 的“打开仓库”:“打开”粗、“仓库”细)。`vendor/gpui-pre-windows` 的 `text_locale`:用户区域不是中日韩时,改用 Windows 语言列表(WinRT `GlobalizationPreferences::Languages`,Win32 的界面语言只给 en-US)里第一个中日韩语言排版(日志 `text: laid out as …`);在 Windows 上打中文须把中文加进该列表,所以它就是用户读的汉字。只换排版的区域,字体族名与字体列表仍按用户区域。读不出语言列表即记警告、照用户区域。Ely 的界面语言是中文时(设置或 `ELY_LOCALE`),`ely_ui::i18n::install_as` 经 `gpui_windows::set_text_language` 让排版随它,不论 Windows 区域(日文区域下“打开仓库”原为 Yu Gothic UI 600 与 Microsoft JhengHei UI 700 两种字);语言下次启动生效,故启动时设一次。组件库 6df9ab0:Ely 用到的组件里写死的英文(下拉的“Choose…”、清除、关闭、移除、取消固定的提示,公式补全的“No suggestions”,设置里字号的重置提示与示例句)改走内建中英目录。a4bf696:查找框(计数、三个选项与上下一处的提示、替换与全部替换)、排序与筛选(添加规则、满足全部或任一、条件、升降序、添加排序)、密码框的显示与隐藏提示同此;筛选条件以目录键为值(`Test::key`);ElyMark 的删除图片按右键所点的字节(`delete_image(at)`)。仍为英文的是内核的文字(LibreOffice 界面语言固定英文:幻灯片占位“Click to add Title”、母版“Default”、配色名、数字格式代码“General”、函数名),以及启动失败对话框(出现在读入语言之前,中英并列)。
- 2026-10-14(用户定:dmg 不再显示未公证):macOS 发布以 Developer ID Application 证书签名、经 `notarytool` 公证并钉票。证书与公证凭据(`xcrun notarytool store-credentials`,App 专用密码只在钥匙串里)装在构建用的 Mac 上;发布流程的 macOS 任务从仓库变量 `ELY_SIGN_IDENTITY`(证书全名)与 `ELY_NOTARY_PROFILE`(凭据名)取得,`ci.sh` 在 macOS 上缺任一即失败,不出未公证的包。本机手动出包同样设这两个变量再跑 `packaging/macos/release.sh`。
+4 -12
View File
@@ -50,14 +50,6 @@ actions!(
]
);
/// Shift with punctuation: Windows names the key, others the character.
pub(crate) fn shifted(mods: &str, key: char, typed: char) -> String {
match cfg!(target_os = "windows") {
true => format!("{mods}-shift-{key}"),
false => format!("{mods}-{typed}"),
}
}
pub fn bind(cx: &mut App) {
let at = Some(commands::CONTEXT);
cx.bind_keys([
@@ -73,14 +65,14 @@ pub fn bind(cx: &mut App) {
KeyBinding::new("secondary-shift-m", MathBlock, at),
KeyBinding::new("secondary-shift-k", CodeFences, at),
KeyBinding::new("secondary-shift-q", Quote, at),
KeyBinding::new(&shifted("secondary", '[', '{'), OrderedList, at),
KeyBinding::new(&shifted("secondary", ']', '}'), BulletList, at),
KeyBinding::new("secondary-{", OrderedList, at),
KeyBinding::new("secondary-}", BulletList, at),
KeyBinding::new("secondary-shift-x", TaskList, at),
KeyBinding::new("secondary-b", Strong, at),
KeyBinding::new("secondary-i", Emphasis, at),
KeyBinding::new("secondary-u", Underline, at),
KeyBinding::new(&shifted("secondary", '`', '~'), InlineCode, at),
KeyBinding::new(&shifted("alt", '5', '%'), Strike, at),
KeyBinding::new("secondary-~", InlineCode, at),
KeyBinding::new("alt-%", Strike, at),
KeyBinding::new("secondary-k", Hyperlink, at),
KeyBinding::new("secondary-shift-i", InsertImage, at),
KeyBinding::new("secondary-\\", ClearFormat, at),
+12 -13
View File
@@ -6,7 +6,6 @@ use gpui::{
};
use crate::{
blocks::shifted,
desk::{
Desk,
tests::{open, start},
@@ -83,9 +82,9 @@ fn paragraph_keys_retype_the_caret_block(cx: &mut TestAppContext) {
assert_eq!(current(&desk, cx), "# Intro\n");
press("secondary-0", cx);
assert_eq!(current(&desk, cx), "Intro\n");
press(&shifted("secondary", '[', '{'), cx);
press("secondary-{", cx);
assert_eq!(current(&desk, cx), "1. Intro\n");
press(&shifted("secondary", ']', '}'), cx);
press("secondary-}", cx);
assert_eq!(current(&desk, cx), "- Intro\n");
press("secondary-shift-q", cx);
assert_eq!(
@@ -102,7 +101,7 @@ fn format_keys_wrap_the_caret_word(cx: &mut TestAppContext) {
assert_eq!(current(&desk, cx), "**word**\n");
press("secondary-\\", cx);
assert_eq!(current(&desk, cx), "word\n");
press(&shifted("alt", '5', '%'), cx);
press("alt-%", cx);
assert_eq!(current(&desk, cx), "~~word~~\n");
}
@@ -144,10 +143,10 @@ fn alt_arrows_move_a_table_row(cx: &mut TestAppContext) {
#[gpui::test]
fn view_keys_follow_typora(cx: &mut TestAppContext) {
let (desk, cx, _files) = opened("a\n", cx);
press(&format!("f8 f9 {}", shifted("secondary", '=', '+')), cx);
press("f8 f9 secondary-+", cx);
let look = desk.read_with(cx, |desk, _| desk.look.clone());
assert!(look.focus && look.typewriter && look.size > 100, "{look:?}");
press(&shifted("secondary", '0', ')'), cx);
press("secondary-)", cx);
assert_eq!(desk.read_with(cx, |desk, _| desk.look.size), 100);
}
@@ -284,14 +283,14 @@ fn every_command_takes_typoras_windows_key(cx: &mut TestAppContext) {
(&MathBlock, "ctrl-shift-m"),
(&CodeFences, "ctrl-shift-k"),
(&Quote, "ctrl-shift-q"),
(&OrderedList, "ctrl-shift-["),
(&BulletList, "ctrl-shift-]"),
(&OrderedList, "ctrl-{"),
(&BulletList, "ctrl-}"),
(&TaskList, "ctrl-shift-x"),
(&Strong, "ctrl-b"),
(&Emphasis, "ctrl-i"),
(&Underline, "ctrl-u"),
(&InlineCode, "ctrl-shift-`"),
(&Strike, "alt-shift-5"),
(&InlineCode, "ctrl-~"),
(&Strike, "alt-%"),
(&Hyperlink, "ctrl-k"),
(&InsertImage, "ctrl-shift-i"),
(&ClearFormat, "ctrl-\\"),
@@ -305,9 +304,9 @@ fn every_command_takes_typoras_windows_key(cx: &mut TestAppContext) {
(&ToggleSource, "ctrl-/"),
(&look::FocusMode, "f8"),
(&look::Typewriter, "f9"),
(&look::Larger, "ctrl-shift-="),
(&look::Smaller, "ctrl-shift--"),
(&look::ActualSize, "ctrl-shift-0"),
(&look::Larger, "ctrl-+"),
(&look::Smaller, "ctrl-_"),
(&look::ActualSize, "ctrl-("),
(&CopyMarkdown, "ctrl-shift-c"),
(&PastePlain, "ctrl-shift-v"),
];
+7 -4
View File
@@ -3,7 +3,7 @@
use ely_ui::{commands, i18n::text};
use gpui::{Action, App, Context, InteractiveElement as _, KeyBinding, Menu, MenuItem, actions};
use crate::{blocks::shifted, desk::Desk, view::Mode};
use crate::{desk::Desk, view::Mode};
actions!(
mark,
@@ -18,11 +18,14 @@ pub fn bind(cx: &mut App) {
KeyBinding::new("secondary-/", ToggleSource, Some("ElyEditor")),
KeyBinding::new("f8", crate::look::FocusMode, at),
KeyBinding::new("f9", crate::look::Typewriter, at),
KeyBinding::new(&shifted("secondary", '=', '+'), crate::look::Larger, at),
KeyBinding::new(&shifted("secondary", '-', '_'), crate::look::Smaller, at),
KeyBinding::new(&shifted("secondary", '0', ')'), crate::look::ActualSize, at),
KeyBinding::new("secondary-+", crate::look::Larger, at),
KeyBinding::new("secondary-_", crate::look::Smaller, at),
KeyBinding::new("secondary-)", crate::look::ActualSize, at),
KeyBinding::new("secondary-f", ely_office::FindReplace, at),
]);
// Windows' Chinese input keeps Ctrl+Shift+0 for itself.
#[cfg(target_os = "windows")]
cx.bind_keys([KeyBinding::new("ctrl-(", crate::look::ActualSize, at)]);
crate::blocks::bind(cx);
crate::tools::bind(cx);
crate::clip::bind(cx);
+2 -2
View File
@@ -16,10 +16,10 @@
## ElyMark 的菜单与快捷键
- 段落与格式菜单照 Typora。标题:Ctrl+1 至 Ctrl+6,Ctrl+0 段落,Ctrl+= 与 Ctrl+- 升降一级。块:Ctrl+Shift+K 代码块,Ctrl+Shift+M 公式块,Ctrl+Shift+Q 引用,Ctrl+Shift+[ 有序列表,Ctrl+Shift+] 无序列表,Ctrl+Shift+X 任务列表。
- 段落与格式菜单照 Typora。菜单里带 Shift 的标点键写成所出的字符,如 Ctrl+{ 即 Ctrl+Shift+[。标题:Ctrl+1 至 Ctrl+6,Ctrl+0 段落,Ctrl+= 与 Ctrl+- 升降一级。块:Ctrl+Shift+K 代码块,Ctrl+Shift+M 公式块,Ctrl+Shift+Q 引用,Ctrl+Shift+[ 有序列表,Ctrl+Shift+] 无序列表,Ctrl+Shift+X 任务列表。
- 格式:Ctrl+B 加粗,Ctrl+I 斜体,Ctrl+U 下划线,Ctrl+Shift+` 代码,Alt+Shift+5 删除线,Ctrl+K 超链接,Ctrl+Shift+I 插入图片,Ctrl+\ 清除样式。
- 表格在“段落 ▸ 表格”:Ctrl+T 插入,Ctrl+Enter 下方插入行,Ctrl+Shift+Backspace 删除行,Alt+方向键移动行列,“格式化表格源码”对齐各列。
- 视图:Ctrl+/ 在源代码与可视之间切换,F8 专注,F9 打字机,Ctrl+Shift+= 放大,Ctrl+Shift+- 缩小,Ctrl+Shift+0 实际大小;可视、源码、预览在“视图”菜单里选。
- 视图:Ctrl+/ 在源代码与可视之间切换,F8 专注,F9 打字机,Ctrl+Shift+= 放大,Ctrl+Shift+- 缩小,Ctrl+Shift+0 实际大小(Windows 的中文输入法占着这个键,在 Windows 上用 Ctrl+Shift+9);可视、源码、预览在“视图”菜单里选。
- 编辑:Ctrl+Shift+C 复制为 Markdown(无选区时复制全文),Ctrl+Shift+V 粘贴为纯文本;另有复制为纯文本、复制为 HTML 代码(图片保留原地址)、复制为富文本。
- 右键菜单照 Typora,随所点之处变化:剪切、复制、粘贴、删除为一行图标;链接可打开、复制地址;图片可打开所在位置(网络图片在浏览器打开)、删除;代码块可复制其内容;公式与 HTML 块可编辑;加粗、斜体、代码、超链接与引用、列表各为一行图标;表格里为“表格 ▸”,别处为“段落 ▸”;“插入 ▸”;引用、列表、代码块等可整块删除。右键落在选区里时选区保留;正在编辑的块右键后仍开着。源码模式只有剪贴板与“复制/粘贴为”,预览只有复制。
- 命令用不了时(如在代码里设标题、插入点不在表格里),提示写明原因,文字不动。macOS 上 Ctrl 为 Cmd。
+44
View File
@@ -0,0 +1,44 @@
# R4 验收核对表(ElyMark 对照 Typora,2026-10-14)
标准:每项功能可用,不求与 Typora 一一相同(用户 2026-10-14 定)。`[x]` 审查通过;`[~]` 三轮审查用尽,最后一轮的问题已修、各有回归测试,未再审。
## 任务
| 条目 | 状态 | 核对 | 证据 | 遗留 |
| --- | --- | --- | --- | --- |
| R4.0 前置 | [x] | 审查改用 gpt-6-astra max fast;PRD §14 与 `agents.md` 记下决定 | `tasks/reviews/R4.0-r1.md` | — |
| R4.1 菜单图标行 | [~] | 右键菜单的剪贴板与格式图标行可点、可键盘、禁用时灰显 | 组件测试;真窗口截图 `menu-right-text.png` | — |
| R4.2 行内扩展 | [~] | 表情、行内 HTML、脚注上标、删除线在可视里画出 | 组件测试;真窗口截图 `visual.png` | — |
| R4.3 块扩展 | [~] | 提示块、`[toc]`、front matter 框、嵌套列表标记、分隔线画出 | 同上 | — |
| R4.4 导出与复制一致 | [~] | 导出 HTML、纯文本、富文本与可视同一读法 | ElyMark 测试 | — |
| R4.5 按下与右键定位 | [~] | 按下块插入点落在所按处;右键事件带目标 | 组件测试;真窗口右键复制链接地址 | — |
| R4.6 行内格式命令 | [~] | Ctrl+B、Ctrl+Shift+`、Alt+Shift+5 包住所选,一步撤销 | 真窗口 `keys.txt`、`shifted.txt` | 128 KiB 内块极多时重读可占界面线程逾 100 毫秒;超过 128 KiB 的文件可视打开落在第 2 行 |
| R4.7 块命令 | [~] | Ctrl+1/0、Ctrl+Shift+[ ]、菜单“段落 › 标题 1” | 真窗口 `keys.txt`、`menus.txt`、`shifted.txt` | 列表与引用的切换不做写后重读核对 |
| R4.8 表格移动与整理 | [~] | Alt+↑ 移行、Alt+→ 移列,撤销两步还原 | 真窗口 `table.txt` | 编辑器本身仍按 LF 分行,文档层把 CR 与 LF 之间的位置挪到行尾 |
| R4.9 菜单与快捷键 | [x] | 段落、格式、视图菜单与键;F8、F9、缩放、Ctrl+/、Ctrl+Shift+C | 真窗口 `keys.txt`、截图 `menu-paragraph.png` | 见下“R4.11 查出” |
| R4.10 右键菜单 | [~] | 按目标变化;复制链接地址;中文菜单 | 真窗口 `menus.txt`、截图 `menu-right-*.png`、`zh-right.png` | 与内容完全相同的后来复制分不出,旧转换照样落下 |
| R4.12 单实例交文件 | [x] | 第二份交出文件即退出,第一份开新标签并到前台 | 真窗口 `.work/R4.12` | macOS 的 `one-instance.sh` 未在 Mac 上跑 |
| R4.13 中文显示 | [x] | 同一词一种字体;查找框、排序筛选、提示中文 | 真窗口 `zh-*.png` | LibreOffice 自己的文字仍为英文(界面语言固定英文) |
| R4.11 验收 | 本条 | 真窗口逐项操作;帮助、PRD、`agents.md` 随之 | 本表;`.work/R4.11` | 待审查 |
## R4.11 查出并已修
- 带 Shift 的标点键在真键盘上按不出:三端的 gpui 都把 Shift 加该键报成字符并去掉 Shift,R4.9 在 Windows 写的是键名。Ctrl+Shift+[ ] ` = -、Alt+Shift+5 改绑所出的字符;真窗口逐个按过(`shifted.txt`、`keys.txt`),Windows 键表测试在旧绑定上失败(`.work/R4.11/red-keys.log`)。
- Ctrl+Shift+0(实际大小)在 Windows 上收不到:中文输入法把它登记为热键(`HKCU\Control Panel\Input Method\Hot Keys\00000104`)。保留它,Windows 另绑 Ctrl+Shift+9,菜单显示后者;真窗口按过。
## 真窗口(Windows,2026-10-14)
脚本在 `.work/R4.11`(`keys.ps1`、`menus.ps1`、`shifted.ps1`、`table.ps1`、`zh.ps1`),以真键盘与鼠标事件驱动调试构建,保存后读文件字节、读 `look.json` 与剪贴板核对;每次运行前后备份并还原 ElyMark 的会话、最近、视图与设置文件。结果 21 项全部通过(`shifted.txt` 里一次 Alt+↑ 失败是脚本在未保存的标签上改写文件,ElyMark 正确拒绝重载;改用新开的文件后通过)。
未在真窗口核对:macOS 与 Linux;导出与打印的系统对话框(单测覆盖)。
## 执行纪律
| 要求 | 核对 |
| --- | --- |
| 任务清单落盘,按序完成 | `tasks/TASKS.md` R4.0–R4.13,自上而下;R4.12、R4.13 为用户插入的急件,先于 R4.10、R4.11 |
| 不用 worktree、分支、子 agent、并行 | 全程在 main 上一条一条做 |
| 每条 codex 审查(gpt-6-astra,max,fast),最多三轮 | `tasks/reviews/R4.*-r*.md` |
| 问题先修再复审,修复带回归测试 | 每轮的红绿日志在 `.work/R4.*-fix*` |
| 文件不超过 500 行,注释一行十字以内 | `tests/scripts/comments.py` 通过;R4 改动的文件都在 500 行内 |
| 推送 | 组件库各提交已推到 Gitea;ElyOffice 本地领先 origin 5 个提交,待用户允许推送 |
+1 -1
View File
@@ -244,7 +244,7 @@
- [x] R4.13 全部应用:中文显示(用户报,2026-10-14):Windows 上同一词里字形粗细不一(gpui 以 en-US 排版,汉字按日文回退);Ely 用到的组件里写死的英文改走中英目录;先于 R4.10 的修复做。第 1 轮未过(三项:排版语言不随 Ely 的中文设置、查找框英文、排序筛选英文),已修,见 `.work/R4.13-fix1`;第 2 轮通过。
- [~] R4.10 ElyMark:右键菜单照 Typora 按目标变化:剪贴板行(剪切、复制、粘贴、删除)、复制/粘贴为 ▸(Markdown、HTML 代码、纯文本、粘贴为纯文本)、格式行、段落 ▸ 或表格 ▸ 或代码项、插入 ▸、链接(打开、复制地址)、图片(打开所在位置、删除图片)、删除块;预览只读时只留复制类。第 1 轮未过(五项:保留选区时目标取选区起点、打开块里 HTML 链接读错、切回标签重开已关的菜单、复制为 HTML 与纯文本卡界面、长注释),已修,见 `.work/R4.10-fix1`。第 2 轮未过(三项:未完的转换盖掉之后的复制、长段落右键的目标查找为平方级、连续右键的目标次序颠倒),已修,见 `.work/R4.10-fix2`。第 3 轮未过(两项:纯文字相同而 HTML 不同的后来复制被转换盖掉、组件计时测试用了 std 的 Instant),三轮用尽,已修并有回归测试(红绿见 `.work/R4.10-fix3`),未再审
- [x] R4.12 全部应用:已开着时再打开文件,交给运行中的那份开成新标签并带到前台,不再弹“已在运行”(用户报,2026-10-14);先于 R4.11 做。第 1 轮 4 项:令牌被拒时连接重置使重试失效、慢速来者占住门、主窗口关后仍回执、ElyMail 与 ElyAgent 不到前台;已修,各有回归;第 2 轮通过
- [ ] R4.11 验收:真窗口逐项操作,每项功能可用(不求与 Typora 一一相同);帮助、PRD、`agents.md` 随之;逐条核对表
- [ ] R4.11 验收:真窗口逐项操作,每项功能可用(不求与 Typora 一一相同);帮助、PRD、`agents.md` 随之;逐条核对表。真窗口查出并修:带 Shift 的标点键按不出(改绑所出的字符)、Windows 中文输入法占用 Ctrl+Shift+0(另绑 Ctrl+Shift+9);核对表 `tasks/R4-acceptance.md`
## R5 ElyDoc 照 Word 的右键与表格(用户 2026-10-13 报:右键没反应;表格不能加行列、不能调大小;三项方案经用户确认)