ElyTable: a sheet starts at the left, even before its geometry arrives (T-03)

This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 10:16:11 -04:00
1 parent ecf977364b
commit a6d8a1de43
8 files changed
+43 -10

No files matched your search

+13 -4
View File
@@ -73,9 +73,16 @@ pub struct Doc {
id: u64,
/// The document's revision when this handle was taken.
pub(crate) rev: u64,
/// LOK_DOCTYPE: 0 text, 1 spreadsheet, 2 presentation.
kind: u64,
}
impl Doc {
/// Whether this is a spreadsheet.
pub fn is_sheet(&self) -> bool {
self.kind == 1
}
/// Whether this handle saw a later state than `other`.
pub fn newer_than(&self, other: &Doc) -> bool {
self.rev > other.rev
@@ -217,9 +224,10 @@ impl Worker {
pack.u64(at(COLUMNS.iter().position(|c| c == column)))
});
let payload = self.request(tag::IMPORT, &pack.bytes())?;
let id = Unpack::new(&payload).u64()?;
let mut reply = Unpack::new(&payload);
let (id, kind) = (reply.u64()?, reply.u64()?);
self.feed.opened(id);
Ok(Doc { worker: self.session, id, rev: 0 })
Ok(Doc { worker: self.session, id, rev: 0, kind })
}
/// Loads `url` with its password; a locked one is PermissionDenied.
@@ -232,9 +240,10 @@ impl Worker {
error
}
})?;
let id = Unpack::new(&payload).u64()?;
let mut reply = Unpack::new(&payload);
let (id, kind) = (reply.u64()?, reply.u64()?);
self.feed.opened(id);
Ok(Doc { worker: self.session, id, rev: 0 })
Ok(Doc { worker: self.session, id, rev: 0, kind })
}
/// Runs a macro by its URL (LOK-11 probe).
+3 -3
View File
@@ -181,17 +181,17 @@ mod tests {
};
feed.push(1, first);
feed.push(1, second);
let batch = feed.wait(&Doc { worker: 0, id: 1, rev: 0 }, 0, 0).expect("a batch");
let batch = feed.wait(&Doc { worker: 0, id: 1, rev: 0, kind: 0 }, 0, 0).expect("a batch");
assert_eq!((batch.seq, batch.all, batch.rects.len()), (2, true, 1));
assert_eq!(
batch.states,
[("b".to_string(), "1".to_string()), ("a".into(), "2".into())]
);
let idle = feed.wait(&Doc { worker: 0, id: 1, rev: 0 }, 2, 0).expect("the snapshot");
let idle = feed.wait(&Doc { worker: 0, id: 1, rev: 0, kind: 0 }, 2, 0).expect("the snapshot");
assert!(idle.rects.is_empty() && idle.states.is_empty() && idle.seq == 2);
feed.closed(1);
assert!(
feed.wait(&Doc { worker: 0, id: 1, rev: 0 }, 2, 0).is_err(),
feed.wait(&Doc { worker: 0, id: 1, rev: 0, kind: 0 }, 2, 0).is_err(),
"a closed document"
);
}
+4
View File
@@ -251,6 +251,10 @@ impl LokView {
/// Room beside a narrow document, which sits centred.
pub(super) fn slack(&self) -> (f32, f32) {
// A sheet's grid grows with the view; it starts left.
if self.doc.is_sheet() {
return (0.0, 0.0);
}
let extent = self.extent();
let slack = |view: f32, doc: i32| (view - self.geom.px_of(doc)).max(0.0) / 2.0;
// A fitted page sits centred both ways.
+5
View File
@@ -186,7 +186,12 @@ fn a_sheet_brings_far_cut_and_frozen_cells_into_view() {
let (view, worker) = live_view_of(app, &install, "short.fods", SHORT_ROWS);
let json = worker.lock().expect("the worker lock").values(&view.read(app).doc, crate::sheet::GEOMETRY).expect("geometry");
view.update(app, |view, cx| {
let wide = Bounds { origin: point(px(0.0), px(0.0)), size: size(px(6000.0), px(200.0)) };
view.prepare(wide);
assert_eq!(view.spare, (0.0, 0.0), "before its geometry a sheet starts left");
view.set_geometry(crate::sheet::geometry(&json).expect("parsed"), cx);
view.prepare(wide);
assert_eq!(view.spare, (0.0, 0.0), "and stays left after it");
view.viewport = (800.0, 200.0);
let (width, height) = (view.geom.twips_of(view.viewport.0), view.geom.twips_of(view.viewport.1));
let shows = |view: &LokView, rect: crate::Rect| {
+8 -2
View File
@@ -187,8 +187,8 @@ fn answer(lok: &Lok, tag: u8, id: u64, payload: &[u8]) {
.str()
.and_then(|url| Ok((url, unpack.str()?)))
.and_then(|(url, password)| load(lok, &url, password, ""))
.map(|id| Pack::new().u64(id).bytes()),
tag::IMPORT => text::import(lok, unpack).map(|id| Pack::new().u64(id).bytes()),
.and_then(loaded),
tag::IMPORT => text::import(lok, unpack).and_then(loaded),
tag::EXPORT_TEXT => text::export(unpack).map(|()| Vec::new()),
tag::DOC_SIZE => unpack
.u64()
@@ -339,6 +339,12 @@ fn load(lok: &Lok, url: &str, password: String, filter: &str) -> io::Result<u64>
Ok(id)
}
/// The reply to a load: the number and LOK_DOCTYPE.
fn loaded(id: u64) -> io::Result<Vec<u8>> {
let kind = with_doc(id, |doc| doc.kind())?;
Ok(Pack::new().u64(id).u64(kind as u64).bytes())
}
/// Stops watching and frees document `id`.
fn close(id: u64) {
let mut docs = docs().lock().expect("the docs lock");
+6 -1
View File
@@ -4,7 +4,7 @@
- [x] T-01 内核的图块与命中按像素网格,Ely 的光标、选区、表头按文档 twips,越远越错位 — R2.16 已修(图块 twips 与打印 twips 互换)
- [x] T-02 单元格光标露出边缘即把视图滚到中央,点击与拖选时视图跳动 — R1 拖选中仍滚、超宽格跳回起点;R2 PASS
- [ ] T-03 视口比工作表宽时网格先居中再左移一次
- [x] T-03 视口比工作表宽时网格先居中再左移一次 — 载入回复带文档种类,表格不居中;R1 测试漏几何到达前的首帧;R2 PASS
- [x] T-04 从不调用 `setClientZoom`,内核命中与几何按默认缩放算 — R2.16 已修(worker 每次报可见区前 setClientZoom)
- [ ] T-05 文档尺寸按内核像素取整,表尾被裁
- [ ] T-06 滚轮向下被内核平铺区卡住
@@ -95,3 +95,8 @@
- [ ] X-12 恢复路径在界面线程做文件 I/O
- [ ] X-13 非 macOS 构建里仍提供只会报“未构建”的入口
- [ ] X-14 `agents.md` 引用的 `docs/engineering-risks.md` 不存在
## 0.1.2 发布
- [ ] REL-1 dmg 里有指向“应用程序”的快捷方式,可直接拖入安装(用户 2026-10-09 报)
- [ ] REL-2 修完上列各条后打包、发布 0.1.2,官网指向新发布页
+3
View File
@@ -0,0 +1,3 @@
FAIL
crates/ely-lok/src/view/tests/large.rs:189 — T-03 回归测试遗漏几何数据到达前的首次绘制。测试先调用 set_geometry,再准备宽视口,因此允许依赖几何就绪的实现通过。具体复现:在隔离副本中将 render.rs:255 的 self.doc.is_sheet() 改成 self.sheet.is_some(),现有 a_sheet_brings_far_cut_and_frozen_cells_into_view 仍通过;对同一 short.fods 在 set_geometry 前绘制 6000×200 视口,首块原点从应有的 (10,20) 变成 (2123.5667,20),横向偏移 2113.5667 像素。ElyTable 的几何由 book.rs 的 reread 异步读取,这个首帧窗口对应实际加载路径。恢复原实现后,同一首帧探针通过。修复方向:在 set_geometry 前加入宽视口首帧断言,核对首块的实际绘制位置和命中坐标;几何到达后再次核对位置稳定。证据:/tmp/ely-t03-mutant-late.log、/tmp/ely-t03-firstframe-mutant.log、/tmp/ely-t03-firstframe-baseline.log。
+1
View File
@@ -0,0 +1 @@
PASS