diff --git a/Docs/RELEASE_NOTES.md b/Docs/RELEASE_NOTES.md index 3c7ba1c..942f700 100644 --- a/Docs/RELEASE_NOTES.md +++ b/Docs/RELEASE_NOTES.md @@ -2,7 +2,8 @@ ## Unreleased -No changes yet. +- Adds a File menu entry that registers Margin as the default editor for + Markdown (.md) files through Launch Services. ## 0.5.1 — native reading and review fixes diff --git a/Docs/screenshots/default-markdown-editor-menu.png b/Docs/screenshots/default-markdown-editor-menu.png new file mode 100644 index 0000000..40f3f34 Binary files /dev/null and b/Docs/screenshots/default-markdown-editor-menu.png differ diff --git a/Sources/MarginApp/AppDelegate.swift b/Sources/MarginApp/AppDelegate.swift index 09ec11b..ddfbeca 100644 --- a/Sources/MarginApp/AppDelegate.swift +++ b/Sources/MarginApp/AppDelegate.swift @@ -1,5 +1,6 @@ import AppKit import MarginCore +import UniformTypeIdentifiers protocol WorkspacePathRenameParticipating: AnyObject { var documentURLForPathRename: URL? { get } @@ -220,6 +221,25 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuItemValidation { } } + @objc func setAsDefaultMarkdownEditor(_ sender: Any?) { + guard let markdownType = UTType(filenameExtension: "md") else { return } + let bundleURL = Bundle.main.bundleURL + let workspace = NSWorkspace.shared + workspace.setDefaultApplication(at: bundleURL, toOpen: markdownType) { error in + DispatchQueue.main.async { + let alert = NSAlert() + if error == nil { + alert.messageText = "Margin is now the default editor for Markdown files." + } else { + alert.messageText = "Margin could not be set as the default Markdown editor." + alert.informativeText = "You can set it manually: choose a .md file in Finder, " + + "press Command-I, and select Margin as the default app." + } + alert.runModal() + } + } + } + @objc func newWindow(_ sender: Any?) { makeWorkspaceWindow(for: nil) } diff --git a/Sources/MarginApp/AppMenu.swift b/Sources/MarginApp/AppMenu.swift index b4039a7..37f703e 100644 --- a/Sources/MarginApp/AppMenu.swift +++ b/Sources/MarginApp/AppMenu.swift @@ -151,6 +151,14 @@ enum AppMenu { ) fileMenu.addItem(.separator()) fileMenu.addItem(item("Close Tab", action: #selector(NSWindow.performClose(_:)), key: "w")) + fileMenu.addItem(.separator()) + fileMenu.addItem( + item( + "Set as Default Markdown Editor", + action: #selector(AppDelegate.setAsDefaultMarkdownEditor(_:)), + target: delegate + ) + ) mainMenu.addItem(menuItem(title: "File", submenu: fileMenu)) let editMenu = NSMenu(title: "Edit") diff --git a/Tests/MarginAppTests/WorkspaceBehaviorTests.swift b/Tests/MarginAppTests/WorkspaceBehaviorTests.swift index 449b33f..d8b84b0 100644 --- a/Tests/MarginAppTests/WorkspaceBehaviorTests.swift +++ b/Tests/MarginAppTests/WorkspaceBehaviorTests.swift @@ -224,6 +224,16 @@ final class WorkspaceBehaviorTests: XCTestCase { ) } + func testFileMenuOffersDefaultMarkdownEditorRegistration() { + let delegate = AppDelegate() + AppMenu.install(for: NSApplication.shared, delegate: delegate) + + let item = menuItem(named: "Set as Default Markdown Editor") + XCTAssertNotNil(item) + XCTAssertEqual(item?.action, #selector(AppDelegate.setAsDefaultMarkdownEditor(_:))) + XCTAssertTrue(item?.target === delegate) + } + func testFileWatcherNeverBlocksTheInteractionThreadWhileOpening() { let openerFinished = expectation(description: "Slow descriptor open finished") let watcher = FileSystemWatcher(