From 498d9aaa9bf5d327e3929a87f97f3f0b9f0f6b6f Mon Sep 17 00:00:00 2001 From: dhruvLearner8 <83899022+dhruvLearner8@users.noreply.github.com> Date: Sun, 18 Oct 2026 02:21:05 -0600 Subject: [PATCH] Context menu: Remove Table of Contents on a TOC entry (#2179) (#2217) --- crates/ui-egui/src/canvas.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 884a68621..ec1e4e752 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -2990,6 +2990,7 @@ fn context_menu(app: &mut WordApp, ui: &mut Ui) { // The TOC field sits in the table's heading; its entries are plain paragraphs. ui.separator(); item(ui, app, tl!("Update Field"), "references.updateToc", json!({})); + item(ui, app, tl!("Remove Table of Contents"), "references.removeToc", json!({})); } let selected_object = wordcraft_engine::cmd::objects::selected(&app.session).is_some(); if selected_object || app.session.sel.focus.path.cell().is_some() { @@ -4105,6 +4106,41 @@ mod tests { assert_eq!(text.matches("Fresh heading").count(), 2, "the new heading is listed in the table: {text}"); } + /// #2179: the context menu on a table of contents entry also offers Remove Table of Contents. + #[test] + fn context_menu_on_a_toc_entry_removes_the_table() { + use egui_kittest::kittest::Queryable; + let mut a = WordApp::new(wordcraft_engine::Session::new(wordcraft_engine::sample::report()), Default::default()); + a.run("caret.docStart", json!({})).unwrap(); + a.run("references.toc", json!({})).unwrap(); + let is_entry = |b: &wordcraft_doc::Block| b.as_para().is_some_and(|p| p.props.style.as_deref() == Some("TOC1")); + let entry = a.session.doc.body.iter().position(|b| is_entry(b)).expect("a TOC entry"); + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1440.0, 900.0)).build_ui_state( + |ui, app: &mut WordApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + a, + ); + for _ in 0..6 { + h.step(); + } + let c = h.state_mut().session.layout().caret(&Pos::body(entry, 2)).expect("the entry is laid out"); + let at = page_to_screen(h.state_mut(), c.page, c.x + 1.0, c.top + c.height / 2.0).expect("on screen"); + h.event(egui::Event::PointerMoved(at)); + for pressed in [true, false] { + h.event(egui::Event::PointerButton { pos: at, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() }); + h.step(); + } + h.step(); + h.get_by_label_contains("Remove Table of Contents").click(); + for _ in 0..3 { + h.step(); + } + assert!(!h.state().session.doc.body.iter().any(|b| is_entry(b)), "the table is gone"); + } + /// #996: on macOS a Control-click is the right-click (the trackpad's and the one-button /// mouse's way to it), so it opens the same menu and leaves the caret where the menu needs it. #[cfg(target_os = "macos")]