@@ -85,18 +85,34 @@ func installDefaultMenuBar(appName: String? = nil) {
8585private func buildAppMenu( appName: String ) -> NSMenuItem {
8686 let menu = NSMenu ( ) // title ignored for app menu
8787
88+ // --- appInfo ---
89+ let appInfoSentinel = NSMenuItem . separator ( )
90+ appInfoSentinel. tag = MenuPlacementTag . appInfo. rawValue
91+ menu. addItem ( appInfoSentinel)
92+
8893 menu. addItem ( withTitle: " About \( appName) " ,
8994 action: #selector( ActionUIApplicationDelegate . showAboutPanel ( _: ) ) ,
9095 keyEquivalent: " " )
9196
92- menu. addItem ( . separator( ) )
97+ // --- appSettings ---
98+ let appSettingsSentinel = NSMenuItem . separator ( )
99+ appSettingsSentinel. tag = MenuPlacementTag . appSettings. rawValue
100+ menu. addItem ( appSettingsSentinel)
101+
102+ // --- systemServices ---
103+ let systemServicesSentinel = NSMenuItem . separator ( )
104+ systemServicesSentinel. tag = MenuPlacementTag . systemServices. rawValue
105+ menu. addItem ( systemServicesSentinel)
93106
94107 let servicesMenu = NSMenu ( title: " Services " )
95108 let servicesItem = menu. addItem ( withTitle: " Services " , action: nil , keyEquivalent: " " )
96109 servicesItem. submenu = servicesMenu
97110 NSApp . servicesMenu = servicesMenu
98111
99- menu. addItem ( . separator( ) )
112+ // --- appVisibility ---
113+ let appVisibilitySentinel = NSMenuItem . separator ( )
114+ appVisibilitySentinel. tag = MenuPlacementTag . appVisibility. rawValue
115+ menu. addItem ( appVisibilitySentinel)
100116
101117 menu. addItem ( withTitle: " Hide \( appName) " ,
102118 action: #selector( NSApplication . hide ( _: ) ) ,
@@ -111,7 +127,10 @@ private func buildAppMenu(appName: String) -> NSMenuItem {
111127 action: #selector( NSApplication . unhideAllApplications ( _: ) ) ,
112128 keyEquivalent: " " )
113129
114- menu. addItem ( . separator( ) )
130+ // --- appTermination ---
131+ let appTerminationSentinel = NSMenuItem . separator ( )
132+ appTerminationSentinel. tag = MenuPlacementTag . appTermination. rawValue
133+ menu. addItem ( appTerminationSentinel)
115134
116135 menu. addItem ( withTitle: " Quit \( appName) " ,
117136 action: #selector( NSApplication . terminate ( _: ) ) ,
@@ -125,10 +144,30 @@ private func buildAppMenu(appName: String) -> NSMenuItem {
125144private func buildFileMenu( ) -> NSMenuItem {
126145 let menu = NSMenu ( title: " File " )
127146
147+ // --- New / Open / Open Recent group ---
148+ let newItemSentinel = NSMenuItem . separator ( )
149+ newItemSentinel. tag = MenuPlacementTag . newItem. rawValue
150+ menu. addItem ( newItemSentinel)
151+
152+ // --- Close / Save group ---
128153 menu. addItem ( withTitle: " Close " ,
129154 action: #selector( NSWindow . performClose ( _: ) ) ,
130155 keyEquivalent: " w " )
131156
157+ let saveItemSentinel = NSMenuItem . separator ( )
158+ saveItemSentinel. tag = MenuPlacementTag . saveItem. rawValue
159+ menu. addItem ( saveItemSentinel)
160+
161+ // --- Import / Export group ---
162+ let importExportSentinel = NSMenuItem . separator ( )
163+ importExportSentinel. tag = MenuPlacementTag . importExport. rawValue
164+ menu. addItem ( importExportSentinel)
165+
166+ // --- Print group ---
167+ let printItemSentinel = NSMenuItem . separator ( )
168+ printItemSentinel. tag = MenuPlacementTag . printItem. rawValue
169+ menu. addItem ( printItemSentinel)
170+
132171 let item = NSMenuItem ( )
133172 item. submenu = menu
134173 return item
@@ -137,6 +176,11 @@ private func buildFileMenu() -> NSMenuItem {
137176private func buildEditMenu( ) -> NSMenuItem {
138177 let menu = NSMenu ( title: " Edit " )
139178
179+ // --- undoRedo ---
180+ let undoRedoSentinel = NSMenuItem . separator ( )
181+ undoRedoSentinel. tag = MenuPlacementTag . undoRedo. rawValue
182+ menu. addItem ( undoRedoSentinel)
183+
140184 menu. addItem ( withTitle: " Undo " ,
141185 action: Selector ( ( " undo: " ) ) ,
142186 keyEquivalent: " z " )
@@ -146,7 +190,10 @@ private func buildEditMenu() -> NSMenuItem {
146190 keyEquivalent: " z " )
147191 redo. keyEquivalentModifierMask = [ . command, . shift]
148192
149- menu. addItem ( . separator( ) )
193+ // --- pasteboard ---
194+ let pasteboardSentinel = NSMenuItem . separator ( )
195+ pasteboardSentinel. tag = MenuPlacementTag . pasteboard. rawValue
196+ menu. addItem ( pasteboardSentinel)
150197
151198 menu. addItem ( withTitle: " Cut " ,
152199 action: #selector( NSText . cut ( _: ) ) ,
@@ -168,6 +215,16 @@ private func buildEditMenu() -> NSMenuItem {
168215 action: #selector( NSText . selectAll ( _: ) ) ,
169216 keyEquivalent: " a " )
170217
218+ // --- textEditing ---
219+ let textEditingSentinel = NSMenuItem . separator ( )
220+ textEditingSentinel. tag = MenuPlacementTag . textEditing. rawValue
221+ menu. addItem ( textEditingSentinel)
222+
223+ // --- textFormatting ---
224+ let textFormattingSentinel = NSMenuItem . separator ( )
225+ textFormattingSentinel. tag = MenuPlacementTag . textFormatting. rawValue
226+ menu. addItem ( textFormattingSentinel)
227+
171228 let item = NSMenuItem ( )
172229 item. submenu = menu
173230 return item
@@ -176,6 +233,11 @@ private func buildEditMenu() -> NSMenuItem {
176233private func buildWindowMenu( ) -> ( NSMenuItem , NSMenu ) {
177234 let menu = NSMenu ( title: " Window " )
178235
236+ // --- windowSize ---
237+ let windowSizeSentinel = NSMenuItem . separator ( )
238+ windowSizeSentinel. tag = MenuPlacementTag . windowSize. rawValue
239+ menu. addItem ( windowSizeSentinel)
240+
179241 menu. addItem ( withTitle: " Minimize " ,
180242 action: #selector( NSWindow . performMiniaturize ( _: ) ) ,
181243 keyEquivalent: " m " )
@@ -184,12 +246,24 @@ private func buildWindowMenu() -> (NSMenuItem, NSMenu) {
184246 action: #selector( NSWindow . performZoom ( _: ) ) ,
185247 keyEquivalent: " " )
186248
187- menu. addItem ( . separator( ) )
249+ // --- windowArrangement ---
250+ let windowArrangementSentinel = NSMenuItem . separator ( )
251+ windowArrangementSentinel. tag = MenuPlacementTag . windowArrangement. rawValue
252+ menu. addItem ( windowArrangementSentinel)
188253
189254 menu. addItem ( withTitle: " Bring All to Front " ,
190255 action: #selector( NSApplication . arrangeInFront ( _: ) ) ,
191256 keyEquivalent: " " )
192257
258+ // --- windowList / singleWindowList ---
259+ let windowListSentinel = NSMenuItem . separator ( )
260+ windowListSentinel. tag = MenuPlacementTag . windowList. rawValue
261+ menu. addItem ( windowListSentinel)
262+
263+ let singleWindowListSentinel = NSMenuItem . separator ( )
264+ singleWindowListSentinel. tag = MenuPlacementTag . singleWindowList. rawValue
265+ menu. addItem ( singleWindowListSentinel)
266+
193267 let item = NSMenuItem ( )
194268 item. submenu = menu
195269 return ( item, menu)
@@ -198,6 +272,11 @@ private func buildWindowMenu() -> (NSMenuItem, NSMenu) {
198272private func buildHelpMenu( appName: String ) -> ( NSMenuItem , NSMenu ) {
199273 let menu = NSMenu ( title: " Help " )
200274
275+ // --- help ---
276+ let helpSentinel = NSMenuItem . separator ( )
277+ helpSentinel. tag = MenuPlacementTag . help. rawValue
278+ menu. addItem ( helpSentinel)
279+
201280 menu. addItem ( withTitle: " \( appName) Help " ,
202281 action: #selector( NSApplication . showHelp ( _: ) ) ,
203282 keyEquivalent: " ? " )
@@ -297,9 +376,11 @@ private final class MenuActionTarget: NSObject {
297376
298377 @objc func performAction( _ sender: NSMenuItem ) {
299378 guard let actionID = actionIDsByTag [ sender. tag] else { return }
379+ // Resolve the front window's UUID so menu actions target the key window
380+ let windowUUID = keyWindowUUID ( )
300381 ActionUIModel . shared. actionHandler (
301382 actionID,
302- windowUUID: " " , // menu actions are not window-scoped
383+ windowUUID: windowUUID ,
303384 viewID: sender. tag,
304385 viewPartID: 0 ,
305386 context: nil
@@ -384,9 +465,15 @@ private func applyCommandMenu(properties: [String: Any],
384465 let menuItem = NSMenuItem ( )
385466 menuItem. submenu = menu
386467
387- // Insert before the Help menu (last item), or append if no items
388- let helpIndex = mainMenu. items. count > 0 ? mainMenu. items. count - 1 : 0
389- mainMenu. insertItem ( menuItem, at: helpIndex)
468+ // Insert before Window menu (or Help if no Window menu found).
469+ // This keeps Window and Help as the rightmost menus per macOS convention.
470+ var insertIndex = mainMenu. items. count
471+ if let windowIndex = mainMenu. items. firstIndex ( where: { $0. submenu? . title == " Window " } ) {
472+ insertIndex = windowIndex
473+ } else if let helpIndex = mainMenu. items. firstIndex ( where: { $0. submenu? . title == " Help " } ) {
474+ insertIndex = helpIndex
475+ }
476+ mainMenu. insertItem ( menuItem, at: insertIndex)
390477}
391478
392479// MARK: - CommandGroup application
0 commit comments