diff --git a/docs-master/Config.md b/docs-master/Config.md index d35455c84..c8bb8c5f6 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -145,6 +145,8 @@ gui: # If true, wrap lines in focused diffs to the width of the view. This makes it # much easier to work with diffs that have long lines, e.g. paragraphs of # markdown text. + # If false, scroll a focused diff sideways with the scrollLeft and scrollRight + # keys (H and L by default). wrapLinesInDiffView: true # If true, hunk selection mode will be enabled by default when focusing a diff. diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index eedde41e0..140defcf3 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -123,6 +123,7 @@ type GuiConfig struct { // - 'top': split the window vertically (side panel on top, main view below) EnlargedSideViewLocation string `yaml:"enlargedSideViewLocation"` // If true, wrap lines in focused diffs to the width of the view. This makes it much easier to work with diffs that have long lines, e.g. paragraphs of markdown text. + // If false, scroll a focused diff sideways with the scrollLeft and scrollRight keys (H and L by default). WrapLinesInDiffView bool `yaml:"wrapLinesInDiffView"` // If true, hunk selection mode will be enabled by default when focusing a diff. UseHunkModeInDiffView bool `yaml:"useHunkModeInDiffView"` diff --git a/pkg/gui/controllers/main_view_controller.go b/pkg/gui/controllers/main_view_controller.go index 7129e1c43..9135f363f 100644 --- a/pkg/gui/controllers/main_view_controller.go +++ b/pkg/gui/controllers/main_view_controller.go @@ -238,6 +238,8 @@ func (self *MainViewController) GetKeybindings(opts types.KeybindingsOpts) []*ty {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.NextPage), Handler: self.handleNextPage, Description: self.c.Tr.NextPage}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop}, {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.GotoBottom), Handler: self.handleGotoBottom, Description: self.c.Tr.GotoBottom}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft), Handler: self.handleScrollLeft, Description: self.c.Tr.ScrollLeft}, + {Tag: "navigation", Keys: opts.GetKeys(opts.Config.Universal.ScrollRight), Handler: self.handleScrollRight, Description: self.c.Tr.ScrollRight}, } } @@ -1052,6 +1054,16 @@ func (self *MainViewController) handleGotoBottom() error { return nil } +func (self *MainViewController) handleScrollLeft() error { + self.context.GetViewTrait().ScrollLeft() + return nil +} + +func (self *MainViewController) handleScrollRight() error { + self.context.GetViewTrait().ScrollRight() + return nil +} + func (self *MainViewController) editLine() error { view := self.context.GetView() if !view.Highlight { diff --git a/pkg/integration/components/view_driver.go b/pkg/integration/components/view_driver.go index b5168487a..d1b65a0d9 100644 --- a/pkg/integration/components/view_driver.go +++ b/pkg/integration/components/view_driver.go @@ -568,6 +568,15 @@ func (self *ViewDriver) OriginY(expected int) *ViewDriver { return self } +func (self *ViewDriver) OriginX(expected int) *ViewDriver { + self.t.assertWithRetries(func() (bool, string) { + actual := self.getView().OriginX() + return expected == actual, fmt.Sprintf("%s: Expected origin X to be %d, got %d", self.context, expected, actual) + }) + + return self +} + // asserts that the selected line is inside the visible area of the view func (self *ViewDriver) SelectedLineIsVisible() *ViewDriver { self.t.assertWithRetries(func() (bool, string) { diff --git a/pkg/integration/tests/main_view/jump_to_another_file_scrolls_to_the_left_edge.go b/pkg/integration/tests/main_view/jump_to_another_file_scrolls_to_the_left_edge.go new file mode 100644 index 000000000..507668d73 --- /dev/null +++ b/pkg/integration/tests/main_view/jump_to_another_file_scrolls_to_the_left_edge.go @@ -0,0 +1,64 @@ +package main_view + +import ( + "strings" + + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var JumpToAnotherFileScrollsToTheLeftEdge = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Jumping to another file of a diff scrolled sideways shows it from the left edge, while jumping to another hunk doesn't", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Gui.WrapLinesInDiffView = false + cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false + }, + SetupRepo: func(shell *Shell) { + long := strings.Repeat("word ", 60) + shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n") + shell.CreateFileAndAdd("file2", "one\ntwo\nthree\n") + shell.Commit("one") + + shell.UpdateFileAndAdd("file1", "one\ntwo\nthree "+long+"\nfour\nfive\nsix\nseven\neight\nnine "+long+"\nten\n") + shell.UpdateFileAndAdd("file2", "one\ntwo\nthree "+long+"\n") + shell.Commit("two") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("two").IsSelected(), + Contains("one"), + ). + Press(keys.Universal.FocusMainView) + + t.Views().Main(). + IsFocused(). + SelectedLines( + Contains("-three"), + ). + Press(keys.Universal.ScrollRight). + OriginX(26). + Press(keys.Main.NextHunk). + SelectedLines( + Contains("-nine"), + ). + OriginX(26). + Press(keys.Main.NextFile). + SelectedLines( + Contains("diff --git a/file2 b/file2"), + ). + OriginX(0). + Press(keys.Universal.ScrollRight). + OriginX(26). + Press(keys.Main.PrevFile). + SelectedLines( + Contains("diff --git a/file1 b/file1"), + ). + OriginX(0) + }, +}) diff --git a/pkg/integration/tests/main_view/scroll_back_when_the_diff_gets_narrower.go b/pkg/integration/tests/main_view/scroll_back_when_the_diff_gets_narrower.go new file mode 100644 index 000000000..57c301ddc --- /dev/null +++ b/pkg/integration/tests/main_view/scroll_back_when_the_diff_gets_narrower.go @@ -0,0 +1,53 @@ +package main_view + +import ( + "strings" + + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var ScrollBackWhenTheDiffGetsNarrower = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "A diff scrolled sideways scrolls back when it is rendered again narrower than where it was scrolled to", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Gui.WrapLinesInDiffView = false + cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\n") + shell.Commit("one") + + shell.UpdateFile("file1", "ONE\ntwo\nthree\nfour\nfive "+strings.Repeat("word ", 60)+"\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Press(keys.Universal.FocusMainView) + + t.Views().Main(). + IsFocused(). + Press(keys.Main.NextHunk). + SelectedLines( + Contains("-five"), + ). + Press(keys.Universal.RangeSelectDown). + SelectedLines( + Contains("-five"), + Contains("+five word"), + ). + Press(keys.Universal.ScrollRight). + Press(keys.Universal.ScrollRight). + OriginX(52). + // What is left of the diff fits in the pane, so the pane goes back to the left + // edge. + PressPrimaryAction(). + SelectedLines( + Contains("+ONE"), + ). + OriginX(0) + }, +}) diff --git a/pkg/integration/tests/main_view/scroll_diff_horizontally.go b/pkg/integration/tests/main_view/scroll_diff_horizontally.go new file mode 100644 index 000000000..ba9f29a5b --- /dev/null +++ b/pkg/integration/tests/main_view/scroll_diff_horizontally.go @@ -0,0 +1,75 @@ +package main_view + +import ( + "strings" + + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var ScrollDiffHorizontally = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "With wrapping turned off for diffs, the focused diff scrolls sideways, and stays scrolled as the selection moves and the diff is rendered again", + ExtraCmdArgs: []string{}, + Skip: false, + Width: 120, + Height: 30, + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Gui.WrapLinesInDiffView = false + cfg.GetUserConfig().Gui.UseHunkModeInDiffView = false + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "one\ntwo\n") + shell.Commit("one") + + long := strings.Repeat("word ", 60) + shell.UpdateFile("file1", "one "+long+"\ntwo "+long+"\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Press(keys.Universal.FocusMainView) + + t.Views().Main(). + IsFocused(). + SelectedLines( + Contains("-one"), + ). + OriginX(0). + // A third of the pane's width at a time. + Press(keys.Universal.ScrollRight). + OriginX(26). + Press(keys.Universal.ScrollLeft). + OriginX(0). + Press(keys.Universal.ScrollLeft). + OriginX(0). + Press(keys.Universal.ScrollRight). + Press(keys.Universal.ScrollRight). + OriginX(52). + SelectNextItem(). + SelectedLines( + Contains("-two"), + ). + OriginX(52). + Press(keys.Universal.IncreaseContextInDiffView). + Tap(func() { + t.ExpectToast(Equals("Changed diff context size to 4")) + }). + SelectedLines( + Contains("-two"), + ). + OriginX(52). + PressPrimaryAction(). + SelectedLines( + Contains("+one"), + ). + OriginX(52). + // Leaving the view gives up the horizontal scroll position. + PressEscape() + + t.Views().Files(). + IsFocused() + + t.Views().Main(). + OriginX(0) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 566baf0dc..2381fa1a2 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -412,6 +412,7 @@ var tests = []*components.IntegrationTest{ main_view.JumpToAFileOfAStashWithNoPrefixes, main_view.JumpToAFileOfTheDiff, main_view.JumpToAFileOnlyOverADiff, + main_view.JumpToAnotherFileScrollsToTheLeftEdge, main_view.KeepAWrappedLineCoveredAcrossARerender, main_view.KeepAnEmptiedPaneEmpty, main_view.KeepBothHalvesOfAChangeSelected, @@ -470,6 +471,8 @@ var tests = []*components.IntegrationTest{ main_view.ResetAPatchBuiltFromACommitsDiff, main_view.ResetPatchWithEscape, main_view.ResetThePatchFromThePaneShowingIt, + main_view.ScrollBackWhenTheDiffGetsNarrower, + main_view.ScrollDiffHorizontally, main_view.SearchCollapsesTheSelection, main_view.SearchFollowsTheSelection, main_view.SelectBelowALongCommitMessage, diff --git a/schema-master/config.json b/schema-master/config.json index 2607715b2..869b8fb60 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -671,7 +671,7 @@ }, "wrapLinesInDiffView": { "type": "boolean", - "description": "If true, wrap lines in focused diffs to the width of the view. This makes it much easier to work with diffs that have long lines, e.g. paragraphs of markdown text.", + "description": "If true, wrap lines in focused diffs to the width of the view. This makes it much easier to work with diffs that have long lines, e.g. paragraphs of markdown text.\nIf false, scroll a focused diff sideways with the scrollLeft and scrollRight keys (H and L by default).", "default": true }, "useHunkModeInDiffView": {