diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index 6ac509bb..902172bf 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -825,12 +825,16 @@ class AppState: ObservableObject { } } - func copyPath(xcode: Xcode) { + func copyPath(xcode: Xcode, pasteboard: NSPasteboard = .general) { guard let installedXcodePath = xcode.installedPath else { return } - NSPasteboard.general.declareTypes([.URL, .string], owner: nil) - NSPasteboard.general.writeObjects([installedXcodePath.url as NSURL]) - NSPasteboard.general.setString(installedXcodePath.string, forType: .string) + // Write a single item with real data for each type. Declaring `.URL` without + // providing data left an empty first item that Terminal and other apps couldn't paste. + let item = NSPasteboardItem() + item.setString(installedXcodePath.url.absoluteString, forType: .fileURL) + item.setString(installedXcodePath.string, forType: .string) + pasteboard.clearContents() + pasteboard.writeObjects([item]) } func copyReleaseNote(from url: URL?) { diff --git a/XcodesTests/AppStateTests.swift b/XcodesTests/AppStateTests.swift index 2945b06c..c4594764 100644 --- a/XcodesTests/AppStateTests.swift +++ b/XcodesTests/AppStateTests.swift @@ -81,6 +81,21 @@ class AppStateTests: XCTestCase { subject = AppState() } + func test_CopyPath_WritesOneItemWithPathAndFileURL() throws { + let installedPath = try XCTUnwrap(Path("/Applications/Xcode 26.0.app")) + let xcode = Xcode(version: Version("26.0.0")!, installState: .installed(installedPath), selected: false, icon: nil) + let pasteboard = NSPasteboard(name: NSPasteboard.Name("AppStateTests-\(UUID().uuidString)")) + defer { pasteboard.releaseGlobally() } + + subject.copyPath(xcode: xcode, pasteboard: pasteboard) + + let items = try XCTUnwrap(pasteboard.pasteboardItems) + XCTAssertEqual(items.count, 1) + XCTAssertEqual(items.first?.types, [.fileURL, .string]) + XCTAssertEqual(items.first?.string(forType: .string), "/Applications/Xcode 26.0.app") + XCTAssertEqual(items.first?.string(forType: .fileURL), "file:///Applications/Xcode%2026.0.app") + } + func test_InstallError_Network401IsUnauthorized() { let error = NetworkError.non200StatusCode(statusCode: 401, data: Data())