package main import ( "flag" "fmt" "io" "log" "os" "time" tea "github.com/charmbracelet/bubbletea" ) // debugLog writes to a debug file var debugFile *os.File func debugLog(format string, args ...any) { if debugFile != nil { fmt.Fprintf(debugFile, format+"\n", args...) debugFile.Sync() } } func main() { // Define flags serverAddr := flag.String("server", "127.0.0.1:9987", "TeamSpeak 3 Server Address") nickname := flag.String("nickname", "TUI-User", "Your nickname") debug := flag.Bool("debug", false, "Enable debug logging to file (default false)") flag.Parse() // Panic Recovery defer func() { if r := recover(); r != nil { fmt.Fprintf(os.Stderr, "Panic recovered: %v\n", r) os.Exit(1) } }() // Disable log output initially log.SetOutput(io.Discard) // Enable debug file logging if requested if *debug { var err error timestamp := time.Now().Format("20060102-150405") filename := fmt.Sprintf("tui-%s.log", timestamp) debugFile, err = os.Create(filename) if err == nil { defer debugFile.Close() debugLog("TUI Debug started at %s", timestamp) // Redirect standard log output to debug file initially log.SetOutput(debugFile) } else { fmt.Fprintf(os.Stderr, "Failed to create debug log: %v\n", err) log.SetOutput(os.Stderr) // Fallback to stderr } } // Silence noise (ALSA/PortAudio) on Linux or if debugFile is set redirectStderr(debugFile) // Create the TUI model m := NewModel(*serverAddr, *nickname) // Create Bubble Tea program p := tea.NewProgram(m, tea.WithAltScreen()) // Pass program reference to model for event handlers m.SetProgram(p) // Set up log capture for UI display r, w, _ := os.Pipe() if debugFile != nil { // Log to both UI (pipe) and Debug File log.SetOutput(io.MultiWriter(w, debugFile)) } else { // Log to UI only log.SetOutput(w) } // Make sure logs have timestamp removed (TUI adds it if needed, or we keep it) log.SetFlags(log.Ltime) // Just time // Goroutine to capture logs and send them to the UI go func() { buf := make([]byte, 1024) for { n, err := r.Read(buf) if err != nil { break } if n > 0 { lines := string(buf[:n]) // Split by newline and send each line p.Send(logMsg(lines)) } } }() // Run if _, err := p.Run(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } }