mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
✅ Added linting
This commit is contained in:
15
.swiftlint.yml
Normal file
15
.swiftlint.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
disabled_rules:
|
||||||
|
- todo
|
||||||
|
- identifier_name
|
||||||
|
- force_try
|
||||||
|
- force_cast
|
||||||
|
|
||||||
|
opt_in_rules:
|
||||||
|
- empty_count
|
||||||
|
|
||||||
|
included:
|
||||||
|
- phpmon
|
||||||
|
- phpmon-tests
|
||||||
|
|
||||||
|
excluded:
|
||||||
|
- phpmon/Vendor
|
@ -230,6 +230,7 @@
|
|||||||
C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
|
C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
|
||||||
C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */; };
|
C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */; };
|
||||||
C4F319C927B034A500AFF46F /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DEB7D327A5D60B00834718 /* Stats.swift */; };
|
C4F319C927B034A500AFF46F /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DEB7D327A5D60B00834718 /* Stats.swift */; };
|
||||||
|
C4F5FBCD28218CB8001065C5 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; };
|
||||||
C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F7809B25D80344000DBC97 /* CommandTest.swift */; };
|
C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F7809B25D80344000DBC97 /* CommandTest.swift */; };
|
||||||
C4F780A825D80AE8000DBC97 /* php.ini in Resources */ = {isa = PBXBuildFile; fileRef = C4F780A725D80AE8000DBC97 /* php.ini */; };
|
C4F780A825D80AE8000DBC97 /* php.ini in Resources */ = {isa = PBXBuildFile; fileRef = C4F780A725D80AE8000DBC97 /* php.ini */; };
|
||||||
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */; };
|
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */; };
|
||||||
@ -405,6 +406,7 @@
|
|||||||
C4F2E4392752F7D00020E974 /* PhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInstallation.swift; sourceTree = "<group>"; };
|
C4F2E4392752F7D00020E974 /* PhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInstallation.swift; sourceTree = "<group>"; };
|
||||||
C4F30B02278E16BA00755FCE /* HomebrewService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewService.swift; sourceTree = "<group>"; };
|
C4F30B02278E16BA00755FCE /* HomebrewService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewService.swift; sourceTree = "<group>"; };
|
||||||
C4F30B06278E195800755FCE /* brew-services.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "brew-services.json"; sourceTree = "<group>"; };
|
C4F30B06278E195800755FCE /* brew-services.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "brew-services.json"; sourceTree = "<group>"; };
|
||||||
|
C4F5FBCC28218C93001065C5 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = "<group>"; };
|
||||||
C4F7807925D7F84B000DBC97 /* phpmon-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "phpmon-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
C4F7807925D7F84B000DBC97 /* phpmon-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "phpmon-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
C4F7807D25D7F84B000DBC97 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
C4F7807D25D7F84B000DBC97 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
C4F7809B25D80344000DBC97 /* CommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandTest.swift; sourceTree = "<group>"; };
|
C4F7809B25D80344000DBC97 /* CommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandTest.swift; sourceTree = "<group>"; };
|
||||||
@ -549,6 +551,7 @@
|
|||||||
C4E713562570150F00007428 /* SECURITY.md */,
|
C4E713562570150F00007428 /* SECURITY.md */,
|
||||||
C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */,
|
C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */,
|
||||||
54D9E0C027E4F5E9003B9AD9 /* LICENSE */,
|
54D9E0C027E4F5E9003B9AD9 /* LICENSE */,
|
||||||
|
C4F5FBCC28218C93001065C5 /* .swiftlint.yml */,
|
||||||
C4E713572570151400007428 /* docs */,
|
C4E713572570151400007428 /* docs */,
|
||||||
C41C1B3522B0097F00E7CF16 /* phpmon */,
|
C41C1B3522B0097F00E7CF16 /* phpmon */,
|
||||||
C4F7807A25D7F84B000DBC97 /* phpmon-tests */,
|
C4F7807A25D7F84B000DBC97 /* phpmon-tests */,
|
||||||
@ -974,6 +977,7 @@
|
|||||||
C41C1B2F22B0097F00E7CF16 /* Sources */,
|
C41C1B2F22B0097F00E7CF16 /* Sources */,
|
||||||
C41C1B3022B0097F00E7CF16 /* Frameworks */,
|
C41C1B3022B0097F00E7CF16 /* Frameworks */,
|
||||||
C41C1B3122B0097F00E7CF16 /* Resources */,
|
C41C1B3122B0097F00E7CF16 /* Resources */,
|
||||||
|
C4F5FBCB28216985001065C5 /* Run `swiftlint` */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -1089,6 +1093,27 @@
|
|||||||
};
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
C4F5FBCB28216985001065C5 /* Run `swiftlint` */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run `swiftlint`";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
C41C1B2F22B0097F00E7CF16 /* Sources */ = {
|
C41C1B2F22B0097F00E7CF16 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
@ -1291,6 +1316,7 @@
|
|||||||
C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */,
|
C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */,
|
||||||
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */,
|
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */,
|
||||||
C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */,
|
C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */,
|
||||||
|
C4F5FBCD28218CB8001065C5 /* Xdebug.swift in Sources */,
|
||||||
C40B24F227A310770018C7D2 /* Events.swift in Sources */,
|
C40B24F227A310770018C7D2 /* Events.swift in Sources */,
|
||||||
C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */,
|
C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */,
|
||||||
C4C0E8E027F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
|
C4C0E8E027F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
|
||||||
|
@ -64,9 +64,9 @@ class HomebrewPackageTest: XCTestCase {
|
|||||||
return ["php", "nginx", "dnsmasq"].contains(service.name)
|
return ["php", "nginx", "dnsmasq"].contains(service.name)
|
||||||
})
|
})
|
||||||
|
|
||||||
XCTAssertTrue(services.contains(where: {$0.name == "php"} ))
|
XCTAssertTrue(services.contains(where: {$0.name == "php"}))
|
||||||
XCTAssertTrue(services.contains(where: {$0.name == "nginx"} ))
|
XCTAssertTrue(services.contains(where: {$0.name == "nginx"}))
|
||||||
XCTAssertTrue(services.contains(where: {$0.name == "dnsmasq"} ))
|
XCTAssertTrue(services.contains(where: {$0.name == "dnsmasq"}))
|
||||||
XCTAssertEqual(services.count, 3)
|
XCTAssertEqual(services.count, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,33 +12,28 @@ class Actions {
|
|||||||
|
|
||||||
// MARK: - Services
|
// MARK: - Services
|
||||||
|
|
||||||
public static func restartPhpFpm()
|
public static func restartPhpFpm() {
|
||||||
{
|
|
||||||
brew("services restart \(PhpEnv.phpInstall.formula)", sudo: true)
|
brew("services restart \(PhpEnv.phpInstall.formula)", sudo: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func restartNginx()
|
public static func restartNginx() {
|
||||||
{
|
|
||||||
brew("services restart nginx", sudo: true)
|
brew("services restart nginx", sudo: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func restartDnsMasq()
|
public static func restartDnsMasq() {
|
||||||
{
|
|
||||||
brew("services restart dnsmasq", sudo: true)
|
brew("services restart dnsmasq", sudo: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func stopAllServices()
|
public static func stopAllServices() {
|
||||||
{
|
|
||||||
brew("services stop \(PhpEnv.phpInstall.formula)", sudo: true)
|
brew("services stop \(PhpEnv.phpInstall.formula)", sudo: true)
|
||||||
brew("services stop nginx", sudo: true)
|
brew("services stop nginx", sudo: true)
|
||||||
brew("services stop dnsmasq", sudo: true)
|
brew("services stop dnsmasq", sudo: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func fixHomebrewPermissions() throws
|
public static func fixHomebrewPermissions() throws {
|
||||||
{
|
|
||||||
var servicesCommands = [
|
var servicesCommands = [
|
||||||
"\(Paths.brew) services stop nginx",
|
"\(Paths.brew) services stop nginx",
|
||||||
"\(Paths.brew) services stop dnsmasq",
|
"\(Paths.brew) services stop dnsmasq"
|
||||||
]
|
]
|
||||||
var cellarCommands = [
|
var cellarCommands = [
|
||||||
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/nginx",
|
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/nginx",
|
||||||
@ -64,34 +59,30 @@ class Actions {
|
|||||||
|
|
||||||
let eventResult: NSAppleEventDescriptor? = appleScript?.executeAndReturnError(nil)
|
let eventResult: NSAppleEventDescriptor? = appleScript?.executeAndReturnError(nil)
|
||||||
|
|
||||||
if (eventResult == nil) {
|
if eventResult == nil {
|
||||||
throw HomebrewPermissionError(kind: .applescriptNilError)
|
throw HomebrewPermissionError(kind: .applescriptNilError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Finding Config Files
|
// MARK: - Finding Config Files
|
||||||
|
|
||||||
public static func openGenericPhpConfigFolder()
|
public static func openGenericPhpConfigFolder() {
|
||||||
{
|
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php")]
|
||||||
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php")];
|
|
||||||
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func openGlobalComposerFolder()
|
public static func openGlobalComposerFolder() {
|
||||||
{
|
|
||||||
let file = FileManager.default.homeDirectoryForCurrentUser
|
let file = FileManager.default.homeDirectoryForCurrentUser
|
||||||
.appendingPathComponent(".composer/composer.json")
|
.appendingPathComponent(".composer/composer.json")
|
||||||
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
|
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func openPhpConfigFolder(version: String)
|
public static func openPhpConfigFolder(version: String) {
|
||||||
{
|
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php/\(version)/php.ini")]
|
||||||
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php/\(version)/php.ini")];
|
|
||||||
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func openValetConfigFolder()
|
public static func openValetConfigFolder() {
|
||||||
{
|
|
||||||
let file = FileManager.default.homeDirectoryForCurrentUser
|
let file = FileManager.default.homeDirectoryForCurrentUser
|
||||||
.appendingPathComponent(".config/valet")
|
.appendingPathComponent(".config/valet")
|
||||||
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
|
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
|
||||||
@ -99,8 +90,7 @@ class Actions {
|
|||||||
|
|
||||||
// MARK: - Other Actions
|
// MARK: - Other Actions
|
||||||
|
|
||||||
public static func createTempPhpInfoFile() -> URL
|
public static func createTempPhpInfoFile() -> URL {
|
||||||
{
|
|
||||||
// Write a file called `phpmon_phpinfo.php` to /tmp
|
// Write a file called `phpmon_phpinfo.php` to /tmp
|
||||||
try! "<?php phpinfo();".write(toFile: "/tmp/phpmon_phpinfo.php", atomically: true, encoding: .utf8)
|
try! "<?php phpinfo();".write(toFile: "/tmp/phpmon_phpinfo.php", atomically: true, encoding: .utf8)
|
||||||
|
|
||||||
@ -124,8 +114,7 @@ class Actions {
|
|||||||
If this does not solve the issue, the user may need to install additional
|
If this does not solve the issue, the user may need to install additional
|
||||||
extensions and/or run `composer global update`.
|
extensions and/or run `composer global update`.
|
||||||
*/
|
*/
|
||||||
public static func fixMyValet(completed: @escaping () -> Void)
|
public static func fixMyValet(completed: @escaping () -> Void) {
|
||||||
{
|
|
||||||
InternalSwitcher().performSwitch(to: PhpEnv.brewPhpVersion, completion: {
|
InternalSwitcher().performSwitch(to: PhpEnv.brewPhpVersion, completion: {
|
||||||
brew("services restart dnsmasq", sudo: true)
|
brew("services restart dnsmasq", sudo: true)
|
||||||
brew("services restart php", sudo: true)
|
brew("services restart php", sudo: true)
|
||||||
|
@ -28,7 +28,7 @@ public class Command {
|
|||||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
let output: String = String.init(data: data, encoding: String.Encoding.utf8)!
|
let output: String = String.init(data: data, encoding: String.Encoding.utf8)!
|
||||||
|
|
||||||
if (trimNewlines) {
|
if trimNewlines {
|
||||||
return output.components(separatedBy: .newlines)
|
return output.components(separatedBy: .newlines)
|
||||||
.filter({ !$0.isEmpty })
|
.filter({ !$0.isEmpty })
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
|
@ -11,24 +11,21 @@
|
|||||||
/**
|
/**
|
||||||
Runs a `valet` command. Defaults to running as superuser.
|
Runs a `valet` command. Defaults to running as superuser.
|
||||||
*/
|
*/
|
||||||
func valet(_ command: String, sudo: Bool = true) -> String
|
func valet(_ command: String, sudo: Bool = true) -> String {
|
||||||
{
|
|
||||||
return Shell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true)
|
return Shell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Runs a `brew` command. Can run as superuser.
|
Runs a `brew` command. Can run as superuser.
|
||||||
*/
|
*/
|
||||||
func brew(_ command: String, sudo: Bool = false)
|
func brew(_ command: String, sudo: Bool = false) {
|
||||||
{
|
|
||||||
Shell.run("\(sudo ? "sudo " : "")" + "\(Paths.brew) \(command)")
|
Shell.run("\(sudo ? "sudo " : "")" + "\(Paths.brew) \(command)")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Runs `sed` in order to replace all occurrences of a string in a specific file with another.
|
Runs `sed` in order to replace all occurrences of a string in a specific file with another.
|
||||||
*/
|
*/
|
||||||
func sed(file: String, original: String, replacement: String)
|
func sed(file: String, original: String, replacement: String) {
|
||||||
{
|
|
||||||
// Escape slashes (or `sed` won't work)
|
// Escape slashes (or `sed` won't work)
|
||||||
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
|
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
|
||||||
let e_replacement = replacement.replacingOccurrences(of: "/", with: "\\/")
|
let e_replacement = replacement.replacingOccurrences(of: "/", with: "\\/")
|
||||||
@ -45,8 +42,7 @@ func sed(file: String, original: String, replacement: String)
|
|||||||
/**
|
/**
|
||||||
Uses `grep` to determine whether a particular query string can be found in a particular file.
|
Uses `grep` to determine whether a particular query string can be found in a particular file.
|
||||||
*/
|
*/
|
||||||
func grepContains(file: String, query: String) -> Bool
|
func grepContains(file: String, query: String) -> Bool {
|
||||||
{
|
|
||||||
return Shell.pipe("""
|
return Shell.pipe("""
|
||||||
grep -q '\(query)' \(file); [ $? -eq 0 ] && echo "YES" || echo "NO"
|
grep -q '\(query)' \(file); [ $? -eq 0 ] && echo "YES" || echo "NO"
|
||||||
""")
|
""")
|
||||||
|
@ -49,7 +49,7 @@ public class Paths {
|
|||||||
// - MARK: Detected Binaries
|
// - MARK: Detected Binaries
|
||||||
|
|
||||||
/** The path to the Composer binary. Can be in multiple locations, so is detected instead. */
|
/** The path to the Composer binary. Can be in multiple locations, so is detected instead. */
|
||||||
public static var composer: String? = nil
|
public static var composer: String?
|
||||||
|
|
||||||
// - MARK: Paths
|
// - MARK: Paths
|
||||||
|
|
||||||
|
@ -35,8 +35,11 @@ extension Process {
|
|||||||
forName: NSNotification.Name.NSFileHandleDataAvailable,
|
forName: NSNotification.Name.NSFileHandleDataAvailable,
|
||||||
object: pipe.fileHandleForReading,
|
object: pipe.fileHandleForReading,
|
||||||
queue: nil
|
queue: nil
|
||||||
) { notification in
|
) { _ in
|
||||||
if let outputString = String(data: pipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) {
|
if let outputString = String(
|
||||||
|
data: pipe.fileHandleForReading.availableData,
|
||||||
|
encoding: String.Encoding.utf8
|
||||||
|
) {
|
||||||
callback(outputString)
|
callback(outputString)
|
||||||
}
|
}
|
||||||
pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||||
|
@ -14,25 +14,25 @@ extension NSWindow {
|
|||||||
/**
|
/**
|
||||||
Shakes a window. Inspired by: http://blog.ericd.net/2016/09/30/shaking-a-macos-window/
|
Shakes a window. Inspired by: http://blog.ericd.net/2016/09/30/shaking-a-macos-window/
|
||||||
*/
|
*/
|
||||||
func shake(){
|
func shake() {
|
||||||
let numberOfShakes = 3, durationOfShake = 0.2, vigourOfShake: CGFloat = 0.03
|
let numberOfShakes = 3, durationOfShake = 0.2, vigourOfShake: CGFloat = 0.03
|
||||||
|
|
||||||
let frame: CGRect = self.frame
|
let frame: CGRect = self.frame
|
||||||
let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation()
|
let shakeAnimation: CAKeyframeAnimation = CAKeyframeAnimation()
|
||||||
|
|
||||||
let shakePath = CGMutablePath()
|
let shakePath = CGMutablePath()
|
||||||
shakePath.move( to: CGPoint(x:NSMinX(frame), y:NSMinY(frame)))
|
shakePath.move( to: CGPoint(x: frame.minX, y: frame.minY))
|
||||||
|
|
||||||
for _ in 0...numberOfShakes-1 {
|
for _ in 0...numberOfShakes-1 {
|
||||||
shakePath.addLine(to: CGPoint(x:NSMinX(frame) - frame.size.width * vigourOfShake, y:NSMinY(frame)))
|
shakePath.addLine(to: CGPoint(x: frame.minX - frame.size.width * vigourOfShake, y: frame.minY))
|
||||||
shakePath.addLine(to: CGPoint(x:NSMinX(frame) + frame.size.width * vigourOfShake, y:NSMinY(frame)))
|
shakePath.addLine(to: CGPoint(x: frame.minX + frame.size.width * vigourOfShake, y: frame.minY))
|
||||||
}
|
}
|
||||||
|
|
||||||
shakePath.closeSubpath()
|
shakePath.closeSubpath()
|
||||||
shakeAnimation.path = shakePath
|
shakeAnimation.path = shakePath
|
||||||
shakeAnimation.duration = durationOfShake
|
shakeAnimation.duration = durationOfShake
|
||||||
|
|
||||||
self.animations = ["frameOrigin":shakeAnimation]
|
self.animations = ["frameOrigin": shakeAnimation]
|
||||||
self.animator().setFrameOrigin(self.frame.origin)
|
self.animator().setFrameOrigin(self.frame.origin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ extension String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func countInstances(of stringToFind: String) -> Int {
|
func countInstances(of stringToFind: String) -> Int {
|
||||||
if (stringToFind.isEmpty) {
|
if stringToFind.isEmpty {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,10 +26,10 @@ extension XibLoadable where Self: NSView {
|
|||||||
|
|
||||||
static func createFromXib(in bundle: Bundle = Bundle.main) -> Self? {
|
static func createFromXib(in bundle: Bundle = Bundle.main) -> Self? {
|
||||||
guard let xibName = xibName else { return nil }
|
guard let xibName = xibName else { return nil }
|
||||||
var topLevelArray: NSArray? = nil
|
var topLevelArray: NSArray?
|
||||||
bundle.loadNibNamed(NSNib.Name(xibName), owner: self, topLevelObjects: &topLevelArray)
|
bundle.loadNibNamed(NSNib.Name(xibName), owner: self, topLevelObjects: &topLevelArray)
|
||||||
guard let results = topLevelArray else { return nil }
|
guard let results = topLevelArray else { return nil }
|
||||||
let views = Array<Any>(results).filter { $0 is Self }
|
let views = [Any](results).filter { $0 is Self }
|
||||||
return views.last as? Self
|
return views.last as? Self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class Alert {
|
|||||||
alert.messageText = messageText
|
alert.messageText = messageText
|
||||||
alert.informativeText = informativeText
|
alert.informativeText = informativeText
|
||||||
alert.addButton(withTitle: buttonTitle)
|
alert.addButton(withTitle: buttonTitle)
|
||||||
if (!secondButtonTitle.isEmpty) {
|
if !secondButtonTitle.isEmpty {
|
||||||
alert.addButton(withTitle: secondButtonTitle)
|
alert.addButton(withTitle: secondButtonTitle)
|
||||||
}
|
}
|
||||||
alert.beginSheetModal(for: window) { response in
|
alert.beginSheetModal(for: window) { response in
|
||||||
|
@ -24,7 +24,7 @@ class MenuBarImageGenerator {
|
|||||||
NSAttributedString.Key.paragraphStyle: textStyle
|
NSAttributedString.Key.paragraphStyle: textStyle
|
||||||
]
|
]
|
||||||
|
|
||||||
let padding : CGFloat = 2.0;
|
let padding: CGFloat = 2.0
|
||||||
|
|
||||||
// Create an attributed string so we'll know how wide the item will need to be
|
// Create an attributed string so we'll know how wide the item will need to be
|
||||||
let attributedString = NSAttributedString(string: text, attributes: textFontAttributes)
|
let attributedString = NSAttributedString(string: text, attributes: textFontAttributes)
|
||||||
|
@ -23,7 +23,7 @@ class VersionExtractor {
|
|||||||
let match = regex.matches(
|
let match = regex.matches(
|
||||||
in: string,
|
in: string,
|
||||||
options: [],
|
options: [],
|
||||||
range: NSMakeRange(0, string.count)
|
range: NSRange(location: 0, length: string.count)
|
||||||
).first
|
).first
|
||||||
|
|
||||||
guard let match = match else {
|
guard let match = match else {
|
||||||
|
@ -35,7 +35,7 @@ class ActivePhpInstallation {
|
|||||||
getVersion()
|
getVersion()
|
||||||
|
|
||||||
// If an error occurred, exit early
|
// If an error occurred, exit early
|
||||||
if (version.error) {
|
if version.error {
|
||||||
limits = Limits()
|
limits = Limits()
|
||||||
extensions = []
|
extensions = []
|
||||||
return
|
return
|
||||||
@ -60,9 +60,9 @@ class ActivePhpInstallation {
|
|||||||
|
|
||||||
// See if any extensions are present in said .ini files
|
// See if any extensions are present in said .ini files
|
||||||
paths.forEach { (iniFilePath) in
|
paths.forEach { (iniFilePath) in
|
||||||
let exts = PhpExtension.load(from: URL(fileURLWithPath: iniFilePath))
|
let loadedExtensions = PhpExtension.load(from: URL(fileURLWithPath: iniFilePath))
|
||||||
if exts.count > 0 {
|
if loadedExtensions.isEmpty {
|
||||||
extensions.append(contentsOf: exts)
|
extensions.append(contentsOf: loadedExtensions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,12 +71,12 @@ class ActivePhpInstallation {
|
|||||||
When the app tries to retrieve the version, the installation is considered broken if the output is nothing,
|
When the app tries to retrieve the version, the installation is considered broken if the output is nothing,
|
||||||
_or_ if the output contains the word "Warning" or "Error". In normal situations this should not be the case.
|
_or_ if the output contains the word "Warning" or "Error". In normal situations this should not be the case.
|
||||||
*/
|
*/
|
||||||
private func getVersion() -> Void {
|
private func getVersion() {
|
||||||
self.version = Version()
|
self.version = Version()
|
||||||
|
|
||||||
let version = Command.execute(path: Paths.phpConfig, arguments: ["--version"], trimNewlines: true)
|
let version = Command.execute(path: Paths.phpConfig, arguments: ["--version"], trimNewlines: true)
|
||||||
|
|
||||||
if (version == "" || version.contains("Warning") || version.contains("Error")) {
|
if version == "" || version.contains("Warning") || version.contains("Error") {
|
||||||
self.version.short = "💩 BROKEN"
|
self.version.short = "💩 BROKEN"
|
||||||
self.version.long = ""
|
self.version.long = ""
|
||||||
self.version.error = true
|
self.version.error = true
|
||||||
@ -112,13 +112,13 @@ class ActivePhpInstallation {
|
|||||||
let value = Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"])
|
let value = Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"])
|
||||||
|
|
||||||
// Check if the value is unlimited
|
// Check if the value is unlimited
|
||||||
if (value == "-1") {
|
if value == "-1" {
|
||||||
return "∞"
|
return "∞"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the syntax is valid otherwise
|
// Check if the syntax is valid otherwise
|
||||||
let regex = try! NSRegularExpression(pattern: #"^([0-9]*)(K|M|G|)$"#, options: [])
|
let regex = try! NSRegularExpression(pattern: #"^([0-9]*)(K|M|G|)$"#, options: [])
|
||||||
let match = regex.matches(in: value, options: [], range: NSMakeRange(0, value.count)).first
|
let match = regex.matches(in: value, options: [], range: NSRange(location: 0, length: value.count)).first
|
||||||
return (match == nil) ? "⚠️" : "\(value)B"
|
return (match == nil) ? "⚠️" : "\(value)B"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class Xdebug {
|
|||||||
"debug",
|
"debug",
|
||||||
"gcstats",
|
"gcstats",
|
||||||
"profile",
|
"profile",
|
||||||
"trace",
|
"trace"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class PhpEnv {
|
|||||||
init() {
|
init() {
|
||||||
self.currentInstall = ActivePhpInstallation()
|
self.currentInstall = ActivePhpInstallation()
|
||||||
|
|
||||||
let brewPhpAlias = Shell.pipe("\(Paths.brew) info php --json");
|
let brewPhpAlias = Shell.pipe("\(Paths.brew) info php --json")
|
||||||
|
|
||||||
self.homebrewPackage = try! JSONDecoder().decode(
|
self.homebrewPackage = try! JSONDecoder().decode(
|
||||||
[HomebrewPackage].self,
|
[HomebrewPackage].self,
|
||||||
@ -76,15 +76,14 @@ class PhpEnv {
|
|||||||
return InternalSwitcher()
|
return InternalSwitcher()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func detectPhpVersions() -> Void {
|
public static func detectPhpVersions() {
|
||||||
_ = Self.shared.detectPhpVersions()
|
_ = Self.shared.detectPhpVersions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Detects which versions of PHP are installed.
|
Detects which versions of PHP are installed.
|
||||||
*/
|
*/
|
||||||
public func detectPhpVersions() -> [String]
|
public func detectPhpVersions() -> [String] {
|
||||||
{
|
|
||||||
let files = Shell.pipe("ls \(Paths.optPath) | grep php@")
|
let files = Shell.pipe("ls \(Paths.optPath) | grep php@")
|
||||||
|
|
||||||
var versionsOnly = extractPhpVersions(from: files.components(separatedBy: "\n"))
|
var versionsOnly = extractPhpVersions(from: files.components(separatedBy: "\n"))
|
||||||
@ -95,7 +94,7 @@ class PhpEnv {
|
|||||||
let phpAlias = homebrewPackage.version
|
let phpAlias = homebrewPackage.version
|
||||||
|
|
||||||
// Avoid inserting a duplicate
|
// Avoid inserting a duplicate
|
||||||
if (!versionsOnly.contains(phpAlias) && Filesystem.fileExists("\(Paths.optPath)/php/bin/php")) {
|
if !versionsOnly.contains(phpAlias) && Filesystem.fileExists("\(Paths.optPath)/php/bin/php") {
|
||||||
versionsOnly.append(phpAlias)
|
versionsOnly.append(phpAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +125,7 @@ class PhpEnv {
|
|||||||
checkBinaries: Bool = true,
|
checkBinaries: Bool = true,
|
||||||
generateHelpers: Bool = true
|
generateHelpers: Bool = true
|
||||||
) -> [String] {
|
) -> [String] {
|
||||||
var output : [String] = []
|
var output: [String] = []
|
||||||
|
|
||||||
var supported = Constants.SupportedPhpVersions
|
var supported = Constants.SupportedPhpVersions
|
||||||
|
|
||||||
@ -144,8 +143,7 @@ class PhpEnv {
|
|||||||
// is supported and where the binary exists (avoids broken installs)
|
// is supported and where the binary exists (avoids broken installs)
|
||||||
if !output.contains(version)
|
if !output.contains(version)
|
||||||
&& supported.contains(version)
|
&& supported.contains(version)
|
||||||
&& (checkBinaries ? Filesystem.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true)
|
&& (checkBinaries ? Filesystem.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true) {
|
||||||
{
|
|
||||||
output.append(version)
|
output.append(version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ class PhpHelper {
|
|||||||
if FileManager.default.fileExists(atPath: destination) {
|
if FileManager.default.fileExists(atPath: destination) {
|
||||||
let contents = try String(contentsOfFile: destination)
|
let contents = try String(contentsOfFile: destination)
|
||||||
if !contents.contains(keyPhrase) {
|
if !contents.contains(keyPhrase) {
|
||||||
Log.info("The file at '\(destination)' already exists and was not generated by PHP Monitor (or is unreadable). Not updating this file.")
|
Log.info("The file at '\(destination)' already exists and was not generated by PHP Monitor "
|
||||||
|
+ "(or is unreadable). Not updating this file.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,12 @@ public struct PhpVersionNumber: Equatable {
|
|||||||
|
|
||||||
public static func make(from versionString: String, type: MatchType = .versionOnly) -> Self? {
|
public static func make(from versionString: String, type: MatchType = .versionOnly) -> Self? {
|
||||||
let regex = try! NSRegularExpression(pattern: type.rawValue, options: [])
|
let regex = try! NSRegularExpression(pattern: type.rawValue, options: [])
|
||||||
let match = regex.matches(in: versionString, options: [], range: NSMakeRange(0, versionString.count)).first
|
|
||||||
|
let match = regex.matches(
|
||||||
|
in: versionString,
|
||||||
|
options: [],
|
||||||
|
range: NSRange(location: 0, length: versionString.count)
|
||||||
|
).first
|
||||||
|
|
||||||
if match != nil {
|
if match != nil {
|
||||||
let major = Int(
|
let major = Int(
|
||||||
@ -143,7 +148,7 @@ public struct PhpVersionNumber: Equatable {
|
|||||||
let minor = Int(
|
let minor = Int(
|
||||||
versionString[Range(match!.range(withName: "minor"), in: versionString)!]
|
versionString[Range(match!.range(withName: "minor"), in: versionString)!]
|
||||||
)!
|
)!
|
||||||
var patch: Int? = nil
|
var patch: Int?
|
||||||
if let minorRange = Range(match!.range(withName: "patch"), in: versionString) {
|
if let minorRange = Range(match!.range(withName: "patch"), in: versionString) {
|
||||||
patch = Int(versionString[minorRange])
|
patch = Int(versionString[minorRange])
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@ class PhpExtension {
|
|||||||
/// The original string that was used to determine this extension is active.
|
/// The original string that was used to determine this extension is active.
|
||||||
var line: String
|
var line: String
|
||||||
|
|
||||||
/// The name of the extension. This is always identical to the name found in the original string. If you want to display this name, capitalize this.
|
/// The name of the extension. This is always identical to the name found in the original string.
|
||||||
|
/// If you want to display this name, capitalize this.
|
||||||
var name: String
|
var name: String
|
||||||
|
|
||||||
/// Whether the extension has been enabled.
|
/// Whether the extension has been enabled.
|
||||||
@ -34,6 +35,7 @@ class PhpExtension {
|
|||||||
return String(file.split(separator: "/").last ?? "php.ini")
|
return String(file.split(separator: "/").last ?? "php.ini")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable line_length
|
||||||
/**
|
/**
|
||||||
This regular expression will allow us to identify lines which activate an extension.
|
This regular expression will allow us to identify lines which activate an extension.
|
||||||
|
|
||||||
@ -47,13 +49,14 @@ class PhpExtension {
|
|||||||
- Note: Extensions that are disabled in a different way will not be detected. This is intentional.
|
- Note: Extensions that are disabled in a different way will not be detected. This is intentional.
|
||||||
*/
|
*/
|
||||||
static let extensionRegex = #"^(extension|zend_extension|;(\s?)extension|;(\s?)zend_extension)(\s?)(=)(\s?)(?<name>["]?(?:\/?.\/?)+(?:\.so)"?)$"#
|
static let extensionRegex = #"^(extension|zend_extension|;(\s?)extension|;(\s?)zend_extension)(\s?)(=)(\s?)(?<name>["]?(?:\/?.\/?)+(?:\.so)"?)$"#
|
||||||
|
// swiftlint:enable line_length
|
||||||
|
|
||||||
/**
|
/**
|
||||||
When registering an extension, we do that based on the line found inside the .ini file.
|
When registering an extension, we do that based on the line found inside the .ini file.
|
||||||
*/
|
*/
|
||||||
init(_ line: String, file: String) {
|
init(_ line: String, file: String) {
|
||||||
let regex = try! NSRegularExpression(pattern: Self.extensionRegex, options: [])
|
let regex = try! NSRegularExpression(pattern: Self.extensionRegex, options: [])
|
||||||
let match = regex.matches(in: line, options: [], range: NSMakeRange(0, line.count)).first
|
let match = regex.matches(in: line, options: [], range: NSRange(location: 0, length: line.count)).first
|
||||||
let range = Range(match!.range(withName: "name"), in: line)!
|
let range = Range(match!.range(withName: "name"), in: line)!
|
||||||
|
|
||||||
self.line = line
|
self.line = line
|
||||||
@ -69,7 +72,8 @@ class PhpExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This simply toggles the extension in the .ini file. You may need to restart the other services in order for this change to apply.
|
This simply toggles the extension in the .ini file.
|
||||||
|
You may need to restart the other services in order for this change to apply.
|
||||||
*/
|
*/
|
||||||
func toggle() {
|
func toggle() {
|
||||||
let newLine = enabled
|
let newLine = enabled
|
||||||
@ -91,7 +95,7 @@ class PhpExtension {
|
|||||||
static func load(from path: URL) -> [PhpExtension] {
|
static func load(from path: URL) -> [PhpExtension] {
|
||||||
let file = try? String(contentsOf: path, encoding: .utf8)
|
let file = try? String(contentsOf: path, encoding: .utf8)
|
||||||
|
|
||||||
if (file == nil) {
|
if file == nil {
|
||||||
Log.err("There was an issue reading the file. Assuming no extensions were found.")
|
Log.err("There was an issue reading the file. Assuming no extensions were found.")
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
the version that is switched to may or may not be identical to `php`
|
the version that is switched to may or may not be identical to `php`
|
||||||
(without @version).
|
(without @version).
|
||||||
*/
|
*/
|
||||||
func performSwitch(to version: String, completion: @escaping () -> Void)
|
func performSwitch(to version: String, completion: @escaping () -> Void) {
|
||||||
{
|
|
||||||
Log.info("Switching to \(version), unlinking all versions...")
|
Log.info("Switching to \(version), unlinking all versions...")
|
||||||
|
|
||||||
let isolated = Valet.shared.sites.filter { site in
|
let isolated = Valet.shared.sites.filter { site in
|
||||||
@ -32,7 +31,7 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
|
|
||||||
var versions: Set<String> = [version]
|
var versions: Set<String> = [version]
|
||||||
|
|
||||||
if (Valet.enabled(feature: .isolatedSites)) {
|
if Valet.enabled(feature: .isolatedSites) {
|
||||||
versions = versions.union(isolated)
|
versions = versions.union(isolated)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +70,9 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
let existing = URL(string: "file://\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf")!
|
let existing = URL(string: "file://\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf")!
|
||||||
let new = URL(string: "file://\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon")!
|
let new = URL(string: "file://\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon")!
|
||||||
do {
|
do {
|
||||||
if (FileManager.default.fileExists(atPath: new.path)) {
|
if FileManager.default.fileExists(atPath: new.path) {
|
||||||
Log.info("A moved `www.conf.disabled-by-phpmon` file was found for PHP \(version), cleaning up so the newer `www.conf` can be moved again.")
|
Log.info("A moved `www.conf.disabled-by-phpmon` file was found for PHP \(version), "
|
||||||
|
+ "cleaning up so the newer `www.conf` can be moved again.")
|
||||||
try FileManager.default.removeItem(at: new)
|
try FileManager.default.removeItem(at: new)
|
||||||
}
|
}
|
||||||
try FileManager.default.moveItem(at: existing, to: new)
|
try FileManager.default.moveItem(at: existing, to: new)
|
||||||
@ -93,7 +93,7 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
private func startPhpVersion(_ version: String, primary: Bool) {
|
private func startPhpVersion(_ version: String, primary: Bool) {
|
||||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||||
|
|
||||||
if (primary) {
|
if primary {
|
||||||
Log.info("\(formula) is the primary formula, linking and starting services...")
|
Log.info("\(formula) is the primary formula, linking and starting services...")
|
||||||
brew("link \(formula) --overwrite --force")
|
brew("link \(formula) --overwrite --force")
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,7 +38,7 @@ extension App {
|
|||||||
If there are no windows open, the app will be an accessory (toolbar) app.
|
If there are no windows open, the app will be an accessory (toolbar) app.
|
||||||
*/
|
*/
|
||||||
public func updateActivationPolicy() {
|
public func updateActivationPolicy() {
|
||||||
NSApp.setActivationPolicy(openWindows.count > 0 ? .regular : .accessory)
|
NSApp.setActivationPolicy(!openWindows.isEmpty ? .regular : .accessory)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,10 @@ class App {
|
|||||||
var preferences: [PreferenceName: Bool]!
|
var preferences: [PreferenceName: Bool]!
|
||||||
|
|
||||||
/** The window controller of the currently active preferences window. */
|
/** The window controller of the currently active preferences window. */
|
||||||
var preferencesWindowController: PrefsWC? = nil
|
var preferencesWindowController: PrefsWC?
|
||||||
|
|
||||||
/** The window controller of the currently active site list window. */
|
/** The window controller of the currently active site list window. */
|
||||||
var domainListWindowController: DomainListWC? = nil
|
var domainListWindowController: DomainListWC?
|
||||||
|
|
||||||
/** List of detected (installed) applications that PHP Monitor can work with. */
|
/** List of detected (installed) applications that PHP Monitor can work with. */
|
||||||
var detectedApplications: [Application] = []
|
var detectedApplications: [Application] = []
|
||||||
@ -57,7 +57,7 @@ class App {
|
|||||||
/**
|
/**
|
||||||
The shortcut the user has requested.
|
The shortcut the user has requested.
|
||||||
*/
|
*/
|
||||||
var shortcutHotkey: HotKey? = nil {
|
var shortcutHotkey: HotKey? {
|
||||||
didSet {
|
didSet {
|
||||||
setupGlobalHotkeyListener()
|
setupGlobalHotkeyListener()
|
||||||
}
|
}
|
||||||
|
@ -44,4 +44,3 @@ extension AppDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class InterApp {
|
|||||||
subtitle: "PHP Monitor can't switch to PHP \(version), as it may not be installed or available."
|
subtitle: "PHP Monitor can't switch to PHP \(version), as it may not be installed or available."
|
||||||
).withPrimary(text: "OK").show()
|
).withPrimary(text: "OK").show()
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
]}
|
]}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,7 @@ class Startup {
|
|||||||
If this method returns false, there was a failed check and an alert was displayed.
|
If this method returns false, there was a failed check and an alert was displayed.
|
||||||
If this method returns true, then all checks succeeded and the app can continue.
|
If this method returns true, then all checks succeeded and the app can continue.
|
||||||
*/
|
*/
|
||||||
func checkEnvironment() async -> Bool
|
func checkEnvironment() async -> Bool {
|
||||||
{
|
|
||||||
// Do the important system setup checks
|
// Do the important system setup checks
|
||||||
Log.info("[ARCH] The user is running PHP Monitor with the architecture: \(App.architecture)")
|
Log.info("[ARCH] The user is running PHP Monitor with the architecture: \(App.architecture)")
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ class AddProxyVC: NSViewController, NSTextFieldDelegate {
|
|||||||
Valet.shared.config.tld
|
Valet.shared.config.tld
|
||||||
)
|
)
|
||||||
|
|
||||||
if (inputProxySubject.stringValue.isEmpty || inputDomainName.stringValue.isEmpty) {
|
if inputProxySubject.stringValue.isEmpty || inputDomainName.stringValue.isEmpty {
|
||||||
previewText.stringValue = "domain_list.add.empty_fields".localized
|
previewText.stringValue = "domain_list.add.empty_fields".localized
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate {
|
|||||||
Valet.shared.config.tld
|
Valet.shared.config.tld
|
||||||
)
|
)
|
||||||
|
|
||||||
if (inputDomainName.stringValue.isEmpty) {
|
if inputDomainName.stringValue.isEmpty {
|
||||||
previewText.stringValue = "domain_list.add.empty_fields".localized
|
previewText.stringValue = "domain_list.add.empty_fields".localized
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class DomainListKindCell: NSTableCellView, DomainListCellProtocol
|
class DomainListKindCell: NSTableCellView, DomainListCellProtocol {
|
||||||
{
|
|
||||||
static let reusableName = "domainListKindCell"
|
static let reusableName = "domainListKindCell"
|
||||||
|
|
||||||
@IBOutlet weak var imageViewType: NSImageView!
|
@IBOutlet weak var imageViewType: NSImageView!
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class DomainListNameCell: NSTableCellView, DomainListCellProtocol
|
class DomainListNameCell: NSTableCellView, DomainListCellProtocol {
|
||||||
{
|
|
||||||
static let reusableName = "domainListNameCell"
|
static let reusableName = "domainListNameCell"
|
||||||
|
|
||||||
@IBOutlet weak var labelSiteName: NSTextField!
|
@IBOutlet weak var labelSiteName: NSTextField!
|
||||||
|
@ -9,11 +9,10 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class DomainListPhpCell: NSTableCellView, DomainListCellProtocol
|
class DomainListPhpCell: NSTableCellView, DomainListCellProtocol {
|
||||||
{
|
|
||||||
static let reusableName = "domainListPhpCell"
|
static let reusableName = "domainListPhpCell"
|
||||||
|
|
||||||
var site: ValetSite? = nil
|
var site: ValetSite?
|
||||||
|
|
||||||
@IBOutlet weak var buttonPhpVersion: NSButton!
|
@IBOutlet weak var buttonPhpVersion: NSButton!
|
||||||
@IBOutlet weak var imageViewPhpVersionOK: NSImageView!
|
@IBOutlet weak var imageViewPhpVersionOK: NSImageView!
|
||||||
@ -53,7 +52,7 @@ class DomainListPhpCell: NSTableCellView, DomainListCellProtocol
|
|||||||
|
|
||||||
var information = ""
|
var information = ""
|
||||||
|
|
||||||
if (self.site?.isolatedPhpVersion != nil) {
|
if self.site?.isolatedPhpVersion != nil {
|
||||||
information += "alert.composer_php_isolated.desc".localized(
|
information += "alert.composer_php_isolated.desc".localized(
|
||||||
self.site!.isolatedPhpVersion!.versionNumber.homebrewVersion,
|
self.site!.isolatedPhpVersion!.versionNumber.homebrewVersion,
|
||||||
PhpEnv.phpInstall.version.short
|
PhpEnv.phpInstall.version.short
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class DomainListTLSCell: NSTableCellView, DomainListCellProtocol
|
class DomainListTLSCell: NSTableCellView, DomainListCellProtocol {
|
||||||
{
|
|
||||||
static let reusableName = "domainListTLSCell"
|
static let reusableName = "domainListTLSCell"
|
||||||
|
|
||||||
@IBOutlet weak var imageViewLock: NSImageView!
|
@IBOutlet weak var imageViewLock: NSImageView!
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class DomainListTypeCell: NSTableCellView, DomainListCellProtocol
|
class DomainListTypeCell: NSTableCellView, DomainListCellProtocol {
|
||||||
{
|
|
||||||
static let reusableName = "domainListTypeCell"
|
static let reusableName = "domainListTypeCell"
|
||||||
|
|
||||||
@IBOutlet weak var labelDriver: NSTextField!
|
@IBOutlet weak var labelDriver: NSTextField!
|
||||||
|
@ -68,11 +68,11 @@ extension DomainListVC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func addDetectedApps(to menu: NSMenu) {
|
private func addDetectedApps(to menu: NSMenu) {
|
||||||
if (applications.count > 0) {
|
if !applications.isEmpty {
|
||||||
menu.addItem(NSMenuItem.separator())
|
menu.addItem(NSMenuItem.separator())
|
||||||
menu.addItem(withTitle: "domain_list.detected_apps".localized, action: nil, keyEquivalent: "")
|
menu.addItem(withTitle: "domain_list.detected_apps".localized, action: nil, keyEquivalent: "")
|
||||||
|
|
||||||
for (_, editor) in applications.enumerated() {
|
for editor in applications {
|
||||||
let editorMenuItem = EditorMenuItem(
|
let editorMenuItem = EditorMenuItem(
|
||||||
title: "Open with \(editor.name)",
|
title: "Open with \(editor.name)",
|
||||||
action: #selector(self.openWithEditor(sender:)),
|
action: #selector(self.openWithEditor(sender:)),
|
||||||
@ -85,7 +85,7 @@ extension DomainListVC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func addUnlink(to menu: NSMenu, with site: ValetSite) {
|
private func addUnlink(to menu: NSMenu, with site: ValetSite) {
|
||||||
if (site.aliasPath != nil) {
|
if site.aliasPath != nil {
|
||||||
menu.addItem(
|
menu.addItem(
|
||||||
withTitle: "domain_list.unlink".localized,
|
withTitle: "domain_list.unlink".localized,
|
||||||
action: #selector(self.unlinkSite),
|
action: #selector(self.unlinkSite),
|
||||||
@ -103,11 +103,15 @@ extension DomainListVC {
|
|||||||
private func addIsolate(to menu: NSMenu, with site: ValetSite) {
|
private func addIsolate(to menu: NSMenu, with site: ValetSite) {
|
||||||
if site.isolatedPhpVersion == nil {
|
if site.isolatedPhpVersion == nil {
|
||||||
// ISOLATION POSSIBLE
|
// ISOLATION POSSIBLE
|
||||||
let isolationMenuItem = NSMenuItem(title:"domain_list.isolate".localized, action: nil, keyEquivalent: "")
|
let isolationMenuItem = NSMenuItem(title: "domain_list.isolate".localized, action: nil, keyEquivalent: "")
|
||||||
let submenu = NSMenu()
|
let submenu = NSMenu()
|
||||||
submenu.addItem(withTitle: "Choose a PHP version", action: nil, keyEquivalent: "")
|
submenu.addItem(withTitle: "Choose a PHP version", action: nil, keyEquivalent: "")
|
||||||
for version in PhpEnv.shared.availablePhpVersions.reversed() {
|
for version in PhpEnv.shared.availablePhpVersions.reversed() {
|
||||||
let item = PhpMenuItem(title: "Always use PHP \(version)", action: #selector(self.isolateSite), keyEquivalent: "")
|
let item = PhpMenuItem(
|
||||||
|
title: "Always use PHP \(version)",
|
||||||
|
action: #selector(self.isolateSite),
|
||||||
|
keyEquivalent: ""
|
||||||
|
)
|
||||||
item.version = version
|
item.version = version
|
||||||
submenu.addItem(item)
|
submenu.addItem(item)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The last sort descriptor used.
|
/// The last sort descriptor used.
|
||||||
var sortDescriptor: NSSortDescriptor? = nil
|
var sortDescriptor: NSSortDescriptor?
|
||||||
|
|
||||||
/// String that was last searched for. Empty by default.
|
/// String that was last searched for. Empty by default.
|
||||||
var lastSearchedFor = ""
|
var lastSearchedFor = ""
|
||||||
@ -55,12 +55,12 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
return domains[tableView.selectedRow]
|
return domains[tableView.selectedRow]
|
||||||
}
|
}
|
||||||
|
|
||||||
var timer: Timer? = nil
|
var timer: Timer?
|
||||||
|
|
||||||
// MARK: - Display
|
// MARK: - Display
|
||||||
|
|
||||||
public static func create(delegate: NSWindowDelegate?) {
|
public static func create(delegate: NSWindowDelegate?) {
|
||||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||||
|
|
||||||
let windowController = storyboard.instantiateController(
|
let windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "domainListWindow"
|
withIdentifier: "domainListWindow"
|
||||||
@ -80,7 +80,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if (App.shared.domainListWindowController == nil) {
|
if App.shared.domainListWindowController == nil {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,8 +137,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
- Parameter execute: Callback of the work that needs to happen.
|
- Parameter execute: Callback of the work that needs to happen.
|
||||||
- Parameter completion: Callback that is fired when the work is done.
|
- Parameter completion: Callback that is fired when the work is done.
|
||||||
*/
|
*/
|
||||||
internal func waitAndExecute(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {})
|
internal func waitAndExecute(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {}) {
|
||||||
{
|
|
||||||
setUIBusy()
|
setUIBusy()
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
execute()
|
execute()
|
||||||
@ -168,17 +167,12 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
var sorted = self.domains
|
var sorted = self.domains
|
||||||
|
|
||||||
switch descriptor.key {
|
switch descriptor.key {
|
||||||
case "Secure":
|
case "Secure": sorted = self.domains.sorted { $0.getListableSecured() && !$1.getListableSecured() }
|
||||||
sorted = self.domains.sorted { $0.getListableSecured() && !$1.getListableSecured() }; break
|
case "Domain": sorted = self.domains.sorted { $0.getListableAbsolutePath() < $1.getListableAbsolutePath() }
|
||||||
case "Domain":
|
case "PHP": sorted = self.domains.sorted { $0.getListablePhpVersion() < $1.getListablePhpVersion() }
|
||||||
sorted = self.domains.sorted { $0.getListableAbsolutePath() < $1.getListableAbsolutePath() }; break
|
case "Kind": sorted = self.domains.sorted { $0.getListableKind() < $1.getListableKind() }
|
||||||
case "PHP":
|
case "Type": sorted = self.domains.sorted { $0.getListableType() < $1.getListableType() }
|
||||||
sorted = self.domains.sorted { $0.getListablePhpVersion() < $1.getListablePhpVersion() }; break
|
default: break
|
||||||
case "Kind":
|
|
||||||
sorted = self.domains.sorted { $0.getListableKind() < $1.getListableKind() }; break
|
|
||||||
case "Type":
|
|
||||||
sorted = self.domains.sorted { $0.getListableType() < $1.getListableType() }; break
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.domains = descriptor.ascending ? sorted.reversed() : sorted
|
self.domains = descriptor.ascending ? sorted.reversed() : sorted
|
||||||
@ -199,7 +193,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
|||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.tableView.selectRowIndexes([site.offset], byExtendingSelection: false)
|
self.tableView.selectRowIndexes([site.offset], byExtendingSelection: false)
|
||||||
self.tableView.scrollRowToVisible(site.offset)
|
self.tableView.scrollRowToVisible(site.offset)
|
||||||
if (secure && !site.element.getListableSecured()) {
|
if secure && !site.element.getListableSecured() {
|
||||||
self.toggleSecure()
|
self.toggleSecure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class DomainListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate
|
|||||||
// MARK: - Add a new site
|
// MARK: - Add a new site
|
||||||
|
|
||||||
func showSelectionWindow() {
|
func showSelectionWindow() {
|
||||||
let storyboard = NSStoryboard(name: "Main", bundle : nil)
|
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||||
|
|
||||||
let windowController = storyboard.instantiateController(
|
let windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "showSelectionWindow"
|
withIdentifier: "showSelectionWindow"
|
||||||
@ -95,7 +95,7 @@ class DomainListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate
|
|||||||
dialog.canChooseFiles = false
|
dialog.canChooseFiles = false
|
||||||
dialog.beginSheetModal(for: self.window!) { response in
|
dialog.beginSheetModal(for: self.window!) { response in
|
||||||
let result = dialog.url
|
let result = dialog.url
|
||||||
if (result != nil && response == .OK) {
|
if result != nil && response == .OK {
|
||||||
let path: String = result!.path
|
let path: String = result!.path
|
||||||
self.showLinkPopup(path)
|
self.showLinkPopup(path)
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ class DomainListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func showLinkPopup(_ folder: String) {
|
private func showLinkPopup(_ folder: String) {
|
||||||
let storyboard = NSStoryboard(name: "Main", bundle : nil)
|
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||||
|
|
||||||
let windowController = storyboard.instantiateController(
|
let windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "addSiteWindow"
|
withIdentifier: "addSiteWindow"
|
||||||
@ -118,7 +118,7 @@ class DomainListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func showProxyPopup() {
|
private func showProxyPopup() {
|
||||||
let storyboard = NSStoryboard(name: "Main", bundle : nil)
|
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||||
|
|
||||||
let windowController = storyboard.instantiateController(
|
let windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "addProxyWindow"
|
withIdentifier: "addProxyWindow"
|
||||||
|
@ -16,8 +16,8 @@ struct ComposerJson: Decodable {
|
|||||||
|
|
||||||
// MARK: - JSON structure
|
// MARK: - JSON structure
|
||||||
|
|
||||||
let dependencies: Dictionary<String, String>?
|
let dependencies: [String: String]?
|
||||||
let devDependencies: Dictionary<String, String>?
|
let devDependencies: [String: String]?
|
||||||
let configuration: Config?
|
let configuration: Config?
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
@ -40,8 +40,7 @@ struct ComposerJson: Decodable {
|
|||||||
Checks what the PHP version constraint is.
|
Checks what the PHP version constraint is.
|
||||||
Returns a tuple (constraint, location of constraint).
|
Returns a tuple (constraint, location of constraint).
|
||||||
*/
|
*/
|
||||||
public func getPhpVersion() -> (String, ValetSite.VersionSource)
|
public func getPhpVersion() -> (String, ValetSite.VersionSource) {
|
||||||
{
|
|
||||||
// Check if in platform
|
// Check if in platform
|
||||||
if configuration?.platform?.php != nil {
|
if configuration?.platform?.php != nil {
|
||||||
return (configuration!.platform!.php!, .platform)
|
return (configuration!.platform!.php!, .platform)
|
||||||
@ -76,5 +75,3 @@ struct ComposerJson: Decodable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ import Foundation
|
|||||||
|
|
||||||
class ComposerWindow {
|
class ComposerWindow {
|
||||||
|
|
||||||
private var menu: MainMenu? = nil
|
private var menu: MainMenu?
|
||||||
private var shouldNotify: Bool! = nil
|
private var shouldNotify: Bool! = nil
|
||||||
private var completion: ((Bool) -> Void)! = nil
|
private var completion: ((Bool) -> Void)! = nil
|
||||||
private var window: ProgressWindowController? = nil
|
private var window: ProgressWindowController?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Updates the global dependencies and runs the completion callback when done.
|
Updates the global dependencies and runs the completion callback when done.
|
||||||
@ -80,7 +80,7 @@ class ComposerWindow {
|
|||||||
// Closing the window should happen after a slight delay
|
// Closing the window should happen after a slight delay
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [self] in
|
||||||
window?.close()
|
window?.close()
|
||||||
if (shouldNotify) {
|
if shouldNotify {
|
||||||
LocalNotification.send(
|
LocalNotification.send(
|
||||||
title: "alert.composer_success.title".localized,
|
title: "alert.composer_success.title".localized,
|
||||||
subtitle: "alert.composer_success.info".localized
|
subtitle: "alert.composer_success.info".localized
|
||||||
|
@ -17,7 +17,7 @@ struct PhpFrameworks {
|
|||||||
public static let DependencyList = [
|
public static let DependencyList = [
|
||||||
|
|
||||||
// COMMON FRAMEWORKS
|
// COMMON FRAMEWORKS
|
||||||
"laravel/framework" : "Laravel",
|
"laravel/framework": "Laravel",
|
||||||
"symfony/symfony": "Symfony",
|
"symfony/symfony": "Symfony",
|
||||||
"laravel/lumen": "Lumen",
|
"laravel/lumen": "Lumen",
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ struct PhpFrameworks {
|
|||||||
"johnpbloch/wordpress-core": "WordPress",
|
"johnpbloch/wordpress-core": "WordPress",
|
||||||
"zendframework/zendframework": "Zend",
|
"zendframework/zendframework": "Zend",
|
||||||
"zendframework/zend-mvc": "Zend",
|
"zendframework/zend-mvc": "Zend",
|
||||||
"typo3/cms-core": "Typo3",
|
"typo3/cms-core": "Typo3"
|
||||||
|
|
||||||
// TODO (6.0): Handle these in v6.0
|
// TODO (6.0): Handle these in v6.0
|
||||||
// "magento/*": "Magento",
|
// "magento/*": "Magento",
|
||||||
@ -61,7 +61,7 @@ struct PhpFrameworks {
|
|||||||
],
|
],
|
||||||
"Typo3": [
|
"Typo3": [
|
||||||
"/typo3",
|
"/typo3",
|
||||||
"/public/typo3",
|
"/public/typo3"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -17,8 +17,7 @@ class HomebrewDiagnostics {
|
|||||||
|
|
||||||
This check only needs to be performed if the `shivammathur/php` tap is active.
|
This check only needs to be performed if the `shivammathur/php` tap is active.
|
||||||
*/
|
*/
|
||||||
public static func hasAliasConflict() -> Bool
|
public static func hasAliasConflict() -> Bool {
|
||||||
{
|
|
||||||
let tapAlias = Shell.pipe("\(Paths.brew) info shivammathur/php/php --json")
|
let tapAlias = Shell.pipe("\(Paths.brew) info shivammathur/php/php --json")
|
||||||
|
|
||||||
if tapAlias.contains("brew tap shivammathur/php") || tapAlias.contains("Error") {
|
if tapAlias.contains("brew tap shivammathur/php") || tapAlias.contains("Error") {
|
||||||
@ -34,7 +33,8 @@ class HomebrewDiagnostics {
|
|||||||
).first!
|
).first!
|
||||||
|
|
||||||
if tapPhp.version != PhpEnv.brewPhpVersion {
|
if tapPhp.version != PhpEnv.brewPhpVersion {
|
||||||
Log.warn("The `php` formula alias seems to be the different between the tap and core. This could be a problem!")
|
Log.warn("The `php` formula alias seems to be the different between the tap and core. "
|
||||||
|
+ "This could be a problem!")
|
||||||
Log.info("Determining whether both of these versions are installed...")
|
Log.info("Determining whether both of these versions are installed...")
|
||||||
|
|
||||||
let bothInstalled = PhpEnv.shared.availablePhpVersions.contains(tapPhp.version)
|
let bothInstalled = PhpEnv.shared.availablePhpVersions.contains(tapPhp.version)
|
||||||
@ -55,12 +55,23 @@ class HomebrewDiagnostics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func presentAlertAboutConflict() {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
BetterAlert()
|
||||||
|
.withInformation(
|
||||||
|
title: "alert.php_alias_conflict.title".localized,
|
||||||
|
subtitle: "alert.php_alias_conflict.info".localized
|
||||||
|
)
|
||||||
|
.withPrimary(text: "OK")
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
In order to see if we support the --json syntax, we'll query nginx.
|
In order to see if we support the --json syntax, we'll query nginx.
|
||||||
If the JSON response cannot be parsed, Homebrew is probably out of date.
|
If the JSON response cannot be parsed, Homebrew is probably out of date.
|
||||||
*/
|
*/
|
||||||
public static func cannotLoadService(_ name: String = "nginx") -> Bool
|
public static func cannotLoadService(_ name: String = "nginx") -> Bool {
|
||||||
{
|
|
||||||
let serviceInfo = try? JSONDecoder().decode(
|
let serviceInfo = try? JSONDecoder().decode(
|
||||||
[HomebrewService].self,
|
[HomebrewService].self,
|
||||||
from: Shell.pipe(
|
from: Shell.pipe(
|
||||||
|
@ -44,7 +44,7 @@ class NginxConfiguration {
|
|||||||
options: []
|
options: []
|
||||||
)
|
)
|
||||||
|
|
||||||
guard let match = regex.firstMatch(in: contents, range: NSMakeRange(0, contents.count))
|
guard let match = regex.firstMatch(in: contents, range: NSRange(location: 0, length: contents.count))
|
||||||
else { return nil }
|
else { return nil }
|
||||||
|
|
||||||
return contents[Range(match.range(withName: "proxy"), in: contents)!]
|
return contents[Range(match.range(withName: "proxy"), in: contents)!]
|
||||||
@ -60,7 +60,7 @@ class NginxConfiguration {
|
|||||||
options: []
|
options: []
|
||||||
)
|
)
|
||||||
|
|
||||||
guard let match = regex.firstMatch(in: contents, range: NSMakeRange(0, contents.count))
|
guard let match = regex.firstMatch(in: contents, range: NSRange(location: 0, length: contents.count))
|
||||||
else { return nil }
|
else { return nil }
|
||||||
|
|
||||||
let major: String = contents[Range(match.range(withName: "major"), in: contents)!],
|
let major: String = contents[Range(match.range(withName: "major"), in: contents)!],
|
||||||
|
@ -8,10 +8,8 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ValetProxyScanner: ProxyScanner
|
class ValetProxyScanner: ProxyScanner {
|
||||||
{
|
func resolveProxies(directoryPath: String) -> [ValetProxy] {
|
||||||
func resolveProxies(directoryPath: String) -> [ValetProxy]
|
|
||||||
{
|
|
||||||
return try! FileManager
|
return try! FileManager
|
||||||
.default
|
.default
|
||||||
.contentsOfDirectory(atPath: directoryPath)
|
.contentsOfDirectory(atPath: directoryPath)
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ValetProxy: DomainListable
|
class ValetProxy: DomainListable {
|
||||||
{
|
|
||||||
var domain: String
|
var domain: String
|
||||||
var tld: String
|
var tld: String
|
||||||
var target: String
|
var target: String
|
||||||
|
@ -6,14 +6,16 @@
|
|||||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
class FakeSiteScanner: SiteScanner
|
class FakeSiteScanner: SiteScanner {
|
||||||
{
|
|
||||||
let fakes = [
|
let fakes = [
|
||||||
ValetSite(fakeWithName: "laravel", tld: "test", secure: true, path: "~/Code/laravel/framework", linked: true),
|
ValetSite(fakeWithName: "laravel", tld: "test", secure: true,
|
||||||
|
path: "~/Code/laravel/framework", linked: true),
|
||||||
|
|
||||||
ValetSite(fakeWithName: "tailwind", tld: "test", secure: true, path: "~/Code/tailwind/site", linked: true, constraint: "8.0"),
|
ValetSite(fakeWithName: "tailwind", tld: "test", secure: true,
|
||||||
|
path: "~/Code/tailwind/site", linked: true, constraint: "8.0"),
|
||||||
|
|
||||||
ValetSite(fakeWithName: "forge", tld: "test", secure: true, path: "~/Code/laravel/forge", linked: true),
|
ValetSite(fakeWithName: "forge", tld: "test", secure: true,
|
||||||
|
path: "~/Code/laravel/forge", linked: true),
|
||||||
|
|
||||||
ValetSite(fakeWithName: "concord", tld: "test", secure: false,
|
ValetSite(fakeWithName: "concord", tld: "test", secure: false,
|
||||||
path: "~/Code/concord", linked: true, driver: "Laravel (^8.0)", constraint: "^7.4", isolated: "7.4"),
|
path: "~/Code/concord", linked: true, driver: "Laravel (^8.0)", constraint: "^7.4", isolated: "7.4"),
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol SiteScanner
|
protocol SiteScanner {
|
||||||
{
|
|
||||||
func resolveSiteCount(paths: [String]) -> Int
|
func resolveSiteCount(paths: [String]) -> Int
|
||||||
|
|
||||||
func resolveSitesFrom(paths: [String]) -> [ValetSite]
|
func resolveSitesFrom(paths: [String]) -> [ValetSite]
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ValetSiteScanner: SiteScanner
|
class ValetSiteScanner: SiteScanner {
|
||||||
{
|
|
||||||
func resolveSiteCount(paths: [String]) -> Int {
|
func resolveSiteCount(paths: [String]) -> Int {
|
||||||
return paths.map { path in
|
return paths.map { path in
|
||||||
|
|
||||||
@ -18,7 +17,7 @@ class ValetSiteScanner: SiteScanner
|
|||||||
|
|
||||||
return entries
|
return entries
|
||||||
.map { self.isSite($0, forPath: path) }
|
.map { self.isSite($0, forPath: path) }
|
||||||
.filter{ $0 == true}
|
.filter { $0 == true}
|
||||||
.count
|
.count
|
||||||
|
|
||||||
}.reduce(0, +)
|
}.reduce(0, +)
|
||||||
|
@ -26,9 +26,9 @@ extension ValetSite {
|
|||||||
|
|
||||||
self.composerPhpCompatibleWithLinked = self.composerPhp.split(separator: "|")
|
self.composerPhpCompatibleWithLinked = self.composerPhp.split(separator: "|")
|
||||||
.map { string in
|
.map { string in
|
||||||
return PhpVersionNumberCollection.make(from: [PhpEnv.phpInstall.version.long])
|
return !PhpVersionNumberCollection.make(from: [PhpEnv.phpInstall.version.long])
|
||||||
.matching(constraint: string.trimmingCharacters(in: .whitespacesAndNewlines))
|
.matching(constraint: string.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||||
.count > 0
|
.isEmpty
|
||||||
}.contains(true)
|
}.contains(true)
|
||||||
|
|
||||||
self.driver = driver
|
self.driver = driver
|
||||||
|
@ -36,7 +36,7 @@ class ValetSite: DomainListable {
|
|||||||
var secured: Bool!
|
var secured: Bool!
|
||||||
|
|
||||||
/// What driver is currently in use. If not detected, defaults to nil.
|
/// What driver is currently in use. If not detected, defaults to nil.
|
||||||
var driver: String? = nil
|
var driver: String?
|
||||||
|
|
||||||
/// Whether the driver was determined by checking the Composer file.
|
/// Whether the driver was determined by checking the Composer file.
|
||||||
var driverDeterminedByComposer: Bool = false
|
var driverDeterminedByComposer: Bool = false
|
||||||
@ -60,10 +60,10 @@ class ValetSite: DomainListable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum VersionSource: String {
|
enum VersionSource: String {
|
||||||
case unknown = "unknown"
|
case unknown
|
||||||
case require = "require"
|
case require
|
||||||
case platform = "platform"
|
case platform
|
||||||
case valetphprc = "valetphprc"
|
case valetphprc
|
||||||
}
|
}
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -103,8 +103,9 @@ class ValetSite: DomainListable {
|
|||||||
*/
|
*/
|
||||||
public func determineIsolated() {
|
public func determineIsolated() {
|
||||||
if let version = ValetSite.isolatedVersion("~/.config/valet/Nginx/\(self.name).\(self.tld)") {
|
if let version = ValetSite.isolatedVersion("~/.config/valet/Nginx/\(self.name).\(self.tld)") {
|
||||||
if (!PhpEnv.shared.cachedPhpInstallations.keys.contains(version)) {
|
if !PhpEnv.shared.cachedPhpInstallations.keys.contains(version) {
|
||||||
Log.err("The PHP version \(version) is isolated for the site \(self.name) but that PHP version is unavailable.")
|
Log.err("The PHP version \(version) is isolated for the site \(self.name) "
|
||||||
|
+ "but that PHP version is unavailable.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.isolatedPhpVersion = PhpEnv.shared.cachedPhpInstallations[version]
|
self.isolatedPhpVersion = PhpEnv.shared.cachedPhpInstallations[version]
|
||||||
@ -144,9 +145,9 @@ class ValetSite: DomainListable {
|
|||||||
// For example, for Laravel 8 projects the value is "^7.3|^8.0"
|
// For example, for Laravel 8 projects the value is "^7.3|^8.0"
|
||||||
self.composerPhpCompatibleWithLinked = self.composerPhp.split(separator: "|")
|
self.composerPhpCompatibleWithLinked = self.composerPhp.split(separator: "|")
|
||||||
.map { string in
|
.map { string in
|
||||||
return PhpVersionNumberCollection.make(from: [PhpEnv.phpInstall.version.long])
|
return !PhpVersionNumberCollection.make(from: [PhpEnv.phpInstall.version.long])
|
||||||
.matching(constraint: string.trimmingCharacters(in: .whitespacesAndNewlines))
|
.matching(constraint: string.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||||
.count > 0
|
.isEmpty
|
||||||
}.contains(true)
|
}.contains(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +67,28 @@ class Valet {
|
|||||||
return self.shared.features.contains(feature)
|
return self.shared.features.contains(feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Retrieve a list of all domains, including sites & proxies.
|
||||||
|
*/
|
||||||
public static func getDomainListable() -> [DomainListable] {
|
public static func getDomainListable() -> [DomainListable] {
|
||||||
return self.shared.sites + self.shared.proxies
|
return self.shared.sites + self.shared.proxies
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Notify the user about a non-default TLD being set.
|
||||||
|
*/
|
||||||
|
public static func notifyAboutUnsupportedTLD() {
|
||||||
|
if Valet.shared.config.tld != "test" {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
BetterAlert().withInformation(
|
||||||
|
title: "alert.warnings.tld_issue.title".localized,
|
||||||
|
subtitle: "alert.warnings.tld_issue.subtitle".localized,
|
||||||
|
description: "alert.warnings.tld_issue.description".localized
|
||||||
|
).withPrimary(text: "OK").show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
We don't want to load the initial config.json file as soon as the class is initialised.
|
We don't want to load the initial config.json file as soon as the class is initialised.
|
||||||
|
|
||||||
@ -118,7 +136,7 @@ class Valet {
|
|||||||
public func reloadSites() {
|
public func reloadSites() {
|
||||||
loadConfiguration()
|
loadConfiguration()
|
||||||
|
|
||||||
if (isBusy) {
|
if isBusy {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +150,7 @@ class Valet {
|
|||||||
`enabled(feature)`, which contains information about the feature set of the version of Valet that is currently
|
`enabled(feature)`, which contains information about the feature set of the version of Valet that is currently
|
||||||
in use. This allows PHP Monitor to do different things when Valet 3.0 is enabled.
|
in use. This allows PHP Monitor to do different things when Valet 3.0 is enabled.
|
||||||
*/
|
*/
|
||||||
public func evaluateFeatureSupport() -> Void {
|
public func evaluateFeatureSupport() {
|
||||||
let isOlderThanVersionThree = version.versionCompare("3.0") == .orderedAscending
|
let isOlderThanVersionThree = version.versionCompare("3.0") == .orderedAscending
|
||||||
|
|
||||||
if isOlderThanVersionThree {
|
if isOlderThanVersionThree {
|
||||||
@ -148,7 +166,7 @@ class Valet {
|
|||||||
Should this procedure fail, the user will get an alert notifying them that the version of Valet they have
|
Should this procedure fail, the user will get an alert notifying them that the version of Valet they have
|
||||||
installed is not recent enough.
|
installed is not recent enough.
|
||||||
*/
|
*/
|
||||||
public func validateVersion() -> Void {
|
public func validateVersion() {
|
||||||
// 1. Evaluate feature support
|
// 1. Evaluate feature support
|
||||||
Valet.shared.evaluateFeatureSupport()
|
Valet.shared.evaluateFeatureSupport()
|
||||||
|
|
||||||
@ -160,13 +178,17 @@ class Valet {
|
|||||||
BetterAlert()
|
BetterAlert()
|
||||||
.withInformation(
|
.withInformation(
|
||||||
title: "alert.min_valet_version.title".localized,
|
title: "alert.min_valet_version.title".localized,
|
||||||
subtitle:"alert.min_valet_version.info".localized(version!, Constants.MinimumRecommendedValetVersion)
|
subtitle: "alert.min_valet_version.info".localized(
|
||||||
|
version!,
|
||||||
|
Constants.MinimumRecommendedValetVersion
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.withPrimary(text: "OK")
|
.withPrimary(text: "OK")
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.info("Valet version \(version!) is recent enough, OK (recommended: \(Constants.MinimumRecommendedValetVersion))")
|
Log.info("Valet version \(version!) is recent enough, OK " +
|
||||||
|
"(recommended: \(Constants.MinimumRecommendedValetVersion))")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +242,11 @@ class Valet {
|
|||||||
/// The default site that is served if the domain is not found. Optional.
|
/// The default site that is served if the domain is not found. Optional.
|
||||||
let defaultSite: String?
|
let defaultSite: String?
|
||||||
|
|
||||||
|
// swiftlint:disable nesting
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case tld, paths, loopback, defaultSite = "default"
|
case tld, paths, loopback, defaultSite = "default"
|
||||||
}
|
}
|
||||||
|
// swiftlint:enable nesting
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ extension MainMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
var error: Error? = nil
|
var error: Error?
|
||||||
|
|
||||||
do { try execute() } catch let e { error = e }
|
do { try execute() } catch let e { error = e }
|
||||||
|
|
||||||
|
@ -26,8 +26,7 @@ extension MainMenu {
|
|||||||
)
|
)
|
||||||
.withPrimary(text: "alert.fix_my_valet.ok".localized)
|
.withPrimary(text: "alert.fix_my_valet.ok".localized)
|
||||||
.withSecondary(text: "alert.fix_my_valet.cancel".localized)
|
.withSecondary(text: "alert.fix_my_valet.cancel".localized)
|
||||||
.didSelectPrimary()
|
.didSelectPrimary() {
|
||||||
{
|
|
||||||
Log.info("The user has chosen to abort Fix My Valet")
|
Log.info("The user has chosen to abort Fix My Valet")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -76,7 +75,7 @@ extension MainMenu {
|
|||||||
MainMenu.shared.switchToPhpVersion(version)
|
MainMenu.shared.switchToPhpVersion(version)
|
||||||
})
|
})
|
||||||
.withSecondary(text: "alert.fix_my_valet_done.stay".localized(PhpEnv.brewPhpVersion))
|
.withSecondary(text: "alert.fix_my_valet_done.stay".localized(PhpEnv.brewPhpVersion))
|
||||||
.withTertiary(text: "", action: { alert in
|
.withTertiary(text: "", action: { _ in
|
||||||
NSWorkspace.shared.open(Constants.Urls.FrequentlyAskedQuestions)
|
NSWorkspace.shared.open(Constants.Urls.FrequentlyAskedQuestions)
|
||||||
})
|
})
|
||||||
.show()
|
.show()
|
||||||
|
@ -42,15 +42,7 @@ extension MainMenu {
|
|||||||
|
|
||||||
// Check for an alias conflict
|
// Check for an alias conflict
|
||||||
if HomebrewDiagnostics.hasAliasConflict() {
|
if HomebrewDiagnostics.hasAliasConflict() {
|
||||||
DispatchQueue.main.async {
|
HomebrewDiagnostics.presentAlertAboutConflict()
|
||||||
BetterAlert()
|
|
||||||
.withInformation(
|
|
||||||
title: "alert.php_alias_conflict.title".localized,
|
|
||||||
subtitle: "alert.php_alias_conflict.info".localized
|
|
||||||
)
|
|
||||||
.withPrimary(text: "OK")
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePhpVersionInStatusBar()
|
updatePhpVersionInStatusBar()
|
||||||
@ -60,22 +52,27 @@ extension MainMenu {
|
|||||||
let installation = PhpEnv.phpInstall
|
let installation = PhpEnv.phpInstall
|
||||||
installation.notifyAboutBrokenPhpFpm()
|
installation.notifyAboutBrokenPhpFpm()
|
||||||
|
|
||||||
// Set up the config watchers on launch (these are automatically updated via delegate methods if the user switches)
|
// Set up the config watchers on launch
|
||||||
|
// (these are automatically updated via delegate methods if the user switches)
|
||||||
Log.info("Setting up watchers...")
|
Log.info("Setting up watchers...")
|
||||||
App.shared.handlePhpConfigWatcher()
|
App.shared.handlePhpConfigWatcher()
|
||||||
|
|
||||||
// Detect applications (preset + custom)
|
// Detect applications (preset + custom)
|
||||||
Log.info("Detecting applications...")
|
Log.info("Detecting applications...")
|
||||||
App.shared.detectedApplications = Application.detectPresetApplications()
|
App.shared.detectedApplications = Application.detectPresetApplications()
|
||||||
|
|
||||||
let customApps = Preferences.custom.scanApps.map { appName in
|
let customApps = Preferences.custom.scanApps.map { appName in
|
||||||
return Application(appName, .user_supplied)
|
return Application(appName, .user_supplied)
|
||||||
}.filter { app in
|
}.filter { app in
|
||||||
return app.isInstalled()
|
return app.isInstalled()
|
||||||
}
|
}
|
||||||
|
|
||||||
App.shared.detectedApplications.append(contentsOf: customApps)
|
App.shared.detectedApplications.append(contentsOf: customApps)
|
||||||
|
|
||||||
let appNames = App.shared.detectedApplications.map { app in
|
let appNames = App.shared.detectedApplications.map { app in
|
||||||
return app.name
|
return app.name
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info("Detected applications: \(appNames)")
|
Log.info("Detected applications: \(appNames)")
|
||||||
|
|
||||||
// Load the global hotkey
|
// Load the global hotkey
|
||||||
@ -85,15 +82,7 @@ extension MainMenu {
|
|||||||
Valet.shared.startPreloadingSites()
|
Valet.shared.startPreloadingSites()
|
||||||
|
|
||||||
// A non-default TLD is not officially supported since Valet 3.2.x
|
// A non-default TLD is not officially supported since Valet 3.2.x
|
||||||
if (Valet.shared.config.tld != "test") {
|
Valet.notifyAboutUnsupportedTLD()
|
||||||
DispatchQueue.main.async {
|
|
||||||
BetterAlert().withInformation(
|
|
||||||
title: "alert.warnings.tld_issue.title".localized,
|
|
||||||
subtitle: "alert.warnings.tld_issue.subtitle".localized,
|
|
||||||
description: "alert.warnings.tld_issue.description".localized
|
|
||||||
).withPrimary(text: "OK").show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationCenter.default.post(name: Events.ServicesUpdated, object: nil)
|
NotificationCenter.default.post(name: Events.ServicesUpdated, object: nil)
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
|
|
||||||
static let shared = MainMenu()
|
static let shared = MainMenu()
|
||||||
|
|
||||||
weak var menuDelegate: NSMenuDelegate? = nil
|
weak var menuDelegate: NSMenuDelegate?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The status bar item with variable length.
|
The status bar item with variable length.
|
||||||
@ -143,7 +143,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
/** Refreshes the icon with the PHP version. */
|
/** Refreshes the icon with the PHP version. */
|
||||||
@objc func refreshIcon() {
|
@objc func refreshIcon() {
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
if (PhpEnv.shared.isBusy) {
|
if PhpEnv.shared.isBusy {
|
||||||
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
} else {
|
} else {
|
||||||
if Preferences.preferences[.shouldDisplayDynamicIcon] as! Bool == false {
|
if Preferences.preferences[.shouldDisplayDynamicIcon] as! Bool == false {
|
||||||
@ -257,7 +257,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func openPhpInfo() {
|
@objc func openPhpInfo() {
|
||||||
var url: URL? = nil
|
var url: URL?
|
||||||
|
|
||||||
asyncWithBusyUI {
|
asyncWithBusyUI {
|
||||||
url = Actions.createTempPhpInfoFile()
|
url = Actions.createTempPhpInfoFile()
|
||||||
@ -274,7 +274,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func openActiveConfigFolder() {
|
@objc func openActiveConfigFolder() {
|
||||||
if (PhpEnv.phpInstall.version.error) {
|
if PhpEnv.phpInstall.version.error {
|
||||||
// php version was not identified
|
// php version was not identified
|
||||||
Actions.openGenericPhpConfigFolder()
|
Actions.openGenericPhpConfigFolder()
|
||||||
return
|
return
|
||||||
|
@ -52,7 +52,7 @@ class ServicesView: NSView, XibLoadable {
|
|||||||
func loadData() {
|
func loadData() {
|
||||||
self.applyAllInfoFieldsFromCachedValue()
|
self.applyAllInfoFieldsFromCachedValue()
|
||||||
HomebrewService.loadAll { services in
|
HomebrewService.loadAll { services in
|
||||||
ServicesView.services = Dictionary(uniqueKeysWithValues: services.map{ ($0.name, $0) })
|
ServicesView.services = Dictionary(uniqueKeysWithValues: services.map { ($0.name, $0) })
|
||||||
self.applyAllInfoFieldsFromCachedValue()
|
self.applyAllInfoFieldsFromCachedValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class StatusMenu : NSMenu {
|
class StatusMenu: NSMenu {
|
||||||
|
|
||||||
func addPhpVersionMenuItems() {
|
func addPhpVersionMenuItems() {
|
||||||
if PhpEnv.phpInstall.version.error {
|
if PhpEnv.phpInstall.version.error {
|
||||||
@ -27,7 +27,7 @@ class StatusMenu : NSMenu {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if PhpEnv.shared.availablePhpVersions.count == 0 {
|
if PhpEnv.shared.availablePhpVersions.isEmpty {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +40,10 @@ class StatusMenu : NSMenu {
|
|||||||
|
|
||||||
func addValetMenuItems() {
|
func addValetMenuItems() {
|
||||||
self.addItem(HeaderView.asMenuItem(text: "mi_valet".localized))
|
self.addItem(HeaderView.asMenuItem(text: "mi_valet".localized))
|
||||||
self.addItem(NSMenuItem(title: "mi_valet_config".localized, action: #selector(MainMenu.openValetConfigFolder), keyEquivalent: "v"))
|
self.addItem(NSMenuItem(
|
||||||
self.addItem(NSMenuItem(title: "mi_domain_list".localized, action: #selector(MainMenu.openDomainList), keyEquivalent: "l"))
|
title: "mi_valet_config".localized, action: #selector(MainMenu.openValetConfigFolder), keyEquivalent: "v"))
|
||||||
|
self.addItem(NSMenuItem(
|
||||||
|
title: "mi_domain_list".localized, action: #selector(MainMenu.openDomainList), keyEquivalent: "l"))
|
||||||
self.addItem(NSMenuItem.separator())
|
self.addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +54,7 @@ class StatusMenu : NSMenu {
|
|||||||
|
|
||||||
self.addComposerMenuItems()
|
self.addComposerMenuItems()
|
||||||
|
|
||||||
if (PhpEnv.shared.isBusy) {
|
if PhpEnv.shared.isBusy {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,24 +74,42 @@ class StatusMenu : NSMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addCoreMenuItems() {
|
func addCoreMenuItems() {
|
||||||
self.addItem(NSMenuItem(title: "mi_preferences".localized, action: #selector(MainMenu.openPrefs), keyEquivalent: ","))
|
self.addItem(
|
||||||
self.addItem(NSMenuItem(title: "mi_about".localized, action: #selector(MainMenu.openAbout), keyEquivalent: ""))
|
NSMenuItem(title: "mi_preferences".localized, action: #selector(MainMenu.openPrefs), keyEquivalent: ",")
|
||||||
self.addItem(NSMenuItem(title: "mi_quit".localized, action: #selector(MainMenu.terminateApp), keyEquivalent: "q"))
|
)
|
||||||
|
self.addItem(
|
||||||
|
NSMenuItem(title: "mi_about".localized, action: #selector(MainMenu.openAbout), keyEquivalent: "")
|
||||||
|
)
|
||||||
|
self.addItem(
|
||||||
|
NSMenuItem(title: "mi_quit".localized, action: #selector(MainMenu.terminateApp), keyEquivalent: "q")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Remaining Menu Items
|
// MARK: Remaining Menu Items
|
||||||
|
|
||||||
func addConfigurationMenuItems() {
|
func addConfigurationMenuItems() {
|
||||||
self.addItem(HeaderView.asMenuItem(text: "mi_configuration".localized))
|
self.addItem(HeaderView.asMenuItem(text: "mi_configuration".localized))
|
||||||
self.addItem(NSMenuItem(title: "mi_php_config".localized, action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c"))
|
self.addItem(
|
||||||
self.addItem(NSMenuItem(title: "mi_phpinfo".localized, action: #selector(MainMenu.openPhpInfo), keyEquivalent: "i"))
|
NSMenuItem(title: "mi_php_config".localized,
|
||||||
|
action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c")
|
||||||
|
)
|
||||||
|
self.addItem(
|
||||||
|
NSMenuItem(title: "mi_phpinfo".localized, action: #selector(MainMenu.openPhpInfo), keyEquivalent: "i")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addComposerMenuItems() {
|
func addComposerMenuItems() {
|
||||||
self.addItem(HeaderView.asMenuItem(text: "mi_composer".localized))
|
self.addItem(HeaderView.asMenuItem(text: "mi_composer".localized))
|
||||||
self.addItem(NSMenuItem(title: "mi_global_composer".localized, action: #selector(MainMenu.openGlobalComposerFolder), keyEquivalent: "g"))
|
self.addItem(
|
||||||
|
NSMenuItem(title: "mi_global_composer".localized,
|
||||||
|
action: #selector(MainMenu.openGlobalComposerFolder), keyEquivalent: "g")
|
||||||
|
)
|
||||||
|
|
||||||
let composerMenuItem = NSMenuItem(title: "mi_update_global_composer".localized, action: PhpEnv.shared.isBusy ? nil : #selector(MainMenu.updateGlobalComposerDependencies), keyEquivalent: "g")
|
let composerMenuItem = NSMenuItem(
|
||||||
|
title: "mi_update_global_composer".localized,
|
||||||
|
action: PhpEnv.shared.isBusy ? nil : #selector(MainMenu.updateGlobalComposerDependencies),
|
||||||
|
keyEquivalent: "g"
|
||||||
|
)
|
||||||
composerMenuItem.keyEquivalentModifierMask = .shift
|
composerMenuItem.keyEquivalentModifierMask = .shift
|
||||||
|
|
||||||
self.addItem(composerMenuItem)
|
self.addItem(composerMenuItem)
|
||||||
@ -108,7 +128,7 @@ class StatusMenu : NSMenu {
|
|||||||
func addExtensionsMenuItems() {
|
func addExtensionsMenuItems() {
|
||||||
self.addItem(HeaderView.asMenuItem(text: "mi_detected_extensions".localized))
|
self.addItem(HeaderView.asMenuItem(text: "mi_detected_extensions".localized))
|
||||||
|
|
||||||
if (PhpEnv.phpInstall.extensions.count == 0) {
|
if PhpEnv.phpInstall.extensions.isEmpty {
|
||||||
self.addItem(NSMenuItem(title: "mi_no_extensions_detected".localized, action: nil, keyEquivalent: ""))
|
self.addItem(NSMenuItem(title: "mi_no_extensions_detected".localized, action: nil, keyEquivalent: ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,18 +192,35 @@ class StatusMenu : NSMenu {
|
|||||||
servicesMenu.addItem(NSMenuItem.separator())
|
servicesMenu.addItem(NSMenuItem.separator())
|
||||||
servicesMenu.addItem(HeaderView.asMenuItem(text: "mi_services".localized))
|
servicesMenu.addItem(HeaderView.asMenuItem(text: "mi_services".localized))
|
||||||
|
|
||||||
servicesMenu.addItem(NSMenuItem(title: "mi_restart_dnsmasq".localized, action: #selector(MainMenu.restartDnsMasq), keyEquivalent: "d"))
|
|
||||||
servicesMenu.addItem(NSMenuItem(title: "mi_restart_php_fpm".localized, action: #selector(MainMenu.restartPhpFpm), keyEquivalent: "p"))
|
|
||||||
servicesMenu.addItem(NSMenuItem(title: "mi_restart_nginx".localized, action: #selector(MainMenu.restartNginx), keyEquivalent: "n"))
|
|
||||||
servicesMenu.addItem(NSMenuItem(title: "mi_restart_all_services".localized, action: #selector(MainMenu.restartAllServices), keyEquivalent: "s"))
|
|
||||||
servicesMenu.addItem(
|
servicesMenu.addItem(
|
||||||
NSMenuItem(title: "mi_stop_all_services".localized, action: #selector(MainMenu.stopAllServices), keyEquivalent: "s"),
|
NSMenuItem(title: "mi_restart_dnsmasq".localized,
|
||||||
withKeyModifier: [.command, .shift])
|
action: #selector(MainMenu.restartDnsMasq), keyEquivalent: "d")
|
||||||
|
)
|
||||||
|
servicesMenu.addItem(
|
||||||
|
NSMenuItem(title: "mi_restart_php_fpm".localized,
|
||||||
|
action: #selector(MainMenu.restartPhpFpm), keyEquivalent: "p")
|
||||||
|
)
|
||||||
|
servicesMenu.addItem(
|
||||||
|
NSMenuItem(title: "mi_restart_nginx".localized,
|
||||||
|
action: #selector(MainMenu.restartNginx), keyEquivalent: "n")
|
||||||
|
)
|
||||||
|
servicesMenu.addItem(
|
||||||
|
NSMenuItem(title: "mi_restart_all_services".localized,
|
||||||
|
action: #selector(MainMenu.restartAllServices), keyEquivalent: "s")
|
||||||
|
)
|
||||||
|
servicesMenu.addItem(
|
||||||
|
NSMenuItem(title: "mi_stop_all_services".localized,
|
||||||
|
action: #selector(MainMenu.stopAllServices), keyEquivalent: "s"),
|
||||||
|
withKeyModifier: [.command, .shift]
|
||||||
|
)
|
||||||
|
|
||||||
servicesMenu.addItem(NSMenuItem.separator())
|
servicesMenu.addItem(NSMenuItem.separator())
|
||||||
servicesMenu.addItem(HeaderView.asMenuItem(text: "mi_manual_actions".localized))
|
servicesMenu.addItem(HeaderView.asMenuItem(text: "mi_manual_actions".localized))
|
||||||
|
|
||||||
servicesMenu.addItem(NSMenuItem(title: "mi_php_refresh".localized, action: #selector(MainMenu.reloadPhpMonitorMenuInForeground), keyEquivalent: "r"))
|
servicesMenu.addItem(
|
||||||
|
NSMenuItem(title: "mi_php_refresh".localized,
|
||||||
|
action: #selector(MainMenu.reloadPhpMonitorMenuInForeground), keyEquivalent: "r")
|
||||||
|
)
|
||||||
|
|
||||||
for item in servicesMenu.items {
|
for item in servicesMenu.items {
|
||||||
item.target = MainMenu.shared
|
item.target = MainMenu.shared
|
||||||
@ -210,11 +247,13 @@ class StatusMenu : NSMenu {
|
|||||||
let brew = (shortVersion == PhpEnv.brewPhpVersion) ? "php" : "php@\(shortVersion)"
|
let brew = (shortVersion == PhpEnv.brewPhpVersion) ? "php" : "php@\(shortVersion)"
|
||||||
let menuItem = PhpMenuItem(
|
let menuItem = PhpMenuItem(
|
||||||
title: "\("mi_php_switch".localized) \(versionString) (\(brew))",
|
title: "\("mi_php_switch".localized) \(versionString) (\(brew))",
|
||||||
action: (shortVersion == PhpEnv.phpInstall.version.short) ? nil : action, keyEquivalent: "\(shortcutKey)"
|
action: (shortVersion == PhpEnv.phpInstall.version.short)
|
||||||
|
? nil
|
||||||
|
: action, keyEquivalent: "\(shortcutKey)"
|
||||||
)
|
)
|
||||||
|
|
||||||
menuItem.version = shortVersion
|
menuItem.version = shortVersion
|
||||||
shortcutKey = shortcutKey + 1
|
shortcutKey += 1
|
||||||
|
|
||||||
self.addItem(menuItem)
|
self.addItem(menuItem)
|
||||||
}
|
}
|
||||||
@ -251,9 +290,9 @@ class XdebugMenuItem: NSMenuItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ExtensionMenuItem: NSMenuItem {
|
class ExtensionMenuItem: NSMenuItem {
|
||||||
var phpExtension: PhpExtension? = nil
|
var phpExtension: PhpExtension?
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditorMenuItem: NSMenuItem {
|
class EditorMenuItem: NSMenuItem {
|
||||||
var editor: Application? = nil
|
var editor: Application?
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class BetterAlert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||||
|
|
||||||
self.windowController = storyboard.instantiateController(
|
self.windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "noticeWindow"
|
withIdentifier: "noticeWindow"
|
||||||
@ -31,8 +31,8 @@ class BetterAlert {
|
|||||||
|
|
||||||
public func withPrimary(
|
public func withPrimary(
|
||||||
text: String,
|
text: String,
|
||||||
action: @escaping (BetterAlertVC) -> Void = {
|
action: @escaping (BetterAlertVC) -> Void = { vc in
|
||||||
vc in vc.close(with: .alertFirstButtonReturn)
|
vc.close(with: .alertFirstButtonReturn)
|
||||||
}
|
}
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.noticeVC.buttonPrimary.title = text
|
self.noticeVC.buttonPrimary.title = text
|
||||||
@ -42,8 +42,8 @@ class BetterAlert {
|
|||||||
|
|
||||||
public func withSecondary(
|
public func withSecondary(
|
||||||
text: String,
|
text: String,
|
||||||
action: ((BetterAlertVC) -> Void)? = {
|
action: ((BetterAlertVC) -> Void)? = { vc in
|
||||||
vc in vc.close(with: .alertSecondButtonReturn)
|
vc.close(with: .alertSecondButtonReturn)
|
||||||
}
|
}
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.noticeVC.buttonSecondary.title = text
|
self.noticeVC.buttonSecondary.title = text
|
||||||
@ -73,7 +73,7 @@ class BetterAlert {
|
|||||||
self.noticeVC.labelDescription.stringValue = description
|
self.noticeVC.labelDescription.stringValue = description
|
||||||
|
|
||||||
// If the description is missing, handle the excess space and change the top margin
|
// If the description is missing, handle the excess space and change the top margin
|
||||||
if (description == "") {
|
if description == "" {
|
||||||
self.noticeVC.labelDescription.isHidden = true
|
self.noticeVC.labelDescription.isHidden = true
|
||||||
self.noticeVC.primaryButtonTopMargin.constant = 0
|
self.noticeVC.primaryButtonTopMargin.constant = 0
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ class BetterAlertVC: NSViewController {
|
|||||||
view.window?.makeFirstResponder(buttonPrimary)
|
view.window?.makeFirstResponder(buttonPrimary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
Log.perf("A BetterAlert has been deinitialized.")
|
Log.perf("A BetterAlert has been deinitialized.")
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,15 @@ struct GlobalKeybindPreference: Codable, CustomStringConvertible {
|
|||||||
|
|
||||||
// MARK: - Internal variables
|
// MARK: - Internal variables
|
||||||
|
|
||||||
let function : Bool
|
let function: Bool
|
||||||
let control : Bool
|
let control: Bool
|
||||||
let command : Bool
|
let command: Bool
|
||||||
let shift : Bool
|
let shift: Bool
|
||||||
let option : Bool
|
let option: Bool
|
||||||
let capsLock : Bool
|
let capsLock: Bool
|
||||||
let carbonFlags : UInt32
|
let carbonFlags: UInt32
|
||||||
let characters : String?
|
let characters: String?
|
||||||
let keyCode : UInt32
|
let keyCode: UInt32
|
||||||
|
|
||||||
// MARK: - How the keybind is display in Preferences
|
// MARK: - How the keybind is display in Preferences
|
||||||
|
|
||||||
|
@ -99,10 +99,9 @@ class Preferences {
|
|||||||
*/
|
*/
|
||||||
static func handleMigration() {
|
static func handleMigration() {
|
||||||
// If the user chose the "no icon" option, migrate it over
|
// If the user chose the "no icon" option, migrate it over
|
||||||
if (
|
if
|
||||||
UserDefaults.standard.value(forKey: RetiredPreferenceName.shouldDisplayPhpHintInIcon.rawValue) != nil &&
|
UserDefaults.standard.value(forKey: RetiredPreferenceName.shouldDisplayPhpHintInIcon.rawValue) != nil &&
|
||||||
UserDefaults.standard.bool(forKey: RetiredPreferenceName.shouldDisplayPhpHintInIcon.rawValue) == false
|
UserDefaults.standard.bool(forKey: RetiredPreferenceName.shouldDisplayPhpHintInIcon.rawValue) == false {
|
||||||
) {
|
|
||||||
Log.info("The preference where the user chose no icon has been migrated over.")
|
Log.info("The preference where the user chose no icon has been migrated over.")
|
||||||
UserDefaults.standard.set(MenuBarIcon.noIcon.rawValue, forKey: PreferenceName.iconTypeToDisplay.rawValue)
|
UserDefaults.standard.set(MenuBarIcon.noIcon.rawValue, forKey: PreferenceName.iconTypeToDisplay.rawValue)
|
||||||
UserDefaults.standard.removeObject(forKey: RetiredPreferenceName.shouldDisplayPhpHintInIcon.rawValue)
|
UserDefaults.standard.removeObject(forKey: RetiredPreferenceName.shouldDisplayPhpHintInIcon.rawValue)
|
||||||
@ -136,20 +135,27 @@ class Preferences {
|
|||||||
private static func cache() -> [PreferenceName: Any] {
|
private static func cache() -> [PreferenceName: Any] {
|
||||||
return [
|
return [
|
||||||
// Part 1: Always Booleans
|
// Part 1: Always Booleans
|
||||||
.shouldDisplayDynamicIcon: UserDefaults.standard.bool(forKey: PreferenceName.shouldDisplayDynamicIcon.rawValue) as Any,
|
.shouldDisplayDynamicIcon: UserDefaults.standard.bool(
|
||||||
.fullPhpVersionDynamicIcon: UserDefaults.standard.bool(forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) as Any,
|
forKey: PreferenceName.shouldDisplayDynamicIcon.rawValue) as Any,
|
||||||
.autoServiceRestartAfterExtensionToggle: UserDefaults.standard.bool(forKey: PreferenceName.autoServiceRestartAfterExtensionToggle.rawValue) as Any,
|
.fullPhpVersionDynamicIcon: UserDefaults.standard.bool(
|
||||||
.autoComposerGlobalUpdateAfterSwitch: UserDefaults.standard.bool(forKey: PreferenceName.autoComposerGlobalUpdateAfterSwitch.rawValue) as Any,
|
forKey: PreferenceName.fullPhpVersionDynamicIcon.rawValue) as Any,
|
||||||
.allowProtocolForIntegrations: UserDefaults.standard.bool(forKey: PreferenceName.allowProtocolForIntegrations.rawValue) as Any,
|
.autoServiceRestartAfterExtensionToggle: UserDefaults.standard.bool(
|
||||||
|
forKey: PreferenceName.autoServiceRestartAfterExtensionToggle.rawValue) as Any,
|
||||||
|
.autoComposerGlobalUpdateAfterSwitch: UserDefaults.standard.bool(
|
||||||
|
forKey: PreferenceName.autoComposerGlobalUpdateAfterSwitch.rawValue) as Any,
|
||||||
|
.allowProtocolForIntegrations: UserDefaults.standard.bool(
|
||||||
|
forKey: PreferenceName.allowProtocolForIntegrations.rawValue) as Any,
|
||||||
|
|
||||||
// Part 2: Always Strings
|
// Part 2: Always Strings
|
||||||
.globalHotkey: UserDefaults.standard.string(forKey: PreferenceName.globalHotkey.rawValue) as Any,
|
.globalHotkey: UserDefaults.standard.string(
|
||||||
.iconTypeToDisplay: UserDefaults.standard.string(forKey: PreferenceName.iconTypeToDisplay.rawValue) as Any,
|
forKey: PreferenceName.globalHotkey.rawValue) as Any,
|
||||||
|
.iconTypeToDisplay: UserDefaults.standard.string(
|
||||||
|
forKey: PreferenceName.iconTypeToDisplay.rawValue) as Any
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
static func update(_ preference: PreferenceName, value: Any?) {
|
static func update(_ preference: PreferenceName, value: Any?) {
|
||||||
if (value == nil) {
|
if value == nil {
|
||||||
UserDefaults.standard.removeObject(forKey: preference.rawValue)
|
UserDefaults.standard.removeObject(forKey: preference.rawValue)
|
||||||
} else {
|
} else {
|
||||||
UserDefaults.standard.setValue(value, forKey: preference.rawValue)
|
UserDefaults.standard.setValue(value, forKey: preference.rawValue)
|
||||||
|
@ -18,7 +18,7 @@ class PrefsVC: NSViewController {
|
|||||||
// MARK: - Display
|
// MARK: - Display
|
||||||
|
|
||||||
public static func create(delegate: NSWindowDelegate?) {
|
public static func create(delegate: NSWindowDelegate?) {
|
||||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||||
|
|
||||||
let windowController = storyboard.instantiateController(
|
let windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "preferencesWindow"
|
withIdentifier: "preferencesWindow"
|
||||||
@ -35,7 +35,7 @@ class PrefsVC: NSViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||||
if (App.shared.preferencesWindowController == nil) {
|
if App.shared.preferencesWindowController == nil {
|
||||||
Self.create(delegate: delegate)
|
Self.create(delegate: delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,18 @@ class PrefsVC: NSViewController {
|
|||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
[
|
[
|
||||||
CheckboxPreferenceView.make(
|
getDynamicIconPreferenceView(),
|
||||||
|
getIconOptionsPreferenceView(),
|
||||||
|
getIconDensityPreferenceView(),
|
||||||
|
getAutoRestartPreferenceView(),
|
||||||
|
getAutomaticComposerUpdatePreferenceView(),
|
||||||
|
getShortcutPreferenceView(),
|
||||||
|
getIntegrationsPreferenceView()
|
||||||
|
].forEach({ self.stackView.addArrangedSubview($0) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getDynamicIconPreferenceView() -> NSView {
|
||||||
|
return CheckboxPreferenceView.make(
|
||||||
sectionText: "prefs.dynamic_icon".localized,
|
sectionText: "prefs.dynamic_icon".localized,
|
||||||
descriptionText: "prefs.dynamic_icon_desc".localized,
|
descriptionText: "prefs.dynamic_icon_desc".localized,
|
||||||
checkboxText: "prefs.dynamic_icon_title".localized,
|
checkboxText: "prefs.dynamic_icon_title".localized,
|
||||||
@ -55,8 +66,11 @@ class PrefsVC: NSViewController {
|
|||||||
action: {
|
action: {
|
||||||
MainMenu.shared.refreshIcon()
|
MainMenu.shared.refreshIcon()
|
||||||
}
|
}
|
||||||
),
|
)
|
||||||
SelectPreferenceView.make(
|
}
|
||||||
|
|
||||||
|
private func getIconOptionsPreferenceView() -> NSView {
|
||||||
|
return SelectPreferenceView.make(
|
||||||
sectionText: "",
|
sectionText: "",
|
||||||
descriptionText: "prefs.icon_options_desc".localized,
|
descriptionText: "prefs.icon_options_desc".localized,
|
||||||
options: MenuBarIcon.allCases.map({ return $0.rawValue }),
|
options: MenuBarIcon.allCases.map({ return $0.rawValue }),
|
||||||
@ -65,8 +79,11 @@ class PrefsVC: NSViewController {
|
|||||||
action: {
|
action: {
|
||||||
MainMenu.shared.refreshIcon()
|
MainMenu.shared.refreshIcon()
|
||||||
}
|
}
|
||||||
),
|
)
|
||||||
CheckboxPreferenceView.make(
|
}
|
||||||
|
|
||||||
|
private func getIconDensityPreferenceView() -> NSView {
|
||||||
|
return CheckboxPreferenceView.make(
|
||||||
sectionText: "prefs.info_density".localized,
|
sectionText: "prefs.info_density".localized,
|
||||||
descriptionText: "prefs.display_full_php_version_desc".localized,
|
descriptionText: "prefs.display_full_php_version_desc".localized,
|
||||||
checkboxText: "prefs.display_full_php_version".localized,
|
checkboxText: "prefs.display_full_php_version".localized,
|
||||||
@ -75,39 +92,50 @@ class PrefsVC: NSViewController {
|
|||||||
MainMenu.shared.refreshIcon()
|
MainMenu.shared.refreshIcon()
|
||||||
MainMenu.shared.rebuild()
|
MainMenu.shared.rebuild()
|
||||||
}
|
}
|
||||||
),
|
)
|
||||||
CheckboxPreferenceView.make(
|
}
|
||||||
|
|
||||||
|
private func getAutoRestartPreferenceView() -> NSView {
|
||||||
|
return CheckboxPreferenceView.make(
|
||||||
sectionText: "prefs.services".localized,
|
sectionText: "prefs.services".localized,
|
||||||
descriptionText: "prefs.auto_restart_services_desc".localized,
|
descriptionText: "prefs.auto_restart_services_desc".localized,
|
||||||
checkboxText: "prefs.auto_restart_services_title".localized,
|
checkboxText: "prefs.auto_restart_services_title".localized,
|
||||||
preference: .autoServiceRestartAfterExtensionToggle,
|
preference: .autoServiceRestartAfterExtensionToggle,
|
||||||
action: {}
|
action: {}
|
||||||
),
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getAutomaticComposerUpdatePreferenceView() -> NSView {
|
||||||
CheckboxPreferenceView.make(
|
CheckboxPreferenceView.make(
|
||||||
sectionText: "prefs.switcher".localized,
|
sectionText: "prefs.switcher".localized,
|
||||||
descriptionText: "prefs.auto_composer_update_desc".localized,
|
descriptionText: "prefs.auto_composer_update_desc".localized,
|
||||||
checkboxText: "prefs.auto_composer_update_title".localized,
|
checkboxText: "prefs.auto_composer_update_title".localized,
|
||||||
preference: .autoComposerGlobalUpdateAfterSwitch,
|
preference: .autoComposerGlobalUpdateAfterSwitch,
|
||||||
action: {}
|
action: {}
|
||||||
),
|
)
|
||||||
HotkeyPreferenceView.make(
|
}
|
||||||
|
|
||||||
|
private func getShortcutPreferenceView() -> NSView {
|
||||||
|
return HotkeyPreferenceView.make(
|
||||||
sectionText: "prefs.global_shortcut".localized,
|
sectionText: "prefs.global_shortcut".localized,
|
||||||
descriptionText: "prefs.shortcut_desc".localized,
|
descriptionText: "prefs.shortcut_desc".localized,
|
||||||
self
|
self
|
||||||
),
|
)
|
||||||
CheckboxPreferenceView.make(
|
}
|
||||||
|
|
||||||
|
private func getIntegrationsPreferenceView() -> NSView {
|
||||||
|
return CheckboxPreferenceView.make(
|
||||||
sectionText: "prefs.integrations".localized,
|
sectionText: "prefs.integrations".localized,
|
||||||
descriptionText: "prefs.open_protocol_desc".localized,
|
descriptionText: "prefs.open_protocol_desc".localized,
|
||||||
checkboxText: "prefs.open_protocol_title".localized,
|
checkboxText: "prefs.open_protocol_title".localized,
|
||||||
preference: .allowProtocolForIntegrations,
|
preference: .allowProtocolForIntegrations,
|
||||||
action: {}
|
action: {}
|
||||||
),
|
)
|
||||||
].forEach({ self.stackView.addArrangedSubview($0) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Listening for hotkey delegate
|
// MARK: - Listening for hotkey delegate
|
||||||
|
|
||||||
var listeningForHotkeyView: HotkeyPreferenceView? = nil
|
var listeningForHotkeyView: HotkeyPreferenceView?
|
||||||
|
|
||||||
override func viewWillDisappear() {
|
override func viewWillDisappear() {
|
||||||
if listeningForHotkeyView !== nil {
|
if listeningForHotkeyView !== nil {
|
||||||
|
@ -96,7 +96,8 @@ class Stats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if Stats.successfulLaunchCount < 7 && Stats.successfulSwitchCount < 40 {
|
if Stats.successfulLaunchCount < 7 && Stats.successfulSwitchCount < 40 {
|
||||||
return Log.info("It is too soon to see the sponsor message (launched \(Stats.successfulLaunchCount) times, switched \(Stats.successfulSwitchCount) times).")
|
return Log.info("It is too soon to see the sponsor message (launched \(Stats.successfulLaunchCount) " +
|
||||||
|
"times, switched \(Stats.successfulSwitchCount) times).")
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
@ -25,7 +23,13 @@ class CheckboxPreferenceView: NSView, XibLoadable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func make(sectionText: String, descriptionText: String, checkboxText: String, preference: PreferenceName, action: @escaping () -> Void) -> NSView {
|
static func make(
|
||||||
|
sectionText: String,
|
||||||
|
descriptionText: String,
|
||||||
|
checkboxText: String,
|
||||||
|
preference: PreferenceName,
|
||||||
|
action: @escaping () -> Void
|
||||||
|
) -> NSView {
|
||||||
let view = Self.createFromXib()!
|
let view = Self.createFromXib()!
|
||||||
view.labelSection.stringValue = sectionText
|
view.labelSection.stringValue = sectionText
|
||||||
view.labelDescription.stringValue = descriptionText
|
view.labelDescription.stringValue = descriptionText
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
@ -66,7 +64,7 @@ class HotkeyPreferenceView: NSView, XibLoadable {
|
|||||||
func loadGlobalKeybindFromPreferences() {
|
func loadGlobalKeybindFromPreferences() {
|
||||||
let globalKeybind = GlobalKeybindPreference.fromJson(Preferences.preferences[.globalHotkey] as! String?)
|
let globalKeybind = GlobalKeybindPreference.fromJson(Preferences.preferences[.globalHotkey] as! String?)
|
||||||
|
|
||||||
if (globalKeybind != nil) {
|
if globalKeybind != nil {
|
||||||
updateKeybindButton(globalKeybind!)
|
updateKeybindButton(globalKeybind!)
|
||||||
} else {
|
} else {
|
||||||
buttonSetShortcut.title = "prefs.shortcut_set".localized
|
buttonSetShortcut.title = "prefs.shortcut_set".localized
|
||||||
|
@ -16,7 +16,7 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
@IBOutlet weak var popupButton: NSPopUpButton!
|
@IBOutlet weak var popupButton: NSPopUpButton!
|
||||||
|
|
||||||
var localizationPrefix: String = ""
|
var localizationPrefix: String = ""
|
||||||
var imagePrefix: String? = nil
|
var imagePrefix: String?
|
||||||
|
|
||||||
var options: [String] = [] {
|
var options: [String] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
@ -50,6 +50,7 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable function_parameter_count
|
||||||
static func make(
|
static func make(
|
||||||
sectionText: String,
|
sectionText: String,
|
||||||
descriptionText: String,
|
descriptionText: String,
|
||||||
@ -57,8 +58,7 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
localizationPrefix: String,
|
localizationPrefix: String,
|
||||||
imagePrefix: String? = nil,
|
imagePrefix: String? = nil,
|
||||||
preference: PreferenceName,
|
preference: PreferenceName,
|
||||||
action: @escaping () -> Void) -> NSView
|
action: @escaping () -> Void) -> NSView {
|
||||||
{
|
|
||||||
let view = Self.createFromXib()!
|
let view = Self.createFromXib()!
|
||||||
|
|
||||||
view.labelSection.stringValue = sectionText
|
view.labelSection.stringValue = sectionText
|
||||||
@ -72,6 +72,7 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
// swiftlint:enable function_parameter_count
|
||||||
|
|
||||||
@IBAction func valueChanged(_ sender: Any) {
|
@IBAction func valueChanged(_ sender: Any) {
|
||||||
let index = self.popupButton.indexOfSelectedItem
|
let index = self.popupButton.indexOfSelectedItem
|
||||||
|
@ -12,7 +12,7 @@ import AppKit
|
|||||||
class ProgressWindowController: NSWindowController, NSWindowDelegate {
|
class ProgressWindowController: NSWindowController, NSWindowDelegate {
|
||||||
|
|
||||||
static func display(title: String, description: String) -> ProgressWindowController {
|
static func display(title: String, description: String) -> ProgressWindowController {
|
||||||
let storyboard = NSStoryboard(name: "ProgressWindow" , bundle : nil)
|
let storyboard = NSStoryboard(name: "ProgressWindow", bundle: nil)
|
||||||
|
|
||||||
let windowController = storyboard.instantiateController(
|
let windowController = storyboard.instantiateController(
|
||||||
withIdentifier: "progressWindow"
|
withIdentifier: "progressWindow"
|
||||||
@ -39,7 +39,7 @@ class ProgressWindowController: NSWindowController, NSWindowDelegate {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
textView.string = textView.string + string
|
textView.string += string
|
||||||
textView.scrollToEndOfDocument(nil)
|
textView.scrollToEndOfDocument(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,17 +15,17 @@ enum HomebrewDir: String {
|
|||||||
class Paths {
|
class Paths {
|
||||||
|
|
||||||
static let shared = Paths()
|
static let shared = Paths()
|
||||||
var baseDir : HomebrewDir
|
var baseDir: HomebrewDir
|
||||||
var userName = String(Shell.pipe("whoami").split(separator: "\n")[0])
|
var userName = String(Shell.pipe("whoami").split(separator: "\n")[0])
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let optBrewFound = Shell.fileExists("\(HomebrewDir.opt.rawValue)/bin/brew")
|
let optBrewFound = Shell.fileExists("\(HomebrewDir.opt.rawValue)/bin/brew")
|
||||||
let usrBrewFound = Shell.fileExists("\(HomebrewDir.usr.rawValue)/bin/brew")
|
let usrBrewFound = Shell.fileExists("\(HomebrewDir.usr.rawValue)/bin/brew")
|
||||||
|
|
||||||
if (optBrewFound) {
|
if optBrewFound {
|
||||||
// This is usually the case with Homebrew installed on Apple Silicon
|
// This is usually the case with Homebrew installed on Apple Silicon
|
||||||
baseDir = .opt
|
baseDir = .opt
|
||||||
} else if (usrBrewFound) {
|
} else if usrBrewFound {
|
||||||
// This is usually the case with Homebrew installed on Intel (or Rosetta 2)
|
// This is usually the case with Homebrew installed on Intel (or Rosetta 2)
|
||||||
baseDir = .usr
|
baseDir = .usr
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,7 +16,7 @@ class PhpConfigWatcher {
|
|||||||
|
|
||||||
var didChange: ((URL) -> Void)?
|
var didChange: ((URL) -> Void)?
|
||||||
|
|
||||||
var lastUpdate: TimeInterval? = nil
|
var lastUpdate: TimeInterval?
|
||||||
|
|
||||||
var watchers: [FSWatcher] = []
|
var watchers: [FSWatcher] = []
|
||||||
|
|
||||||
@ -46,7 +46,11 @@ class PhpConfigWatcher {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func addWatcher(for url: URL, eventMask: DispatchSource.FileSystemEvent, behaviour: FSWatcherBehaviour = .reloadsMenu) {
|
func addWatcher(
|
||||||
|
for url: URL,
|
||||||
|
eventMask: DispatchSource.FileSystemEvent,
|
||||||
|
behaviour: FSWatcherBehaviour = .reloadsMenu
|
||||||
|
) {
|
||||||
if !Filesystem.fileExists(url.path) {
|
if !Filesystem.fileExists(url.path) {
|
||||||
Log.warn("No watcher was created for \(url.path) because the requested file does not exist.")
|
Log.warn("No watcher was created for \(url.path) because the requested file does not exist.")
|
||||||
return
|
return
|
||||||
@ -84,13 +88,21 @@ class FSWatcher {
|
|||||||
|
|
||||||
let url: URL
|
let url: URL
|
||||||
|
|
||||||
init(for url: URL, eventMask: DispatchSource.FileSystemEvent, parent: PhpConfigWatcher, behaviour: FSWatcherBehaviour = .reloadsMenu) {
|
init(
|
||||||
|
for url: URL,
|
||||||
|
eventMask: DispatchSource.FileSystemEvent,
|
||||||
|
parent: PhpConfigWatcher,
|
||||||
|
behaviour: FSWatcherBehaviour = .reloadsMenu
|
||||||
|
) {
|
||||||
self.url = url
|
self.url = url
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.startMonitoring(eventMask, behaviour: behaviour)
|
self.startMonitoring(eventMask, behaviour: behaviour)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startMonitoring(_ eventMask: DispatchSource.FileSystemEvent, behaviour: FSWatcherBehaviour) {
|
func startMonitoring(
|
||||||
|
_ eventMask: DispatchSource.FileSystemEvent,
|
||||||
|
behaviour: FSWatcherBehaviour
|
||||||
|
) {
|
||||||
guard folderMonitorSource == nil && monitoredFolderFileDescriptor == -1 else {
|
guard folderMonitorSource == nil && monitoredFolderFileDescriptor == -1 else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
2
phpmon/Vendor/HotKey/HotKeysController.swift
vendored
2
phpmon/Vendor/HotKey/HotKeysController.swift
vendored
@ -91,7 +91,6 @@ final class HotKeysController {
|
|||||||
hotKeys.removeValue(forKey: box.carbonHotKeyID)
|
hotKeys.removeValue(forKey: box.carbonHotKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Events
|
// MARK: - Events
|
||||||
|
|
||||||
static func handleCarbonEvent(_ event: EventRef?) -> OSStatus {
|
static func handleCarbonEvent(_ event: EventRef?) -> OSStatus {
|
||||||
@ -157,7 +156,6 @@ final class HotKeysController {
|
|||||||
InstallEventHandler(GetEventDispatcherTarget(), hotKeyEventHandler, 2, eventSpec, nil, &eventHandler)
|
InstallEventHandler(GetEventDispatcherTarget(), hotKeyEventHandler, 2, eventSpec, nil, &eventHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Querying
|
// MARK: - Querying
|
||||||
|
|
||||||
private static func hotKey(for carbonHotKeyID: UInt32) -> HotKey? {
|
private static func hotKey(for carbonHotKeyID: UInt32) -> HotKey? {
|
||||||
|
Reference in New Issue
Block a user