mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 15:46:26 -04:00
Replace the hard-coded side panel order, tab groupings, and window assignments with values resolved from the gui.sidePanels config. The panel order (SideWindows and the layout boxes), the tab strips (viewTabMap), the per-context window names, each window's default view, and the jump-label groups all now come from the config rather than from five separate hard-coded lists. A panel's window name is the name of its first tab, and panels not listed in the config get their own window name so their views stay hidden instead of overlapping a visible panel. Three small lookups translate config names into views, tab titles, and contexts; a test keeps them in sync with the set of valid names. The lookups are split this way (rather than one resolver) because configureViewProperties runs before the context tree exists, so the title/view lookups must not depend on it. The config is applied to a repo's contexts via applySidePanelConfig on every repo entry, including the cached-repo path: a repo's per-repo config can differ from the previously visited one's, so each repo's contexts must be (re)assigned from its own config rather than kept from when they were first built. With the default config this reproduces today's layout exactly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
149 lines
4.3 KiB
Go
149 lines
4.3 KiB
Go
package helpers
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/config"
|
|
"github.com/jesseduffield/lazygit/pkg/gocui"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
type WindowHelper struct {
|
|
c *HelperCommon
|
|
viewHelper *ViewHelper
|
|
}
|
|
|
|
func NewWindowHelper(c *HelperCommon, viewHelper *ViewHelper) *WindowHelper {
|
|
return &WindowHelper{
|
|
c: c,
|
|
viewHelper: viewHelper,
|
|
}
|
|
}
|
|
|
|
// A window refers to a place on the screen which can hold one or more views.
|
|
// A view is a box that renders content, and within a window only one view will
|
|
// appear at a time. When a view appears within a window, it occupies the whole
|
|
// space. Right now most windows are 1:1 with views, except for commitFiles which
|
|
// is a view that moves between windows
|
|
|
|
func (self *WindowHelper) GetViewNameForWindow(window string) string {
|
|
viewName, ok := self.windowViewNameMap().Get(window)
|
|
if !ok {
|
|
panic(fmt.Sprintf("Viewname not found for window: %s", window))
|
|
}
|
|
|
|
return viewName
|
|
}
|
|
|
|
func (self *WindowHelper) GetContextForWindow(window string) types.Context {
|
|
viewName := self.GetViewNameForWindow(window)
|
|
|
|
context, ok := self.viewHelper.ContextForView(viewName)
|
|
if !ok {
|
|
panic("TODO: fix this")
|
|
}
|
|
|
|
return context
|
|
}
|
|
|
|
// for now all we actually care about is the context's view so we're storing that
|
|
func (self *WindowHelper) SetWindowContext(c types.Context) {
|
|
if c.IsTransient() {
|
|
self.resetWindowContext(c)
|
|
}
|
|
|
|
self.windowViewNameMap().Set(c.GetWindowName(), c.GetViewName())
|
|
}
|
|
|
|
func (self *WindowHelper) windowViewNameMap() *utils.ThreadSafeMap[string, string] {
|
|
return self.c.State().GetRepoState().GetWindowViewNameMap()
|
|
}
|
|
|
|
func (self *WindowHelper) CurrentWindow() string {
|
|
return self.c.Context().Current().GetWindowName()
|
|
}
|
|
|
|
// assumes the context's windowName has been set to the new window if necessary
|
|
func (self *WindowHelper) resetWindowContext(c types.Context) {
|
|
for _, windowName := range self.windowViewNameMap().Keys() {
|
|
viewName, ok := self.windowViewNameMap().Get(windowName)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if viewName == c.GetViewName() && windowName != c.GetWindowName() {
|
|
for _, context := range self.c.Contexts().Flatten() {
|
|
if context.GetKey() != c.GetKey() && context.GetWindowName() == windowName {
|
|
self.windowViewNameMap().Set(windowName, context.GetViewName())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// moves given context's view to the top of the window
|
|
func (self *WindowHelper) MoveToTopOfWindow(context types.Context) {
|
|
view := context.GetView()
|
|
if view == nil {
|
|
return
|
|
}
|
|
|
|
window := context.GetWindowName()
|
|
|
|
topView := self.TopViewInWindow(window, true)
|
|
|
|
if topView != nil && view.Name() != topView.Name() {
|
|
if err := self.c.GocuiGui().SetViewOnTopOf(view.Name(), topView.Name()); err != nil {
|
|
self.c.Log.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (self *WindowHelper) TopViewInWindow(windowName string, includeInvisibleViews bool) *gocui.View {
|
|
// now I need to find all views in that same window, via contexts. And I guess then I need to find the index of the highest view in that list.
|
|
viewNamesInWindow := self.viewNamesInWindow(windowName)
|
|
|
|
// The views list is ordered highest-last, so we're grabbing the last view of the window
|
|
var topView *gocui.View
|
|
for _, currentView := range self.c.GocuiGui().Views() {
|
|
if lo.Contains(viewNamesInWindow, currentView.Name()) && (currentView.Visible || includeInvisibleViews) {
|
|
topView = currentView
|
|
}
|
|
}
|
|
|
|
return topView
|
|
}
|
|
|
|
func (self *WindowHelper) viewNamesInWindow(windowName string) []string {
|
|
result := []string{}
|
|
for _, context := range self.c.Contexts().Flatten() {
|
|
if context.GetWindowName() == windowName {
|
|
result = append(result, context.GetViewName())
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (self *WindowHelper) WindowForView(viewName string) string {
|
|
context, ok := self.viewHelper.ContextForView(viewName)
|
|
if !ok {
|
|
panic("todo: deal with this")
|
|
}
|
|
|
|
return context.GetWindowName()
|
|
}
|
|
|
|
func (self *WindowHelper) SideWindows() []string {
|
|
return sideWindowNames(self.c.UserConfig())
|
|
}
|
|
|
|
// sideWindowNames returns the side panel window names in order, derived from the
|
|
// gui.sidePanels config. A panel's window name is the name of its first tab.
|
|
func sideWindowNames(userConfig *config.UserConfig) []string {
|
|
return lo.Map(userConfig.Gui.SidePanels, func(panel config.SidePanel, _ int) string {
|
|
return panel[0]
|
|
})
|
|
}
|