diff --git a/pkg/gui/arrangement.go b/pkg/gui/arrangement.go index a8ae19e6..bcd4aa1c 100644 --- a/pkg/gui/arrangement.go +++ b/pkg/gui/arrangement.go @@ -2,6 +2,7 @@ package gui import ( "github.com/jesseduffield/lazycore/pkg/boxlayout" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/mattn/go-runewidth" "github.com/samber/lo" @@ -129,12 +130,12 @@ func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []* } func (gui *Gui) sideViewNames() []string { - visibleSidePanels := lo.Filter(gui.allSidePanels(), func(panel ISideListPanel, _ int) bool { + visibleSidePanels := lo.Filter(gui.allSidePanels(), func(panel panels.ISideListPanel, _ int) bool { return !panel.IsHidden() }) - return lo.Map(visibleSidePanels, func(panel ISideListPanel, _ int) string { - return panel.View().Name() + return lo.Map(visibleSidePanels, func(panel panels.ISideListPanel, _ int) string { + return panel.GetView().Name() }) } diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index 1ba8302a..aad842c7 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -11,11 +11,12 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" ) -func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] { +func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container] { // Standalone containers are containers which are either one-off containers, or whose service is not part of this docker-compose context. isStandaloneContainer := func(container *commands.Container) bool { if container.OneOff || container.ServiceName == "" { @@ -27,34 +28,34 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] { }) } - return &SideListPanel[*commands.Container]{ - ContextState: &ContextState[*commands.Container]{ - GetContexts: func() []ContextConfig[*commands.Container] { - return []ContextConfig[*commands.Container]{ + return &panels.SideListPanel[*commands.Container]{ + ContextState: &panels.ContextState[*commands.Container]{ + GetContexts: func() []panels.ContextConfig[*commands.Container] { + return []panels.ContextConfig[*commands.Container]{ { - key: "logs", - title: gui.Tr.LogsTitle, - render: gui.renderContainerLogsToMain, + Key: "logs", + Title: gui.Tr.LogsTitle, + Render: gui.renderContainerLogsToMain, }, { - key: "stats", - title: gui.Tr.StatsTitle, - render: gui.renderContainerStats, + Key: "stats", + Title: gui.Tr.StatsTitle, + Render: gui.renderContainerStats, }, { - key: "env", - title: gui.Tr.EnvTitle, - render: gui.renderContainerEnv, + Key: "env", + Title: gui.Tr.EnvTitle, + Render: gui.renderContainerEnv, }, { - key: "config", - title: gui.Tr.ConfigTitle, - render: gui.renderContainerConfig, + Key: "config", + Title: gui.Tr.ConfigTitle, + Render: gui.renderContainerConfig, }, { - key: "top", - title: gui.Tr.TopTitle, - render: gui.renderContainerTop, + Key: "top", + Title: gui.Tr.TopTitle, + Render: gui.renderContainerTop, }, } }, @@ -62,12 +63,12 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] { return "containers-" + container.ID + "-" + container.Container.State }, }, - ListPanel: ListPanel[*commands.Container]{ - List: NewFilteredList[*commands.Container](), - view: gui.Views.Containers, + ListPanel: panels.ListPanel[*commands.Container]{ + List: panels.NewFilteredList[*commands.Container](), + View: gui.Views.Containers, }, NoItemsMessage: gui.Tr.NoContainers, - gui: gui.intoInterface(), + Gui: gui.intoInterface(), // sortedContainers returns containers sorted by state if c.SortContainersByState is true (follows 1- running, 2- exited, 3- created) // and sorted by name if c.SortContainersByState is false Sort: func(a *commands.Container, b *commands.Container) bool { @@ -282,7 +283,7 @@ func (gui *Gui) refreshContainersAndServices() error { if i == originalSelectedLineIdx { break } - gui.Panels.Services.setSelectedLineIdx(i) + gui.Panels.Services.SetSelectedLineIdx(i) gui.Panels.Services.Refocus() } } diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index a50ca625..37cf0c1b 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -24,7 +24,7 @@ func (gui *Gui) handleOpenFilter() error { func (gui *Gui) onNewFilterNeedle(value string) error { gui.State.Filter.needle = value - gui.ResetOrigin(gui.State.Filter.panel.View()) + gui.ResetOrigin(gui.State.Filter.panel.GetView()) return gui.State.Filter.panel.RerenderList() } @@ -59,7 +59,7 @@ func (gui *Gui) clearFilter() error { return nil } - gui.ResetOrigin(panel.View()) + gui.ResetOrigin(panel.GetView()) return panel.RerenderList() } diff --git a/pkg/gui/focus.go b/pkg/gui/focus.go index c07808e0..cc414a53 100644 --- a/pkg/gui/focus.go +++ b/pkg/gui/focus.go @@ -52,7 +52,7 @@ func (gui *Gui) switchFocusAux(newView *gocui.View) error { newViewStack := gui.State.ViewStack - if gui.State.Filter.panel != nil && !lo.Contains(newViewStack, gui.State.Filter.panel.View().Name()) { + if gui.State.Filter.panel != nil && !lo.Contains(newViewStack, gui.State.Filter.panel.GetView().Name()) { if err := gui.clearFilter(); err != nil { return err } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b3f70414..bc2f8e30 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -15,6 +15,7 @@ import ( lcUtils "github.com/jesseduffield/lazycore/pkg/utils" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/i18n" "github.com/jesseduffield/lazydocker/pkg/tasks" "github.com/sasha-s/go-deadlock" @@ -49,12 +50,12 @@ type Gui struct { } type Panels struct { - Projects *SideListPanel[*commands.Project] - Services *SideListPanel[*commands.Service] - Containers *SideListPanel[*commands.Container] - Images *SideListPanel[*commands.Image] - Volumes *SideListPanel[*commands.Volume] - Menu *SideListPanel[*MenuItem] + Projects *panels.SideListPanel[*commands.Project] + Services *panels.SideListPanel[*commands.Service] + Containers *panels.SideListPanel[*commands.Container] + Images *panels.SideListPanel[*commands.Image] + Volumes *panels.SideListPanel[*commands.Volume] + Menu *panels.SideListPanel[*MenuItem] } type Mutexes struct { @@ -94,7 +95,7 @@ type filterState struct { // or we've committed the filter and we're back in the list view active bool // The panel that we're filtering. - panel ISideListPanel + panel panels.ISideListPanel // The string that we're filtering on needle string } diff --git a/pkg/gui/images_panel.go b/pkg/gui/images_panel.go index eb0cb72d..001b1574 100644 --- a/pkg/gui/images_panel.go +++ b/pkg/gui/images_panel.go @@ -10,21 +10,22 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" ) -func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] { +func (gui *Gui) getImagesPanel() *panels.SideListPanel[*commands.Image] { noneLabel := "" - return &SideListPanel[*commands.Image]{ - ContextState: &ContextState[*commands.Image]{ - GetContexts: func() []ContextConfig[*commands.Image] { - return []ContextConfig[*commands.Image]{ + return &panels.SideListPanel[*commands.Image]{ + ContextState: &panels.ContextState[*commands.Image]{ + GetContexts: func() []panels.ContextConfig[*commands.Image] { + return []panels.ContextConfig[*commands.Image]{ { - key: "config", - title: gui.Tr.ConfigTitle, - render: func(image *commands.Image) error { + Key: "config", + Title: gui.Tr.ConfigTitle, + Render: func(image *commands.Image) error { return gui.renderImageConfig(image) }, }, @@ -34,12 +35,12 @@ func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] { return "images-" + image.ID }, }, - ListPanel: ListPanel[*commands.Image]{ - List: NewFilteredList[*commands.Image](), - view: gui.Views.Images, + ListPanel: panels.ListPanel[*commands.Image]{ + List: panels.NewFilteredList[*commands.Image](), + View: gui.Views.Images, }, NoItemsMessage: gui.Tr.NoImages, - gui: gui.intoInterface(), + Gui: gui.intoInterface(), Sort: func(a *commands.Image, b *commands.Image) bool { if a.Name == noneLabel && b.Name != noneLabel { return false @@ -114,7 +115,7 @@ func (gui *Gui) refreshStateImages() error { } func (gui *Gui) FilterString(view *gocui.View) string { - if gui.State.Filter.panel != nil && gui.State.Filter.panel.View() != view { + if gui.State.Filter.panel != nil && gui.State.Filter.panel.GetView() != view { return "" } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index bd86167a..00934a6a 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -492,12 +492,12 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { for _, panel := range gui.allSidePanels() { bindings = append(bindings, []*Binding{ - {ViewName: panel.View().Name(), Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView}, - {ViewName: panel.View().Name(), Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView}, - {ViewName: panel.View().Name(), Key: 'h', Modifier: gocui.ModNone, Handler: gui.previousView}, - {ViewName: panel.View().Name(), Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView}, - {ViewName: panel.View().Name(), Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView}, - {ViewName: panel.View().Name(), Key: gocui.KeyBacktab, Modifier: gocui.ModNone, Handler: gui.previousView}, + {ViewName: panel.GetView().Name(), Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView}, + {ViewName: panel.GetView().Name(), Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView}, + {ViewName: panel.GetView().Name(), Key: 'h', Modifier: gocui.ModNone, Handler: gui.previousView}, + {ViewName: panel.GetView().Name(), Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView}, + {ViewName: panel.GetView().Name(), Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView}, + {ViewName: panel.GetView().Name(), Key: gocui.KeyBacktab, Modifier: gocui.ModNone, Handler: gui.previousView}, }...) } @@ -514,7 +514,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { } for _, panel := range gui.allListPanels() { - setUpDownClickBindings(panel.View().Name(), panel.HandlePrevLine, panel.HandleNextLine, panel.HandleClick) + setUpDownClickBindings(panel.GetView().Name(), panel.HandlePrevLine, panel.HandleNextLine, panel.HandleClick) } setUpDownClickBindings("main", gui.scrollUpMain, gui.scrollDownMain, gui.handleMainClick) @@ -522,21 +522,21 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { for _, panel := range gui.allSidePanels() { bindings = append(bindings, &Binding{ - ViewName: panel.View().Name(), + ViewName: panel.GetView().Name(), Key: gocui.KeyEnter, Modifier: gocui.ModNone, Handler: gui.handleEnterMain, Description: gui.Tr.FocusMain, }, &Binding{ - ViewName: panel.View().Name(), + ViewName: panel.GetView().Name(), Key: '[', Modifier: gocui.ModNone, Handler: wrappedHandler(panel.HandlePrevContext), Description: gui.Tr.PreviousContext, }, &Binding{ - ViewName: panel.View().Name(), + ViewName: panel.GetView().Name(), Key: ']', Modifier: gocui.ModNone, Handler: wrappedHandler(panel.HandleNextContext), @@ -547,7 +547,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { for _, panel := range gui.allListPanels() { bindings = append(bindings, &Binding{ - ViewName: panel.View().Name(), + ViewName: panel.GetView().Name(), Key: '/', Modifier: gocui.ModNone, Handler: wrappedHandler(gui.handleOpenFilter), diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 63ade0ee..76f57c2a 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -1,6 +1,7 @@ package gui import ( + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" ) @@ -22,14 +23,14 @@ type CreateMenuOptions struct { HideCancel bool } -func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] { - return &SideListPanel[*MenuItem]{ - ListPanel: ListPanel[*MenuItem]{ - List: NewFilteredList[*MenuItem](), - view: gui.Views.Menu, +func (gui *Gui) getMenuPanel() *panels.SideListPanel[*MenuItem] { + return &panels.SideListPanel[*MenuItem]{ + ListPanel: panels.ListPanel[*MenuItem]{ + List: panels.NewFilteredList[*MenuItem](), + View: gui.Views.Menu, }, NoItemsMessage: "", - gui: gui.intoInterface(), + Gui: gui.intoInterface(), OnClick: gui.onMenuPress, Sort: nil, GetDisplayStrings: func(menuItem *MenuItem) []string { @@ -101,7 +102,7 @@ func (gui *Gui) Menu(opts CreateMenuOptions) error { } gui.Panels.Menu.SetItems(opts.Items) - gui.Panels.Menu.setSelectedLineIdx(0) + gui.Panels.Menu.SetSelectedLineIdx(0) if err := gui.Panels.Menu.RerenderList(); err != nil { return err diff --git a/pkg/gui/panels.go b/pkg/gui/panels.go new file mode 100644 index 00000000..b92e44e1 --- /dev/null +++ b/pkg/gui/panels.go @@ -0,0 +1,7 @@ +package gui + +import "github.com/jesseduffield/lazydocker/pkg/gui/panels" + +func (gui *Gui) intoInterface() panels.IGui { + return gui +} diff --git a/pkg/gui/filtered_list.go b/pkg/gui/panels/filtered_list.go similarity index 99% rename from pkg/gui/filtered_list.go rename to pkg/gui/panels/filtered_list.go index 428edba8..21d3519d 100644 --- a/pkg/gui/filtered_list.go +++ b/pkg/gui/panels/filtered_list.go @@ -1,4 +1,4 @@ -package gui +package panels import ( "sort" diff --git a/pkg/gui/filtered_list_test.go b/pkg/gui/panels/filtered_list_test.go similarity index 99% rename from pkg/gui/filtered_list_test.go rename to pkg/gui/panels/filtered_list_test.go index 00d4c5ac..1d36cb6f 100644 --- a/pkg/gui/filtered_list_test.go +++ b/pkg/gui/panels/filtered_list_test.go @@ -1,4 +1,4 @@ -package gui +package panels import ( "testing" diff --git a/pkg/gui/panels/list_panel.go b/pkg/gui/panels/list_panel.go new file mode 100644 index 00000000..65bae779 --- /dev/null +++ b/pkg/gui/panels/list_panel.go @@ -0,0 +1,42 @@ +package panels + +import ( + "github.com/jesseduffield/gocui" + lcUtils "github.com/jesseduffield/lazycore/pkg/utils" +) + +type ListPanel[T comparable] struct { + SelectedIdx int + List *FilteredList[T] + View *gocui.View +} + +func (self *ListPanel[T]) SetSelectedLineIdx(value int) { + clampedValue := 0 + if self.List.Len() > 0 { + clampedValue = lcUtils.Clamp(value, 0, self.List.Len()-1) + } + + self.SelectedIdx = clampedValue +} + +func (self *ListPanel[T]) clampSelectedLineIdx() { + clamped := lcUtils.Clamp(self.SelectedIdx, 0, self.List.Len()-1) + + if clamped != self.SelectedIdx { + self.SelectedIdx = clamped + } +} + +// moves the cursor up or down by the given amount (up for negative values) +func (self *ListPanel[T]) moveSelectedLine(delta int) { + self.SetSelectedLineIdx(self.SelectedIdx + delta) +} + +func (self *ListPanel[T]) SelectNextLine() { + self.moveSelectedLine(1) +} + +func (self *ListPanel[T]) SelectPrevLine() { + self.moveSelectedLine(-1) +} diff --git a/pkg/gui/list_panel.go b/pkg/gui/panels/side_list_panel.go similarity index 78% rename from pkg/gui/list_panel.go rename to pkg/gui/panels/side_list_panel.go index 84ef6f13..f6e329ca 100644 --- a/pkg/gui/list_panel.go +++ b/pkg/gui/panels/side_list_panel.go @@ -1,4 +1,4 @@ -package gui +package panels import ( "fmt" @@ -6,53 +6,23 @@ import ( "github.com/go-errors/errors" "github.com/jesseduffield/gocui" - lcUtils "github.com/jesseduffield/lazycore/pkg/utils" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" ) -type ListPanel[T comparable] struct { - SelectedIdx int - List *FilteredList[T] - view *gocui.View -} - -func (self *ListPanel[T]) setSelectedLineIdx(value int) { - clampedValue := 0 - if self.List.Len() > 0 { - clampedValue = lcUtils.Clamp(value, 0, self.List.Len()-1) - } - - self.SelectedIdx = clampedValue -} - -func (self *ListPanel[T]) clampSelectedLineIdx() { - clamped := lcUtils.Clamp(self.SelectedIdx, 0, self.List.Len()-1) - - if clamped != self.SelectedIdx { - self.SelectedIdx = clamped - } -} - -// moves the cursor up or down by the given amount (up for negative values) -func (self *ListPanel[T]) moveSelectedLine(delta int) { - self.setSelectedLineIdx(self.SelectedIdx + delta) -} - -func (self *ListPanel[T]) SelectNextLine() { - self.moveSelectedLine(1) -} - -func (self *ListPanel[T]) SelectPrevLine() { - self.moveSelectedLine(-1) -} - -type ContextState[T any] struct { - contextIdx int - // contexts []ContextConfig[T] - GetContexts func() []ContextConfig[T] - // this tells us whether we need to re-render to the main panel - GetContextCacheKey func(item T) string +type ISideListPanel interface { + SetContextIndex(int) + HandleSelect() error + GetView() *gocui.View + Refocus() + RerenderList() error + IsFilterDisabled() bool + IsHidden() bool + HandleNextLine() error + HandlePrevLine() error + HandleClick() error + HandlePrevContext() error + HandleNextContext() error } // list panel at the side of the screen that renders content to the main panel @@ -65,7 +35,7 @@ type SideListPanel[T comparable] struct { // and it has focus. Leave empty if you don't want to render anything NoItemsMessage string - gui IGui + Gui IGui // this Filter is applied on top of additional default filters Filter func(T) bool @@ -85,27 +55,20 @@ type SideListPanel[T comparable] struct { Hide func() bool } -type ISideListPanel interface { - SetContextIndex(int) - HandleSelect() error - View() *gocui.View - Refocus() - RerenderList() error - IsFilterDisabled() bool - IsHidden() bool - HandleNextLine() error - HandlePrevLine() error - HandleClick() error - HandlePrevContext() error - HandleNextContext() error -} - var _ ISideListPanel = &SideListPanel[int]{} +type ContextState[T any] struct { + contextIdx int + // contexts []ContextConfig[T] + GetContexts func() []ContextConfig[T] + // this tells us whether we need to re-render to the main panel + GetContextCacheKey func(item T) string +} + type ContextConfig[T any] struct { - key string - title string - render func(item T) error + Key string + Title string + Render func(item T) error } type IGui interface { @@ -121,16 +84,12 @@ type IGui interface { Update(func() error) } -func (gui *Gui) intoInterface() IGui { - return gui -} - func (self *SideListPanel[T]) HandleClick() error { itemCount := self.List.Len() handleSelect := self.HandleSelect selectedLine := &self.SelectedIdx - if err := self.gui.HandleClick(self.view, itemCount, selectedLine, handleSelect); err != nil { + if err := self.Gui.HandleClick(self.View, itemCount, selectedLine, handleSelect); err != nil { return err } @@ -144,8 +103,8 @@ func (self *SideListPanel[T]) HandleClick() error { return nil } -func (self *SideListPanel[T]) View() *gocui.View { - return self.view +func (self *SideListPanel[T]) GetView() *gocui.View { + return self.View } func (self *SideListPanel[T]) HandleSelect() error { @@ -156,7 +115,7 @@ func (self *SideListPanel[T]) HandleSelect() error { } if self.NoItemsMessage != "" { - return self.gui.RenderStringMain(self.NoItemsMessage) + return self.Gui.RenderStringMain(self.NoItemsMessage) } return nil @@ -173,25 +132,25 @@ func (self *SideListPanel[T]) renderContext(item T) error { } key := self.ContextState.GetCurrentContextKey(item) - if !self.gui.ShouldRefresh(key) { + if !self.Gui.ShouldRefresh(key) { return nil } - mainView := self.gui.GetMainView() + mainView := self.Gui.GetMainView() mainView.Tabs = self.ContextState.GetContextTitles() mainView.TabIndex = self.ContextState.contextIdx - return self.ContextState.GetCurrentContext().render(item) + return self.ContextState.GetCurrentContext().Render(item) } func (self *ContextState[T]) GetContextTitles() []string { return lo.Map(self.GetContexts(), func(context ContextConfig[T], _ int) string { - return context.title + return context.Title }) } func (self *ContextState[T]) GetCurrentContextKey(item T) string { - return self.GetContextCacheKey(item) + "-" + self.GetCurrentContext().key + return self.GetContextCacheKey(item) + "-" + self.GetCurrentContext().Key } func (self *ContextState[T]) GetCurrentContext() ContextConfig[T] { @@ -263,7 +222,7 @@ func (self *SideListPanel[T]) HandlePrevContext() error { } func (self *SideListPanel[T]) Refocus() { - self.gui.FocusY(self.SelectedIdx, self.List.Len(), self.view) + self.Gui.FocusY(self.SelectedIdx, self.List.Len(), self.View) } func (self *SideListPanel[T]) SetItems(items []T) { @@ -272,14 +231,14 @@ func (self *SideListPanel[T]) SetItems(items []T) { } func (self *SideListPanel[T]) FilterAndSort() { - filterString := self.gui.FilterString(self.view) + filterString := self.Gui.FilterString(self.View) self.List.Filter(func(item T, index int) bool { if self.Filter != nil && !self.Filter(item) { return false } - if lo.SomeBy(self.gui.IgnoreStrings(), func(ignore string) bool { + if lo.SomeBy(self.Gui.IgnoreStrings(), func(ignore string) bool { return lo.SomeBy(self.GetDisplayStrings(item), func(searchString string) bool { return strings.Contains(searchString, ignore) }) @@ -304,8 +263,8 @@ func (self *SideListPanel[T]) FilterAndSort() { func (self *SideListPanel[T]) RerenderList() error { self.FilterAndSort() - self.gui.Update(func() error { - self.view.Clear() + self.Gui.Update(func() error { + self.View.Clear() table := lo.Map(self.List.GetItems(), func(item T, index int) []string { return self.GetDisplayStrings(item) }) @@ -313,7 +272,7 @@ func (self *SideListPanel[T]) RerenderList() error { if err != nil { return err } - fmt.Fprint(self.view, renderedTable) + fmt.Fprint(self.View, renderedTable) if self.OnRerender != nil { if err := self.OnRerender(); err != nil { @@ -321,7 +280,7 @@ func (self *SideListPanel[T]) RerenderList() error { } } - if self.view == self.gui.CurrentView() { + if self.View == self.Gui.CurrentView() { return self.HandleSelect() } return nil diff --git a/pkg/gui/project_panel.go b/pkg/gui/project_panel.go index 6ba9ba28..c3a192f8 100644 --- a/pkg/gui/project_panel.go +++ b/pkg/gui/project_panel.go @@ -8,6 +8,7 @@ import ( "github.com/fatih/color" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/jesseduffield/yaml" ) @@ -15,35 +16,35 @@ import ( // Although at the moment we'll only have one project, in future we could have // a list of projects in the project panel. -func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] { - return &SideListPanel[*commands.Project]{ - ContextState: &ContextState[*commands.Project]{ - GetContexts: func() []ContextConfig[*commands.Project] { +func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] { + return &panels.SideListPanel[*commands.Project]{ + ContextState: &panels.ContextState[*commands.Project]{ + GetContexts: func() []panels.ContextConfig[*commands.Project] { if gui.DockerCommand.InDockerComposeProject { - return []ContextConfig[*commands.Project]{ + return []panels.ContextConfig[*commands.Project]{ { - key: "logs", - title: gui.Tr.LogsTitle, - render: gui.renderAllLogs, + Key: "logs", + Title: gui.Tr.LogsTitle, + Render: gui.renderAllLogs, }, { - key: "config", - title: gui.Tr.DockerComposeConfigTitle, - render: gui.renderDockerComposeConfig, + Key: "config", + Title: gui.Tr.DockerComposeConfigTitle, + Render: gui.renderDockerComposeConfig, }, { - key: "credits", - title: gui.Tr.CreditsTitle, - render: gui.renderCredits, + Key: "credits", + Title: gui.Tr.CreditsTitle, + Render: gui.renderCredits, }, } } - return []ContextConfig[*commands.Project]{ + return []panels.ContextConfig[*commands.Project]{ { - key: "credits", - title: gui.Tr.CreditsTitle, - render: gui.renderCredits, + Key: "credits", + Title: gui.Tr.CreditsTitle, + Render: gui.renderCredits, }, } }, @@ -52,12 +53,12 @@ func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] { }, }, - ListPanel: ListPanel[*commands.Project]{ - List: NewFilteredList[*commands.Project](), - view: gui.Views.Project, + ListPanel: panels.ListPanel[*commands.Project]{ + List: panels.NewFilteredList[*commands.Project](), + View: gui.Views.Project, }, NoItemsMessage: "", - gui: gui.intoInterface(), + Gui: gui.intoInterface(), Sort: func(a *commands.Project, b *commands.Project) bool { return false diff --git a/pkg/gui/services_panel.go b/pkg/gui/services_panel.go index 2bb06f6e..09a04068 100644 --- a/pkg/gui/services_panel.go +++ b/pkg/gui/services_panel.go @@ -8,39 +8,40 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" ) -func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] { - return &SideListPanel[*commands.Service]{ - ContextState: &ContextState[*commands.Service]{ - GetContexts: func() []ContextConfig[*commands.Service] { - return []ContextConfig[*commands.Service]{ +func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] { + return &panels.SideListPanel[*commands.Service]{ + ContextState: &panels.ContextState[*commands.Service]{ + GetContexts: func() []panels.ContextConfig[*commands.Service] { + return []panels.ContextConfig[*commands.Service]{ { - key: "logs", - title: gui.Tr.LogsTitle, - render: gui.renderServiceLogs, + Key: "logs", + Title: gui.Tr.LogsTitle, + Render: gui.renderServiceLogs, }, { - key: "stats", - title: gui.Tr.StatsTitle, - render: gui.renderServiceStats, + Key: "stats", + Title: gui.Tr.StatsTitle, + Render: gui.renderServiceStats, }, { - key: "container-env", - title: gui.Tr.ContainerEnvTitle, - render: gui.renderServiceContainerEnv, + Key: "container-env", + Title: gui.Tr.ContainerEnvTitle, + Render: gui.renderServiceContainerEnv, }, { - key: "container-config", - title: gui.Tr.ContainerConfigTitle, - render: gui.renderServiceContainerConfig, + Key: "container-config", + Title: gui.Tr.ContainerConfigTitle, + Render: gui.renderServiceContainerConfig, }, { - key: "top", - title: gui.Tr.TopTitle, - render: gui.renderServiceTop, + Key: "top", + Title: gui.Tr.TopTitle, + Render: gui.renderServiceTop, }, } }, @@ -51,13 +52,12 @@ func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] { return "services-" + service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State }, }, - ListPanel: ListPanel[*commands.Service]{ - List: NewFilteredList[*commands.Service](), - view: gui.Views.Services, + ListPanel: panels.ListPanel[*commands.Service]{ + List: panels.NewFilteredList[*commands.Service](), + View: gui.Views.Services, }, - // TODO: i18n - NoItemsMessage: "no service selected", - gui: gui.intoInterface(), + NoItemsMessage: gui.Tr.NoServices, + Gui: gui.intoInterface(), // sort services first by whether they have a linked container, and second by alphabetical order Sort: func(a *commands.Service, b *commands.Service) bool { if a.Container != nil && b.Container == nil { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 70cb4996..b5bdf55d 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" "github.com/spkg/bom" @@ -329,11 +330,11 @@ func (gui *Gui) CurrentView() *gocui.View { return gui.g.CurrentView() } -func (gui *Gui) currentSidePanel() (ISideListPanel, bool) { +func (gui *Gui) currentSidePanel() (panels.ISideListPanel, bool) { viewName := gui.currentViewName() for _, sidePanel := range gui.allSidePanels() { - if sidePanel.View().Name() == viewName { + if sidePanel.GetView().Name() == viewName { return sidePanel, true } } @@ -342,11 +343,11 @@ func (gui *Gui) currentSidePanel() (ISideListPanel, bool) { } // returns the current list panel. If no list panel is focused, returns false. -func (gui *Gui) currentListPanel() (ISideListPanel, bool) { +func (gui *Gui) currentListPanel() (panels.ISideListPanel, bool) { viewName := gui.currentViewName() for _, sidePanel := range gui.allListPanels() { - if sidePanel.View().Name() == viewName { + if sidePanel.GetView().Name() == viewName { return sidePanel, true } } @@ -354,8 +355,8 @@ func (gui *Gui) currentListPanel() (ISideListPanel, bool) { return nil, false } -func (gui *Gui) allSidePanels() []ISideListPanel { - return []ISideListPanel{ +func (gui *Gui) allSidePanels() []panels.ISideListPanel { + return []panels.ISideListPanel{ gui.Panels.Projects, gui.Panels.Services, gui.Panels.Containers, @@ -364,6 +365,6 @@ func (gui *Gui) allSidePanels() []ISideListPanel { } } -func (gui *Gui) allListPanels() []ISideListPanel { +func (gui *Gui) allListPanels() []panels.ISideListPanel { return append(gui.allSidePanels(), gui.Panels.Menu) } diff --git a/pkg/gui/volumes_panel.go b/pkg/gui/volumes_panel.go index bc70d18f..fc2274e4 100644 --- a/pkg/gui/volumes_panel.go +++ b/pkg/gui/volumes_panel.go @@ -7,19 +7,20 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/gui/panels" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" ) -func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] { - return &SideListPanel[*commands.Volume]{ - ContextState: &ContextState[*commands.Volume]{ - GetContexts: func() []ContextConfig[*commands.Volume] { - return []ContextConfig[*commands.Volume]{ +func (gui *Gui) getVolumesPanel() *panels.SideListPanel[*commands.Volume] { + return &panels.SideListPanel[*commands.Volume]{ + ContextState: &panels.ContextState[*commands.Volume]{ + GetContexts: func() []panels.ContextConfig[*commands.Volume] { + return []panels.ContextConfig[*commands.Volume]{ { - key: "config", - title: gui.Tr.ConfigTitle, - render: gui.renderVolumeConfig, + Key: "config", + Title: gui.Tr.ConfigTitle, + Render: gui.renderVolumeConfig, }, } }, @@ -27,12 +28,12 @@ func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] { return "volumes-" + volume.Name }, }, - ListPanel: ListPanel[*commands.Volume]{ - List: NewFilteredList[*commands.Volume](), - view: gui.Views.Volumes, + ListPanel: panels.ListPanel[*commands.Volume]{ + List: panels.NewFilteredList[*commands.Volume](), + View: gui.Views.Volumes, }, NoItemsMessage: gui.Tr.NoVolumes, - gui: gui.intoInterface(), + Gui: gui.intoInterface(), // we're sorting these volumes based on whether they have labels defined, // because those are the ones you typically care about. // Within that, we also sort them alphabetically diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 779bc2c5..59287d38 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -76,6 +76,7 @@ type TranslationSet struct { NoContainer string NoImages string NoVolumes string + NoServices string RemoveImage string RemoveVolume string RemoveWithoutPrune string @@ -225,6 +226,7 @@ func englishSet() TranslationSet { NoContainer: "No container", NoImages: "No images", NoVolumes: "No volumes", + NoServices: "No services", ConfirmQuit: "Are you sure you want to quit?", ConfirmUpProject: "Are you sure you want to 'up' your docker compose project?",