Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ final class SplitViewController {
convenience init(rootNode: SplitNode? = nil) {
self.init(
rootNode: rootNode,
tabDragTransferRegistry: .process
tabDragTransferRegistry: TabDragTransferRegistry()
)
}

Expand Down
21 changes: 18 additions & 3 deletions Sources/Bonsplit/Public/BonsplitController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,30 @@ public final class BonsplitController {

// MARK: - Initialization

/// Create a new controller with the specified configuration
/// Creates an isolated controller with the specified configuration.
///
/// Use ``init(configuration:tabDragTransferRegistry:)`` when multiple
/// controllers may exchange tabs.
///
/// - Parameter configuration: The controller's behavior and appearance.
public init(configuration: BonsplitConfiguration = .default) {
self.configuration = configuration
self.internalController = SplitViewController()
configureInternalController()
}

init(
configuration: BonsplitConfiguration = .default,
/// Creates a controller with explicit ownership of its tab-drag capabilities.
///
/// Controllers that exchange tabs must receive the same registry. Controllers
/// created without one are isolated, which keeps independent hosts and tests
/// from sharing hidden process state.
///
/// - Parameters:
/// - configuration: The controller's behavior and appearance.
/// - tabDragTransferRegistry: The capability registry shared by controllers
/// that may exchange tabs.
public init(
configuration: BonsplitConfiguration,
tabDragTransferRegistry: TabDragTransferRegistry
) {
self.configuration = configuration
Expand Down
6 changes: 0 additions & 6 deletions Sources/Bonsplit/Public/TabDragTransferRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ import UniformTypeIdentifiers
/// Process-local capability store shared by tab-drag sources and destinations.
@MainActor
public final class TabDragTransferRegistry {
/// The registry used by Bonsplit controllers created with the default initializer.
///
/// AppKit exposes one drag pasteboard for the process, so the default registry
/// is process-wide as well. Construct a separate registry for isolated tests.
public static let process = TabDragTransferRegistry()

/// The AppKit pasteboard type that carries opaque tab-drag capabilities.
public static let pasteboardType = NSPasteboard.PasteboardType(
UTType.tabTransfer.identifier
Expand Down
17 changes: 14 additions & 3 deletions Tests/BonsplitTests/TabDragTransferRegistryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ struct TabDragTransferRegistryTests {

@Test("A registered capability routes across controllers")
func registeredCapabilityRoutesAcrossControllers() throws {
let sourceController = makeController()
let targetController = makeController()
let registry = sourceController.internalController.tabDragTransferRegistry
let registry = TabDragTransferRegistry()
let sourceController = makeController(registry: registry)
let targetController = makeController(registry: registry)
let sourcePane = try #require(sourceController.internalController.focusedPane)
let sourceTab = try #require(sourcePane.selectedTab)
let targetPane = try #require(targetController.internalController.focusedPane)
Expand All @@ -53,6 +53,17 @@ struct TabDragTransferRegistryTests {
#expect(receivedRequest?.sourcePaneId == sourcePane.id)
}

@Test("Controllers do not share an implicit capability registry")
func defaultControllersHaveIsolatedCapabilityRegistries() {
let firstController = makeController()
let secondController = makeController()

#expect(
firstController.internalController.tabDragTransferRegistry
!== secondController.internalController.tabDragTransferRegistry
)
}

@Test("An unregistered capability is rejected")
func unregisteredCapabilityIsRejected() throws {
let registry = TabDragTransferRegistry()
Expand Down
Loading