mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-21 23:01:03 +00:00
create filtered list struct
This commit is contained in:
parent
57379252a5
commit
cb38e48add
10 changed files with 387 additions and 63 deletions
|
|
@ -40,11 +40,11 @@ type DockerCommand struct {
|
|||
ErrorChan chan error
|
||||
ContainerMutex sync.Mutex
|
||||
ServiceMutex sync.Mutex
|
||||
Services []*Service
|
||||
Containers []*Container
|
||||
|
||||
Services []*Service
|
||||
Containers []*Container
|
||||
// DisplayContainers is the array of containers we will display in the containers panel. If Gui.ShowAllContainers is false, this will only be those containers which aren't based on a service. This reduces clutter and duplication in the UI
|
||||
DisplayContainers []*Container
|
||||
Images []*Image
|
||||
Volumes []*Volume
|
||||
Closers []io.Closer
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ package commands
|
|||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
|
@ -103,7 +101,7 @@ func (i *Image) RenderHistory() (string, error) {
|
|||
}
|
||||
|
||||
// RefreshImages returns a slice of docker images
|
||||
func (c *DockerCommand) RefreshImages(filterString string) ([]*Image, error) {
|
||||
func (c *DockerCommand) RefreshImages() ([]*Image, error) {
|
||||
images, err := c.Client.ImageList(context.Background(), types.ImageListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -145,32 +143,6 @@ func (c *DockerCommand) RefreshImages(filterString string) ([]*Image, error) {
|
|||
}
|
||||
}
|
||||
|
||||
ownImages = lo.Filter(ownImages, func(image *Image, _ int) bool {
|
||||
return !lo.SomeBy(c.Config.UserConfig.Ignore, func(ignore string) bool {
|
||||
return strings.Contains(image.Name, ignore)
|
||||
})
|
||||
})
|
||||
|
||||
if filterString != "" {
|
||||
ownImages = lo.Filter(ownImages, func(image *Image, _ int) bool {
|
||||
return strings.Contains(image.Name, filterString)
|
||||
})
|
||||
}
|
||||
|
||||
noneLabel := "<none>"
|
||||
|
||||
sort.Slice(ownImages, func(i, j int) bool {
|
||||
if ownImages[i].Name == noneLabel && ownImages[j].Name != noneLabel {
|
||||
return false
|
||||
}
|
||||
|
||||
if ownImages[i].Name != noneLabel && ownImages[j].Name == noneLabel {
|
||||
return true
|
||||
}
|
||||
|
||||
return ownImages[i].Name < ownImages[j].Name
|
||||
})
|
||||
|
||||
return ownImages, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
88
pkg/gui/filtered_list.go
Normal file
88
pkg/gui/filtered_list.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type FilteredList[T comparable] struct {
|
||||
allItems []T
|
||||
// indices of items in the allItems slice that are included in the filtered list
|
||||
indices []int
|
||||
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func NewFilteredList[T comparable]() *FilteredList[T] {
|
||||
return &FilteredList[T]{}
|
||||
}
|
||||
|
||||
func (self *FilteredList[T]) SetItems(items []T) {
|
||||
self.mutex.Lock()
|
||||
defer self.mutex.Unlock()
|
||||
|
||||
self.allItems = items
|
||||
self.indices = make([]int, len(items))
|
||||
for i := range self.indices {
|
||||
self.indices[i] = i
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilteredList[T]) Filter(filter func(T, int) bool) {
|
||||
self.mutex.Lock()
|
||||
defer self.mutex.Unlock()
|
||||
|
||||
self.indices = self.indices[:0]
|
||||
for i, item := range self.allItems {
|
||||
if filter(item, i) {
|
||||
self.indices = append(self.indices, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilteredList[T]) Sort(less func(T, T) bool) {
|
||||
self.mutex.Lock()
|
||||
defer self.mutex.Unlock()
|
||||
|
||||
sort.Slice(self.indices, func(i, j int) bool {
|
||||
return less(self.allItems[self.indices[i]], self.allItems[self.indices[j]])
|
||||
})
|
||||
}
|
||||
|
||||
func (self *FilteredList[T]) Get(index int) T {
|
||||
self.mutex.RLock()
|
||||
defer self.mutex.RUnlock()
|
||||
|
||||
return self.allItems[self.indices[index]]
|
||||
}
|
||||
|
||||
// returns the length of the filtered list
|
||||
func (self *FilteredList[T]) Len() int {
|
||||
self.mutex.RLock()
|
||||
defer self.mutex.RUnlock()
|
||||
|
||||
return len(self.indices)
|
||||
}
|
||||
|
||||
func (self *FilteredList[T]) GetIndex(item T) int {
|
||||
self.mutex.RLock()
|
||||
defer self.mutex.RUnlock()
|
||||
|
||||
for i, index := range self.indices {
|
||||
if self.allItems[index] == item {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (self *FilteredList[T]) GetItems() []T {
|
||||
self.mutex.RLock()
|
||||
defer self.mutex.RUnlock()
|
||||
|
||||
result := make([]T, len(self.indices))
|
||||
for i, index := range self.indices {
|
||||
result[i] = self.allItems[index]
|
||||
}
|
||||
return result
|
||||
}
|
||||
183
pkg/gui/filtered_list_test.go
Normal file
183
pkg/gui/filtered_list_test.go
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFilteredListGet(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
args int
|
||||
want int
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: 1,
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: 2,
|
||||
want: 3,
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{1}},
|
||||
args: 0,
|
||||
want: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if got := tt.f.Get(tt.args); got != tt.want {
|
||||
t.Errorf("FilteredList.Get() = %v, want %v", got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredListLen(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
want int
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
want: 3,
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{1}},
|
||||
want: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if got := tt.f.Len(); got != tt.want {
|
||||
t.Errorf("FilteredList.Len() = %v, want %v", got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredListFilter(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
args func(int, int) bool
|
||||
want FilteredList[int]
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: func(i int, _ int) bool { return i%2 == 0 },
|
||||
want: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{1}},
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: func(i int, _ int) bool { return i%2 == 1 },
|
||||
want: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 2}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt.f.Filter(tt.args)
|
||||
assert.EqualValues(t, tt.f.indices, tt.want.indices)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredListSort(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
args func(int, int) bool
|
||||
want FilteredList[int]
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: func(i int, j int) bool { return i < j },
|
||||
want: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: func(i int, j int) bool { return i > j },
|
||||
want: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{2, 1, 0}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt.f.Sort(tt.args)
|
||||
assert.EqualValues(t, tt.f.indices, tt.want.indices)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredListGetIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
args int
|
||||
want int
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: 1,
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: 2,
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{1}},
|
||||
args: 0,
|
||||
want: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if got := tt.f.GetIndex(tt.args); got != tt.want {
|
||||
t.Errorf("FilteredList.GetIndex() = %v, want %v", got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredListGetItems(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
want []int
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{1}},
|
||||
want: []int{2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got := tt.f.GetItems()
|
||||
assert.EqualValues(t, got, tt.want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredListSetItems(t *testing.T) {
|
||||
tests := []struct {
|
||||
f FilteredList[int]
|
||||
args []int
|
||||
want FilteredList[int]
|
||||
}{
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{0, 1, 2}},
|
||||
args: []int{4, 5, 6},
|
||||
want: FilteredList[int]{allItems: []int{4, 5, 6}, indices: []int{0, 1, 2}},
|
||||
},
|
||||
{
|
||||
f: FilteredList[int]{allItems: []int{1, 2, 3}, indices: []int{1}},
|
||||
args: []int{4},
|
||||
want: FilteredList[int]{allItems: []int{4}, indices: []int{0}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt.f.SetItems(tt.args)
|
||||
assert.EqualValues(t, tt.f.indices, tt.want.indices)
|
||||
assert.EqualValues(t, tt.f.allItems, tt.want.allItems)
|
||||
}
|
||||
}
|
||||
|
|
@ -137,6 +137,16 @@ type guiState struct {
|
|||
ScreenMode WindowMaximisation
|
||||
|
||||
Searching searchingState
|
||||
|
||||
Lists Lists
|
||||
}
|
||||
|
||||
// these are the items we display, after filtering is applied.
|
||||
type Lists struct {
|
||||
Containers *FilteredList[*commands.Container]
|
||||
Services *FilteredList[*commands.Service]
|
||||
Images *FilteredList[*commands.Image]
|
||||
Volumes *FilteredList[*commands.Volume]
|
||||
}
|
||||
|
||||
type searchingState struct {
|
||||
|
|
@ -173,6 +183,12 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
|||
Project: &projectState{ContextIndex: 0},
|
||||
},
|
||||
ViewStack: []string{},
|
||||
Lists: Lists{
|
||||
Containers: NewFilteredList[*commands.Container](),
|
||||
Services: NewFilteredList[*commands.Service](),
|
||||
Images: NewFilteredList[*commands.Image](),
|
||||
Volumes: NewFilteredList[*commands.Volume](),
|
||||
},
|
||||
}
|
||||
|
||||
cyclableViews := []string{"project", "containers", "images", "volumes"}
|
||||
|
|
@ -313,7 +329,7 @@ func (gui *Gui) refresh() {
|
|||
}
|
||||
}()
|
||||
go func() {
|
||||
if err := gui.refreshImages(); err != nil {
|
||||
if err := gui.reloadImages(); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/config"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// list panel functions
|
||||
|
|
@ -30,11 +31,11 @@ func (gui *Gui) getSelectedImage() (*commands.Image, error) {
|
|||
return &commands.Image{}, gui.Errors.ErrNoImages
|
||||
}
|
||||
|
||||
return gui.DockerCommand.Images[selectedLine], nil
|
||||
return gui.State.Lists.Images.Get(selectedLine), nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleImagesClick(g *gocui.Gui, v *gocui.View) error {
|
||||
itemCount := len(gui.DockerCommand.Images)
|
||||
itemCount := gui.State.Lists.Images.Len()
|
||||
handleSelect := gui.handleImageSelect
|
||||
selectedLine := &gui.State.Panels.Images.SelectedLine
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ func (gui *Gui) handleImageSelect(g *gocui.Gui, v *gocui.View) error {
|
|||
return gui.renderString(g, "main", gui.Tr.NoImages)
|
||||
}
|
||||
|
||||
gui.focusY(gui.State.Panels.Images.SelectedLine, len(gui.DockerCommand.Images), v)
|
||||
gui.focusY(gui.State.Panels.Images.SelectedLine, gui.State.Lists.Images.Len(), v)
|
||||
|
||||
key := "images-" + Image.ID + "-" + gui.getImageContexts()[gui.State.Panels.Images.ContextIndex]
|
||||
if !gui.shouldRefresh(key) {
|
||||
|
|
@ -97,34 +98,63 @@ func (gui *Gui) renderImageConfig(mainView *gocui.View, image *commands.Image) e
|
|||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshImages() error {
|
||||
ImagesView := gui.getImagesView()
|
||||
if ImagesView == nil {
|
||||
// if the ImagesView hasn't been instantiated yet we just return
|
||||
return nil
|
||||
}
|
||||
func (gui *Gui) reloadImages() error {
|
||||
if err := gui.refreshStateImages(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(gui.DockerCommand.Images) > 0 && gui.State.Panels.Images.SelectedLine == -1 {
|
||||
return gui.rerenderImages()
|
||||
}
|
||||
|
||||
func (gui *Gui) rerenderImages() error {
|
||||
filterString := gui.filterString(gui.Views.Images)
|
||||
|
||||
gui.State.Lists.Images.Filter(func(image *commands.Image, index int) bool {
|
||||
if lo.SomeBy(gui.Config.UserConfig.Ignore, func(ignore string) bool {
|
||||
return strings.Contains(image.Name, ignore)
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
|
||||
if filterString != "" {
|
||||
return strings.Contains(image.Name, filterString)
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
noneLabel := "<none>"
|
||||
|
||||
gui.State.Lists.Images.Sort(func(a *commands.Image, b *commands.Image) bool {
|
||||
if a.Name == noneLabel && b.Name != noneLabel {
|
||||
return false
|
||||
}
|
||||
|
||||
if a.Name != noneLabel && b.Name == noneLabel {
|
||||
return true
|
||||
}
|
||||
|
||||
return a.Name < b.Name
|
||||
})
|
||||
|
||||
if gui.State.Lists.Images.Len() > 0 && gui.State.Panels.Images.SelectedLine == -1 {
|
||||
gui.State.Panels.Images.SelectedLine = 0
|
||||
}
|
||||
if len(gui.DockerCommand.Images)-1 < gui.State.Panels.Images.SelectedLine {
|
||||
gui.State.Panels.Images.SelectedLine = len(gui.DockerCommand.Images) - 1
|
||||
if gui.State.Lists.Images.Len()-1 < gui.State.Panels.Images.SelectedLine {
|
||||
gui.State.Panels.Images.SelectedLine = gui.State.Lists.Images.Len() - 1
|
||||
}
|
||||
|
||||
gui.g.Update(func(g *gocui.Gui) error {
|
||||
ImagesView.Clear()
|
||||
gui.Views.Images.Clear()
|
||||
isFocused := gui.g.CurrentView() == gui.Views.Images
|
||||
list, err := utils.RenderList(gui.DockerCommand.Images, utils.IsFocused(isFocused))
|
||||
list, err := utils.RenderList(gui.State.Lists.Images.GetItems(), utils.IsFocused(isFocused))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(ImagesView, list)
|
||||
fmt.Fprint(gui.Views.Images, list)
|
||||
|
||||
if ImagesView == g.CurrentView() {
|
||||
return gui.handleImageSelect(g, ImagesView)
|
||||
if gui.Views.Images == g.CurrentView() {
|
||||
return gui.handleImageSelect(g, gui.Views.Images)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
|
@ -132,14 +162,14 @@ func (gui *Gui) refreshImages() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// TODO: leave this to DockerCommand
|
||||
func (gui *Gui) refreshStateImages() error {
|
||||
Images, err := gui.DockerCommand.RefreshImages(gui.filterString(gui.Views.Images))
|
||||
images, err := gui.DockerCommand.RefreshImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.DockerCommand.Images = Images
|
||||
// TODO: think about also re-filtering/sorting
|
||||
gui.State.Lists.Images.SetItems(images)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -158,7 +188,7 @@ func (gui *Gui) handleImagesNextLine(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
panelState := gui.State.Panels.Images
|
||||
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Images), false)
|
||||
gui.changeSelectedLine(&panelState.SelectedLine, gui.State.Lists.Images.Len(), false)
|
||||
|
||||
return gui.handleImageSelect(gui.g, v)
|
||||
}
|
||||
|
|
@ -169,7 +199,7 @@ func (gui *Gui) handleImagesPrevLine(g *gocui.Gui, v *gocui.View) error {
|
|||
}
|
||||
|
||||
panelState := gui.State.Panels.Images
|
||||
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Images), true)
|
||||
gui.changeSelectedLine(&panelState.SelectedLine, gui.State.Lists.Images.Len(), true)
|
||||
|
||||
return gui.handleImageSelect(gui.g, v)
|
||||
}
|
||||
|
|
@ -274,7 +304,7 @@ func (gui *Gui) handlePruneImages() error {
|
|||
if err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
return gui.refreshImages()
|
||||
return gui.reloadImages()
|
||||
})
|
||||
}, nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -516,6 +516,18 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollRightMain,
|
||||
},
|
||||
{
|
||||
ViewName: "search",
|
||||
Key: gocui.KeyEnter,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: wrappedHandler(gui.commitSearch),
|
||||
},
|
||||
{
|
||||
ViewName: "search",
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: wrappedHandler(gui.escapeSearchPrompt),
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
Key: 'J',
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ func (gui *Gui) focusPointInView(view *gocui.View) {
|
|||
|
||||
listViews := map[string]listViewState{
|
||||
"containers": {selectedLine: gui.State.Panels.Containers.SelectedLine, lineCount: len(gui.DockerCommand.DisplayContainers)},
|
||||
"images": {selectedLine: gui.State.Panels.Images.SelectedLine, lineCount: len(gui.DockerCommand.Images)},
|
||||
"images": {selectedLine: gui.State.Panels.Images.SelectedLine, lineCount: gui.State.Lists.Images.Len()},
|
||||
"volumes": {selectedLine: gui.State.Panels.Volumes.SelectedLine, lineCount: len(gui.DockerCommand.Volumes)},
|
||||
"services": {selectedLine: gui.State.Panels.Services.SelectedLine, lineCount: len(gui.DockerCommand.Services)},
|
||||
"menu": {selectedLine: gui.State.Panels.Menu.SelectedLine, lineCount: gui.State.MenuItemCount},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package gui
|
||||
|
||||
import "github.com/jesseduffield/gocui"
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
func (gui *Gui) handleOpenImageSearch() error {
|
||||
return gui.handleOpenSearch(gui.Views.Images)
|
||||
|
|
@ -10,23 +12,44 @@ func (gui *Gui) handleOpenSearch(view *gocui.View) error {
|
|||
gui.State.Searching.isSearching = true
|
||||
gui.State.Searching.view = view
|
||||
|
||||
gui.Views.Search.ClearTextArea()
|
||||
|
||||
return gui.switchFocus(gui.Views.Search)
|
||||
}
|
||||
|
||||
func (gui *Gui) onNewSearchString(value string) error {
|
||||
// need to refresh the right list panel.
|
||||
gui.State.Searching.searchString = value
|
||||
return gui.refreshImages()
|
||||
return gui.rerenderImages()
|
||||
}
|
||||
|
||||
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 {
|
||||
return func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := f(v, key, ch, mod)
|
||||
if matched {
|
||||
gui.onNewSearchString(v.TextArea.GetContent())
|
||||
// TODO: handle error
|
||||
_ = gui.onNewSearchString(v.TextArea.GetContent())
|
||||
}
|
||||
return matched
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) escapeSearchPrompt() error {
|
||||
if err := gui.clearSearch(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.returnFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) clearSearch() error {
|
||||
gui.State.Searching.searchString = ""
|
||||
gui.State.Searching.isSearching = false
|
||||
gui.State.Searching.view = nil
|
||||
gui.Views.Search.ClearTextArea()
|
||||
|
||||
return gui.rerenderImages()
|
||||
}
|
||||
|
||||
// returns to the list view with the filter still applied
|
||||
func (gui *Gui) commitSearch() error {
|
||||
return gui.returnFocus()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ func (gui *Gui) createAllViews() error {
|
|||
gui.Views.Search.FgColor = gocui.ColorGreen
|
||||
gui.Views.Search.Editable = true
|
||||
gui.Views.Search.Frame = false
|
||||
// gui.Views.Search.Editor = gocui.EditorFunc(gui.wrapEditor(gocui.SimpleEditor))
|
||||
gui.Views.Search.Editor = gocui.EditorFunc(gui.wrapEditor(gocui.SimpleEditor))
|
||||
|
||||
gui.waitForIntro.Done()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue