From 2de15961157343ff7dbeacc1281df97a3af6c624 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 27 Aug 2026 14:34:15 -0700 Subject: [PATCH 1/3] macos: normalize action working directory paths Discussion #14048 Directory URLs no longer export a trailing slash through PWD, which keeps zsh's %1~ prompt expansion from resolving to an empty string. A shared URL helper removes trailing separators while preserving the filesystem root and percent-decoding behavior. Tests cover normal, repeated, encoded, and root paths. --- .../App Intents/NewTerminalIntent.swift | 2 +- .../Features/Services/ServiceProvider.swift | 2 +- .../Helpers/Extensions/URL+Extension.swift | 12 +++++++++ macos/Tests/URLTests.swift | 25 +++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 macos/Sources/Helpers/Extensions/URL+Extension.swift create mode 100644 macos/Tests/URLTests.swift diff --git a/macos/Sources/Features/App Intents/NewTerminalIntent.swift b/macos/Sources/Features/App Intents/NewTerminalIntent.swift index 35f53169f..67d1a9676 100644 --- a/macos/Sources/Features/App Intents/NewTerminalIntent.swift +++ b/macos/Sources/Features/App Intents/NewTerminalIntent.swift @@ -74,7 +74,7 @@ struct NewTerminalIntent: AppIntent { // If we were given a working directory then open that directory if let url = workingDirectory?.fileURL { let dir = url.hasDirectoryPath ? url : url.deletingLastPathComponent() - config.workingDirectory = dir.path(percentEncoded: false) + config.workingDirectory = dir.pathWithoutTrailingSlash } // Parse environment variables from KEY=VALUE format diff --git a/macos/Sources/Features/Services/ServiceProvider.swift b/macos/Sources/Features/Services/ServiceProvider.swift index aa5ab7c8a..5f51c9ed4 100644 --- a/macos/Sources/Features/Services/ServiceProvider.swift +++ b/macos/Sources/Features/Services/ServiceProvider.swift @@ -59,7 +59,7 @@ class ServiceProvider: NSObject { for url in directoryURLs { var config = Ghostty.SurfaceConfiguration() - config.workingDirectory = url.path(percentEncoded: false) + config.workingDirectory = url.pathWithoutTrailingSlash switch target { case .window: diff --git a/macos/Sources/Helpers/Extensions/URL+Extension.swift b/macos/Sources/Helpers/Extensions/URL+Extension.swift new file mode 100644 index 000000000..e3554b599 --- /dev/null +++ b/macos/Sources/Helpers/Extensions/URL+Extension.swift @@ -0,0 +1,12 @@ +import Foundation + +extension URL { + /// The decoded path with trailing separators removed, except for the root path. + var pathWithoutTrailingSlash: String { + var result = path(percentEncoded: false) + while result.count > 1 && result.hasSuffix("/") { + result.removeLast() + } + return result + } +} diff --git a/macos/Tests/URLTests.swift b/macos/Tests/URLTests.swift new file mode 100644 index 000000000..f3f0ec151 --- /dev/null +++ b/macos/Tests/URLTests.swift @@ -0,0 +1,25 @@ +import Foundation +import Testing +@testable import Ghostty + +struct URLTests { + @Test func pathWithoutTrailingSlash() { + let url = URL(string: "file:///tmp/example/")! + #expect(url.pathWithoutTrailingSlash == "/tmp/example") + } + + @Test func pathWithoutMultipleTrailingSlashes() { + let url = URL(string: "file:///tmp/example///")! + #expect(url.pathWithoutTrailingSlash == "/tmp/example") + } + + @Test func pathWithoutTrailingSlashDecodesPath() { + let url = URL(string: "file:///tmp/example%20directory/")! + #expect(url.pathWithoutTrailingSlash == "/tmp/example directory") + } + + @Test func pathWithoutTrailingSlashPreservesRoot() { + let url = URL(string: "file:///")! + #expect(url.pathWithoutTrailingSlash == "/") + } +} From 07abbd1e7ee1f98d40cffacf537577e0bcb3522b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 27 Aug 2026 14:57:59 -0700 Subject: [PATCH 2/3] Update macos/Sources/Helpers/Extensions/URL+Extension.swift Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com> --- macos/Sources/Helpers/Extensions/URL+Extension.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/macos/Sources/Helpers/Extensions/URL+Extension.swift b/macos/Sources/Helpers/Extensions/URL+Extension.swift index e3554b599..1a87cc028 100644 --- a/macos/Sources/Helpers/Extensions/URL+Extension.swift +++ b/macos/Sources/Helpers/Extensions/URL+Extension.swift @@ -3,10 +3,6 @@ import Foundation extension URL { /// The decoded path with trailing separators removed, except for the root path. var pathWithoutTrailingSlash: String { - var result = path(percentEncoded: false) - while result.count > 1 && result.hasSuffix("/") { - result.removeLast() - } - return result + FilePath(path(percentEncoded: false)).string } } From 1c3a4a8314669a97177e4b39cd5d6451f4c257f3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 27 Aug 2026 14:58:06 -0700 Subject: [PATCH 3/3] Update macos/Sources/Helpers/Extensions/URL+Extension.swift Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com> --- macos/Sources/Helpers/Extensions/URL+Extension.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/macos/Sources/Helpers/Extensions/URL+Extension.swift b/macos/Sources/Helpers/Extensions/URL+Extension.swift index 1a87cc028..1e5090111 100644 --- a/macos/Sources/Helpers/Extensions/URL+Extension.swift +++ b/macos/Sources/Helpers/Extensions/URL+Extension.swift @@ -1,4 +1,5 @@ import Foundation +import System extension URL { /// The decoded path with trailing separators removed, except for the root path.