diff --git a/crates/ely-lok/src/view/scroll.rs b/crates/ely-lok/src/view/scroll.rs index 89d7eee..f8219af 100644 --- a/crates/ely-lok/src/view/scroll.rs +++ b/crates/ely-lok/src/view/scroll.rs @@ -113,7 +113,18 @@ impl LokView { } // The kernel sizes a sheet in tile twips already. let reach = self.tile_of(self.reach); - (self.doc_size.0.max(reach.0), self.doc_size.1.max(reach.1)) + let (w, h) = (self.doc_size.0.max(reach.0), self.doc_size.1.max(reach.1)); + let Some(sheet) = &self.sheet else { + return (w, h); + }; + // Sheets scroll ahead of the kernel, to their end. + let end = self.tile_of((sheet.columns.start(sheet.columns.count()), sheet.rows.start(sheet.rows.count()))); + let (fx, fy) = self.frozen_tiles(); + let ahead = ( + fx + self.scroll.0 + 2 * self.geom.twips_of(self.viewport.0), + fy + self.scroll.1 + 2 * self.geom.twips_of(self.viewport.1), + ); + (w.max(ahead.0.min(end.0)), h.max(ahead.1.min(end.1))) } /// The print-twips document point under a view position (LOK-04). diff --git a/crates/ely-lok/src/view/tests/large.rs b/crates/ely-lok/src/view/tests/large.rs index 53c2c33..dd8ebb8 100644 --- a/crates/ely-lok/src/view/tests/large.rs +++ b/crates/ely-lok/src/view/tests/large.rs @@ -202,7 +202,8 @@ fn a_sheet_brings_far_cut_and_frozen_cells_into_view() { assert_eq!(view.spare, (0.0, 0.0), "and stays left after it"); let size = view.doc_size; view.doc_size = view.tile_of((view.print_of(size).0 + 20 * 1280, size.1)); - assert_eq!(view.extent(), view.doc_size, "the kernel's size is the extent, uncut"); + let extent = view.extent(); + assert!(extent.0 >= view.doc_size.0 && extent.1 >= view.doc_size.1, "the kernel's size is uncut"); view.doc_size = size; view.viewport = (800.0, 200.0); let (width, height) = (view.geom.twips_of(view.viewport.0), view.geom.twips_of(view.viewport.1)); @@ -440,3 +441,30 @@ fn the_first_size_has_a_scale_and_keeps_the_row() { let after = middle(&mut cx); assert!(before.abs_diff(after) <= 1, "row {before} became {after} when the first size landed"); } + +#[test] +fn an_empty_sheet_scrolls_on_without_waiting() { + let Some(install) = crate::client::tests::install() else { + eprintln!("SKIP: no pinned LOK build"); + return; + }; + let mut cx = gpui::TestAppContext::single(); + let (view, worker) = cx.update(|app| live_view_of(app, &install, "short.fods", SHORT_ROWS)); + let json = cx.update(|app| worker.lock().expect("the worker lock").values(&view.read(app).doc, crate::sheet::GEOMETRY).expect("geometry")); + let geometry = crate::sheet::geometry(&json).expect("parsed"); + let bounds = Bounds { origin: point(px(0.0), px(0.0)), size: size(px(400.0), px(200.0)) }; + cx.update(|app| view.update(app, |view, cx| { + view.set_geometry(geometry.clone(), cx); + view.prepare(bounds); + })); + // Each step a viewport down, before the kernel answers. + for step in 1..=20 { + let moved = cx.update(|app| view.update(app, |view, cx| { + let from = view.scroll.1; + view.scroll_by(0.0, -200.0, cx); + view.scroll.1 - from + })); + let full = cx.update(|app| view.read(app).geom.twips_of(200.0)); + assert_eq!(moved, full, "step {step} went the whole way"); + } +} diff --git a/tasks/BUGS.md b/tasks/BUGS.md index faf551c..3cd79bf 100644 --- a/tasks/BUGS.md +++ b/tasks/BUGS.md @@ -13,7 +13,7 @@ - [x] T-03 视口比工作表宽时网格先居中再左移一次 — 载入回复带文档种类,表格不居中;R1 测试漏几何到达前的首帧;R2 PASS - [x] T-04 从不调用 `setClientZoom`,内核命中与几何按默认缩放算 — R2.16 已修(worker 每次报可见区前 setClientZoom) - [x] T-05 文档尺寸按内核像素取整,表尾被裁 — 内核尺寸按其测量时的比例换到当前比例(加载即设比例、缩放即改比例并重测、迟到的测量也换算);R1–R4 缩放后未重测、表尾锚点被截、连续缩放迟到、首次测量无比例与文件超行;R5 PASS -- [ ] T-06 滚轮向下被内核平铺区卡住 +- [x] T-06 滚轮向下被内核平铺区卡住 — 表格的可滚范围先行两屏、止于表尾;R1 PASS - [x] T-07 表头点选、行高列宽拖动是“按编号的命令”,而每次点击与拖选都推进修订,紧接着的表头操作被当作过期拒绝 — 行列号不再算作按编号的命令;R1 PASS - [ ] T-08 自动筛选的列菜单对光标所在的表而不是按钮所在的表筛选、排序 - [ ] T-09 导入文本文件时整文件的 UTF-8 校验在界面线程跑 diff --git a/tasks/reviews/T-06-r1.md b/tasks/reviews/T-06-r1.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/T-06-r1.md @@ -0,0 +1 @@ +PASS