From f98da780de98b464085e8608a03539ed239690be Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 12 Jun 2024 16:52:27 +0200 Subject: [PATCH 1/2] Fix possible off-by-one error wrt PTY size All PTYs were created with the size of the main view, on the assumption that main and secondary always have the same size. That's not true though; in horizontal split mode, the width of the two views can differ by one because of rounding, and when using a pager that draws a horizontal line across the width of the view, this is visible and looks very ugly. --- pkg/gui/pty.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/gui/pty.go b/pkg/gui/pty.go index cf3176f75..969e1aada 100644 --- a/pkg/gui/pty.go +++ b/pkg/gui/pty.go @@ -15,8 +15,8 @@ import ( "github.com/samber/lo" ) -func (gui *Gui) desiredPtySize() *pty.Winsize { - width, height := gui.Views.Main.Size() +func (gui *Gui) desiredPtySize(view *gocui.View) *pty.Winsize { + width, height := view.Size() return &pty.Winsize{Cols: uint16(width), Rows: uint16(height)} } @@ -25,11 +25,12 @@ func (gui *Gui) onResize() error { gui.Mutexes.PtyMutex.Lock() defer gui.Mutexes.PtyMutex.Unlock() - for _, ptmx := range gui.viewPtmxMap { + for viewName, ptmx := range gui.viewPtmxMap { // TODO: handle resizing properly: we need to actually clear the main view // and re-read the output from our pty. Or we could just re-run the original // command from scratch - if err := pty.Setsize(ptmx, gui.desiredPtySize()); err != nil { + view, _ := gui.g.View(viewName) + if err := pty.Setsize(ptmx, gui.desiredPtySize(view)); err != nil { return utils.WrapError(err) } } @@ -44,7 +45,7 @@ func (gui *Gui) onResize() error { // pseudo-terminal meaning we'll get the behaviour we want from the underlying // command. func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error { - width, _ := gui.Views.Main.Size() + width, _ := view.Size() pager := gui.git.Config.GetPager(width) externalDiffCommand := gui.Config.GetUserConfig().Git.Paging.ExternalDiffCommand @@ -69,7 +70,7 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error var ptmx *os.File start := func() (*exec.Cmd, io.Reader) { var err error - ptmx, err = pty.StartWithSize(cmd, gui.desiredPtySize()) + ptmx, err = pty.StartWithSize(cmd, gui.desiredPtySize(view)) if err != nil { gui.c.Log.Error(err) } From 8b8343b8a9f81c3000117ce869c734611cf87b7b Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 12 Jun 2024 17:23:42 +0200 Subject: [PATCH 2/2] Run PTY tasks after layout so that they get the correct view size This is important when using a pager that draws a horizontal line across the entire width of the view; when changing from a file or directory that has only unstaged (or only staged) changes to one that has both, the main view is split in half, but the PTY task would be run on the view in its old state, so the horizonal line would be too long and wrap around. --- pkg/gui/gui.go | 9 +++++++++ pkg/gui/gui_common.go | 7 +------ pkg/gui/main_panels.go | 5 ++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 5f2fd55bf..06228e759 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -959,3 +959,12 @@ func (gui *Gui) onWorker(f func(gocui.Task) error) { func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map[string]boxlayout.Dimensions { return gui.helpers.WindowArrangement.GetWindowDimensions(informationStr, appStatus) } + +func (gui *Gui) afterLayout(f func() error) { + select { + case gui.afterLayoutFuncs <- f: + default: + // hopefully this never happens + gui.c.Log.Error("afterLayoutFuncs channel is full, skipping function") + } +} diff --git a/pkg/gui/gui_common.go b/pkg/gui/gui_common.go index a75aa3658..434f4b38b 100644 --- a/pkg/gui/gui_common.go +++ b/pkg/gui/gui_common.go @@ -189,12 +189,7 @@ func (self *guiCommon) GetInitialKeybindingsWithCustomCommands() ([]*types.Bindi } func (self *guiCommon) AfterLayout(f func() error) { - select { - case self.gui.afterLayoutFuncs <- f: - default: - // hopefully this never happens - self.gui.c.Log.Error("afterLayoutFuncs channel is full, skipping function") - } + self.gui.afterLayout(f) } func (self *guiCommon) RunningIntegrationTest() bool { diff --git a/pkg/gui/main_panels.go b/pkg/gui/main_panels.go index bf30331cd..49d278399 100644 --- a/pkg/gui/main_panels.go +++ b/pkg/gui/main_panels.go @@ -20,7 +20,10 @@ func (gui *Gui) runTaskForView(view *gocui.View, task types.UpdateTask) error { return gui.newCmdTask(view, v.Cmd, v.Prefix) case *types.RunPtyTask: - return gui.newPtyTask(view, v.Cmd, v.Prefix) + gui.afterLayout(func() error { + return gui.newPtyTask(view, v.Cmd, v.Prefix) + }) + return nil } return nil