// // ContentView.swift // MSG Desktop // // Created by Chad Nelson on 3/8/25. // 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) 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 { ContentView() }