diff --git a/pkg/gui/controllers/helpers/window_arrangement_helper.go b/pkg/gui/controllers/helpers/window_arrangement_helper.go index 5379e9c09..7428d17e3 100644 --- a/pkg/gui/controllers/helpers/window_arrangement_helper.go +++ b/pkg/gui/controllers/helpers/window_arrangement_helper.go @@ -60,7 +60,7 @@ type WindowArrangementArgs struct { ContentHeightForWindow func(window string) int // Whether the main panel is split (as is the case e.g. when a file has both // staged and unstaged changes) - SplitMainPanel bool + MainPanes types.MainPanes // The current screen mode (normal, half, full) ScreenMode types.ScreenMode // The content shown on the bottom left of the screen when showing a loader @@ -103,7 +103,7 @@ func (self *WindowArrangementHelper) GetWindowDimensions(informationStr string, ContentHeightForWindow: func(window string) int { return self.windowHelper.GetContextForWindow(window).TotalContentHeight() }, - SplitMainPanel: repoState.GetSplitMainPanel(), + MainPanes: repoState.GetMainPanes(), ScreenMode: repoState.GetScreenMode(), AppStatus: appStatus, InformationStr: informationStr, @@ -215,36 +215,27 @@ func MergeMaps[K comparable, V any](maps ...map[K]V) map[K]V { } func mainSectionChildren(args WindowArrangementArgs) []*boxlayout.Box { - // if we're not in split mode we can just show the one main panel. Likewise if - // the main panel is focused and we're in full-screen mode - if !args.SplitMainPanel || (args.ScreenMode == types.SCREEN_FULL && args.CurrentWindow == "main") { - return []*boxlayout.Box{ - { - Window: "main", - Weight: 1, - }, + mainPane := &boxlayout.Box{Window: "main", Weight: 1} + secondaryPane := &boxlayout.Box{Window: "secondary", Weight: 1} + + switch args.MainPanes { + case types.MainPaneOnly: + return []*boxlayout.Box{mainPane} + case types.SecondaryPaneOnly: + return []*boxlayout.Box{secondaryPane} + case types.BothMainPanes: + // In full-screen mode the focused one takes the whole section anyway. + if args.ScreenMode == types.SCREEN_FULL { + if args.CurrentWindow == "main" { + return []*boxlayout.Box{mainPane} + } + if args.CurrentWindow == "secondary" { + return []*boxlayout.Box{secondaryPane} + } } } - if args.CurrentWindow == "secondary" && args.ScreenMode == types.SCREEN_FULL { - return []*boxlayout.Box{ - { - Window: "secondary", - Weight: 1, - }, - } - } - - return []*boxlayout.Box{ - { - Window: "main", - Weight: 1, - }, - { - Window: "secondary", - Weight: 1, - }, - } + return []*boxlayout.Box{mainPane, secondaryPane} } func getMidSectionWeights(args WindowArrangementArgs) (int, int) { @@ -382,7 +373,7 @@ func infoSectionChildren(args WindowArrangementArgs) []*boxlayout.Box { } func splitMainPanelSideBySide(args WindowArrangementArgs) bool { - if !args.SplitMainPanel { + if args.MainPanes != types.BothMainPanes { return false } diff --git a/pkg/gui/controllers/helpers/window_arrangement_helper_test.go b/pkg/gui/controllers/helpers/window_arrangement_helper_test.go index 365d7f104..2235d7fb4 100644 --- a/pkg/gui/controllers/helpers/window_arrangement_helper_test.go +++ b/pkg/gui/controllers/helpers/window_arrangement_helper_test.go @@ -35,7 +35,7 @@ func TestGetWindowDimensions(t *testing.T) { // Each panel shows its first tab by default; for the special-cased // panels (status, stash) the view name matches the window name. ActiveViewForWindow: func(window string) string { return window }, - SplitMainPanel: false, + MainPanes: types.MainPaneOnly, ScreenMode: types.SCREEN_NORMAL, AppStatus: "", InformationStr: "information", diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 3f6233fa7..6739a2175 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -231,7 +231,7 @@ type GuiRepoState struct { Model *types.Model Modes *types.Modes - SplitMainPanel bool + MainPanes types.MainPanes SearchState *types.SearchState // Lets us not load everything at once. Written and read from refresh @@ -321,12 +321,12 @@ func (self *GuiRepoState) GetSearchState() *types.SearchState { return self.SearchState } -func (self *GuiRepoState) SetSplitMainPanel(value bool) { - self.SplitMainPanel = value +func (self *GuiRepoState) SetMainPanes(value types.MainPanes) { + self.MainPanes = value } -func (self *GuiRepoState) GetSplitMainPanel() bool { - return self.SplitMainPanel +func (self *GuiRepoState) GetMainPanes() types.MainPanes { + return self.MainPanes } func (gui *Gui) onSwitchToNewRepo(startArgs appTypes.StartArgs, contextKey types.ContextKey) error { diff --git a/pkg/gui/main_panels.go b/pkg/gui/main_panels.go index 566993a0f..988e5df0b 100644 --- a/pkg/gui/main_panels.go +++ b/pkg/gui/main_panels.go @@ -112,6 +112,8 @@ func (gui *Gui) refreshMainViews(opts types.RefreshMainOpts) { if opts.Main != nil { gui.RefreshMainView(opts.Main, opts.Pair.Main) + } else { + opts.Pair.Main.GetView().Clear() } if opts.Secondary != nil { @@ -134,7 +136,20 @@ func (gui *Gui) refreshMainViews(opts types.RefreshMainOpts) { } } - gui.splitMainPanel(opts.Secondary != nil) + gui.setMainPanes(mainPanesFor(opts)) +} + +// mainPanesFor says which panes the given render occupies: the one it has content for, +// or both when it has content for both. +func mainPanesFor(opts types.RefreshMainOpts) types.MainPanes { + switch { + case opts.Secondary == nil: + return types.MainPaneOnly + case opts.Main == nil: + return types.SecondaryPaneOnly + default: + return types.BothMainPanes + } } // clampDiffSelectionToContent brings the focused main view's selection back onto the @@ -298,8 +313,8 @@ func (gui *Gui) mainContextForView(view *gocui.View) *context.MainContext { return nil } -func (gui *Gui) splitMainPanel(splitMainPanel bool) { - gui.State.SplitMainPanel = splitMainPanel +func (gui *Gui) setMainPanes(panes types.MainPanes) { + gui.State.MainPanes = panes } // reApplySearch runs a search the view holds again over the content a render has just diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 1603df9bb..1baf6b3f9 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -461,8 +461,8 @@ type IRepoStateAccessor interface { SetScreenMode(ScreenMode) InSearchPrompt() bool GetSearchState() *SearchState - SetSplitMainPanel(bool) - GetSplitMainPanel() bool + SetMainPanes(MainPanes) + GetMainPanes() MainPanes GetMergeOrRebaseStartedInLazygit() bool SetMergeOrRebaseStartedInLazygit(bool) } diff --git a/pkg/gui/types/rendering.go b/pkg/gui/types/rendering.go index 0d9baf395..f59a535ba 100644 --- a/pkg/gui/types/rendering.go +++ b/pkg/gui/types/rendering.go @@ -13,6 +13,19 @@ func NewMainContextPair(main Context, secondary Context) MainContextPair { return MainContextPair{Main: main, Secondary: secondary} } +// MainPanes says which of the two panes of the main section are shown. Most content +// takes the main pane alone; content with two sides to it — the working tree's +// unstaged and staged changes, a commit's diff and the patch built from it — takes +// both; and content whose only side is the second one takes the secondary pane alone, +// so that it has the whole section rather than sitting under an empty pane. +type MainPanes int + +const ( + MainPaneOnly MainPanes = iota + BothMainPanes + SecondaryPaneOnly +) + type MainViewPairs struct { Normal MainContextPair MergeConflicts MainContextPair