ronantakizawa/codereview-bench huggingface dataset:
Repository: jesseduffield/lazygit
File: pkg/integration/tests/commit/staged.go (Go)

Code before:
				// we start with both lines having been staged
				t.Views().StagingSecondary().Content(Contains("+myfile content"))
				t.Views().StagingSecondary().Content(Contains("+with a second line"))
				t.Views().Staging().Content(DoesNotContain("+myfile content"))
				t.Views().Staging().Content(DoesNotContain("+with a second line"))
			}).
			// unstage the selected line
			PressPrimaryAction().
			Tap(func() {
				// the line should have been moved to the main view
				t.Views().StagingSecondary().Content(DoesNotContain("+myfile content"))
				t.Views().StagingSecondary().Content(Contains("+with a second line"))
				t.Views().Staging().Content(Contains("+myfile content"))
				t.Views().Staging().Content(DoesNotContain("+with a second line"))
			}).
			Press(keys.Files.CommitChanges)

		commitMessage := "my commit message"
		t.ExpectPopup().CommitMessagePanel().Type(commitMessage).Confirm()

		t.Views().Commits().
			Lines(
				Contains(commitMessage),
			)

		t.Views().Staging().IsFocused().Tap(func() {
			// the secondary staging area should be cleared
			t.Views().StagingSecondary().IsEmpty()
			t.Views().Staging().Content(Contains("+myfile content"))
			t.Views().Staging().Content(DoesNotContain("+with a second line"))
		})
	},
})


Review comment (suggestion):
The Tap function is only really needed when we want to make an assertion about another view and then afterwards chain more method calls onto the original one. But in this case it's not necessary; we can instead go:
```go
t.Views().StagingSecondary().
	IsEmpty()
	
t.Views().Staging().
	IsFocused().
	Content(Contains("+myfile content")).
	Content(DoesNotContain("+with a second line"))

```

Code after:
				// we start with both lines having been staged
				t.Views().StagingSecondary().Content(Contains("+myfile content"))
				t.Views().StagingSecondary().Content(Contains("+with a second line"))
				t.Views().Staging().Content(DoesNotContain("+myfile content"))
				t.Views().Staging().Content(DoesNotContain("+with a second line"))
			}).
			// unstage the selected line
			PressPrimaryAction().
			Tap(func() {
				// the line should have been moved to the main view
				t.Views().StagingSecondary().Content(DoesNotContain("+myfile content"))
				t.Views().StagingSecondary().Content(Contains("+with a second line"))
				t.Views().Staging().Content(Contains("+myfile content"))
				t.Views().Staging().Content(DoesNotContain("+with a second line"))
			}).
			Press(keys.Files.CommitChanges)

		commitMessage := "my commit message"
		t.ExpectPopup().CommitMessagePanel().Type(commitMessage).Confirm()

		t.Views().Commits().
			Lines(
				Contains(commitMessage),
			)

		t.Views().StagingSecondary().
			IsEmpty()

		t.Views().Staging().
			IsFocused().
			Content(Contains("+myfile content")).
			Content(DoesNotContain("+with a second line"))
	},
})
Repository: jesseduffield/lazygit
File: pkg/gui/whitespace-toggle.go (Go)

Code before:
package gui

import (
	"github.com/jesseduffield/lazygit/pkg/gui/types"
)

func (gui *Gui) toggleWhitespaceInDiffView() error {
	gui.IgnoreWhitespaceInDiffView = !gui.IgnoreWhitespaceInDiffView

	toastMessage := gui.c.Tr.ShowingWhitespaceInDiffView
	if gui.IgnoreWhitespaceInDiffView {
		toastMessage = gui.c.Tr.IgnoringWhitespaceInDiffView
	}
	gui.c.Toast(toastMessage)

	return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}


Review comment (suggestion):
This is probably too big of a hammer, I guess we could be more considerate as to which views we refresh. But it's easy, and [there's precedence for this](https://github.com/jesseduffield/lazygit/blob/master/pkg/gui/diffing.go#L119). 😄 

Code after:
package gui

import (
	"github.com/jesseduffield/lazygit/pkg/gui/types"
)

func (gui *Gui) toggleWhitespaceInDiffView() error {
	gui.IgnoreWhitespaceInDiffView = !gui.IgnoreWhitespaceInDiffView

	toastMessage := gui.c.Tr.ShowingWhitespaceInDiffView
	if gui.IgnoreWhitespaceInDiffView {
		toastMessage = gui.c.Tr.IgnoringWhitespaceInDiffView
	}
	gui.c.Toast(toastMessage)

	return gui.currentSideListContext().HandleFocus(types.OnFocusOpts{})
}
Repository: jesseduffield/lazygit
File: pkg/integration/components/git.go (Go)

Code before:
package components

import (
	"fmt"
	"strings"
)

type Git struct {
	*assertionHelper
	shell *Shell
}

func (self *Git) CurrentBranchName(expectedName string) *Git {
	return self.assert("git rev-parse --abbrev-ref HEAD", expectedName)
}

func (self *Git) TagNamesAt(ref string, expectedNames []string) *Git {
	return self.assert(fmt.Sprintf(`git tag --contains "%s"`, ref), strings.Join(expectedNames, "\n"))
}

func (self *Git) assert(cmdStr string, expected string) *Git {
	self.assertWithRetries(func() (bool, string) {
		output, err := self.shell.runCommandWithOutput(cmdStr)
		if err != nil {
			return false, fmt.Sprintf("Unexpected error running command: `%s`. Error: %s", cmdStr, err.Error())
		}
		actual := strings.TrimSpace(output)
		return actual == expected, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expected, actual)
	})

	return self
}


Review comment (suggestion):
```suggestion
	return self.assert(fmt.Sprintf(`git tag --points-at "%s"`, ref), strings.Join(expectedNames, "\n"))
```
This is what we really want here

Code after:
package components

import (
	"fmt"
	"strings"
)

type Git struct {
	*assertionHelper
	shell *Shell
}

func (self *Git) CurrentBranchName(expectedName string) *Git {
	return self.assert("git rev-parse --abbrev-ref HEAD", expectedName)
}

func (self *Git) TagNamesAt(ref string, expectedNames []string) *Git {
	return self.assert(fmt.Sprintf(`git tag --sort=v:refname --points-at "%s"`, ref), strings.Join(expectedNames, "\n"))
}

func (self *Git) assert(cmdStr string, expected string) *Git {
	self.assertWithRetries(func() (bool, string) {
		output, err := self.shell.runCommandWithOutput(cmdStr)
		if err != nil {
			return false, fmt.Sprintf("Unexpected error running command: `%s`. Error: %s", cmdStr, err.Error())
		}
		actual := strings.TrimSpace(output)
		return actual == expected, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expected, actual)
	})

	return self
}
Repository: jesseduffield/lazygit
File: pkg/integration/tests/branch/create_tag.go (Go)

Code before:
	SetupRepo: func(shell *Shell) {
		shell.
			CreateNCommits(10).
			NewBranch("new-branch").
			EmptyCommit("new commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Branches().
			Focus().
			Lines(
				MatchesRegexp(`\*\s*new-branch`).IsSelected(),
				MatchesRegexp(`master`),
			).
			SelectNextItem().
			Press(keys.Branches.CreateTag)

		t.ExpectPopup().Menu().
			Title(Equals("Create tag")).
			Confirm()

		t.ExpectPopup().Prompt().
			Title(Equals("Tag name:")).
			Type("new-tag").
			Confirm()

		t.Views().Tags().
			Lines(
				MatchesRegexp(`new-tag`).IsSelected(),
			)

		t.Git().
			TagNamesAt("HEAD", []string{}).
			TagNamesAt("master", []string{"new-tag"})
	},
})


Review comment (suggestion):
```suggestion
		t.Views().Tags().Focus().
```
Adding the focus to mimic user interaction, and also cos in the future we might not render to hidden views

Code after:
	SetupRepo: func(shell *Shell) {
		shell.
			CreateNCommits(10).
			NewBranch("new-branch").
			EmptyCommit("new commit")
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Branches().
			Focus().
			Lines(
				MatchesRegexp(`\*\s*new-branch`).IsSelected(),
				MatchesRegexp(`master`),
			).
			SelectNextItem().
			Press(keys.Branches.CreateTag)

		t.ExpectPopup().Menu().
			Title(Equals("Create tag")).
			Confirm()

		t.ExpectPopup().Prompt().
			Title(Equals("Tag name:")).
			Type("new-tag").
			Confirm()

		t.Views().Tags().Focus().
			Lines(
				MatchesRegexp(`new-tag`).IsSelected(),
			)

		t.Git().
			TagNamesAt("HEAD", []string{}).
			TagNamesAt("master", []string{"new-tag"})
	},
})
Repository: jesseduffield/lazygit
File: pkg/commands/patch/patch_modifier.go (Go)

Code before:
package patch

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/sirupsen/logrus"
)

var (
	hunkHeaderRegexp  = regexp.MustCompile(`(?m)^@@ -(\d+)[^\+]+\+(\d+)[^@]+@@(.*)$`)
	patchHeaderRegexp = regexp.MustCompile(`(?ms)(^diff.*?)^@@`)
)

type PatchOptions struct {
	// Create a reverse patch
	Reverse bool

	// If true, we're building a patch that we are going to apply using
	// "git apply --reverse". In that case the filtering of partial hunks needs
	// to be done a little differently.
	WillBeAppliedReverse bool

	// Whether to keep or discard the original diff header including the
	// "index deadbeef..fa1afe1 100644" line.
	KeepOriginalHeader bool
}

func GetHeaderFromDiff(diff string) string {
	match := patchHeaderRegexp.FindStringSubmatch(diff)
	if len(match) <= 1 {
		return ""
	}
	return match[1]
}

func GetHunksFromDiff(diff string) []*PatchHunk {
	hunks := []*PatchHunk{}
	firstLineIdx := -1
	var hunkLines []string //nolint:prealloc
	pastDiffHeader := false

	lines := strings.SplitAfter(diff, "\n")

	for lineIdx, line := range lines {
		isHunkHeader := strings.HasPrefix(line, "@@ -")


Review comment (suggestion):
I'd like this comment to be more explicit about the difference between creating a reverse patch (i.e. what the `Reverse` option is for) and creating a patch to be applied in reverse. In fact it's just occurred to me that I don't properly understand the difference haha

Code after:
package patch

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/sirupsen/logrus"
)

var (
	hunkHeaderRegexp  = regexp.MustCompile(`(?m)^@@ -(\d+)[^\+]+\+(\d+)[^@]+@@(.*)$`)
	patchHeaderRegexp = regexp.MustCompile(`(?ms)(^diff.*?)^@@`)
)

type PatchOptions struct {
	// Create a patch that will applied in reverse with `git apply --reverse`.
	// This affects how unselected lines are treated when only parts of a hunk
	// are selected: usually, for unselected lines we change '-' lines to
	// context lines and remove '+' lines, but when Reverse is true we need to
	// turn '+' lines into context lines and remove '-' lines.
	Reverse bool

	// Whether to keep or discard the original diff header including the
	// "index deadbeef..fa1afe1 100644" line.
	KeepOriginalHeader bool
}

func GetHeaderFromDiff(diff string) string {
	match := patchHeaderRegexp.FindStringSubmatch(diff)
	if len(match) <= 1 {
		return ""
	}
	return match[1]
}

func GetHunksFromDiff(diff string) []*PatchHunk {
	hunks := []*PatchHunk{}
	firstLineIdx := -1
	var hunkLines []string //nolint:prealloc
	pastDiffHeader := false

	lines := strings.SplitAfter(diff, "\n")

	for lineIdx, line := range lines {
		isHunkHeader := strings.HasPrefix(line, "@@ -")

		if isHunkHeader {
Repository: jesseduffield/lazygit
File: pkg/gui/presentation/commits.go (Go)

Code before:
	commitCount int
}

var (
	pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe)
	mutex        deadlock.Mutex
)

type bisectBounds struct {
	newIndex int
	oldIndex int
}

func GetCommitListDisplayStrings(
	commits []*models.Commit,
	fullDescription bool,
	cherryPickedCommitShaSet *set.Set[string],
	diffName string,
	timeFormat string,
	parseEmoji bool,
	selectedCommitSha string,
	startIdx int,
	length int,
	showGraph bool,
	bisectInfo *git_commands.BisectInfo,
	youAreHereStr string, // non-empty only when we are rebasing
) [][]string {
	mutex.Lock()
	defer mutex.Unlock()

	if len(commits) == 0 {
		return nil
	}

	if startIdx > len(commits) {
		return nil
	}

	end := utils.Min(startIdx+length, len(commits))
	// this is where my non-TODO commits begin
	rebaseOffset := utils.Min(indexOfFirstNonTODOCommit(commits), end)

	filteredCommits := commits[startIdx:end]

	bisectBounds := getbisectBounds(commits, bisectInfo)

	// function expects to be passed the index of the commit in terms of the `commits` slice
	var getGraphLine func(int) string
	if showGraph {
		// this is where the graph begins (may be beyond the TODO commits depending on startIdx,
		// but we'll never include TODO commits as part of the graph because it'll be messy)

Review comment (suggestion):
I'm kind of abusing this parameter as both a way to pass in the translated string (`Tr` isn't known in here), and as a flag to say whether we should add the label or not. Hopefully the comment makes this clear enough.

Code after:
	commitSha   string
	commitCount int
}

var (
	pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe)
	mutex        deadlock.Mutex
)

type bisectBounds struct {
	newIndex int
	oldIndex int
}

func GetCommitListDisplayStrings(
	common *common.Common,
	commits []*models.Commit,
	fullDescription bool,
	cherryPickedCommitShaSet *set.Set[string],
	diffName string,
	timeFormat string,
	parseEmoji bool,
	selectedCommitSha string,
	startIdx int,
	length int,
	showGraph bool,
	bisectInfo *git_commands.BisectInfo,
	showYouAreHereLabel bool,
) [][]string {
	mutex.Lock()
	defer mutex.Unlock()

	if len(commits) == 0 {
		return nil
	}

	if startIdx > len(commits) {
		return nil
	}

	end := utils.Min(startIdx+length, len(commits))
	// this is where my non-TODO commits begin
	rebaseOffset := utils.Min(indexOfFirstNonTODOCommit(commits), end)

	filteredCommits := commits[startIdx:end]

	bisectBounds := getbisectBounds(commits, bisectInfo)

	// function expects to be passed the index of the commit in terms of the `commits` slice
	var getGraphLine func(int) string
	if showGraph {
Repository: jesseduffield/lazygit
File: pkg/gui/presentation/commits.go (Go)

Code before:
		return style.Sprintf("<-- " + bisectInfo.OldTerm())
	case BisectStatusCurrent:
		// TODO: i18n
		return style.Sprintf("<-- current")
	case BisectStatusSkipped:
		return style.Sprintf("<-- skipped")
	case BisectStatusCandidate:
		return style.Sprintf("?")
	case BisectStatusNone:
		return ""
	}

	return ""
}

func displayCommit(
	commit *models.Commit,
	cherryPickedCommitShaSet *set.Set[string],
	diffName string,
	timeFormat string,
	parseEmoji bool,
	graphLine string,
	fullDescription bool,
	bisectStatus BisectStatus,
	bisectInfo *git_commands.BisectInfo,
	youAreHereStr string, // non-empty only if we're rebasing and this is the current commit
) []string {
	shaColor := getShaColor(commit, diffName, cherryPickedCommitShaSet, bisectStatus, bisectInfo)
	bisectString := getBisectStatusText(bisectStatus, bisectInfo)

	actionString := ""
	if commit.Action != "" {
		actionString = actionColorMap(commit.Action).Sprint(commit.Action) + " "
	}

	tagString := ""
	if fullDescription {
		if commit.ExtraInfo != "" {
			tagString = style.FgMagenta.SetBold().Sprint(commit.ExtraInfo) + " "
		}
	} else {
		if len(commit.Tags) > 0 {
			tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(commit.Tags, " ")) + " "
		}
	}

	name := commit.Name
	if parseEmoji {
		name = emoji.Sprint(name)
	}


Review comment (suggestion):
Same here, the string is both for knowing the translated string and a flag whether this particular commit should get the label. A separate bool might be clearer, but is also a bit redundant.

Alternatively, I considered passing in `common.Common` so that we know the translated text, and a bool. However, that would make it more awkward for the test below, which would now have to instantiate a `common.Common`.

Code after:
		return style.Sprintf("<-- " + bisectInfo.OldTerm())
	case BisectStatusCurrent:
		// TODO: i18n
		return style.Sprintf("<-- current")
	case BisectStatusSkipped:
		return style.Sprintf("<-- skipped")
	case BisectStatusCandidate:
		return style.Sprintf("?")
	case BisectStatusNone:
		return ""
	}

	return ""
}

func displayCommit(
	common *common.Common,
	commit *models.Commit,
	cherryPickedCommitShaSet *set.Set[string],
	diffName string,
	timeFormat string,
	parseEmoji bool,
	graphLine string,
	fullDescription bool,
	bisectStatus BisectStatus,
	bisectInfo *git_commands.BisectInfo,
	isYouAreHereCommit bool,
) []string {
	shaColor := getShaColor(commit, diffName, cherryPickedCommitShaSet, bisectStatus, bisectInfo)
	bisectString := getBisectStatusText(bisectStatus, bisectInfo)

	actionString := ""
	if commit.Action != "" {
		actionString = actionColorMap(commit.Action).Sprint(commit.Action) + " "
	}

	tagString := ""
	if fullDescription {
		if commit.ExtraInfo != "" {
			tagString = style.FgMagenta.SetBold().Sprint(commit.ExtraInfo) + " "
		}
	} else {
		if len(commit.Tags) > 0 {
			tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(commit.Tags, " ")) + " "
		}
	}

	name := commit.Name
	if parseEmoji {
		name = emoji.Sprint(name)
	}
Repository: jesseduffield/lazygit
File: pkg/integration/tests/interactive_rebase/drop_with_custom_comment_char.go (Go)

Code before:
package interactive_rebase

import (
	"github.com/jesseduffield/lazygit/pkg/config"
	. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var DropWithCustomCommentChar = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Drops a commit with the 'core.commentChar' option set to a custom character",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.SetConfig("core.commentChar", ";")
		shell.CreateNCommits(2)
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		confirmCommitDrop := func() {
			t.ExpectPopup().Confirmation().
				Title(Equals("Delete commit")).
				Content(Equals("Are you sure you want to delete this commit?")).
				Confirm()
		}

		t.Views().Commits().Focus().
			Lines(
				Contains("commit 02").IsSelected(),
				Contains("commit 01"),
			).
			Press(keys.Universal.Remove).
			Tap(confirmCommitDrop).
			// TODO(gus): look into why this is not failing.
			Lines(
				Contains("commit 02").IsSelected(),
				Contains("commit 01"),
			)
	},
})


Review comment (refactor):
I'm not a fan of having local functions like this in tests. It makes the flow of what happens in which order harder to understand, so I'd just have inlined this below where you need it.

However, I see that you copied this from other existing tests that do it in the same way. How about extracting this to a new file in `pkg/integration/tests/shared`? Doing this for the existing tests could be a separate commit at the beginning of the branch.

Code after:
package interactive_rebase

import (
	"github.com/jesseduffield/lazygit/pkg/config"
	. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var DropWithCustomCommentChar = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Drops a commit with the 'core.commentChar' option set to a custom character",
	ExtraCmdArgs: []string{},
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.SetConfig("core.commentChar", ";")
		shell.CreateNCommits(2)
	},
	Run: func(t *TestDriver, keys config.KeybindingConfig) {
		t.Views().Commits().Focus().
			Lines(
				Contains("commit 02").IsSelected(),
				Contains("commit 01"),
			).
			Press(keys.Universal.Remove).
			Tap(func() {
				t.ExpectPopup().Confirmation().
					Title(Equals("Delete commit")).
					Content(Equals("Are you sure you want to delete this commit?")).
					Confirm()
			}).
			Lines(
				Contains("commit 01").IsSelected(),
			)
	},
})
Repository: jesseduffield/lazygit
File: pkg/gui/gui_common.go (Go)

Code before:
func (self *guiCommon) GocuiGui() *gocui.Gui {
	return self.gui.g
}

func (self *guiCommon) OnUIThread(f func() error) {
	self.gui.onUIThread(f)
}

func (self *guiCommon) RenderToMainViews(opts types.RefreshMainOpts) error {
	return self.gui.refreshMainViews(opts)
}

func (self *guiCommon) MainViewPairs() types.MainViewPairs {
	return types.MainViewPairs{
		Normal:         self.gui.normalMainContextPair(),
		Staging:        self.gui.stagingMainContextPair(),
		PatchBuilding:  self.gui.patchBuildingMainContextPair(),
		MergeConflicts: self.gui.mergingMainContextPair(),
	}
}

func (self *guiCommon) State() types.IStateAccessor {
	return self.gui.stateAccessor
}

func (self *guiCommon) IgnoringWhitespaceSubTitle() string {
	if self.State().GetIgnoreWhitespaceInDiffView() {
		return self.gui.Tr.IgnoreWhitespaceDiffViewSubTitle
	}

	return ""
}

func (self *guiCommon) KeybindingsOpts() types.KeybindingsOpts {
	return self.gui.keybindingOpts()
}

func (self *guiCommon) IsAnyModeActive() bool {
	return self.gui.helpers.Mode.IsAnyModeActive()
}

func (self *guiCommon) GetInitialKeybindingsWithCustomCommands() ([]*types.Binding, []*gocui.ViewMouseBinding) {
	return self.gui.GetInitialKeybindingsWithCustomCommands()
}


Review comment (refactor):
I want `gui_common` to only hold stuff that could be of general use to avoid namespace pollution, and I don't think this qualifies. I'd chuck this in `pkg/gui/controllers/helpers/diff_helper.go` instead.

Code after:
func (self *guiCommon) GocuiGui() *gocui.Gui {
	return self.gui.g
}

func (self *guiCommon) OnUIThread(f func() error) {
	self.gui.onUIThread(f)
}

func (self *guiCommon) RenderToMainViews(opts types.RefreshMainOpts) error {
	return self.gui.refreshMainViews(opts)
}

func (self *guiCommon) MainViewPairs() types.MainViewPairs {
	return types.MainViewPairs{
		Normal:         self.gui.normalMainContextPair(),
		Staging:        self.gui.stagingMainContextPair(),
		PatchBuilding:  self.gui.patchBuildingMainContextPair(),
		MergeConflicts: self.gui.mergingMainContextPair(),
	}
}

func (self *guiCommon) State() types.IStateAccessor {
	return self.gui.stateAccessor
}

func (self *guiCommon) KeybindingsOpts() types.KeybindingsOpts {
	return self.gui.keybindingOpts()
}

func (self *guiCommon) IsAnyModeActive() bool {
	return self.gui.helpers.Mode.IsAnyModeActive()
}

func (self *guiCommon) GetInitialKeybindingsWithCustomCommands() ([]*types.Binding, []*gocui.ViewMouseBinding) {
	return self.gui.GetInitialKeybindingsWithCustomCommands()
}
Repository: jesseduffield/lazygit
File: pkg/gui/controllers/toggle_whitespace_action.go (Go)

Code before:
package controllers

import (
	"github.com/jesseduffield/lazygit/pkg/gui/types"
)

type ToggleWhitespaceAction struct {
	c *ControllerCommon
}

func (self *ToggleWhitespaceAction) Call() error {
	self.c.State().SetIgnoreWhitespaceInDiffView(!self.c.State().GetIgnoreWhitespaceInDiffView())

	toastMessage := self.c.Tr.ShowingWhitespaceInDiffView
	if self.c.State().GetIgnoreWhitespaceInDiffView() {
		toastMessage = self.c.Tr.IgnoringWhitespaceInDiffView
	}
	self.c.Toast(toastMessage)

	return self.c.CurrentSideContext().HandleFocus(types.OnFocusOpts{})
}


Review comment (bug):
I've pushed a change here after testing locally: I thought that the error message wasn't appearing cos of some bug but in fact it was the case that ignore-whitespace was enabled and so I couldn't _disable_ it meaning I was spamming the keybinding but didn't see a change. So I've changed it to just show the error regardless of whether you're toggling on/off, which I think is fine.

Code after:
package controllers

import (
	"github.com/jesseduffield/lazygit/pkg/gui/context"
	"github.com/jesseduffield/lazygit/pkg/gui/types"
	"github.com/samber/lo"
)

type ToggleWhitespaceAction struct {
	c *ControllerCommon
}

func (self *ToggleWhitespaceAction) Call() error {
	contextsThatDontSupportIgnoringWhitespace := []types.ContextKey{
		context.STAGING_MAIN_CONTEXT_KEY,
		context.STAGING_SECONDARY_CONTEXT_KEY,
		context.PATCH_BUILDING_MAIN_CONTEXT_KEY,
	}

	if lo.Contains(contextsThatDontSupportIgnoringWhitespace, self.c.CurrentContext().GetKey()) {
		// Ignoring whitespace is not supported in these views. Let the user
		// know that it's not going to work in case they try to turn it on.
		return self.c.ErrorMsg(self.c.Tr.IgnoreWhitespaceNotSupportedHere)
	}

	self.c.State().SetIgnoreWhitespaceInDiffView(!self.c.State().GetIgnoreWhitespaceInDiffView())

	return self.c.CurrentSideContext().HandleFocus(types.OnFocusOpts{})
}