diff --git a/pkg/gui/tasks_adapter.go b/pkg/gui/tasks_adapter.go index ed8203237..7a67f4447 100644 --- a/pkg/gui/tasks_adapter.go +++ b/pkg/gui/tasks_adapter.go @@ -27,11 +27,17 @@ func (gui *Gui) newCmdTask(view *gocui.View, cmd *exec.Cmd, prefix string) error // thumb to shrink and snap back as the rest loads. view.FreezeScrollbarHeight() - // Snapshot the view width here, on the UI thread, so the task goroutine - // doesn't read the view's live dimensions while it streams output. - spec := renderSpec{view: view, cmd: cmd, width: view.InnerWidth()} + // The command lays its output out to the width of the view (git's diffstat + // graph does), and only the layout settles that, so the task is created after + // it, as a diff renderer's is. Taking the width there, on the UI thread, also + // keeps the task goroutine from reading the view's live dimensions while it + // streams output. + gui.afterLayout(func() error { + spec := renderSpec{view: view, cmd: cmd, width: view.InnerWidth()} + return gui.newTaskForRender(spec, prefix, cmdStr, gui.plainRender) + }) - return gui.newTaskForRender(spec, prefix, cmdStr, gui.plainRender) + return nil } // plainRender runs the command as it is, with its output going straight into diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index dfae58c4b..ca29eff69 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -141,6 +141,39 @@ func (self *ViewDriver) VisibleLines(matchers ...*TextMatcher) *ViewDriver { return self.assertLines(originY, matchers...) } +// ContainsViewLines asserts that somewhere in the view there are consecutive view lines +// matching the given matchers. View lines are the rows the view draws its content in, +// so a line too long for the view is as many view lines as the view wraps it into. +func (self *ViewDriver) ContainsViewLines(matchers ...*TextMatcher) *ViewDriver { + self.validateMatchersPassed(matchers) + + self.t.assertWithRetries(func() (bool, string) { + lines := self.getView().ViewBufferLines() + + for i := 0; i+len(matchers) <= len(lines); i++ { + matches := true + for j, matcher := range matchers { + if ok, _ := matcher.test(lines[i+j]); !ok { + matches = false + break + } + } + if matches { + return true, "" + } + } + + return false, fmt.Sprintf( + "%s: Expected the following view lines to be contained:\n-----\n%s\n-----\nBut got:\n-----\n%s\n-----", + self.context, + expectedContentFromMatchers(matchers), + strings.Join(lines, "\n"), + ) + }) + + return self +} + // asserts that somewhere in the view there are consecutive lines matching the given matchers. func (self *ViewDriver) ContainsLines(matchers ...*TextMatcher) *ViewDriver { self.validateMatchersPassed(matchers) diff --git a/pkg/integration/tests/diff/stat_follows_a_screen_mode_change.go b/pkg/integration/tests/diff/stat_follows_a_screen_mode_change.go new file mode 100644 index 000000000..1c44caa62 --- /dev/null +++ b/pkg/integration/tests/diff/stat_follows_a_screen_mode_change.go @@ -0,0 +1,55 @@ +package diff + +import ( + "strconv" + "strings" + + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var StatFollowsAScreenModeChange = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "A commit's diffstat is laid out again to the width the view has after a screen mode change narrows it", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(cfg *config.AppConfig) { + // git's own diff, so that the render runs as a plain command rather + // than through a renderer. + cfg.GetUserConfig().Git.DiffRenderers = []config.DiffRendererConfig{ + {Type: "rawGit"}, + } + }, + SetupRepo: func(shell *Shell) { + // Enough added lines that git scales the graph to the width it has, + // rather than drawing one mark per line. + lines := make([]string, 200) + for i := range lines { + lines[i] = "line " + strconv.Itoa(i) + } + shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n") + shell.Commit("add file1") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("add file1").IsSelected(), + ) + + t.Views().Main(). + ContainsViewLines( + Contains("file1 | 200"), + Contains("1 file changed"), + ) + + // The focused panel takes half the screen, which leaves the main view + // narrower than it was. + t.Views().Commits().Press(keys.Universal.NextScreenMode) + + t.Views().Main(). + ContainsViewLines( + Contains("file1 | 200"), + Contains("1 file changed"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 372b82c8f..67caf3bbb 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -231,6 +231,7 @@ var tests = []*components.IntegrationTest{ diff.IgnoreWhitespace, diff.RenameSimilarityThresholdChange, diff.RenderThroughAPipe, + diff.StatFollowsAScreenModeChange, diff.StatUsesTheViewWidth, file.ClickArrowToCollapse, file.CollapseExpand,