diff --git a/docs/Config.md b/docs/Config.md index 857a4e359..071cf5a11 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -266,6 +266,9 @@ gui: # If true, show jump-to-window keybindings in window titles. showPanelJumps: true + # If true, show separate Unstaged/Staged tabs in the Files window. + showFileChangeTabs: false + # Nerd fonts version to use. # One of: '2' | '3' | empty string (default) # If empty, do not show icons. diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 9738186d9..d894f2af6 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -168,6 +168,8 @@ type GuiConfig struct { ShowBottomLine bool `yaml:"showBottomLine"` // If true, show jump-to-window keybindings in window titles. ShowPanelJumps bool `yaml:"showPanelJumps"` + // If true, show separate Unstaged/Staged tabs in the Files window. + ShowFileChangeTabs bool `yaml:"showFileChangeTabs"` // Deprecated: use nerdFontsVersion instead ShowIcons bool `yaml:"showIcons" jsonschema:"deprecated"` // Nerd fonts version to use. @@ -901,6 +903,7 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig { ShowCommandLog: true, ShowBottomLine: true, ShowPanelJumps: true, + ShowFileChangeTabs: false, ShowFileTree: true, ShowRootItemInFileTree: true, FileTreeSortOrder: "mixed", diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 801fe14d3..971b39d80 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -904,12 +904,33 @@ func (gui *Gui) viewTabMap() map[string][]context.TabView { // A single-tab panel shows its view's own title, not a tab strip. continue } - result[panel[0]] = lo.Map(panel, func(name string, _ int) context.TabView { + tabViews := lo.Map(panel, func(name string, _ int) context.TabView { return context.TabView{ Tab: titles[name], ViewName: sidePanelViewNames[name], } }) + if panel[0] == "files" && gui.c.UserConfig().Gui.ShowFileChangeTabs { + expanded := make([]context.TabView, 0, len(tabViews)+2) + if len(tabViews) > 0 { + expanded = append(expanded, tabViews[0]) + } + expanded = append(expanded, + context.TabView{ + Tab: gui.c.Tr.UnstagedChanges, + ViewName: "files", + }, + context.TabView{ + Tab: gui.c.Tr.StagedChanges, + ViewName: "files", + }, + ) + if len(tabViews) > 1 { + expanded = append(expanded, tabViews[1:]...) + } + tabViews = expanded + } + result[panel[0]] = tabViews } return result diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 3d924a566..3c7bffc17 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -5,6 +5,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/tasks" "github.com/jesseduffield/lazygit/pkg/utils" @@ -75,6 +76,12 @@ func (gui *Gui) onViewTabClick(windowName string, tabIndex int) error { return nil } + if windowName == "files" { + if err := gui.applyFilesTab(tabs[tabIndex].Tab); err != nil { + return err + } + } + viewName := tabs[tabIndex].ViewName context, ok := gui.helpers.View.ContextForView(viewName) @@ -126,9 +133,61 @@ func getTabbedView(gui *Gui) *gocui.View { // It safe assumption that only static contexts have tabs context := gui.c.Context().CurrentStatic() view, _ := gui.g.View(context.GetViewName()) + if view != nil && view.Name() == "files" { + view.TabIndex = gui.filesTabIndex() + } return view } +func (gui *Gui) filesTabIndex() int { + if gui.State == nil || gui.State.Contexts == nil || gui.State.Contexts.Files == nil { + return 0 + } + if !gui.c.UserConfig().Gui.ShowFileChangeTabs { + return 0 + } + + filter := gui.State.Contexts.Files.GetStatusFilter() + switch filter { + case filetree.DisplayUnstaged: + return 1 + case filetree.DisplayStaged: + return 2 + default: + return 0 + } +} + +func (gui *Gui) applyFilesTab(tabName string) error { + if gui.State == nil || gui.State.Contexts == nil || gui.State.Contexts.Files == nil { + return nil + } + + if !gui.c.UserConfig().Gui.ShowFileChangeTabs { + return nil + } + + filesContext := gui.State.Contexts.Files + desiredFilter := filetree.DisplayAll + + switch tabName { + case gui.c.Tr.UnstagedChanges: + desiredFilter = filetree.DisplayUnstaged + case gui.c.Tr.StagedChanges: + desiredFilter = filetree.DisplayStaged + case gui.c.Tr.FilesTitle: + desiredFilter = filetree.DisplayAll + default: + return nil + } + + filesContext.FileTreeViewModel.SetStatusFilter(desiredFilter) + filesContext.GetView().Subtitle = "" + filesContext.GetView().TabIndex = gui.filesTabIndex() + gui.postRefreshUpdate(filesContext) + return nil +} + func (gui *Gui) render() { gui.c.OnUIThread(func() error { return nil }) } diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 7b6fa93eb..a0266e73b 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -302,4 +302,7 @@ func (gui *Gui) configureViewProperties() { view.Tabs = vt.tabs view.TabIndex = vt.index } + if gui.Views.Files != nil { + gui.Views.Files.TabIndex = gui.filesTabIndex() + } }