allow searching in any list view

This commit is contained in:
Jesse Duffield 2022-10-22 20:10:35 -07:00
parent b6b5373999
commit 702361559f
8 changed files with 52 additions and 24 deletions

View file

@ -52,8 +52,8 @@ func (gui *Gui) getMessageHeight(wrap bool, message string, width int) int {
return lineCount return lineCount
} }
func (gui *Gui) getConfirmationPanelDimensions(g *gocui.Gui, wrap bool, prompt string) (int, int, int, int) { func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, int, int, int) {
width, height := g.Size() width, height := gui.g.Size()
panelWidth := width / 2 panelWidth := width / 2
panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth) panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth)
return width/2 - panelWidth/2, return width/2 - panelWidth/2,
@ -73,7 +73,7 @@ func (gui *Gui) createPromptPanel(title string, handleConfirm func(*gocui.Gui, *
} }
func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool) error { func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool) error {
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(gui.g, true, prompt) x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(true, prompt)
confirmationView := gui.Views.Confirmation confirmationView := gui.Views.Confirmation
_, err := gui.g.SetView("confirmation", x0, y0, x1, y1, 0) _, err := gui.g.SetView("confirmation", x0, y0, x1, y1, 0)
if err != nil { if err != nil {

View file

@ -88,6 +88,7 @@ type guiState struct {
type searchingState struct { type searchingState struct {
view *gocui.View view *gocui.View
panel ISideListPanel
isSearching bool isSearching bool
searchString string searchString string
} }

View file

@ -450,13 +450,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleImagesBulkCommand, Handler: gui.handleImagesBulkCommand,
Description: gui.Tr.ViewBulkCommands, Description: gui.Tr.ViewBulkCommands,
}, },
{
ViewName: "images",
Key: '/',
Modifier: gocui.ModNone,
Handler: wrappedHandler(gui.handleOpenImageSearch),
Description: gui.Tr.FilterList,
},
{ {
ViewName: "volumes", ViewName: "volumes",
Key: '[', Key: '[',
@ -620,6 +613,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
}) })
} }
for _, panel := range gui.allListPanels() {
bindings = append(bindings,
&Binding{
ViewName: panel.View().Name(),
Key: '/',
Modifier: gocui.ModNone,
Handler: wrappedHandler(gui.handleOpenSearch),
Description: gui.Tr.LcFilter,
})
}
return bindings return bindings
} }

View file

@ -73,6 +73,9 @@ type SideListPanel[T comparable] struct {
onClick func(T) error onClick func(T) error
getDisplayStrings func(T) []string getDisplayStrings func(T) []string
// function to be called after re-rendering list. Can be nil
onRerender func() error
} }
type ISideListPanel interface { type ISideListPanel interface {
@ -80,6 +83,7 @@ type ISideListPanel interface {
HandleSelect() error HandleSelect() error
View() *gocui.View View() *gocui.View
Refocus() Refocus()
RerenderList() error
} }
var _ ISideListPanel = &SideListPanel[int]{} var _ ISideListPanel = &SideListPanel[int]{}
@ -275,6 +279,12 @@ func (self *SideListPanel[T]) RerenderList() error {
} }
fmt.Fprint(self.view, renderedTable) fmt.Fprint(self.view, renderedTable)
if self.onRerender != nil {
if err := self.onRerender(); err != nil {
return err
}
}
if self.view == self.gui.CurrentView() { if self.view == self.gui.CurrentView() {
return self.HandleSelect() return self.HandleSelect()
} }

View file

@ -39,6 +39,9 @@ func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] {
getDisplayStrings: func(menuItem *MenuItem) []string { getDisplayStrings: func(menuItem *MenuItem) []string {
return menuItem.LabelColumns return menuItem.LabelColumns
}, },
onRerender: func() error {
return gui.resizePopupPanel(gui.Views.Menu)
},
// the menu panel doesn't actually have any contexts to display on the main view // the menu panel doesn't actually have any contexts to display on the main view
// so what follows are all dummy values // so what follows are all dummy values

View file

@ -4,13 +4,15 @@ import (
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
) )
func (gui *Gui) handleOpenImageSearch() error { func (gui *Gui) handleOpenSearch() error {
return gui.handleOpenSearch(gui.Views.Images) panel, ok := gui.currentListPanel()
} if !ok {
return nil
}
func (gui *Gui) handleOpenSearch(view *gocui.View) error {
gui.State.Searching.isSearching = true gui.State.Searching.isSearching = true
gui.State.Searching.view = view gui.State.Searching.view = panel.View()
gui.State.Searching.panel = panel
return gui.switchFocus(gui.Views.Search) return gui.switchFocus(gui.Views.Search)
} }
@ -18,7 +20,7 @@ func (gui *Gui) handleOpenSearch(view *gocui.View) error {
func (gui *Gui) onNewSearchString(value string) error { func (gui *Gui) onNewSearchString(value string) error {
// need to refresh the right list panel. // need to refresh the right list panel.
gui.State.Searching.searchString = value gui.State.Searching.searchString = value
return gui.Panels.Images.RerenderList() return gui.State.Searching.panel.RerenderList()
} }
func (gui *Gui) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool { func (gui *Gui) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
@ -44,9 +46,11 @@ func (gui *Gui) clearSearch() error {
gui.State.Searching.searchString = "" gui.State.Searching.searchString = ""
gui.State.Searching.isSearching = false gui.State.Searching.isSearching = false
gui.State.Searching.view = nil gui.State.Searching.view = nil
panel := gui.State.Searching.panel
gui.State.Searching.panel = nil
gui.Views.Search.ClearTextArea() gui.Views.Search.ClearTextArea()
return gui.Panels.Images.RerenderList() return panel.RerenderList()
} }
// returns to the list view with the filter still applied // returns to the list view with the filter still applied

View file

@ -133,9 +133,12 @@ func (gui *Gui) returnFocus() error {
// Not to be called directly. Use `switchFocus` instead // Not to be called directly. Use `switchFocus` instead
func (gui *Gui) pushView(name string) { func (gui *Gui) pushView(name string) {
// No matter what view we're pushing, we first remove all popup panels from the stack // No matter what view we're pushing, we first remove all popup panels from the stack
gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool { // (unless it's the search view because we may be searching the menu panel)
return !gui.isPopupPanel(viewName) if name != "search" {
}) gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool {
return !gui.isPopupPanel(viewName)
})
}
// If we're pushing a side panel, we remove all other panels // If we're pushing a side panel, we remove all other panels
if lo.Contains(gui.sideViewNames(), name) { if lo.Contains(gui.sideViewNames(), name) {
@ -318,21 +321,21 @@ func (gui *Gui) currentViewName() string {
func (gui *Gui) resizeCurrentPopupPanel(g *gocui.Gui) error { func (gui *Gui) resizeCurrentPopupPanel(g *gocui.Gui) error {
v := g.CurrentView() v := g.CurrentView()
if gui.isPopupPanel(v.Name()) { if gui.isPopupPanel(v.Name()) {
return gui.resizePopupPanel(g, v) return gui.resizePopupPanel(v)
} }
return nil return nil
} }
func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) resizePopupPanel(v *gocui.View) error {
// If the confirmation panel is already displayed, just resize the width, // If the confirmation panel is already displayed, just resize the width,
// otherwise continue // otherwise continue
content := v.Buffer() content := v.Buffer()
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(g, v.Wrap, content) x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(v.Wrap, content)
vx0, vy0, vx1, vy1 := v.Dimensions() vx0, vy0, vx1, vy1 := v.Dimensions()
if vx0 == x0 && vy0 == y0 && vx1 == x1 && vy1 == y1 { if vx0 == x0 && vy0 == y0 && vx1 == x1 && vy1 == y1 {
return nil return nil
} }
_, err := g.SetView(v.Name(), x0, y0, x1, y1, 0) _, err := gui.g.SetView(v.Name(), x0, y0, x1, y1, 0)
return err return err
} }
@ -482,6 +485,7 @@ func (gui *Gui) currentSidePanel() (ISideListPanel, bool) {
return nil, false return nil, false
} }
// returns the current list panel. If no list panel is focused, returns false.
func (gui *Gui) currentListPanel() (ISideListPanel, bool) { func (gui *Gui) currentListPanel() (ISideListPanel, bool) {
viewName := gui.currentViewName() viewName := gui.currentViewName()

View file

@ -38,6 +38,7 @@ type TranslationSet struct {
Confirm string Confirm string
Return string Return string
FocusMain string FocusMain string
LcFilter string
StopContainer string StopContainer string
RestartingStatus string RestartingStatus string
StartingStatus string StartingStatus string
@ -148,6 +149,7 @@ func englishSet() TranslationSet {
Return: "return", Return: "return",
FocusMain: "focus main panel", FocusMain: "focus main panel",
LcFilter: "filter list",
Navigate: "navigate", Navigate: "navigate",
Execute: "execute", Execute: "execute",
Close: "close", Close: "close",