diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/Contents.json b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/Contents.json
index 3f00db4..366e387 100644
--- a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,51 +1,61 @@
{
"images" : [
{
+ "filename" : "gigakamiguru -v.1.2 CMYK16x16.eps.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMYK32x32.eps.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMYK32x32.eps 1.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMYK64x64.eps.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMY128x128.eps.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMY256x256.eps.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMY256x256.eps 1.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMY512x512.eps.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMY512x512.eps 1.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
+ "filename" : "gigakamiguru -v.1.2 CMY1024x1024.eps.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY1024x1024.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY1024x1024.eps.png
new file mode 100644
index 0000000..ddcf78c
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY1024x1024.eps.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY128x128.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY128x128.eps.png
new file mode 100644
index 0000000..0486b0c
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY128x128.eps.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY256x256.eps 1.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY256x256.eps 1.png
new file mode 100644
index 0000000..2c5ee3c
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY256x256.eps 1.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY256x256.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY256x256.eps.png
new file mode 100644
index 0000000..2c5ee3c
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY256x256.eps.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY512x512.eps 1.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY512x512.eps 1.png
new file mode 100644
index 0000000..465493e
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY512x512.eps 1.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY512x512.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY512x512.eps.png
new file mode 100644
index 0000000..465493e
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMY512x512.eps.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK16x16.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK16x16.eps.png
new file mode 100644
index 0000000..76aafd1
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK16x16.eps.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK32x32.eps 1.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK32x32.eps 1.png
new file mode 100644
index 0000000..d8d39d0
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK32x32.eps 1.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK32x32.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK32x32.eps.png
new file mode 100644
index 0000000..d8d39d0
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK32x32.eps.png differ
diff --git a/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK64x64.eps.png b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK64x64.eps.png
new file mode 100644
index 0000000..4df0673
Binary files /dev/null and b/MSG Desktop/Assets.xcassets/AppIcon.appiconset/gigakamiguru -v.1.2 CMYK64x64.eps.png differ
diff --git a/MSG Desktop/ContentView.swift b/MSG Desktop/ContentView.swift
index 433b0f0..0d5af2f 100644
--- a/MSG Desktop/ContentView.swift
+++ b/MSG Desktop/ContentView.swift
@@ -8,15 +8,96 @@
import SwiftUI
struct ContentView: View {
+ @State public var output: String = "Please select an option \n"
+ private let maxLines = 300
+ @State private var showCancelButton: Bool = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
- Text("Hello, world!")
+ ScrollViewReader { proxy in
+ ScrollView {
+ VStack(alignment: .leading) {
+ TextEditor(text: $output)
+ .font(.system(.body, design: .monospaced))
+ .frame(minWidth: 750, minHeight: 300)
+ .padding()
+ .disabled(true)
+
+ Text("")
+ .id("bottom")
+ }
+ }
+ .onChange(of: output) { _, _ in
+ trimLinesIfNeeded()
+ withAnimation {
+ proxy.scrollTo("bottom", anchor: .bottom)
+ }
+ }
+ }
+ HStack {
+ Button(action: {
+ DispatchQueue.main.async {
+ self.showCancelButton = true
+ }
+ runShellCommandAsync(command: "msg machine init", outputText: $output, showButton: $showCancelButton)
+
+ }) {
+ Text("Init")
+ }
+ Button(action: {
+ DispatchQueue.main.async {
+ self.showCancelButton = true
+ }
+ runShellCommandAsync(command: "rm -rf ~/.guix && msg machine init", outputText: $output, showButton: nil) }) {
+ Text("Reinit")
+ }
+ Button(action: {
+ runShellCommandAsync(command: "msg machine start", outputText: $output, showButton: nil) }) {
+ Text("Start")
+ }
+ if showCancelButton {
+ Button(action: {
+ runShellCommandAsync(command: "kill $(ps aux | grep '[g]uile' | awk '{print $2}')", outputText: $output, showButton: nil)
+ runShellCommandAsync(command: "kill $(ps aux | grep '[q]emu' | awk '{print $2}')", outputText: $output, showButton: nil)
+ DispatchQueue.main.async {
+ self.showCancelButton = false
+ }}) {
+ Text("Cancel")
+ }
+ }
+ if !showCancelButton{
+ Button(action: {
+ runShellCommandAsync(command: "msg machine stop", outputText: $output, showButton: nil) }) {
+ Text("Stop")
+ }
+ }
+
+ Button(action: {
+ runShellCommandAsync(command: "osascript -e 'tell application \"Terminal\" to do script \"msg shell\"' -e 'tell application \"Terminal\" to activate'", outputText: $output, showButton: nil)
+
+ }) {
+ Text("Shell")
+ }
+ }
+
+
}
.padding()
+ .frame(width: 800, height: 400)
}
+
+
+ private func trimLinesIfNeeded() {
+ let lines = output.split(separator: "\n")
+
+ if lines.count > maxLines {
+ _ = lines.count - maxLines
+ let trimmedLines = lines.suffix(maxLines) // Keep only the last 300 lines
+ output = trimmedLines.joined(separator: "\n") // Join back to a single string
+ }
+ }
}
#Preview {
diff --git a/MSG Desktop/MSG_Desktop.entitlements b/MSG Desktop/MSG_Desktop.entitlements
index 18aff0c..51a7cc5 100644
--- a/MSG Desktop/MSG_Desktop.entitlements
+++ b/MSG Desktop/MSG_Desktop.entitlements
@@ -3,8 +3,8 @@
com.apple.security.app-sandbox
-
+
com.apple.security.files.user-selected.read-only
-
+
diff --git a/MSG Desktop/MSG_DesktopApp.swift b/MSG Desktop/MSG_DesktopApp.swift
index d5627be..9fe5e55 100644
--- a/MSG Desktop/MSG_DesktopApp.swift
+++ b/MSG Desktop/MSG_DesktopApp.swift
@@ -6,6 +6,96 @@
//
import SwiftUI
+import Foundation
+
+func oldshell(_ command: String) -> String {
+ let task = Process()
+ let pipe = Pipe()
+
+ task.standardOutput = pipe
+ task.standardError = pipe
+ task.arguments = ["-c", command]
+ task.launchPath = "/bin/zsh"
+ task.standardInput = nil
+ task.launch()
+
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
+ let output = String(data: data, encoding: .utf8)!
+ return output
+}
+
+func runShellCommandAsync(command: String, outputText: Binding, showButton: Binding?) {
+ DispatchQueue.global(qos: .background).async {
+ let task = Process()
+ let pipe = Pipe()
+
+ task.standardOutput = pipe
+ task.standardError = pipe
+ task.arguments = ["-c", command]
+ task.launchPath = "/bin/zsh"
+ task.standardInput = nil
+
+ task.environment = [
+ "GUILE_LOAD_PATH": "/opt/homebrew/share/guile/site/3.0:/usr/local/share/guile/site/3.0/",
+ "GUILE_LOAD_COMPILED_PATH": "/opt/homebrew/lib/guile/3.0/site-ccache:/usr/local/lib/guile/3.0/site-ccache/",
+ "GUILE_SYSTEM_EXTENSIONS_PATH": "/opt/homebrew/lib/guile/3.0/extensions:/usr/local/lib/guile/3.0/extensions/",
+ "PATH": "$PATH:/opt/homebrew/bin:/usr/bin:/usr/local/bin:/bin"
+ ]
+
+ task.launch()
+
+ let fileHandle = pipe.fileHandleForReading
+ fileHandle.waitForDataInBackgroundAndNotify()
+
+ var observer: NSObjectProtocol?
+
+ observer = NotificationCenter.default.addObserver(forName: .NSFileHandleDataAvailable, object: fileHandle, queue: nil) { _ in
+ let data = fileHandle.availableData
+ if let output = String(data: data, encoding: .utf8), !output.isEmpty {
+ DispatchQueue.main.async {
+ outputText.wrappedValue += output
+ }
+ }
+ fileHandle.waitForDataInBackgroundAndNotify()
+ }
+
+ task.waitUntilExit()
+
+ if let observer = observer {
+ NotificationCenter.default.removeObserver(observer)
+ }
+
+ if showButton != nil {
+ showButton?.wrappedValue = false;
+ }
+ }
+}
+
+func shell(_ command: String) -> String {
+ let task = Process()
+ let pipe = Pipe()
+
+ task.standardOutput = pipe
+ task.standardError = pipe
+ task.arguments = ["-c", command]
+ task.launchPath = "/bin/zsh"
+ task.standardInput = nil
+
+ task.environment = [
+ "GUILE_LOAD_PATH": "/opt/homebrew/share/guile/site/3.0:/usr/local/share/guile/site/3.0/",
+ "GUILE_LOAD_COMPILED_PATH": "/opt/homebrew/lib/guile/3.0/site-ccache:/usr/local/lib/guile/3.0/site-ccache/",
+ "GUILE_SYSTEM_EXTENSIONS_PATH": "/opt/homebrew/lib/guile/3.0/extensions:/usr/local/lib/guile/3.0/extensions/",
+ "PATH": "$PATH:/opt/homebrew/bin:/usr/bin:/usr/local/bin:/bin"
+ ]
+
+ task.launch()
+
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
+ let output = String(data: data, encoding: .utf8) ?? "Error reading output"
+
+ return output.trimmingCharacters(in: .whitespacesAndNewlines)
+}
+
@main
struct MSG_DesktopApp: App {