TurtleGit for Mac

View Markdown source ↗

External workspace requests during standalone Merge

TortoiseGit uses distinct TortoiseProc and TortoiseMerge processes. TurtleGit's single macOS application bundle must preserve that separation when Git invokes its Merge entry and Launch Services subsequently delivers Finder actions or patch files to the running application. This is a native process/lifetime adaptation, not an upstream dialog certification. It complements IDD_OPENDLG in src/Resources/TortoiseMergeENG.rc and the standalone frame audit.

NSApplicationDelegate.application(_:open:) is now the single external event receiver. Workspace mode queues events before its routing model/startup command are ready, then consumes that queue once in original order. Subsequent repeated user events remain independent. RepositoryWindow no longer registers a second SwiftUI onOpenURL handler.

Tool mode validates supported Finder request URLs with the existing typed parser and accepts case-insensitive .patch/.diff file opens. It ignores unsupported schemes, actions and file kinds. Each accepted batch passes unchanged URLs to NSWorkspace.open with a new application instance, activation and empty arguments. No Merge input/output arguments or scope is synthesized for the child. The child's ordinary workspace routing and repository/file authorization apply. A URL path/reflected name is not an access grant. Actual signed Launch Services scope transfer remains an acceptance gate.

The handoff retains selected-file scope leases until the actual launch callback. Launch success means Launch Services accepted the application, not that every child Git action finished. The child has its own UI and action ownership. Failed launches retain a native acknowledgment window or sheet; closing the original sheet owner retires its acknowledgment exactly once. If the Merge editor closes first, its captured Git status waits through accepted launches and failure acknowledgments. Shutdown yields recheck pending work before exit. Quit refuses active handoff ownership. Retirement keeps uncancellable launch receipts until the real callback but neither publishes late failures nor terminates children.

The grouped private fixture covers unsupported-input refusal, literal URL order/ duplicates, actual new-instance/empty-argument configuration, one-shot launch and failure replies, ownerless/sheet failure dismissal, retirement drain, early workspace ordering and a real readonly Merge command close whose Git status waits through a held failed workspace launch/acknowledgment. It opens no external processes. Batch evidence records actual checks; fixture existence alone is not a pass.

Physical Finder/document event dispatch, an actual independently launched signed workspace, App Store terminal/Launch Services grants, minimum-OS/Intel, full visual/keyboard/VoiceOver and whole-app parity remain open. The unbundled SwiftPM entry cannot launch a workspace application bundle and reports an owned error.