Skip to main content

Mountain/Binary/Build/
AppMenu.rs

1//! macOS application menu - Edit submenu without Undo/Redo.
2//!
3//! Tauri's `Builder::default()` on macOS installs the standard AppKit menu
4//! bar, which includes `Edit → Undo (Cmd+Z)` and `Edit → Redo (Cmd+Shift+Z)`.
5//! These native items intercept Cmd+Z at the macOS responder-chain level
6//! *before* the WKWebView's JavaScript keydown handler fires, so VS Code's
7//! Monaco editor never sees the event - the native WKWebView text-buffer undo
8//! runs instead, and nothing happens visually (Monaco's undo stack is
9//! untouched). Ctrl+Z reaches the JS layer because no native menu binds it.
10//!
11//! Removing Undo/Redo from the native Edit menu lets Cmd+Z pass through to
12//! the WKWebView's keydown handler where VS Code registers `meta+z` → undo.
13//! Cut/Copy/Paste/SelectAll stay as predefined items so native text fields
14//! (e.g., address bar inputs) keep working correctly.
15//!
16//! On Windows / Linux, no menu override is applied - those platforms do not
17//! have the same WKWebView responder-chain interception.
18
19use crate::dev_log;
20
21/// Install a custom app menu on `App`, removing Undo/Redo from the Edit
22/// submenu so Cmd+Z reaches VS Code's Monaco keybinding handler.
23///
24/// Called once from `AppLifecycleSetup` immediately after the main window
25/// is built. A failure here is non-fatal (logs a warning and skips the
26/// override so the default menu remains).
27#[cfg(target_os = "macos")]
28pub fn SetAppMenu(App:&tauri::App) {
29	use tauri::menu::{MenuBuilder, SubmenuBuilder};
30
31	let Result = (|| -> Result<(), Box<dyn std::error::Error>> {
32		// Build Edit submenu: Cut / Copy / Paste / ── / Select All.
33		// Undo and Redo are intentionally absent so Cmd+Z and Cmd+Shift+Z
34		// reach the WKWebView JS layer where Monaco handles them.
35		// `.cut()/.copy()/.paste()/.separator()/.select_all()` are the
36		// infallible convenience methods on SubmenuBuilder (return Self).
37		let EditSubmenu = SubmenuBuilder::new(App, "Edit")
38			.cut()
39			.copy()
40			.paste()
41			.separator()
42			.select_all()
43			.build()?;
44
45		// MenuBuilder automatically prepends the macOS App menu (About,
46		// Services, Hide, Quit etc.) as the first entry when running on
47		// macOS, so we only need to append the submenus we care about.
48		// `.item()` on MenuBuilder also returns Self (infallible).
49		let Menu = MenuBuilder::new(App).item(&EditSubmenu).build()?;
50
51		App.set_menu(Menu)?;
52
53		dev_log!(
54			"lifecycle",
55			"[UI] [Menu] macOS Edit menu set (Undo/Redo removed; Cmd+Z routes to Monaco)."
56		);
57
58		Ok(())
59	})();
60
61	if let Err(Error) = Result {
62		dev_log!(
63			"lifecycle",
64			"warn: [UI] [Menu] Failed to override macOS app menu ({}); default menu retained - Cmd+Z may trigger \
65			 native undo instead of Monaco undo.",
66			Error
67		);
68	}
69}
70
71/// No-op on non-macOS platforms - the Edit menu interception is macOS-specific.
72#[cfg(not(target_os = "macos"))]
73pub fn SetAppMenu(_App:&tauri::App) {}