Repository: jesseduffield/lazygit (language: go)

Issue:
Text background color turns blue when unstaging chunks
**Description**

When I stage a whole file and then jump into it to unstage selected chunks, the background color of the staged section turns blue. If you change which files you're looking at, their backgrounds are also blue.

**Steps to Reproduce**

1. Go to section 2: `Files - Worktrees - Submodules`
2. Find a file with changes and press `<Space>` to stage all of it
3. Press `<Enter>` on it and move to the `Staged changes` section
4. Press `<Space>` on some chunks to unstage them
5. The previously hidden `Unstaged changes` section reappears and the unstaged text's background color is blue.

**NOTE:** See context. Not always reproducible via these steps; might be unrelated to (un)staging.

**Expected behavior**

Background colors don't change.

**Screenshots**

![Screenshot from 2024-06-15 05-44-56](https://github.com/jesseduffield/lazygit/assets/81123101/294913f3-a188-49f5-80f1-1e4b62c07add)

**Version info:**

Latest release (at the time of this writing):

```
$ lazygit --version
commit=6fcb7eb8bb616c170506312870b3bf15f3dbe37c, build date=2024-05-19T10:15:28Z, build source=binaryRelease, version=0.42.0, os=linux, arch=amd64, git version=2.43.0
```

Git:
```
$ git --version
git version 2.43.0
```

**Additional context**

The above steps are just *one* way in which I've triggered the issue. It *doesn't always* get triggered. A bit more messing around between (un)staging files and/or chunks also triggered it, with the background color remaining blue in both the staged and unstaged portions.

I'm speculating that it *might* have something to do with the staged/unstaged sections becoming hidden/visible. A bit more messing showed that the bg colors went back to normal by causing the whole section to be split by staging/unstaging some chunks.

You'll need to play with it. I just pulled another all-nighter and can't really dig any deeper.



Discussion / hints:
Thanks for the reproduction recipe. I've seen this several times myself, and it always drove me nuts, but I could never figure out how it happened. With your reproduction steps it was pretty easy to figure out.

Here's a PR that fixes it for me: #3667

(In the meantime, a workaround is to press tab twice.)
Sounds great. Thanks a lot for the tool and the follow-up.

Fix patch:
diff --git a/docs/Config.md b/docs/Config.md
index 11cc1333396..67d73ebd4d0 100644
--- a/docs/Config.md
+++ b/docs/Config.md
@@ -122,6 +122,10 @@ gui:
     selectedLineBgColor:
       - blue
 
+    # Background color of selected line when view doesn't have focus.
+    inactiveViewSelectedLineBgColor:
+      - bold
+
     # Foreground color of copied commit
     cherryPickedCommitFgColor:
       - blue
diff --git a/go.mod b/go.mod
index 4e189992ba6..69546555d27 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
 	github.com/integrii/flaggy v1.4.0
 	github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
 	github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
-	github.com/jesseduffield/gocui v0.3.1-0.20240623095254-05e1204c2454
+	github.com/jesseduffield/gocui v0.3.1-0.20240623124136-ce5274be521d
 	github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
 	github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
 	github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
diff --git a/go.sum b/go.sum
index 19c69818978..dae59e80722 100644
--- a/go.sum
+++ b/go.sum
@@ -188,8 +188,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
 github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
 github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
-github.com/jesseduffield/gocui v0.3.1-0.20240623095254-05e1204c2454 h1:rTPA5WiPM1SPUA3r2kSb3RiILC93am6irMvOLjO7JNA=
-github.com/jesseduffield/gocui v0.3.1-0.20240623095254-05e1204c2454/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
+github.com/jesseduffield/gocui v0.3.1-0.20240623124136-ce5274be521d h1:I6rViLB+ZW5SnS8P7ZE0FdY6lMfx803qZ9ZYEYCvfro=
+github.com/jesseduffield/gocui v0.3.1-0.20240623124136-ce5274be521d/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
 github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
 github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 47fbe2eea65..7ab567fbe25 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -179,6 +179,8 @@ type ThemeConfig struct {
 	// Background color of selected line.
 	// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#highlighting-the-selected-line
 	SelectedLineBgColor []string `yaml:"selectedLineBgColor" jsonschema:"minItems=1,uniqueItems=true"`
+	// Background color of selected line when view doesn't have focus.
+	InactiveViewSelectedLineBgColor []string `yaml:"inactiveViewSelectedLineBgColor" jsonschema:"minItems=1,uniqueItems=true"`
 	// Foreground color of copied commit
 	CherryPickedCommitFgColor []string `yaml:"cherryPickedCommitFgColor" jsonschema:"minItems=1,uniqueItems=true"`
 	// Background color of copied commit
@@ -668,17 +670,18 @@ func GetDefaultConfig() *UserConfig {
 			TimeFormat:               "02 Jan 06",
 			ShortTimeFormat:          time.Kitchen,
 			Theme: ThemeConfig{
-				ActiveBorderColor:          []string{"green", "bold"},
-				SearchingActiveBorderColor: []string{"cyan", "bold"},
-				InactiveBorderColor:        []string{"default"},
-				OptionsTextColor:           []string{"blue"},
-				SelectedLineBgColor:        []string{"blue"},
-				CherryPickedCommitBgColor:  []string{"cyan"},
-				CherryPickedCommitFgColor:  []string{"blue"},
-				MarkedBaseCommitBgColor:    []string{"yellow"},
-				MarkedBaseCommitFgColor:    []string{"blue"},
-				UnstagedChangesColor:       []string{"red"},
-				DefaultFgColor:             []string{"default"},
+				ActiveBorderColor:               []string{"green", "bold"},
+				SearchingActiveBorderColor:      []string{"cyan", "bold"},
+				InactiveBorderColor:             []string{"default"},
+				OptionsTextColor:                []string{"blue"},
+				SelectedLineBgColor:             []string{"blue"},
+				InactiveViewSelectedLineBgColor: []string{"bold"},
+				CherryPickedCommitBgColor:       []string{"cyan"},
+				CherryPickedCommitFgColor:       []string{"blue"},
+				MarkedBaseCommitBgColor:         []string{"yellow"},
+				MarkedBaseCommitFgColor:         []string{"blue"},
+				UnstagedChangesColor:            []string{"red"},
+				DefaultFgColor:                  []string{"default"},
 			},
 			CommitAuthorFormat:           "auto",
 			CommitLength:                 CommitLengthConfig{Show: true},
diff --git a/pkg/gui/context.go b/pkg/gui/context.go
index be5a720e331..28ecf240549 100644
--- a/pkg/gui/context.go
+++ b/pkg/gui/context.go
@@ -230,6 +230,10 @@ func (self *ContextMgr) ActivateContext(c types.Context, opts types.OnFocusOpts)
 	self.gui.helpers.Window.SetWindowContext(c)
 
 	self.gui.helpers.Window.MoveToTopOfWindow(c)
+	oldView := self.gui.c.GocuiGui().CurrentView()
+	if oldView != nil && oldView.Name() != viewName {
+		oldView.HighlightInactive = true
+	}
 	if _, err := self.gui.c.GocuiGui().SetCurrentView(viewName); err != nil {
 		return err
 	}
diff --git a/pkg/gui/context/simple_context.go b/pkg/gui/context/simple_context.go
index 7c00e09f741..cef871cefea 100644
--- a/pkg/gui/context/simple_context.go
+++ b/pkg/gui/context/simple_context.go
@@ -52,6 +52,8 @@ func (self *SimpleContext) HandleFocus(opts types.OnFocusOpts) error {
 }
 
 func (self *SimpleContext) HandleFocusLost(opts types.OnFocusLostOpts) error {
+	self.GetViewTrait().SetHighlight(false)
+	_ = self.view.SetOriginX(0)
 	if self.onFocusLostFn != nil {
 		return self.onFocusLostFn(opts)
 	}
diff --git a/pkg/gui/context/view_trait.go b/pkg/gui/context/view_trait.go
index 19141989740..5342071ef88 100644
--- a/pkg/gui/context/view_trait.go
+++ b/pkg/gui/context/view_trait.go
@@ -49,6 +49,7 @@ func (self *ViewTrait) SetContent(content string) {
 
 func (self *ViewTrait) SetHighlight(highlight bool) {
 	self.view.Highlight = highlight
+	self.view.HighlightInactive = false
 }
 
 func (self *ViewTrait) SetFooter(value string) {
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 06228e759cb..66fe5cb9ced 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -678,7 +678,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
 		return err
 	}
 
-	gui.g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout()))
+	gui.g.SetManager(gocui.ManagerFunc(gui.layout))
 
 	if err := gui.createAllViews(); err != nil {
 		return err
diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go
index 2123731e42d..861bb0bd124 100644
--- a/pkg/gui/layout.go
+++ b/pkg/gui/layout.go
@@ -288,35 +288,6 @@ func (gui *Gui) onInitialViewsCreation() error {
 	return nil
 }
 
-// getFocusLayout returns a manager function for when view gain and lose focus
-func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error {
-	var previousView *gocui.View
-	return func(g *gocui.Gui) error {
-		newView := gui.g.CurrentView()
-		// for now we don't consider losing focus to a popup panel as actually losing focus
-		if newView != previousView && !gui.helpers.Confirmation.IsPopupPanel(newView.Name()) {
-			if err := gui.onViewFocusLost(previousView); err != nil {
-				return err
-			}
-
-			previousView = newView
-		}
-		return nil
-	}
-}
-
-func (gui *Gui) onViewFocusLost(oldView *gocui.View) error {
-	if oldView == nil {
-		return nil
-	}
-
-	oldView.Highlight = false
-
-	_ = oldView.SetOriginX(0)
-
-	return nil
-}
-
 func (gui *Gui) transientContexts() []types.Context {
 	return lo.Filter(gui.State.Contexts.Flatten(), func(context types.Context, _ int) bool {
 		return context.IsTransient()
diff --git a/pkg/gui/views.go b/pkg/gui/views.go
index 9fd775764d3..9a4fa0a479a 100644
--- a/pkg/gui/views.go
+++ b/pkg/gui/views.go
@@ -92,6 +92,7 @@ func (gui *Gui) createAllViews() error {
 		(*mapping.viewPtr).FrameRunes = frameRunes
 		(*mapping.viewPtr).FgColor = theme.GocuiDefaultTextColor
 		(*mapping.viewPtr).SelBgColor = theme.GocuiSelectedLineBgColor
+		(*mapping.viewPtr).InactiveViewSelBgColor = theme.GocuiInactiveViewSelectedLineBgColor
 	}
 
 	gui.Views.Options.Frame = false
diff --git a/pkg/theme/theme.go b/pkg/theme/theme.go
index 78be46fb635..acd8ebf7161 100644
--- a/pkg/theme/theme.go
+++ b/pkg/theme/theme.go
@@ -24,11 +24,15 @@ var (
 
 	// GocuiSelectedLineBgColor is the background color for the selected line in gocui
 	GocuiSelectedLineBgColor gocui.Attribute
+	// GocuiInactiveViewSelectedLineBgColor is the background color for the selected line in gocui if the view doesn't have focus
+	GocuiInactiveViewSelectedLineBgColor gocui.Attribute
 
 	OptionsColor gocui.Attribute
 
 	// SelectedLineBgColor is the background color for the selected line
 	SelectedLineBgColor = style.New()
+	// InactiveViewSelectedLineBgColor is the background color for the selected line if the view doesn't have the focus
+	InactiveViewSelectedLineBgColor = style.New()
 
 	// CherryPickedCommitColor is the text style when cherry picking a commit
 	CherryPickedCommitTextStyle = style.New()
@@ -49,6 +53,7 @@ func UpdateTheme(themeConfig config.ThemeConfig) {
 	InactiveBorderColor = GetGocuiStyle(themeConfig.InactiveBorderColor)
 	SearchingActiveBorderColor = GetGocuiStyle(themeConfig.SearchingActiveBorderColor)
 	SelectedLineBgColor = GetTextStyle(themeConfig.SelectedLineBgColor, true)
+	InactiveViewSelectedLineBgColor = GetTextStyle(themeConfig.InactiveViewSelectedLineBgColor, true)
 
 	cherryPickedCommitBgTextStyle := GetTextStyle(themeConfig.CherryPickedCommitBgColor, true)
 	cherryPickedCommitFgTextStyle := GetTextStyle(themeConfig.CherryPickedCommitFgColor, false)
@@ -62,6 +67,7 @@ func UpdateTheme(themeConfig config.ThemeConfig) {
 	UnstagedChangesColor = unstagedChangesTextStyle
 
 	GocuiSelectedLineBgColor = GetGocuiStyle(themeConfig.SelectedLineBgColor)
+	GocuiInactiveViewSelectedLineBgColor = GetGocuiStyle(themeConfig.InactiveViewSelectedLineBgColor)
 	OptionsColor = GetGocuiStyle(themeConfig.OptionsTextColor)
 	OptionsFgColor = GetTextStyle(themeConfig.OptionsTextColor, false)
 
diff --git a/schema/config.json b/schema/config.json
index 271fd8be645..802069bed66 100644
--- a/schema/config.json
+++ b/schema/config.json
@@ -186,6 +186,18 @@
                 "blue"
               ]
             },
+            "inactiveViewSelectedLineBgColor": {
+              "items": {
+                "type": "string"
+              },
+              "type": "array",
+              "minItems": 1,
+              "uniqueItems": true,
+              "description": "Background color of selected line when view doesn't have focus.",
+              "default": [
+                "bold"
+              ]
+            },
             "cherryPickedCommitFgColor": {
               "items": {
                 "type": "string"
diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go
index a32519b801f..6589c69811d 100644
--- a/vendor/github.com/jesseduffield/gocui/view.go
+++ b/vendor/github.com/jesseduffield/gocui/view.go
@@ -81,6 +81,11 @@ type View struct {
 	// foreground colors of the selected line, when it is highlighted.
 	SelBgColor, SelFgColor Attribute
 
+	// InactiveViewSelBgColor is used to configure the background color of the
+	// selected line, when it is highlighted but the view doesn't have the
+	// focus.
+	InactiveViewSelBgColor Attribute
+
 	// If Editable is true, keystrokes will be added to the view's internal
 	// buffer at the cursor position.
 	Editable bool
@@ -96,6 +101,9 @@ type View struct {
 	// If Highlight is true, Sel{Bg,Fg}Colors will be used
 	// for the line under the cursor position.
 	Highlight bool
+	// If HighlightInactive is true, InavtiveViewSel{Bg,Fg}Colors will be used
+	// instead of Sel{Bg,Fg}Colors for highlighting selected lines.
+	HighlightInactive bool
 
 	// If Frame is true, a border will be drawn around the view.
 	Frame bool
@@ -404,6 +412,7 @@ func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
 
 	v.FgColor, v.BgColor = ColorDefault, ColorDefault
 	v.SelFgColor, v.SelBgColor = ColorDefault, ColorDefault
+	v.InactiveViewSelBgColor = ColorDefault
 	v.TitleColor, v.FrameColor = ColorDefault, ColorDefault
 	return v
 }
@@ -506,7 +515,11 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
 				fgColor += 8
 			}
 			fgColor = fgColor | AttrBold
-			bgColor = bgColor | v.SelBgColor
+			if v.HighlightInactive {
+				bgColor = bgColor | v.InactiveViewSelBgColor
+			} else {
+				bgColor = bgColor | v.SelBgColor
+			}
 		}
 	}
 
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 62d47eea4e7..c7d601a9326 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
 github.com/jesseduffield/go-git/v5/utils/merkletrie/index
 github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
 github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
-# github.com/jesseduffield/gocui v0.3.1-0.20240623095254-05e1204c2454
+# github.com/jesseduffield/gocui v0.3.1-0.20240623124136-ce5274be521d
 ## explicit; go 1.12
 github.com/jesseduffield/gocui
 # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10


Test patch: