mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-02-07 00:55:44 +01:00
macos: quote input strings used for shell commands (#10583)
When we're building an input string that's explicitly meant to be used as a shell command, quote it using the same logic as Python's `shlex.quote` function. This specifically addresses issues we've seen when open(1)'ing Ghostty with filename arguments that contain spaces. See #2633, #3030
This commit is contained in:
@@ -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); exit\n"
|
||||
config.initialInput = "\(filename.shellQuoted()); 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
|
||||
|
||||
@@ -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); exit\n"
|
||||
config.initialInput = "\(command.shellQuoted()); exit\n"
|
||||
}
|
||||
|
||||
// If we were given a working directory then open that directory
|
||||
|
||||
@@ -26,4 +26,12 @@ extension String {
|
||||
return self
|
||||
}
|
||||
#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: #"'"'"'"#) + "'"
|
||||
}
|
||||
}
|
||||
|
||||
19
macos/Tests/Helpers/Extensions/StringExtensionTests.swift
Normal file
19
macos/Tests/Helpers/Extensions/StringExtensionTests.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
import Testing
|
||||
@testable import Ghostty
|
||||
|
||||
struct StringExtensionTests {
|
||||
@Test(arguments: [
|
||||
("", "''"),
|
||||
("filename", "filename"),
|
||||
("abcABC123@%_-+=:,./", "abcABC123@%_-+=:,./"),
|
||||
("file name", "'file name'"),
|
||||
("file$name", "'file$name'"),
|
||||
("file!name", "'file!name'"),
|
||||
("file\\name", "'file\\name'"),
|
||||
("it's", "'it'\"'\"'s'"),
|
||||
("file$'name'", "'file$'\"'\"'name'\"'\"''"),
|
||||
])
|
||||
func shellQuoted(input: String, expected: String) {
|
||||
#expect(input.shellQuoted() == expected)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user