macos: rename shellQuoted() to Ghostty.Shell.quote() (#10765)

We already had an established Ghostty.Shell namespace (previously a
struct; now a more idiomatic enum), and locating these functions next to
each other makes it clearer how they relate to one another.
This commit is contained in:
Mitchell Hashimoto
2026-02-16 12:40:13 -08:00
committed by GitHub
5 changed files with 18 additions and 14 deletions

View File

@@ -476,7 +476,7 @@ class AppDelegate: NSObject,
// profile/rc files for the shell, which is super important on macOS
// due to things like Homebrew. Instead, we set the command to
// `<filename>; exit` which is what Terminal and iTerm2 do.
config.initialInput = "\(filename.shellQuoted()); exit\n"
config.initialInput = "\(Ghostty.Shell.quote(filename)); exit\n"
// For commands executed directly, we want to ensure we wait after exit
// because in most cases scripts don't block on exit and we don't want

View File

@@ -68,7 +68,7 @@ struct NewTerminalIntent: AppIntent {
// We don't run command as "command" and instead use "initialInput" so
// that we can get all the login scripts to setup things like PATH.
if let command {
config.initialInput = "\(command.shellQuoted()); exit\n"
config.initialInput = "\(Ghostty.Shell.quote(command)); exit\n"
}
// If we were given a working directory then open that directory

View File

@@ -1,9 +1,10 @@
extension Ghostty {
struct Shell {
enum Shell {
// Characters to escape in the shell.
static let escapeCharacters = "\\ ()[]{}<>\"'`!#$&;|*?\t"
private static let escapeCharacters = "\\ ()[]{}<>\"'`!#$&;|*?\t"
/// Escape shell-sensitive characters in string.
/// Escape shell-sensitive characters in a string by prefixing each with a
/// backslash. Suitable for inserting paths/URLs into a live terminal buffer.
static func escape(_ str: String) -> String {
var result = str
for char in escapeCharacters {
@@ -15,5 +16,14 @@ extension Ghostty {
return result
}
private static let quoteUnsafe = /[^\w@%+=:,.\/-]/
/// Returns a shell-quoted version of the string, like Python's shlex.quote.
/// Suitable for building shell command lines that will be executed.
static func quote(_ str: String) -> String {
guard str.isEmpty || str.contains(Self.quoteUnsafe) else { return str }
return "'" + str.replacingOccurrences(of: "'", with: #"'"'"'"#) + "'"
}
}
}

View File

@@ -27,11 +27,5 @@ extension String {
}
#endif
private static let shellUnsafe = /[^\w@%+=:,.\/-]/
/// Returns a shell-escaped version of the string, like Python's shlex.quote.
func shellQuoted() -> String {
guard self.isEmpty || self.contains(Self.shellUnsafe) else { return self };
return "'" + self.replacingOccurrences(of: "'", with: #"'"'"'"#) + "'"
}
}

View File

@@ -1,7 +1,7 @@
import Testing
@testable import Ghostty
struct StringExtensionTests {
struct ShellTests {
@Test(arguments: [
("", "''"),
("filename", "filename"),
@@ -13,7 +13,7 @@ struct StringExtensionTests {
("it's", "'it'\"'\"'s'"),
("file$'name'", "'file$'\"'\"'name'\"'\"''"),
])
func shellQuoted(input: String, expected: String) {
#expect(input.shellQuoted() == expected)
func quote(input: String, expected: String) {
#expect(Ghostty.Shell.quote(input) == expected)
}
}