1
0
mirror of https://github.com/Toxblh/MTMR.git synced 2026-01-10 17:08:39 +00:00
MTMR/MTMR/ShellScriptTouchBarItem.swift
Piss Man ac0e44db4d
Modified the way shell script are called (#430)
* Added shell detection

* Replaced deprecated object to supported version

* Updated haptic feedback.swift to support for newer mac

Added support for m1 mac
2022-02-16 19:00:28 +00:00

114 lines
4.1 KiB
Swift

//
// ShellScriptTouchBarItem.swift
// MTMR
//
// Created by bobr on 08/08/2019.
// Copyright © 2019 Anton Palgunov. All rights reserved.
//
import Foundation
class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
private let interval: TimeInterval
private let source: String
private var forceHideConstraint: NSLayoutConstraint!
struct ScriptResult: Decodable {
var title: String?
var image: Source?
}
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval) {
self.interval = interval
self.source = source.string ?? "echo No \"source\""
super.init(identifier: identifier, title: "")
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
DispatchQueue.shellScriptQueue.async {
self.refreshAndSchedule()
}
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func refreshAndSchedule() {
// Execute script and get result
let scriptResult = execute(source)
var rawTitle: String, image: NSImage?
var json: Bool
do {
let decoder = JSONDecoder()
let result = try decoder.decode(ScriptResult.self, from: scriptResult.data(using: .utf8)!)
json = true
rawTitle = result.title ?? ""
image = result.image?.image
} catch {
json = false
rawTitle = scriptResult
}
// Apply returned text attributes (if they were returned) to our result string
let helper = AMR_ANSIEscapeHelper.init()
helper.defaultStringColor = NSColor.white
helper.font = "1".defaultTouchbarAttributedString.attribute(.font, at: 0, effectiveRange: nil) as? NSFont
let title = NSMutableAttributedString.init(attributedString: helper.attributedString(withANSIEscapedString: rawTitle) ?? NSAttributedString(string: ""))
title.addAttributes([.baselineOffset: 1], range: NSRange(location: 0, length: title.length))
let newBackgoundColor: NSColor? = title.length != 0 ? title.attribute(.backgroundColor, at: 0, effectiveRange: nil) as? NSColor : nil
// Update UI
DispatchQueue.main.async { [weak self, newBackgoundColor] in
if (newBackgoundColor != self?.backgroundColor) { // performance optimization because of reinstallButton
self?.backgroundColor = newBackgoundColor
}
self?.attributedTitle = title
if json {
self?.image = image
}
self?.forceHideConstraint.isActive = scriptResult == ""
}
// Schedule next update
DispatchQueue.shellScriptQueue.asyncAfter(deadline: .now() + interval) { [weak self] in
self?.refreshAndSchedule()
}
}
func execute(_ command: String) -> String {
let task = Process()
if let shell = getenv("SHELL") {
task.launchPath = String.init(cString: shell)
} else {
task.launchPath = "/bin/bash"
}
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
// kill process if it is over update interval
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak task] in
task?.terminate()
}
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
var output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as String? ?? ""
//always wait until task end or you can catch "task still running" error while accessing task.terminationStatus variable
task.waitUntilExit()
if (output == "" && task.terminationStatus != 0) {
output = "error"
}
return output.replacingOccurrences(of: "\\n+$", with: "", options: .regularExpression)
}
}
extension DispatchQueue {
static let shellScriptQueue = DispatchQueue(label: "mtmr.shellscript")
}