mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-21 23:01:03 +00:00
stop support menu filtering for simplicity
This commit is contained in:
parent
e6d4a97545
commit
f7beb6e83f
13 changed files with 326 additions and 231 deletions
|
|
@ -28,7 +28,7 @@ func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map
|
|||
sidePanelsDirection = boxlayout.ROW
|
||||
}
|
||||
|
||||
showInfoSection := gui.Config.UserConfig.Gui.ShowBottomLine || gui.State.Searching.isSearching
|
||||
showInfoSection := gui.Config.UserConfig.Gui.ShowBottomLine || gui.State.Filter.active
|
||||
infoSectionSize := 0
|
||||
if showInfoSection {
|
||||
infoSectionSize = 1
|
||||
|
|
@ -87,14 +87,14 @@ func (gui *Gui) getMidSectionWeights() (int, int) {
|
|||
}
|
||||
|
||||
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
||||
if gui.State.Searching.isSearching {
|
||||
if gui.State.Filter.active {
|
||||
return []*boxlayout.Box{
|
||||
{
|
||||
Window: "searchPrefix",
|
||||
Size: runewidth.StringWidth(SEARCH_PREFIX),
|
||||
Window: "filterPrefix",
|
||||
Size: runewidth.StringWidth(gui.filterPrompt()),
|
||||
},
|
||||
{
|
||||
Window: "search",
|
||||
Window: "filter",
|
||||
Weight: 1,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
80
pkg/gui/filtering.go
Normal file
80
pkg/gui/filtering.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
func (gui *Gui) handleOpenFilter() error {
|
||||
panel, ok := gui.currentListPanel()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if panel.IsFilterDisabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
gui.State.Filter.active = true
|
||||
gui.State.Filter.panel = panel
|
||||
|
||||
return gui.switchFocus(gui.Views.Filter)
|
||||
}
|
||||
|
||||
func (gui *Gui) onNewFilterNeedle(value string) error {
|
||||
gui.State.Filter.needle = value
|
||||
gui.ResetOrigin(gui.State.Filter.panel.View())
|
||||
return gui.State.Filter.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 {
|
||||
return func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := f(v, key, ch, mod)
|
||||
if matched {
|
||||
if err := gui.onNewFilterNeedle(v.TextArea.GetContent()); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
}
|
||||
return matched
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) escapeFilterPrompt() error {
|
||||
if err := gui.clearFilter(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.returnFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) clearFilter() error {
|
||||
gui.State.Filter.needle = ""
|
||||
gui.State.Filter.active = false
|
||||
panel := gui.State.Filter.panel
|
||||
gui.State.Filter.panel = nil
|
||||
gui.Views.Filter.ClearTextArea()
|
||||
|
||||
if panel == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gui.ResetOrigin(panel.View())
|
||||
|
||||
return panel.RerenderList()
|
||||
}
|
||||
|
||||
// returns to the list view with the filter still applied
|
||||
func (gui *Gui) commitFilter() error {
|
||||
if gui.State.Filter.needle == "" {
|
||||
if err := gui.clearFilter(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return gui.returnFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) filterPrompt() string {
|
||||
return fmt.Sprintf("%s: ", gui.Tr.FilterPrompt)
|
||||
}
|
||||
146
pkg/gui/focus.go
Normal file
146
pkg/gui/focus.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func (gui *Gui) newLineFocused(v *gocui.View) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentListPanel, ok := gui.currentListPanel()
|
||||
if ok {
|
||||
return currentListPanel.HandleSelect()
|
||||
}
|
||||
|
||||
switch v.Name() {
|
||||
case "confirmation":
|
||||
return nil
|
||||
case "main":
|
||||
v.Highlight = false
|
||||
return nil
|
||||
case "filter":
|
||||
return nil
|
||||
default:
|
||||
panic(gui.Tr.NoViewMachingNewLineFocusedSwitchStatement)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move some of this logic into our onFocusLost and onFocus hooks
|
||||
func (gui *Gui) switchFocus(newView *gocui.View) error {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
return gui.switchFocusAux(newView)
|
||||
}
|
||||
|
||||
func (gui *Gui) switchFocusAux(newView *gocui.View) error {
|
||||
gui.pushView(newView.Name())
|
||||
gui.Log.Info("setting highlight to true for view " + newView.Name())
|
||||
gui.Log.Info("new focused view is " + newView.Name())
|
||||
if _, err := gui.g.SetCurrentView(newView.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.g.Cursor = newView.Editable
|
||||
|
||||
if err := gui.renderPanelOptions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newViewStack := gui.State.ViewStack
|
||||
|
||||
if gui.State.Filter.panel != nil && !lo.Contains(newViewStack, gui.State.Filter.panel.View().Name()) {
|
||||
if err := gui.clearFilter(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add 'onFocusLost' hook
|
||||
if !lo.Contains(newViewStack, "menu") {
|
||||
gui.Views.Menu.Visible = false
|
||||
}
|
||||
|
||||
return gui.newLineFocused(newView)
|
||||
}
|
||||
|
||||
func (gui *Gui) returnFocus() error {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
if len(gui.State.ViewStack) <= 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
previousViewName := gui.State.ViewStack[len(gui.State.ViewStack)-2]
|
||||
previousView, err := gui.g.View(previousViewName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.switchFocusAux(previousView)
|
||||
}
|
||||
|
||||
func (gui *Gui) removeViewFromStack(view *gocui.View) {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool {
|
||||
return viewName != view.Name()
|
||||
})
|
||||
}
|
||||
|
||||
// Not to be called directly. Use `switchFocus` instead
|
||||
func (gui *Gui) pushView(name string) {
|
||||
// No matter what view we're pushing, we first remove all popup panels from the stack
|
||||
// (unless it's the search view because we may be searching the menu panel)
|
||||
if name != "filter" {
|
||||
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 lo.Contains(gui.sideViewNames(), name) {
|
||||
gui.State.ViewStack = []string{}
|
||||
}
|
||||
|
||||
// If we're pushing a panel that's already in the stack, we remove it
|
||||
gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool {
|
||||
return viewName != name
|
||||
})
|
||||
|
||||
gui.State.ViewStack = append(gui.State.ViewStack, name)
|
||||
}
|
||||
|
||||
// excludes popups
|
||||
func (gui *Gui) currentStaticViewName() string {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
for i := len(gui.State.ViewStack) - 1; i >= 0; i-- {
|
||||
if !lo.Contains(gui.popupViewNames(), gui.State.ViewStack[i]) {
|
||||
return gui.State.ViewStack[i]
|
||||
}
|
||||
}
|
||||
|
||||
return gui.initiallyFocusedViewName()
|
||||
}
|
||||
|
||||
func (gui *Gui) currentSideViewName() string {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
// we expect that there is a side window somewhere in the view stack, so we will search from top to bottom
|
||||
for idx := range gui.State.ViewStack {
|
||||
reversedIdx := len(gui.State.ViewStack) - 1 - idx
|
||||
viewName := gui.State.ViewStack[reversedIdx]
|
||||
if lo.Contains(gui.sideViewNames(), viewName) {
|
||||
return viewName
|
||||
}
|
||||
}
|
||||
|
||||
return gui.initiallyFocusedViewName()
|
||||
}
|
||||
|
|
@ -83,13 +83,19 @@ type guiState struct {
|
|||
|
||||
ScreenMode WindowMaximisation
|
||||
|
||||
Searching searchingState
|
||||
// Maintains the state of manual filtering i.e. typing in a substring
|
||||
// to filter on in the current panel.
|
||||
Filter filterState
|
||||
}
|
||||
|
||||
type searchingState struct {
|
||||
panel ISideListPanel
|
||||
isSearching bool
|
||||
searchString string
|
||||
type filterState struct {
|
||||
// If true then we're either currently inside the filter view
|
||||
// or we've committed the filter and we're back in the list view
|
||||
active bool
|
||||
// The panel that we're filtering.
|
||||
panel ISideListPanel
|
||||
// The string that we're filtering on
|
||||
needle string
|
||||
}
|
||||
|
||||
// screen sizing determines how much space your selected window takes up (window
|
||||
|
|
@ -368,6 +374,16 @@ func (gui *Gui) quit(g *gocui.Gui, v *gocui.View) error {
|
|||
return gocui.ErrQuit
|
||||
}
|
||||
|
||||
// this handler is executed when we press escape when there is only one view
|
||||
// on the stack.
|
||||
func (gui *Gui) escape() error {
|
||||
if gui.State.Filter.active {
|
||||
return gui.clearFilter()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleDonate(g *gocui.Gui, v *gocui.View) error {
|
||||
if !gui.g.Mouse {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -110,11 +110,11 @@ func (gui *Gui) refreshStateImages() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) filterString(view *gocui.View) string {
|
||||
if gui.State.Searching.panel != nil && gui.State.Searching.panel.View() != view {
|
||||
if gui.State.Filter.panel != nil && gui.State.Filter.panel.View() != view {
|
||||
return ""
|
||||
}
|
||||
|
||||
return gui.State.Searching.searchString
|
||||
return gui.State.Filter.needle
|
||||
}
|
||||
|
||||
// TODO: merge into the above
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ func (b *Binding) GetKey() string {
|
|||
// GetInitialKeybindings is a function.
|
||||
func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||
bindings := []*Binding{
|
||||
{
|
||||
ViewName: "",
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: wrappedHandler(gui.escape),
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
Key: 'q',
|
||||
|
|
@ -68,12 +74,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Modifier: gocui.ModNone,
|
||||
Handler: gui.quit,
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.quit,
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
Key: gocui.KeyPgup,
|
||||
|
|
@ -173,13 +173,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
ViewName: "menu",
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleMenuClose,
|
||||
Handler: wrappedHandler(gui.handleMenuClose),
|
||||
},
|
||||
{
|
||||
ViewName: "menu",
|
||||
Key: 'q',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleMenuClose,
|
||||
Handler: wrappedHandler(gui.handleMenuClose),
|
||||
},
|
||||
{
|
||||
ViewName: "menu",
|
||||
|
|
@ -517,16 +517,16 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Handler: gui.scrollRightMain,
|
||||
},
|
||||
{
|
||||
ViewName: "search",
|
||||
ViewName: "filter",
|
||||
Key: gocui.KeyEnter,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: wrappedHandler(gui.commitSearch),
|
||||
Handler: wrappedHandler(gui.commitFilter),
|
||||
},
|
||||
{
|
||||
ViewName: "search",
|
||||
ViewName: "filter",
|
||||
Key: gocui.KeyEsc,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: wrappedHandler(gui.escapeSearchPrompt),
|
||||
Handler: wrappedHandler(gui.escapeFilterPrompt),
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
|
|
@ -619,7 +619,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
ViewName: panel.View().Name(),
|
||||
Key: '/',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: wrappedHandler(gui.handleOpenSearch),
|
||||
Handler: wrappedHandler(gui.handleOpenFilter),
|
||||
Description: gui.Tr.LcFilter,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ type SideListPanel[T comparable] struct {
|
|||
|
||||
// function to be called after re-rendering list. Can be nil
|
||||
onRerender func() error
|
||||
|
||||
// set this to true if you don't want to allow manual filtering via '/'
|
||||
disableFilter bool
|
||||
}
|
||||
|
||||
type ISideListPanel interface {
|
||||
|
|
@ -81,6 +84,7 @@ type ISideListPanel interface {
|
|||
View() *gocui.View
|
||||
Refocus()
|
||||
RerenderList() error
|
||||
IsFilterDisabled() bool
|
||||
}
|
||||
|
||||
var _ ISideListPanel = &SideListPanel[int]{}
|
||||
|
|
@ -294,3 +298,7 @@ func (self *SideListPanel[T]) RerenderList() error {
|
|||
func (self *SideListPanel[T]) SetContextIndex(index int) {
|
||||
self.contextIdx = index
|
||||
}
|
||||
|
||||
func (self *SideListPanel[T]) IsFilterDisabled() bool {
|
||||
return self.disableFilter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
)
|
||||
|
||||
|
|
@ -39,6 +38,11 @@ func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] {
|
|||
onRerender: func() error {
|
||||
return gui.resizePopupPanel(gui.Views.Menu)
|
||||
},
|
||||
// so that we can avoid some UI trickiness, the menu will not have filtering
|
||||
// abillity yet. To support it, we would need to have filter state against
|
||||
// each panel (e.g. for when you filter the images panel, then bring up
|
||||
// the options menu, then try to filter that too.
|
||||
disableFilter: true,
|
||||
|
||||
// the menu panel doesn't actually have any contexts to display on the main view
|
||||
// so what follows are all dummy values
|
||||
|
|
@ -54,17 +58,15 @@ func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] {
|
|||
}
|
||||
|
||||
func (gui *Gui) onMenuPress(menuItem *MenuItem) error {
|
||||
gui.Views.Menu.Visible = false
|
||||
err := gui.returnFocus()
|
||||
if err != nil {
|
||||
if err := gui.handleMenuClose(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if menuItem.OnPress == nil {
|
||||
return nil
|
||||
if menuItem.OnPress != nil {
|
||||
return menuItem.OnPress()
|
||||
}
|
||||
|
||||
return menuItem.OnPress()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleMenuPress() error {
|
||||
|
|
@ -133,7 +135,21 @@ func (gui *Gui) renderMenuOptions() error {
|
|||
return gui.renderOptionsMap(optionsMap)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleMenuClose(g *gocui.Gui, v *gocui.View) error {
|
||||
func (gui *Gui) handleMenuClose() error {
|
||||
gui.Views.Menu.Visible = false
|
||||
|
||||
// this code is here for when we do add filter ability to the menu panel,
|
||||
// though it's currently disabled
|
||||
if gui.State.Filter.panel == gui.Panels.Menu {
|
||||
if err := gui.clearFilter(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we need to remove the view from the view stack because we're about to
|
||||
// return focus and don't want to land in the search view when it was searching
|
||||
// the menu in the first place
|
||||
gui.removeViewFromStack(gui.Views.Filter)
|
||||
}
|
||||
|
||||
return gui.returnFocus()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] {
|
|||
getDisplayStrings: func(project *commands.Project) []string {
|
||||
return []string{project.Name}
|
||||
},
|
||||
// It doesn't make sense to filter a list of only one item.
|
||||
disableFilter: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
func (gui *Gui) handleOpenSearch() error {
|
||||
panel, ok := gui.currentListPanel()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
gui.State.Searching.isSearching = true
|
||||
gui.State.Searching.panel = panel
|
||||
|
||||
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
|
||||
gui.ResetOrigin(gui.State.Searching.panel.View())
|
||||
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 {
|
||||
return func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := f(v, key, ch, mod)
|
||||
if matched {
|
||||
// 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
|
||||
panel := gui.State.Searching.panel
|
||||
gui.State.Searching.panel = nil
|
||||
gui.Views.Search.ClearTextArea()
|
||||
|
||||
gui.ResetOrigin(panel.View())
|
||||
|
||||
return panel.RerenderList()
|
||||
}
|
||||
|
||||
// returns to the list view with the filter still applied
|
||||
func (gui *Gui) commitSearch() error {
|
||||
return gui.returnFocus()
|
||||
}
|
||||
|
|
@ -66,123 +66,6 @@ func (gui *Gui) resetMainView() {
|
|||
gui.getMainView().Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
|
||||
}
|
||||
|
||||
func (gui *Gui) newLineFocused(v *gocui.View) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentListPanel, ok := gui.currentListPanel()
|
||||
if ok {
|
||||
return currentListPanel.HandleSelect()
|
||||
}
|
||||
|
||||
switch v.Name() {
|
||||
case "confirmation":
|
||||
return nil
|
||||
case "main":
|
||||
v.Highlight = false
|
||||
return nil
|
||||
case "search":
|
||||
return nil
|
||||
default:
|
||||
panic(gui.Tr.NoViewMachingNewLineFocusedSwitchStatement)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move some of this logic into our onFocusLost and onFocus hooks
|
||||
func (gui *Gui) switchFocus(newView *gocui.View) error {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
return gui.switchFocusAux(newView)
|
||||
}
|
||||
|
||||
func (gui *Gui) switchFocusAux(newView *gocui.View) error {
|
||||
gui.pushView(newView.Name())
|
||||
gui.Log.Info("setting highlight to true for view " + newView.Name())
|
||||
gui.Log.Info("new focused view is " + newView.Name())
|
||||
if _, err := gui.g.SetCurrentView(newView.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.g.Cursor = newView.Editable
|
||||
|
||||
if err := gui.renderPanelOptions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.newLineFocused(newView)
|
||||
}
|
||||
|
||||
func (gui *Gui) returnFocus() error {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
if len(gui.State.ViewStack) <= 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
previousViewName := gui.State.ViewStack[len(gui.State.ViewStack)-2]
|
||||
previousView, err := gui.g.View(previousViewName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return gui.switchFocusAux(previousView)
|
||||
}
|
||||
|
||||
// Not to be called directly. Use `switchFocus` instead
|
||||
func (gui *Gui) pushView(name string) {
|
||||
// No matter what view we're pushing, we first remove all popup panels from the stack
|
||||
// (unless it's the search view because we may be searching the menu panel)
|
||||
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 lo.Contains(gui.sideViewNames(), name) {
|
||||
gui.State.ViewStack = []string{}
|
||||
}
|
||||
|
||||
// If we're pushing a panel that's already in the stack, we remove it
|
||||
gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool {
|
||||
return viewName != name
|
||||
})
|
||||
|
||||
gui.State.ViewStack = append(gui.State.ViewStack, name)
|
||||
}
|
||||
|
||||
// excludes popups
|
||||
func (gui *Gui) currentStaticViewName() string {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
for i := len(gui.State.ViewStack) - 1; i >= 0; i-- {
|
||||
if !lo.Contains(gui.popupViewNames(), gui.State.ViewStack[i]) {
|
||||
return gui.State.ViewStack[i]
|
||||
}
|
||||
}
|
||||
|
||||
return gui.initiallyFocusedViewName()
|
||||
}
|
||||
|
||||
func (gui *Gui) currentSideViewName() string {
|
||||
gui.Mutexes.ViewStackMutex.Lock()
|
||||
defer gui.Mutexes.ViewStackMutex.Unlock()
|
||||
|
||||
// we expect that there is a side window somewhere in the view stack, so we will search from top to bottom
|
||||
for idx := range gui.State.ViewStack {
|
||||
reversedIdx := len(gui.State.ViewStack) - 1 - idx
|
||||
viewName := gui.State.ViewStack[reversedIdx]
|
||||
if lo.Contains(gui.sideViewNames(), viewName) {
|
||||
return viewName
|
||||
}
|
||||
}
|
||||
|
||||
return gui.initiallyFocusedViewName()
|
||||
}
|
||||
|
||||
// if the cursor down past the last item, move it to the last line
|
||||
// nolint:unparam
|
||||
func (gui *Gui) focusPoint(selectedX int, selectedY int, lineCount int, v *gocui.View) {
|
||||
|
|
@ -396,10 +279,6 @@ func (gui *Gui) handleClick(v *gocui.View, itemCount int, selectedLine *int, han
|
|||
return nil
|
||||
}
|
||||
|
||||
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, cy := v.Cursor()
|
||||
_, oy := v.Origin()
|
||||
|
||||
|
|
@ -415,6 +294,12 @@ func (gui *Gui) handleClick(v *gocui.View, itemCount int, selectedLine *int, han
|
|||
|
||||
*selectedLine = newSelectedLine
|
||||
|
||||
if gui.currentViewName() != v.Name() {
|
||||
if err := gui.switchFocus(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return handleSelect(gui.g, v)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import (
|
|||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
const SEARCH_PREFIX = "filter: "
|
||||
|
||||
type Views struct {
|
||||
// side panels
|
||||
Project *gocui.View
|
||||
|
|
@ -23,9 +21,9 @@ type Views struct {
|
|||
Information *gocui.View
|
||||
AppStatus *gocui.View
|
||||
// text that prompts you to enter text in the Search view
|
||||
SearchPrefix *gocui.View
|
||||
FilterPrefix *gocui.View
|
||||
// appears next to the SearchPrefix view, it's where you type in the search string
|
||||
Search *gocui.View
|
||||
Filter *gocui.View
|
||||
|
||||
// popups
|
||||
Confirmation *gocui.View
|
||||
|
|
@ -56,8 +54,8 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
|||
{viewPtr: &gui.Views.Options, name: "options"},
|
||||
{viewPtr: &gui.Views.AppStatus, name: "appStatus"},
|
||||
{viewPtr: &gui.Views.Information, name: "information"},
|
||||
{viewPtr: &gui.Views.Search, name: "search"},
|
||||
{viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"},
|
||||
{viewPtr: &gui.Views.Filter, name: "filter"},
|
||||
{viewPtr: &gui.Views.FilterPrefix, name: "filterPrefix"},
|
||||
|
||||
// popups.
|
||||
{viewPtr: &gui.Views.Menu, name: "menu"},
|
||||
|
|
@ -128,16 +126,16 @@ func (gui *Gui) createAllViews() error {
|
|||
gui.Views.Limit.Title = gui.Tr.NotEnoughSpace
|
||||
gui.Views.Limit.Wrap = true
|
||||
|
||||
gui.Views.SearchPrefix.BgColor = gocui.ColorDefault
|
||||
gui.Views.SearchPrefix.FgColor = gocui.ColorGreen
|
||||
gui.Views.SearchPrefix.Frame = false
|
||||
_ = gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX)
|
||||
gui.Views.FilterPrefix.BgColor = gocui.ColorDefault
|
||||
gui.Views.FilterPrefix.FgColor = gocui.ColorGreen
|
||||
gui.Views.FilterPrefix.Frame = false
|
||||
_ = gui.setViewContent(gui.Views.FilterPrefix, gui.filterPrompt())
|
||||
|
||||
gui.Views.Search.BgColor = gocui.ColorDefault
|
||||
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.Filter.BgColor = gocui.ColorDefault
|
||||
gui.Views.Filter.FgColor = gocui.ColorGreen
|
||||
gui.Views.Filter.Editable = true
|
||||
gui.Views.Filter.Frame = false
|
||||
gui.Views.Filter.Editor = gocui.EditorFunc(gui.wrapEditor(gocui.SimpleEditor))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -169,7 +167,7 @@ func (gui *Gui) controlledBoundsViewNames() []string {
|
|||
"appStatus",
|
||||
"main",
|
||||
"limit",
|
||||
"searchPrefix",
|
||||
"search",
|
||||
"filterPrefix",
|
||||
"filter",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ type TranslationSet struct {
|
|||
|
||||
LcNextScreenMode string
|
||||
LcPrevScreenMode string
|
||||
FilterPrompt string
|
||||
PressEscToCancel string
|
||||
}
|
||||
|
||||
func englishSet() TranslationSet {
|
||||
|
|
@ -243,5 +245,7 @@ func englishSet() TranslationSet {
|
|||
|
||||
LcNextScreenMode: "next screen mode (normal/half/fullscreen)",
|
||||
LcPrevScreenMode: "prev screen mode",
|
||||
FilterPrompt: "filter",
|
||||
PressEscToCancel: "press escape to cancel",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue