@@ -233,53 +233,77 @@ public final class AppKitBackend: AppBackend {
233
233
return appMenu
234
234
}
235
235
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
+
236
253
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 (
239
263
withTitle: " Undo " ,
240
- action: " undo: " ,
264
+ action: #selector ( FirstResponder . undo ( _ : ) ) ,
241
265
keyEquivalent: " z "
242
266
)
243
267
undoItem. keyEquivalentModifierMask = . command
244
268
245
- let redoItem = appMenu . addItem (
269
+ let redoItem = editMenu . addItem (
246
270
withTitle: " Redo " ,
247
- action: " redo: " ,
271
+ action: #selector ( FirstResponder . redo ( _ : ) ) ,
248
272
keyEquivalent: " z "
249
273
)
250
274
redoItem. keyEquivalentModifierMask = [ . command, . shift]
251
275
252
- appMenu . addItem ( NSMenuItem . separator ( ) )
276
+ editMenu . addItem ( NSMenuItem . separator ( ) )
253
277
254
- let cutItem = appMenu . addItem (
278
+ let cutItem = editMenu . addItem (
255
279
withTitle: " Cut " ,
256
- action: " cut: " ,
280
+ action: #selector ( NSTextView . cut) ,
257
281
keyEquivalent: " x "
258
282
)
259
283
cutItem. keyEquivalentModifierMask = . command
260
284
261
- let copyItem = appMenu . addItem (
285
+ let copyItem = editMenu . addItem (
262
286
withTitle: " Copy " ,
263
- action: " copy: " ,
287
+ action: #selector ( NSTextView . copy) ,
264
288
keyEquivalent: " c "
265
289
)
266
290
copyItem. keyEquivalentModifierMask = . command
267
291
268
- let pasteItem = appMenu . addItem (
292
+ let pasteItem = editMenu . addItem (
269
293
withTitle: " Paste " ,
270
- action: " paste: " ,
294
+ action: #selector ( NSTextView . paste) ,
271
295
keyEquivalent: " v "
272
296
)
273
297
pasteItem. keyEquivalentModifierMask = . command
274
298
275
- let selectAllItem = appMenu . addItem (
299
+ let selectAllItem = editMenu . addItem (
276
300
withTitle: " Select all " ,
277
- action: " selectAll: " ,
301
+ action: #selector ( NSTextView . selectAll) ,
278
302
keyEquivalent: " a "
279
303
)
280
304
selectAllItem. keyEquivalentModifierMask = . command
281
305
282
- return appMenu
306
+ return editMenu
283
307
}
284
308
285
309
public func setApplicationMenu( _ submenus: [ ResolvedMenu . Submenu ] ) {
0 commit comments