R7.2: the settings window draws no app menus or update banner

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-16 11:43:20 -04:00
1 parent b12858c7f0
commit 03e8e9bcb3
9 files changed
+88 -6

No files matched your search

+1
View File
@@ -309,3 +309,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
- 2026-10-15(用户报:macOS 打开一个文档,程序坞里有两个同样的图标):LOK worker 在应用包的 `Contents/MacOS` 里启动 AppKit,系统按包的 Info.plist 把它也登记为常规应用(`lsappinfo` 里应用与 worker 都是 Foreground),程序坞多一个图标;内核自己从不设激活策略。worker 在内核启动 AppKit 之前(`Lok::hook` 打开内核之后、调钩子之前)把本进程主包信息里的 `LSUIElement` 设为真,AppKit 登记时即为辅助应用(无程序坞图标、无菜单栏,仍可建屏外窗口);钩子之后核对激活策略是辅助,不是即报错、不启动(`ffi/accessory.rs`);包外的 worker(`cargo run`、单测)无包可登记,策略为禁止,此时改设辅助(R6.12 第 2 轮)。原先在登记之后才改策略,审查实测 15 次启动有 11 次先登记为 Foreground 约 30 毫秒(R6.12 第 1 轮)。`tests/scripts/dock-macos.sh` 连续启动三个应用与包外的开发构建,从 worker 启动起采样其类型到首块图块,见 Foreground 即失败(R6.12)。
- 2026-10-15(用户报:ElyShow 编辑区滚轮与上下键不换页,三端):内核在未选中对象时把上下键当作滚动窗口(`fupoor.cxx`),Ely 的画布整页适合、无处可滚,滚轮同样。`LokView::turn_parts`(ElyShow 首次适合时调用)之后:整页可见时滚轮换页(`view/turn.rs`):滚轮的行按本平台每格的行数(`ely_lok::notch`:macOS 1,Windows 取系统设置,X11 与 Wayland 为 3)折成格,整格的行每格一页(快速连滚与一次多格都照格数);一串行里出现不足一格的(X11、Windows 的触控板)即为平滑滚动,此后到停顿前不再换页,像素(macOS、Wayland 的触控板)同按手势:一次手势换一页(满一格或 50 像素),惯性不算;有起止的手势(macOS)只到结束才算完,没有起止的停 200 毫秒即为下一次。X11 的滚轮与触控板同为行、gpui 不分,以整格开头的触控板滑动在出现小数之前会按格换页(已知限制)。未选中对象、未编辑文字时上下键换页。换页一律经有序输入队列交 worker(`TURN`):worker 按之前各输入回报后的状态判定,有选区、选中对象或插入点即把方向键照常交内核,否则当场切页(到首末页即停,同缩略图条的 `setPart`),视图在落地时换上 worker 所示的页,其后排队的键与点按都落在新页上(Tab 后紧接的 Down 移动所选对象;Down、Tab、Down 是换页后在新页上选中并移动);ElyShow 后台读回的当前页只在视图已无待落地输入时采用(R6.13)。
- 2026-10-16(用户定):合集安装包(R7.1)。macOS 一个公证的 `ElyOffice-<版本>-<架构>.dmg`,装首批六个已签名的 .app 与“应用程序”替身,用户拖入所要的(`release.sh` 的 `dmg` 与单个应用共用);无 Developer ID Installer 证书,不出 .pkg。Windows 一个 `ElyOffice-<版本>-windows-x86_64-setup.exe`(`packaging/windows/bundle.nsi`),组件页勾选应用,所选的各自的安装程序以 `/S` 运行,所以装法、位置、升级、卸载项与单装完全相同;某个退出码非零即停下并写明其名与退出码(2 为文件被占用或位置被占),之前装上的照旧。Linux 不出合集。单个应用的包、更新清单照旧。
- 2026-10-16(Gitea #6):设置窗口多出一行应用菜单(R7.2)。设置窗口沿用主窗口的外壳 `Shell`,Windows 与 Linux 上随之画出菜单栏(macOS 菜单在系统菜单栏,不受影响)与更新横幅。菜单栏与更新横幅只属主窗口:`Shell::secondary` 去掉两者,设置窗口用它;`settings/tests.rs` 量内容起点距标题栏底:只装菜单时主窗口大于零(macOS 为零),再有待下载的新版时更大,设置窗口为零。
+41
View File
@@ -53,3 +53,44 @@ fn each_app_shows_its_own_sections(cx: &mut TestAppContext) {
assert_eq!(shown, keys, "{app:?}");
}
}
/// A main window's frame.
struct Main(gpui::FocusHandle);
impl gpui::Render for Main {
fn render(&mut self, _: &mut gpui::Window, _: &mut gpui::Context<Self>) -> impl gpui::IntoElement {
crate::shell::Shell::new("main", &self.0)
}
}
/// How far below the title bar the content starts.
fn below_title(cx: &mut TestAppContext, window: gpui::AnyWindowHandle) -> gpui::Pixels {
let mut shown = gpui::VisualTestContext::from_window(window, cx);
for _ in 0..3 {
shown.update(|window, _| window.refresh());
shown.run_until_parked();
}
let title = shown.debug_bounds("shell-title").expect("a title bar");
shown.debug_bounds("shell-body").expect("a body").origin.y - title.bottom()
}
#[gpui::test]
fn only_the_main_window_carries_menus_and_updates(cx: &mut TestAppContext) {
installed(cx);
cx.update(|cx| {
let menus = crate::commands::menus(AppId::Mark, &crate::commands::OPENING, false, Vec::new(), cx);
cx.set_menus(menus);
});
let main = cx.add_window(|_, cx| Main(cx.focus_handle()));
let menus = below_title(cx, main.into());
// macOS keeps menus in the system bar.
match cfg!(target_os = "macos") {
true => assert_eq!(menus, gpui::px(0.0), "no menu row on macOS"),
false => assert!(menus > gpui::px(0.0), "the main window shows the menus"),
}
cx.update(crate::updates::offer_for_tests);
let main = cx.add_window(|_, cx| Main(cx.focus_handle()));
assert!(below_title(cx, main.into()) > menus, "the main window shows the update");
let settings = cx.add_window(|window, cx| SettingsView::new(AppId::Mark, window, cx));
assert_eq!(below_title(cx, settings.into()), gpui::px(0.0), "settings repeats neither");
}
+1
View File
@@ -353,6 +353,7 @@ impl Render for SettingsView {
})
.collect();
Shell::new(text(cx, "settings.title", &[]), &self.focus)
.secondary()
.child(div().size_full().p_6().flex().flex_col().gap_4().children(unreadable).children(app_error).children(unsaved).child(layout))
.children(dialog)
}
+18 -5
View File
@@ -10,8 +10,8 @@ use ely_gpui_component::{
theme::{ActiveTheme, TextSize},
};
use gpui::{
AnyElement, AnyView, App, ElementId, FocusHandle, IntoElement, ParentElement, RenderOnce,
SharedString, Styled, Window, div,
AnyElement, AnyView, App, ElementId, FocusHandle, InteractiveElement, IntoElement,
ParentElement, RenderOnce, SharedString, Styled, Window, div,
};
mod page;
@@ -32,6 +32,7 @@ pub struct Shell {
right: Option<AnyView>,
status: Option<StatusBar>,
page: Option<ElementId>,
main: bool,
body: Vec<AnyElement>,
}
@@ -45,10 +46,17 @@ impl Shell {
right: None,
status: None,
page: None,
main: true,
body: Vec::new(),
}
}
/// Beside the main window: no menus, no update banner.
pub fn secondary(mut self) -> Self {
self.main = false;
self
}
pub fn tabs(mut self, tabs: EditorTabs) -> Self {
self.tabs = Some(tabs);
self
@@ -98,6 +106,7 @@ impl RenderOnce for Shell {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let length = motion::duration(motion::BASE, cx);
let content = div()
.debug_selector(|| "shell-body".into())
.flex_1()
.min_w_0()
.h_full()
@@ -123,9 +132,13 @@ impl RenderOnce for Shell {
let header = div()
.flex()
.flex_col()
.child(TitleBar::new("titlebar").title(self.title))
.children(crate::updates::updater(cx))
.children(menu_bar(cx))
.child(
div()
.debug_selector(|| "shell-title".into())
.child(TitleBar::new("titlebar").title(self.title)),
)
.children(self.main.then(|| crate::updates::updater(cx)).flatten())
.children(self.main.then(|| menu_bar(cx)).flatten())
.children(self.tabs);
// Panels give way so the content keeps its room.
let (left, right) = (panel::fitted(Side::Left, window, cx), panel::fitted(Side::Right, window, cx));
+19
View File
@@ -359,6 +359,25 @@ impl Render for Updates {
}
}
/// An offered release, for window tests.
#[cfg(test)]
pub(crate) fn offer_for_tests(cx: &mut App) {
let release = Release {
version: semver::Version::new(9, 0, 0),
url: "https://example.test/9.dmg".into(),
sha256: String::new(),
};
let updates = cx.new(|_| Updates {
app: AppId::Mark,
bundle: PathBuf::new(),
offer: Some((release, Phase::Offered)),
dismissed: false,
pending: None,
note: None,
});
cx.set_global(Updater(updates));
}
#[cfg(test)]
mod tests {
use super::*;
+1 -1
View File
@@ -277,7 +277,7 @@
## R7 0.1.6(用户 2026-10-16 定:Gitea #3 至 #6 与 ElyMark 正文块;合集安装包;修完发 0.1.6,逐条答复,功能建议另开 [FEATURE REQUEST])
- [x] R7.1 合集安装包(§4,用户定):macOS 一个公证的 dmg 装六个 .app 与“应用程序”替身,用户拖入所要的;Windows 一个安装程序,组件页勾选六个应用,每个与单独安装程序装得一样;Linux 不做合集;单个应用的包照旧(`release.sh` 的 `dmg` 单个与合集共用,Mac mini 上以两个假应用核对卷内内容;`bundle.nsi` 逐个以 `/S` 运行所选的安装程序,某个退出码非零即停下并写明;`windows-bundle.sh` 三个假应用:都装上,第二个被拒时退出码 2、第三个不运行;真包随 R7.7 建出 — 第 1 轮:被拒的是最后一个,去掉 `Abort` 测试仍过;加第三个应用后去掉即失败;第 2 轮 PASS)
- [ ] R7.2 设置窗口多出一行应用菜单(#6,§5):设置窗口沿用主窗口的外壳 `Shell`,Windows 与 Linux 上随之画出菜单栏与更新横幅;设置窗口不画这两者
- [x] R7.2 设置窗口多出一行应用菜单(#6,§5):设置窗口沿用主窗口的外壳 `Shell`,Windows 与 Linux 上随之画出菜单栏与更新横幅;设置窗口不画这两者(`Shell::secondary`;测试量内容起点距标题栏底,五种变体各自失败 — 第 1 轮:只查标记容器;第 2 轮:主窗口两者合计;第 3 轮 PASS)
- [ ] R7.3 装了宋体仍报缺少(#4,§7、§8):内核按 `宋体` 找到 SimSun,缺字检查却比较原名与所用字体的英文名,报为缺失;查明 Linux 上的版面是否真用 SimSun,一页变两页的根因
- [ ] R7.4 打开 PDF 总说已损坏(#5,§11):画图块时 MuPDF 的任何警告都算损坏,未嵌入的中日韩字体(“non-embedded font using identity encoding”)即触发;损坏只认结构修复、读不出的对象与流、画不出的图片与内容
- [ ] R7.5 ElyMark 打开的正文块变成一块深色框(§14,用户定):按下的段落保持原样,不加底色与内边距,不挪位置;代码块仍有自己的底板
+3
View File
@@ -0,0 +1,3 @@
FAIL
crates/ely-ui/src/settings/tests.rs:72 — 回归测试只断言 `shell-menus` 标记容器是否存在,没有检查实际菜单,也没有安装带可见更新状态的 updater,因而不能验证 R7.2 要求隐藏的两种控件。具体复现:在隔离副本中保留该容器及其 `self.main` 条件,把 `.children(crate::updates::updater(cx))` 和 `.children(menu_bar(cx))` 移回无条件绘制的 header,设置窗口便恢复重复菜单,并会在有更新时显示横幅,但新增测试及全部 41 个 ely-ui 单元测试仍通过(原代码的 `cargo test -p ely-ui --lib` 也为 41 项通过;证据在 `.work/R7.2-r1-review/mutation.diff.log` 与 `mutation-test.log`)。修复方向:断言实际菜单内容,并注入可见更新状态,分别核对主窗口保留、设置窗口隐藏;恢复任一控件时对应测试必须失败。
+3
View File
@@ -0,0 +1,3 @@
FAIL
crates/ely-ui/src/settings/tests.rs:85 — 主窗口断言只要求标题下方的总间距大于零,菜单和更新横幅任留一个即可通过,仍未落实第 1 轮要求的“主窗口分别保留两者”。设置窗口恢复任一控件现在确实会使测试失败,但在 Windows 的隔离副本中,分别删除 `shell/mod.rs:140` 的 updater 子节点或 `:141` 的菜单子节点,主窗口分别失去更新下载入口或整行应用菜单,每种变体的全部 41 项测试仍通过。原树的 `cargo build -p ely-ui` 与 `cargo test -p ely-ui --lib` 均通过;变体证据在 `.work/R7.2-r2-review/main-update-removed-test.log`、`main-menu-removed-test.log` 及对应的 `.diff.log`,副本与构建目录已删除。修复方向:分别验证主窗口实际渲染菜单和更新横幅,例如分开设置菜单与更新状态后各自断言;删除任一控件必须使对应测试失败,不能以两者合计的间距代替。
+1
View File
@@ -0,0 +1 @@
PASS