1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 20:10:08 +02:00

♻️ Cleanup

- Bump version number to 2.3
- Disable Metal validation in project configuration
- Added comments to various files to clarify code
- Moved various strings to Localizable.strings
- Removed references to old view controller for command log
- No longer log previously ran commands
This commit is contained in:
2020-07-16 23:16:39 +02:00
parent 5d69b423c1
commit 70c04d4dc7
9 changed files with 168 additions and 89 deletions

View File

@ -405,7 +405,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 24; CURRENT_PROJECT_VERSION = 25;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = phpmon/Info.plist; INFOPLIST_FILE = phpmon/Info.plist;
@ -413,7 +413,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 2.2; MARKETING_VERSION = 2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -429,7 +429,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 24; CURRENT_PROJECT_VERSION = 25;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = phpmon/Info.plist; INFOPLIST_FILE = phpmon/Info.plist;
@ -437,7 +437,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 2.2; MARKETING_VERSION = 2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -39,6 +39,7 @@
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">

View File

@ -10,16 +10,34 @@ import Cocoa
import UserNotifications import UserNotifications
@NSApplicationMain @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
// MARK: - Variables // MARK: - Variables
/**
The Shell singleton that keeps track of the history of all
(invoked by PHP Monitor) shell commands. It is used to
invoke all commands in this application.
*/
let sharedShell : Shell let sharedShell : Shell
/**
The App singleton contains information about the state of
the application and global variables.
*/
let state : App let state : App
/**
The MainMenu singleton is responsible for rendering the
menu bar item and its menu, as well as its actions.
*/
let menu : MainMenu let menu : MainMenu
// MARK: - Initializer // MARK: - Initializer
/**
When the application initializes, create all singletons.
*/
override init() { override init() {
self.sharedShell = Shell.user self.sharedShell = Shell.user
self.state = App.shared self.state = App.shared
@ -29,20 +47,28 @@ class AppDelegate: NSObject, NSApplicationDelegate {
// MARK: - Lifecycle // MARK: - Lifecycle
/**
When the application has finished launching, we'll want to set up
the user notification center delegate, and kickoff the menu
startup procedure.
*/
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
NSUserNotificationCenter.default.delegate = self NSUserNotificationCenter.default.delegate = self
self.menu.startup() self.menu.startup()
} }
func applicationWillTerminate(_ aNotification: Notification) { // MARK: - NSUserNotificationCenterDelegate
self.state.windowController = nil
} /**
} When a notification is sent, the delegate of the notification center
is asked whether the notification should be presented or not. Since
extension AppDelegate: NSUserNotificationCenterDelegate { the user can now disable notifications per application since macOS
func userNotificationCenter(_ center: NSUserNotificationCenter, Catalina, any and all notifications should be displayed.
shouldPresent notification: NSUserNotification) -> Bool { */
func userNotificationCenter(
_ center: NSUserNotificationCenter,
shouldPresent notification: NSUserNotification
) -> Bool {
return true return true
} }
} }

View File

@ -12,17 +12,18 @@ class StatusMenu : NSMenu {
public func addPhpVersionMenuItems() public func addPhpVersionMenuItems()
{ {
var string = "We are not sure what version of PHP you are running." var string = "mi_unsure".localized
if (App.shared.currentVersion != nil) { if (App.shared.currentVersion != nil) {
if (!App.shared.currentVersion!.error) { if (!App.shared.currentVersion!.error) {
string = "You are running PHP \(App.shared.currentVersion!.long)" // in case the php version loaded without issue
string = "\("mi_php_version".localized) \(App.shared.currentVersion!.long)"
self.addItem(NSMenuItem(title: string, action: nil, keyEquivalent: "")) self.addItem(NSMenuItem(title: string, action: nil, keyEquivalent: ""))
} else { } else {
// in case of an error show the error message // in case of an error show the error message
self.addItem(NSMenuItem(title: "Oof! It appears your PHP installation is broken...", action: nil, keyEquivalent: "")) ["mi_php_broken_1", "mi_php_broken_2",
self.addItem(NSMenuItem(title: "Try running `php -v` in your terminal.", action: nil, keyEquivalent: "")) "mi_php_broken_3", "mi_php_broken_4"].forEach { (message) in
self.addItem(NSMenuItem(title: "You could also try switching to another version.", action: nil, keyEquivalent: "")) self.addItem(NSMenuItem(title: message.localized, action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Running `brew reinstall php` (or for the equivalent version) might help.", action: nil, keyEquivalent: "")) }
} }
} }
} }
@ -34,30 +35,30 @@ class StatusMenu : NSMenu {
for index in (0..<App.shared.availablePhpVersions.count).reversed() { for index in (0..<App.shared.availablePhpVersions.count).reversed() {
let version = App.shared.availablePhpVersions[index] let version = App.shared.availablePhpVersions[index]
let action = #selector(MainMenu.switchToPhpVersion(sender:)) let action = #selector(MainMenu.switchToPhpVersion(sender:))
let menuItem = NSMenuItem(title: "Switch to PHP \(version)", action: (version == App.shared.currentVersion?.short) ? nil : action, keyEquivalent: "\(shortcutKey)") let menuItem = NSMenuItem(title: "\("mi_php_switch".localized) \(version)", action: (version == App.shared.currentVersion?.short) ? nil : action, keyEquivalent: "\(shortcutKey)")
menuItem.tag = index menuItem.tag = index
shortcutKey = shortcutKey + 1 shortcutKey = shortcutKey + 1
self.addItem(menuItem) self.addItem(menuItem)
} }
self.addItem(NSMenuItem.separator()) self.addItem(NSMenuItem.separator())
self.addItem(NSMenuItem(title: "Active Services", action: nil, keyEquivalent: "")) self.addItem(NSMenuItem(title: "mi_active_services".localized, action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Restart php-fpm service", action: #selector(MainMenu.restartPhpFpm), keyEquivalent: "f")) self.addItem(NSMenuItem(title: "mi_restart_php_fpm".localized, action: #selector(MainMenu.restartPhpFpm), keyEquivalent: "f"))
self.addItem(NSMenuItem(title: "Restart nginx service", action: #selector(MainMenu.restartNginx), keyEquivalent: "n")) self.addItem(NSMenuItem(title: "mi_restart_nginx".localized, action: #selector(MainMenu.restartNginx), keyEquivalent: "n"))
self.addItem(NSMenuItem(title: "Force load latest PHP version", action: #selector(MainMenu.forceRestartLatestPhp), keyEquivalent: "")) self.addItem(NSMenuItem(title: "mi_force_load_latest".localized, action: #selector(MainMenu.forceRestartLatestPhp), keyEquivalent: ""))
} }
if (App.shared.busy) { if (App.shared.busy) {
self.addItem(NSMenuItem(title: "PHP Monitor is busy...", action: nil, keyEquivalent: "")) self.addItem(NSMenuItem(title: "mi_busy".localized, action: nil, keyEquivalent: ""))
} }
} }
public func addPhpConfigurationMenuItems() public func addPhpConfigurationMenuItems()
{ {
if (App.shared.currentVersion != nil) { if (App.shared.currentVersion != nil) {
self.addItem(NSMenuItem(title: "Configuration", action: nil, keyEquivalent: "")) self.addItem(NSMenuItem(title: "mi_configuration".localized, action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Valet configuration (.config/valet)", action: #selector(MainMenu.openValetConfigFolder), keyEquivalent: "v")) self.addItem(NSMenuItem(title: "mi_valet_config".localized, action: #selector(MainMenu.openValetConfigFolder), keyEquivalent: "v"))
self.addItem(NSMenuItem(title: "PHP configuration file (php.ini)", action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c")) self.addItem(NSMenuItem(title: "mi_php_config".localized, action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c"))
self.addItem(NSMenuItem.separator()) self.addItem(NSMenuItem.separator())
self.addItem(NSMenuItem(title: "Enabled Extensions", action: nil, keyEquivalent: "")) self.addItem(NSMenuItem(title: "mi_enabled_extensions".localized, action: nil, keyEquivalent: ""))
self.addXdebugMenuItem() self.addXdebugMenuItem()
} }
} }
@ -68,7 +69,7 @@ class StatusMenu : NSMenu {
if (xdebugFound) { if (xdebugFound) {
let xdebugOn = App.shared.currentVersion!.xdebugEnabled let xdebugOn = App.shared.currentVersion!.xdebugEnabled
let xdebugToggleMenuItem = NSMenuItem( let xdebugToggleMenuItem = NSMenuItem(
title: "Xdebug", title: "mi_xdebug".localized,
action: #selector(MainMenu.toggleXdebug), keyEquivalent: "x" action: #selector(MainMenu.toggleXdebug), keyEquivalent: "x"
) )
if (xdebugOn) { if (xdebugOn) {
@ -77,7 +78,7 @@ class StatusMenu : NSMenu {
self.addItem(xdebugToggleMenuItem) self.addItem(xdebugToggleMenuItem)
} else { } else {
let disabledItem = NSMenuItem( let disabledItem = NSMenuItem(
title: "xdebug.so missing", title: "mi_xdebug_missing".localized,
action: nil, keyEquivalent: "x" action: nil, keyEquivalent: "x"
) )
disabledItem.isEnabled = false disabledItem.isEnabled = false

View File

@ -6,6 +6,33 @@
Copyright © 2020 Nico Verbruggen. All rights reserved. Copyright © 2020 Nico Verbruggen. All rights reserved.
*/ */
// MENU ITEMS (MI)
"mi_busy" = "PHP Monitor is busy...";
"mi_unsure" = "We are not sure what version of PHP you are running.";
"mi_php_version" = "You are running PHP";
"mi_php_switch" = "Switch to PHP";
"mi_php_broken_1" = "Oof! It appears your PHP installation is broken...";
"mi_php_broken_2" = "Try running `php -v` in your terminal.";
"mi_php_broken_3" = "You could also try switching to another version.";
"mi_php_broken_4" = "Running `brew reinstall php` (or for the equivalent version) might help.";
"mi_active_services" = "Active Services";
"mi_restart_php_fpm" = "Restart php-fpm service";
"mi_restart_nginx" = "Restart nginx service";
"mi_force_load_latest" = "Force load latest PHP version";
"mi_configuration" = "Configuration";
"mi_valet_config" = "Valet configuration (.config/valet)";
"mi_php_config" = "PHP Configuration file (php.ini)";
"mi_enabled_extensions" = "Enabled Extensions";
"mi_xdebug" = "Xdebug";
"mi_xdebug_missing" = "xdebug.so missing";
"mi_quit" = "Quit PHP Monitor";
"mi_about" = "About PHP Monitor";
// ALERTS // ALERTS
// Force Reload Started // Force Reload Started
@ -15,3 +42,9 @@
// Force Reload Done // Force Reload Done
"alert.force_reload_done.title" = "PHP has been force reloaded"; "alert.force_reload_done.title" = "PHP has been force reloaded";
"alert.force_reload_done.info" = "All appropriate services have been restarted, and the latest version of PHP is now active. You can now try switching to another version of PHP."; "alert.force_reload_done.info" = "All appropriate services have been restarted, and the latest version of PHP is now active. You can now try switching to another version of PHP.";
// PHP Monitor Cannot Start
"alert.cannot_start.title" = "PHP Monitor cannot start";
"alert.cannot_start.info" = "The issue you were just notified about is keeping PHP Monitor from functioning correctly. Please fix the issue and restart PHP Monitor. After clicking on OK, PHP Monitor will close.\n\nIf you have fixed the issue (or don't remember what the exact issue is) you can click on Retry, which will have PHP Monitor retry the startup checks.";
"alert.cannot_start.close" = "Close";
"alert.cannot_start.retry" = "Retry";

View File

@ -32,9 +32,4 @@ class App {
*/ */
var timer: Timer? var timer: Timer?
/**
The window controller that will show the log.
*/
var windowController: NSWindowController? = nil
} }

View File

@ -9,8 +9,13 @@
import Cocoa import Cocoa
class Command { class Command {
/// Immediately executes a command. /**
Immediately executes a command.
- Parameter path: The path of the command or program to invoke.
- Parameter arguments: A list of arguments that are passed on.
*/
public static func execute(path: String, arguments: [String]) -> String { public static func execute(path: String, arguments: [String]) -> String {
let task = Process() let task = Process()
task.launchPath = path task.launchPath = path

View File

@ -12,10 +12,18 @@ class MainMenu: NSObject, NSWindowDelegate {
static let shared = MainMenu() static let shared = MainMenu()
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) /**
The status bar item with variable length.
*/
let statusItem = NSStatusBar.system.statusItem(
withLength: NSStatusItem.variableLength
)
// MARK: - UI related // MARK: - UI related
/**
Kick off the startup of the rendering of the main menu.
*/
public func startup() { public func startup() {
// Start with the icon // Start with the icon
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!) self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
@ -29,6 +37,9 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
} }
/**
When the environment is all clear and the app can run, let's go.
*/
private func onEnvironmentPass() { private func onEnvironmentPass() {
App.shared.availablePhpVersions = Actions.detectPhpVersions() App.shared.availablePhpVersions = Actions.detectPhpVersions()
self.updatePhpVersionInStatusBar() self.updatePhpVersionInStatusBar()
@ -44,13 +55,16 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
} }
/**
When the environment is not OK, present an alert to inform the user.
*/
private func onEnvironmentFail() { private func onEnvironmentFail() {
DispatchQueue.main.async { DispatchQueue.main.async {
let close = Alert.present( let close = Alert.present(
messageText: "PHP Monitor cannot start", messageText: "alert.cannot_start.title".localized,
informativeText: "The issue you were just notified about is keeping PHP Monitor from functioning correctly. Please fix the issue and restart PHP Monitor. After clicking on OK, PHP Monitor will close.\n\nIf you have fixed the issue (or don't remember what the exact issue is) you can click on Retry, which will have PHP Monitor retry the startup checks.", informativeText: "alert.cannot_start.info".localized,
buttonTitle: "Close", buttonTitle: "alert.cannot_start.close".localized,
secondButtonTitle: "Retry" secondButtonTitle: "alert.cannot_start.retry".localized
) )
if (!close) { if (!close) {
self.startup() self.startup()
@ -60,6 +74,9 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
} }
/**
Update the menu's contents, based on what's going on.
*/
public func update() { public func update() {
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
// Create a new menu // Create a new menu
@ -78,8 +95,8 @@ class MainMenu: NSObject, NSWindowDelegate {
menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem.separator())
// Add about & quit menu items // Add about & quit menu items
menu.addItem(NSMenuItem(title: "About PHP Monitor", action: #selector(self.openAbout), keyEquivalent: "")) menu.addItem(NSMenuItem(title: "mi_about".localized, action: #selector(self.openAbout), keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Quit PHP Monitor", action: #selector(self.terminateApp), keyEquivalent: "q")) menu.addItem(NSMenuItem(title: "mi_quit".localized, action: #selector(self.terminateApp), keyEquivalent: "q"))
// Make sure every item can be interacted with // Make sure every item can be interacted with
menu.items.forEach({ (item) in menu.items.forEach({ (item) in
@ -93,10 +110,19 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
} }
/**
Sets the status bar image based on a version string.
*/
func setStatusBarImage(version: String) { func setStatusBarImage(version: String) {
self.setStatusBar(image: MenuBarImageGenerator.textToImage(text: version)) self.setStatusBar(
image: MenuBarImageGenerator.textToImage(text: version)
)
} }
/**
Sets the status bar image, based on the provided NSImage.
The image will be used as a template image.
*/
func setStatusBar(image: NSImage) { func setStatusBar(image: NSImage) {
if let button = statusItem.button { if let button = statusItem.button {
image.isTemplate = true image.isTemplate = true
@ -106,6 +132,14 @@ class MainMenu: NSObject, NSWindowDelegate {
// MARK: - Nicer callbacks // MARK: - Nicer callbacks
/**
Executes a specific callback and fires the completion callback,
while updating the UI as required. As long as the completion callback
does not fire, the app is presumed to be busy and the UI reflects this.
- Parameter execute: Escaping callback of the work that needs to happen.
- Parameter completion: Callback that is fired when the work is done.
*/
private func waitAndExecute(_ execute: @escaping () -> Void, _ completion: @escaping () -> Void = {}) private func waitAndExecute(_ execute: @escaping () -> Void, _ completion: @escaping () -> Void = {})
{ {
App.shared.busy = true App.shared.busy = true
@ -122,7 +156,7 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
} }
// MARK: - Actions // MARK: - User Interface
@objc func updatePhpVersionInStatusBar() { @objc func updatePhpVersionInStatusBar() {
App.shared.currentVersion = PhpVersion() App.shared.currentVersion = PhpVersion()
@ -144,6 +178,8 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
} }
// MARK: - Actions
@objc public func restartPhpFpm() { @objc public func restartPhpFpm() {
self.waitAndExecute({ self.waitAndExecute({
Actions.restartPhpFpm() Actions.restartPhpFpm()
@ -163,10 +199,12 @@ class MainMenu: NSObject, NSWindowDelegate {
} }
@objc public func forceRestartLatestPhp() { @objc public func forceRestartLatestPhp() {
// Tell the user the switch is about to occur
_ = Alert.present( _ = Alert.present(
messageText: "alert.force_reload.title".localized, messageText: "alert.force_reload.title".localized,
informativeText: "alert.force_reload.info".localized informativeText: "alert.force_reload.info".localized
) )
// Start switching
self.waitAndExecute({ Actions.fixMyPhp() }, { self.waitAndExecute({ Actions.fixMyPhp() }, {
_ = Alert.present( _ = Alert.present(
messageText: "alert.force_reload_done.title".localized, messageText: "alert.force_reload_done.title".localized,
@ -192,6 +230,7 @@ class MainMenu: NSObject, NSWindowDelegate {
@objc public func switchToPhpVersion(sender: AnyObject) { @objc public func switchToPhpVersion(sender: AnyObject) {
self.setBusyImage() self.setBusyImage()
// TODO: A wise man once said: using tags is not good. Fix this.
let index = sender.tag! let index = sender.tag!
let version = App.shared.availablePhpVersions[index] let version = App.shared.availablePhpVersions[index]
App.shared.busy = true App.shared.busy = true
@ -211,6 +250,7 @@ class MainMenu: NSObject, NSWindowDelegate {
DispatchQueue.main.async { DispatchQueue.main.async {
self.updatePhpVersionInStatusBar() self.updatePhpVersionInStatusBar()
self.update() self.update()
// Send a notification that the switch has been completed
LocalNotification.send( LocalNotification.send(
title: "PHP \(version) is now active", title: "PHP \(version) is now active",
subtitle: "PHP Monitor has finished switching to PHP \(version)." subtitle: "PHP Monitor has finished switching to PHP \(version)."
@ -227,11 +267,4 @@ class MainMenu: NSObject, NSWindowDelegate {
@objc public func terminateApp() { @objc public func terminateApp() {
NSApplication.shared.terminate(nil) NSApplication.shared.terminate(nil)
} }
// MARK: - Cleanup when window closes
func windowWillClose(_ notification: Notification) {
App.shared.windowController = nil
Shell.user.delegate = nil
}
} }

View File

@ -8,38 +8,30 @@
import Cocoa import Cocoa
protocol ShellDelegate: class {
func didCompleteCommand(historyItem: ShellHistoryItem)
}
class ShellHistoryItem {
var command: String
var output: String
var date: Date
init(command: String, output: String) {
self.command = command
self.output = output
self.date = Date()
}
}
class Shell { class Shell {
// Singleton to access a user shell (with --login) /**
Singleton to access a user shell (with --login)
*/
static let user = Shell() static let user = Shell()
var history : [ShellHistoryItem] = [] /**
Runs a shell command without using the output.
var delegate : ShellDelegate? Uses the default shell.
/// Runs a shell command without using the description. - Parameter command: The command to run
*/
public func run(_ command: String) { public func run(_ command: String) {
// Equivalent of piping to /dev/null; don't do anything with the string // Equivalent of piping to /dev/null; don't do anything with the string
_ = self.pipe(command) _ = self.pipe(command)
} }
/// Runs a shell command and returns the output. /**
Runs a shell command and returns the output.
- Parameter command: The command to run
- Parameter shell: Path to the shell to invoke
*/
public func pipe(_ command: String, shell: String = "/bin/sh") -> String { public func pipe(_ command: String, shell: String = "/bin/sh") -> String {
let task = Process() let task = Process()
task.launchPath = shell task.launchPath = shell
@ -51,17 +43,10 @@ class Shell {
let data = pipe.fileHandleForReading.readDataToEndOfFile() let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String let output: String = NSString(
data: data,
let historyItem = ShellHistoryItem(command: command, output: output) encoding: String.Encoding.utf8.rawValue
)! as String
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
self.history.append(historyItem)
// Keep the last 100 items
self.history = self.history.suffix(100)
}
delegate?.didCompleteCommand(historyItem: historyItem)
return output return output
} }