package gui import ( "fmt" "io/ioutil" "os" "os/signal" "strings" "github.com/fatih/color" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/utils" ) // RunWithSubprocesses loops, instantiating a new gocui.Gui with each iteration // if the error returned from a run is a ErrSubProcess, it runs the subprocess // otherwise it handles the error, possibly by quitting the application func (gui *Gui) RunWithSubprocesses() error { for { if err := gui.Run(); err != nil { if err == gocui.ErrQuit { break } else if err == gui.Errors.ErrSubProcess { // preparing the state for when we return gui.pushPreviousView(gui.currentViewName()) // giving goEvery goroutines time to finish gui.State.SessionIndex++ if err := gui.runCommand(); err != nil { return err } // pop here so we don't stack up view names gui.popPreviousView() // ensuring we render e.g. the logs of the currently selected item upon return gui.State.Panels.Main.ObjectKey = "" } else { return err } } } return nil } func (gui *Gui) runCommand() error { gui.SubProcess.Stdout = os.Stdout gui.SubProcess.Stderr = os.Stdout gui.SubProcess.Stdin = os.Stdin c := make(chan os.Signal, 1) go func() { signal.Notify(c, os.Interrupt) <-c signal.Stop(c) if err := gui.OSCommand.Kill(gui.SubProcess); err != nil { gui.Log.Error(err) } }() fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString("+ "+strings.Join(gui.SubProcess.Args, " "), color.FgBlue)) if err := gui.SubProcess.Run(); err != nil { // not handling the error explicitly because usually we're going to see it // in the output anyway gui.Log.Error(err) } gui.SubProcess.Stdin = nil gui.SubProcess.Stdout = ioutil.Discard gui.SubProcess.Stderr = ioutil.Discard gui.SubProcess = nil signal.Stop(c) if !gui.Config.UserConfig.Gui.ReturnImmediately { fmt.Fprintf(os.Stdout, "\n\n%s", utils.ColoredString(gui.Tr.PressEnterToReturn, color.FgGreen)) // wait for enter press if _, err := fmt.Scanln(); err != nil { gui.Log.Error(err) } } return nil }