diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index 683d090e..5e1e1274 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -5,7 +5,12 @@ import ( "context" "encoding/json" "fmt" + "io" + "os" "os/exec" + "os/signal" + "strings" + "syscall" "time" "github.com/docker/docker/api/types" @@ -14,6 +19,8 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/utils" + "github.com/jesseduffield/pty" + "golang.org/x/crypto/ssh/terminal" "golang.org/x/xerrors" ) @@ -50,10 +57,10 @@ func (gui *Gui) handleContainersFocus(g *gocui.Gui, v *gocui.View) error { gui.State.Panels.Containers.SelectedLine = newSelectedLine if prevSelectedLine == newSelectedLine && gui.currentViewName() == v.Name() { - return gui.handleContainerPress(gui.g, v) - } else { - return gui.handleContainerSelect(gui.g, v) + return nil } + + return gui.handleContainerSelect(gui.g, v) } func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View) error { @@ -69,6 +76,12 @@ func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View) error { return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedContainers")) } + // if we are in an attached state, we won't do anything here + // TODO: generalise + if strings.HasPrefix(gui.State.Panels.Main.ObjectKey, "attached-") { + return nil + } + key := container.ID + "-" + gui.getContainerContexts()[gui.State.Panels.Containers.ContextIndex] if gui.State.Panels.Main.ObjectKey == key { return nil @@ -263,10 +276,6 @@ func (gui *Gui) handleContainersPrevLine(g *gocui.Gui, v *gocui.View) error { return gui.handleContainerSelect(gui.g, v) } -func (gui *Gui) handleContainerPress(g *gocui.Gui, v *gocui.View) error { - return nil -} - func (gui *Gui) handleContainersPrevContext(g *gocui.Gui, v *gocui.View) error { contexts := gui.getContainerContexts() if gui.State.Panels.Containers.ContextIndex >= len(contexts)-1 { @@ -394,11 +403,65 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error { return nil } - subProcess := container.Attach() - if subProcess != nil { - gui.SubProcess = subProcess - return gui.Errors.ErrSubProcess + gui.State.Panels.Main.WriterID++ + + // Create arbitrary command. + c := exec.Command("bash") + + // Start the command with a pty. + ptmx, err := pty.Start(c) + if err != nil { + return err } + // Handle pty size. + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGWINCH) + go func() { + + for range ch { + x, y := gui.getMainView().Size() + if err := pty.Setsize(ptmx, &pty.Winsize{Cols: uint16(x), Rows: uint16(y), X: 0, Y: 0}); err != nil { + gui.Log.Error(err) + } + } + }() + ch <- syscall.SIGWINCH // Initial resize. + + go func() { + // Set stdin in raw mode. + oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())) + if err != nil { + panic(err) + } + defer func() { _ = terminal.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort. + defer func() { _ = ptmx.Close() }() // Best effort. + + go func() { _, _ = io.Copy(ptmx, os.Stdin) }() + + mainView := gui.getMainView() + mainView.Clear() + mainView.Autoscroll = true + gui.State.Panels.Main.ObjectKey = "attached-" + container.ID + + scanner := bufio.NewScanner(ptmx) + scanner.Split(bufio.ScanRunes) + + content := "" + for scanner.Scan() { + content += scanner.Text() + gui.Log.Warn("content") + gui.Log.Warn(content) + + gui.renderString(gui.g, "main", content) + } + + // reset object key + gui.State.Panels.Main.ObjectKey = "" + gui.State.Panels.Main.WriterID++ + + gui.handleContainerSelect(gui.g, v) + }() + return nil }