1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-12-21 03:10:06 +01:00

♻️ Use replacing(with:) instead of .replacingOccurrences(of:with:)

The newer Swift native method is broadly supported and can properly
handle complex UTF-8 characters like emoji, whereas the old API does
not work correctly with emoji.

In most cases, this likely wouldn't have caused any issues but it does
make things a little cleaner now, and ensures we won't encounter emoji
trouble in the future.
This commit is contained in:
2025-11-11 12:55:23 +01:00
parent ae26c74029
commit 38b3c108bf
27 changed files with 60 additions and 56 deletions

View File

@@ -3920,7 +3920,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1695;
CURRENT_PROJECT_VERSION = 1697;
DEAD_CODE_STRIPPING = YES;
DEBUG = YES;
ENABLE_APP_SANDBOX = NO;
@@ -3939,7 +3939,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.5;
MARKETING_VERSION = 25.10.2;
MARKETING_VERSION = 25.10.3;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3964,7 +3964,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1695;
CURRENT_PROJECT_VERSION = 1697;
DEAD_CODE_STRIPPING = YES;
DEBUG = NO;
ENABLE_APP_SANDBOX = NO;
@@ -3983,7 +3983,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.5;
MARKETING_VERSION = 25.10.2;
MARKETING_VERSION = 25.10.3;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -4146,7 +4146,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1695;
CURRENT_PROJECT_VERSION = 1697;
DEAD_CODE_STRIPPING = YES;
DEBUG = YES;
ENABLE_APP_SANDBOX = NO;
@@ -4165,7 +4165,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.5;
MARKETING_VERSION = 25.10.2;
MARKETING_VERSION = 25.10.3;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) EAP";
@@ -4339,7 +4339,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1695;
CURRENT_PROJECT_VERSION = 1697;
DEAD_CODE_STRIPPING = YES;
DEBUG = NO;
ENABLE_APP_SANDBOX = NO;
@@ -4358,7 +4358,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.5;
MARKETING_VERSION = 25.10.2;
MARKETING_VERSION = 25.10.3;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) EAP";

View File

@@ -31,8 +31,8 @@ func sed(
replacement: String
) async {
// Escape slashes (or `sed` won't work)
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
let e_replacement = replacement.replacingOccurrences(of: "/", with: "\\/")
let e_original = original.replacing("/", with: "\\/")
let e_replacement = replacement.replacing("/", with: "\\/")
// Check if gsed exists; it is able to follow symlinks,
// which we want to do to toggle the extension

View File

@@ -65,7 +65,7 @@ extension String {
return NSLocalizedString(self, bundle: bundle, comment: "")
}
return string.replacingOccurrences(of: "Preferences", with: "Settings")
return string.replacing("Preferences", with: "Settings")
}
var localizedForSwiftUI: LocalizedStringKey {

View File

@@ -12,11 +12,15 @@ extension String {
var replacingTildeWithHomeDirectory: String {
// Try and check if there's a shared container
if let paths = App.shared.container.paths {
return self.replacingOccurrences(of: "~", with: paths.homePath)
return self.replacing("~", with: paths.homePath)
}
// TODO: Come up with some other way to handle this when the app container is not available, especially for tests
return self
// It's also okay if we're running tests
if isRunningTests {
return self
}
fatalError("The app container is not available, the home directory could not be inferred.")
}
}

View File

@@ -15,7 +15,7 @@ struct HomebrewPackage: Decodable {
public var version: String {
return aliases.first!
.replacingOccurrences(of: "php@", with: "")
.replacing("php@", with: "")
}
}

View File

@@ -16,7 +16,7 @@ class PhpHelper {
for version: String
) async {
// Take the PHP version (e.g. "7.2") and generate a dotless version
let dotless = version.replacingOccurrences(of: ".", with: "")
let dotless = version.replacing(".", with: "")
// Determine the dotless name for this PHP version
let destination = "\(container.paths.homePath)/.config/phpmon/bin/pm\(dotless)"

View File

@@ -36,7 +36,7 @@ class PhpConfigurationFile: CreatedFromFile {
_ container: Container,
filePath: String
) -> Self? {
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
let path = filePath.replacing("~", with: container.paths.homePath)
do {
let fileContents = try container.filesystem.getStringFromFile(path)
@@ -96,7 +96,7 @@ class PhpConfigurationFile: CreatedFromFile {
// Replace the value with the new one
components[1] = components[1]
.replacingOccurrences(of: item.value, with: value)
.replacing(item.value, with: value)
// Replace the specific line
self.lines[item.lineIndex] = components.joined(separator: "=")

View File

@@ -70,8 +70,8 @@ class PhpExtension {
self.line = line
let fullPath = String(line[range])
.replacingOccurrences(of: "\"", with: "") // replace excess "
.replacingOccurrences(of: ".so", with: "") // replace excess .so
.replacing("\"", with: "") // replace excess "
.replacing(".so", with: "") // replace excess .so
self.name = String(fullPath.split(separator: "/").last!) // take last segment
@@ -88,7 +88,7 @@ class PhpExtension {
// DISABLED: Commented out line
? "; \(line)"
// ENABLED: Line where the comment delimiter (;) is removed
: line.replacingOccurrences(of: "; ", with: "")
: line.replacing("; ", with: "")
await sed(container, file: file, original: line, replacement: newLine)

View File

@@ -74,7 +74,7 @@ extension InternalSwitcher {
var contents = try container.filesystem.getStringFromFile("~/.composer/vendor/laravel/valet" + file.source)
for (original, replacement) in file.replacements {
contents = contents.replacingOccurrences(of: original, with: replacement)
contents = contents.replacing(original, with: replacement)
}
try container.filesystem.writeAtomicallyToFile(
@@ -103,7 +103,7 @@ extension InternalSwitcher {
replacements: [
"VALET_USER": container.paths.whoami,
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory,
"valet.sock": "valet\(version.replacingOccurrences(of: ".", with: "")).sock"
"valet.sock": "valet\(version.replacing(".", with: "")).sock"
],
applies: { Valet.shared.version!.major > 2 }
),

View File

@@ -111,7 +111,7 @@ class InternalSwitcher: PhpSwitcher {
await brew(container, "services start \(formula)", sudo: true)
if Valet.enabled(feature: .isolatedSites) && primary {
let socketVersion = version.replacingOccurrences(of: ".", with: "")
let socketVersion = version.replacing(".", with: "")
await container.shell.quiet("ln -sF ~/.config/valet/valet\(socketVersion).sock ~/.config/valet/valet.sock")
Log.info("Symlinked new socket version (valet\(socketVersion).sock → valet.sock).")
}

View File

@@ -20,7 +20,7 @@ class TestableFileSystem: FileSystemProtocol {
// Ensure that each of the ~ characters are replaced with the home directory path
accessQueue.sync {
for (key, value) in files {
let adjustedKey = key.contains("~") ? key.replacingOccurrences(of: "~", with: self.homeDirectory) : key
let adjustedKey = key.contains("~") ? key.replacing("~", with: self.homeDirectory) : key
self.files[adjustedKey] = value
}
@@ -102,7 +102,7 @@ class TestableFileSystem: FileSystemProtocol {
return accessQueue.sync {
self.files.keys
.filter { $0.hasPrefix(seek) }
.map { $0.replacingOccurrences(of: seek, with: "") }
.map { $0.replacing(seek, with: "") }
.filter { !$0.contains("/") }
}
}
@@ -142,7 +142,7 @@ class TestableFileSystem: FileSystemProtocol {
if key.hasPrefix(path) {
self.files.renameKey(
fromKey: key,
toKey: key.replacingOccurrences(of: path, with: newPath)
toKey: key.replacing(path, with: newPath)
)
}
}

View File

@@ -29,7 +29,7 @@ extension AppDelegate {
guard let url = urls.first else { return }
self.interpretCommand(
url.absoluteString.replacingOccurrences(of: "phpmon://", with: ""),
url.absoluteString.replacing("phpmon://", with: ""),
commands: InterApp.getCommands()
)
}

View File

@@ -54,7 +54,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
#if DEBUG
logger.verbosity = .performance
if let profile = CommandLine.arguments.first(where: { $0.matches(pattern: "--configuration:*") }) {
AppDelegate.initializeTestingProfile(profile.replacingOccurrences(of: "--configuration:", with: ""))
AppDelegate.initializeTestingProfile(profile.replacing("--configuration:", with: ""))
}
#endif

View File

@@ -148,7 +148,7 @@ class AppUpdater {
system_quiet("mkdir -p ~/.config/phpmon/updater 2> /dev/null")
let updaterDirectory = "~/.config/phpmon/updater"
.replacingOccurrences(of: "~", with: NSHomeDirectory())
.replacing("~", with: NSHomeDirectory())
system_quiet("cp -R \"\(updater)\" \"\(updaterDirectory)/PHP Monitor Self-Updater.app\"")

View File

@@ -97,8 +97,8 @@ class Startup {
subtitleText: "alert.homebrew_missing.subtitle".localized,
descriptionText: "alert.homebrew_missing.info".localized(
App.architecture
.replacingOccurrences(of: "x86_64", with: "Intel")
.replacingOccurrences(of: "arm64", with: "Apple Silicon"),
.replacing("x86_64", with: "Intel")
.replacing("arm64", with: "Apple Silicon"),
App.shared.container.paths.brew
),
buttonText: "alert.homebrew_missing.quit".localized,

View File

@@ -31,13 +31,13 @@ struct RCFile {
let content = line.split(separator: "=")
let key = String(content[0])
.trimmingCharacters(in: .whitespaces)
.replacingOccurrences(of: "\"", with: "")
.replacing("\"", with: "")
if key.starts(with: "#") {
return
}
let value = String(content[1])
.trimmingCharacters(in: .whitespaces)
.replacingOccurrences(of: "\"", with: "")
.replacing("\"", with: "")
fields[key] = value
}
})

View File

@@ -101,7 +101,7 @@ class BrewDiagnostics {
}) {
for symlink in contents {
let version = symlink.replacingOccurrences(of: "php@", with: "")
let version = symlink.replacing("php@", with: "")
if let destination = try? filesystem.getDestinationOfSymlink("\(container.paths.optPath)/\(symlink)") {
if !destination.contains("Cellar/php/\(version)")
&& !destination.contains("Cellar/php@\(version)") {

View File

@@ -21,8 +21,8 @@ struct BrewPhpExtension: Hashable, Comparable {
$0.contains("shivammathur/extensions/") && $0.contains("@\(phpVersion)")
}
.map {
$0.replacingOccurrences(of: "shivammathur/extensions/", with: "")
.replacingOccurrences(of: "@\(phpVersion)", with: "")
$0.replacing("shivammathur/extensions/", with: "")
.replacing("@\(phpVersion)", with: "")
}
}

View File

@@ -80,8 +80,8 @@ struct BrewPhpFormula: Equatable {
/// The associated Homebrew folder with this PHP formula.
var homebrewFolder: String {
let resolved = name
.replacingOccurrences(of: "shivammathur/php/", with: "")
.replacingOccurrences(of: "php@" + PhpEnvironments.brewPhpAlias, with: "php")
.replacing("shivammathur/php/", with: "")
.replacing("php@" + PhpEnvironments.brewPhpAlias, with: "php")
return "\(App.shared.container.paths.optPath)/\(resolved)/bin"
}
@@ -89,7 +89,7 @@ struct BrewPhpFormula: Equatable {
/// The short version associated with this formula, if installed.
var shortVersion: String? {
guard let version = self.installedVersion else {
return self.displayName.replacingOccurrences(of: "PHP ", with: "")
return self.displayName.replacing("PHP ", with: "")
}
return VersionNumber.make(from: version)?.short ?? nil
@@ -112,7 +112,7 @@ struct BrewPhpFormula: Equatable {
return container.filesystem.fileExists(
"\(container.paths.tapPath)/shivammathur/homebrew-php/Formula/php@\(version).rb"
.replacingOccurrences(of: "php@" + PhpEnvironments.brewPhpAlias, with: "php")
.replacing("php@" + PhpEnvironments.brewPhpAlias, with: "php")
)
}

View File

@@ -63,8 +63,8 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
fullVersion = install.isPreRelease ? "\(fullVersion!)-dev" : fullVersion
upgradeVersion = outdated?.first(where: { formula in
return formula.name.replacingOccurrences(of: "shivammathur/php/", with: "")
== install.formulaName.replacingOccurrences(of: "shivammathur/php/", with: "")
return formula.name.replacing("shivammathur/php/", with: "")
== install.formulaName.replacing("shivammathur/php/", with: "")
})?.current_version
isPrerelease = install.isPreRelease

View File

@@ -28,8 +28,8 @@ class RemovePhpVersionCommand: BrewCommand {
) {
self.container = container
self.version = formula
.replacingOccurrences(of: "php@", with: "")
.replacingOccurrences(of: "shivammathur/php/", with: "")
.replacing("php@", with: "")
.replacing("shivammathur/php/", with: "")
self.formula = formula
self.phpGuard = PhpGuard()
}

View File

@@ -23,7 +23,7 @@ class NginxConfigurationFile: CreatedFromFile {
_ container: Container,
filePath: String,
) -> Self? {
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
let path = filePath.replacing("~", with: container.paths.homePath)
do {
let fileContents = try String(contentsOfFile: path)
@@ -40,7 +40,7 @@ class NginxConfigurationFile: CreatedFromFile {
let tld = String(domain.split(separator: ".").last!)
self.contents = contents
self.domain = domain.replacingOccurrences(of: ".\(tld)", with: "")
self.domain = domain.replacing(".\(tld)", with: "")
self.tld = tld
}

View File

@@ -48,10 +48,10 @@ class CertificateValidator {
// Remove PEM headers and footers, and whitespace
let cleanedCertificate = certificateString
.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "")
.replacingOccurrences(of: "-----END CERTIFICATE-----", with: "")
.replacingOccurrences(of: "\n", with: "")
.replacingOccurrences(of: "\r", with: "")
.replacing("-----BEGIN CERTIFICATE-----", with: "")
.replacing("-----END CERTIFICATE-----", with: "")
.replacing("\n", with: "")
.replacing("\r", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
guard let certificateData = Data(base64Encoded: cleanedCertificate) else {

View File

@@ -23,7 +23,7 @@ class ValetSite: ValetListable {
/// replacing the user's home folder with ~.
lazy var absolutePathRelative: String = {
return self.absolutePath
.replacingOccurrences(of: container.paths.homePath, with: "~")
.replacing(container.paths.homePath, with: "~")
}()
/// The TLD used to locate this site.

View File

@@ -135,10 +135,10 @@ class AddProxyVC: NSViewController, NSTextFieldDelegate {
func updateTextField() {
inputDomainName.stringValue = inputDomainName.stringValue
.replacingOccurrences(of: " ", with: "-")
.replacing(" ", with: "-")
inputProxySubject.stringValue = inputProxySubject.stringValue
.replacingOccurrences(of: " ", with: "-")
.replacing(" ", with: "-")
buttonCreateProxy.isEnabled = validate(
domain: inputDomainName.stringValue,

View File

@@ -129,7 +129,7 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate {
func updateTextField() {
inputDomainName.stringValue = inputDomainName.stringValue
.replacingOccurrences(of: " ", with: "-")
.replacing(" ", with: "-")
buttonCreateLink.isEnabled = isValidLinkName(inputDomainName.stringValue)
updatePreview()

View File

@@ -118,7 +118,7 @@ struct RealFileSystemTest {
#expect(filesystem.fileExists(executable))
let newExecutable = executable.replacingOccurrences(of: "/exec.sh", with: "/file.txt")
let newExecutable = executable.replacing("/exec.sh", with: "/file.txt")
try! filesystem.move(from: executable, to: newExecutable)