From 554019cdd582207835a2f895344483389a016cb0 Mon Sep 17 00:00:00 2001 From: noah1400 <48360809+noah1400@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:32:16 +0200 Subject: [PATCH] Tables: table.options limits header and footer rows (#861) table.options added as many rows as the requested header and footer counts needed, without a limit. A large number typed into the Table panel's Header Rows field froze the app and exhausted memory. Both counts are now capped at 100, the limit table.insert already has. --- crates/engine/src/cmd/table.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/table.rs b/crates/engine/src/cmd/table.rs index ad306be8e..7851ab858 100644 --- a/crates/engine/src/cmd/table.rs +++ b/crates/engine/src/cmd/table.rs @@ -931,8 +931,9 @@ fn options(s: &mut Session, p: &Value) -> Result { if let Some(v) = p.get("altCols") { o.alt_cols = parse_alt(v); } - let h = p.get("headerRows").and_then(Value::as_u64).map(|v| v as usize); - let f = p.get("footerRows").and_then(Value::as_u64).map(|v| v as usize); + // At most 100 of each, as in `table.insert`: the rows the table lacks are added below. + let h = p.get("headerRows").and_then(Value::as_u64).map(|v| v.min(100) as usize); + let f = p.get("footerRows").and_then(Value::as_u64).map(|v| v.min(100) as usize); if h.is_some() || f.is_some() { let (h, f) = (h.unwrap_or(t.header_rows()), f.unwrap_or(t.footer_rows())); // Add rows when there aren't enough for the requested header/footer plus one body row. @@ -1680,6 +1681,19 @@ mod sort_tests { s.execute("table.moveColumn", &json!({"from": 1, "to": 0})).unwrap(); assert_eq!((cell(&s, 2, 0), cell(&s, 2, 1)), ("x".to_string(), "a".to_string())); } + + #[test] + fn table_options_limits_header_and_footer_rows() { + let mut s = Session::new(); + s.execute("file.new", &json!({})).unwrap(); + let r = s.execute("frame.create", &json!({"rect": [72, 72, 500, 700], "content": "text", "text": ""})).unwrap(); + s.execute("text.select", &json!({"story": r["story"], "anchor": 0, "focus": 0})).unwrap(); + s.execute("table.insert", &json!({"rows": 2, "cols": 2})).unwrap(); + // The limit `table.insert` has: the table used to grow by as many rows as were asked for. + s.execute("table.options", &json!({"headerRows": 5000, "footerRows": 5000})).unwrap(); + let t = table(&s); + assert_eq!((t.header_rows(), t.footer_rows(), t.nrows()), (100, 100, 201)); + } } #[cfg(test)]