import AppKit import Foundation // MARK: - Copy Link's pasteboard seam /// The pasteboard Board ▸ Copy Link and the card context menu's own Copy Link row write through — /// shared by both so the two surfaces can never come to carry different bytes (`BoardStore.copyCardLink`, /// `CardFaceView.copyLink`). /// /// Design ruling (2026-08-09, card 737a949f "Add an option to card context menu to copy a link to /// the card folder"): "writes the card FOLDER's `file://` URL to the general pasteboard in one write /// with two representations: file URL and plain absolute-path string, so Finder-aware surfaces get /// the URL and terminals/editors get the path." /// /// A protocol rather than a bare `NSPasteboard` call, for `ClipboardPasteboard`'s exact reason /// (`ClipboardManifest.swift`): this write is a one-off outbound action — never a participant in /// `ClipboardStore`'s cut/copy/paste cycle, so it needs no `changeCount` and no takeover detection — /// but a test still has to read back what was written without racing the machine's one real /// pasteboard, or every other test in the run. @MainActor protocol FolderLinkPasteboard: AnyObject { func write(fileURL: URL, path: String) } extension FolderLinkPasteboard { /// The one call both Copy Link surfaces make: a card folder's URL and the plain path derived /// from that very same URL, never two separately-resolved strings that could disagree. func write(link folder: URL) { write(fileURL: folder, path: folder.path) } } /// The real pasteboard — `NSPasteboard.general`, the ruling's own words. /// /// **One `NSPasteboardItem` carrying both representations** — `SystemPasteboard.write(manifest:text:)`'s /// own shape (`ClipboardManifest.swift`) — rather than two separate items, so a paste target sees one /// clipboard entry and reads whichever flavor it understands: `.fileURL` for Finder-aware surfaces /// (open panels, other apps that resolve dropped/pasted files), `.string` for terminals and editors /// that only understand text and want the plain absolute path rather than a `file://` string. @MainActor final class SystemFolderLinkPasteboard: FolderLinkPasteboard { private let pasteboard: NSPasteboard init(_ pasteboard: NSPasteboard = .general) { self.pasteboard = pasteboard } func write(fileURL: URL, path: String) { pasteboard.clearContents() let item = NSPasteboardItem() item.setString(fileURL.absoluteString, forType: .fileURL) item.setString(path, forType: .string) pasteboard.writeObjects([item]) } }