@@ -233,53 +233,77 @@ public final class AppKitBackend: AppBackend {
233233 return appMenu
234234 }
235235
236+ /// A vessel for empty methods that we use to construct selectors. We only
237+ /// do it this way, because Swift complains if we provide method selectors
238+ /// such as `undo:` and `redo:` as strings (even though they don't come
239+ /// from any particular class as far as I can tell).
240+ ///
241+ /// I've failed to find which class (if any) these methods are supposed to
242+ /// come from, and the following Apple documentation article makes it sound
243+ /// like undo and redo are just stringly-typed objc messages:
244+ /// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/UndoArchitecture/Articles/AppKitUndo.html
245+ class FirstResponder {
246+ /// I'm not sure exactly what type this first argument is meant to have,
247+ /// but I believe that it actually doesn't matter, because the number
248+ /// of parameters (and their corresponding labels) are what actually matter.
249+ @objc func undo( _ sender: NSObject ) { }
250+ @objc func redo( _ sender: NSObject ) { }
251+ }
252+
236253 public static func createDefaultEditMenu( ) -> NSMenu {
237- let appMenu = NSMenu ( title: " Edit " )
238- let undoItem = appMenu. addItem (
254+ // You may notice that multiple different base types are used in the
255+ // action selectors of the various menu items. This is because the
256+ // selectors get sent to the app's first responder at the time of
257+ // the command getting sent. If the first responder doesn't have a
258+ // method matching the selector, then AppKit automatically disables
259+ // the corresponding menu item.
260+
261+ let editMenu = NSMenu ( title: " Edit " )
262+ let undoItem = editMenu. addItem (
239263 withTitle: " Undo " ,
240- action: " undo: " ,
264+ action: #selector ( FirstResponder . undo ( _ : ) ) ,
241265 keyEquivalent: " z "
242266 )
243267 undoItem. keyEquivalentModifierMask = . command
244268
245- let redoItem = appMenu . addItem (
269+ let redoItem = editMenu . addItem (
246270 withTitle: " Redo " ,
247- action: " redo: " ,
271+ action: #selector ( FirstResponder . redo ( _ : ) ) ,
248272 keyEquivalent: " z "
249273 )
250274 redoItem. keyEquivalentModifierMask = [ . command, . shift]
251275
252- appMenu . addItem ( NSMenuItem . separator ( ) )
276+ editMenu . addItem ( NSMenuItem . separator ( ) )
253277
254- let cutItem = appMenu . addItem (
278+ let cutItem = editMenu . addItem (
255279 withTitle: " Cut " ,
256- action: " cut: " ,
280+ action: #selector ( NSTextView . cut) ,
257281 keyEquivalent: " x "
258282 )
259283 cutItem. keyEquivalentModifierMask = . command
260284
261- let copyItem = appMenu . addItem (
285+ let copyItem = editMenu . addItem (
262286 withTitle: " Copy " ,
263- action: " copy: " ,
287+ action: #selector ( NSTextView . copy) ,
264288 keyEquivalent: " c "
265289 )
266290 copyItem. keyEquivalentModifierMask = . command
267291
268- let pasteItem = appMenu . addItem (
292+ let pasteItem = editMenu . addItem (
269293 withTitle: " Paste " ,
270- action: " paste: " ,
294+ action: #selector ( NSTextView . paste) ,
271295 keyEquivalent: " v "
272296 )
273297 pasteItem. keyEquivalentModifierMask = . command
274298
275- let selectAllItem = appMenu . addItem (
299+ let selectAllItem = editMenu . addItem (
276300 withTitle: " Select all " ,
277- action: " selectAll: " ,
301+ action: #selector ( NSTextView . selectAll) ,
278302 keyEquivalent: " a "
279303 )
280304 selectAllItem. keyEquivalentModifierMask = . command
281305
282- return appMenu
306+ return editMenu
283307 }
284308
285309 public func setApplicationMenu( _ submenus: [ ResolvedMenu . Submenu ] ) {
0 commit comments