diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2024-01-14 13:51:20 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2024-01-19 10:50:49 +1100 |
commit | 51fb82d6bf26153f294477883a1b2abd592441f9 (patch) | |
tree | 1be91ee6e52592f6d1eec311e26b22725237a200 /pkg/gui/controllers/list_controller_trait.go | |
parent | 280b4d60f893a0e20897091ab02617c32180b45d (diff) |
Enforce single-item selection in various actions
We want to show an error when the user tries to invoke an action that expects only
a single item to be selected.
We're using the GetDisabledReason field to enforce this (as well as DisabledReason
on menu items).
I've created a ListControllerTrait to store some shared convenience functions for this.
Diffstat (limited to 'pkg/gui/controllers/list_controller_trait.go')
-rw-r--r-- | pkg/gui/controllers/list_controller_trait.go | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/pkg/gui/controllers/list_controller_trait.go b/pkg/gui/controllers/list_controller_trait.go new file mode 100644 index 000000000..fa60223b9 --- /dev/null +++ b/pkg/gui/controllers/list_controller_trait.go @@ -0,0 +1,95 @@ +package controllers + +import "github.com/jesseduffield/lazygit/pkg/gui/types" + +// Embed this into your list controller to get some convenience methods for +// ensuring a single item is selected, etc. + +type ListControllerTrait[T comparable] struct { + c *ControllerCommon + context types.IListContext + getSelected func() T +} + +func NewListControllerTrait[T comparable]( + c *ControllerCommon, + context types.IListContext, + getSelected func() T, +) *ListControllerTrait[T] { + return &ListControllerTrait[T]{ + c: c, + context: context, + getSelected: getSelected, + } +} + +// Convenience function for combining multiple disabledReason callbacks. +// The first callback to return a disabled reason will be the one returned. +func (self *ListControllerTrait[T]) require(callbacks ...func() *types.DisabledReason) func() *types.DisabledReason { + return func() *types.DisabledReason { + for _, callback := range callbacks { + if disabledReason := callback(); disabledReason != nil { + return disabledReason + } + } + + return nil + } +} + +// Convenience function for enforcing that a single item is selected. +// Also takes callbacks for additional disabled reasons, and passes the selected +// item into each one. +func (self *ListControllerTrait[T]) singleItemSelected(callbacks ...func(T) *types.DisabledReason) func() *types.DisabledReason { + return func() *types.DisabledReason { + if self.context.GetList().AreMultipleItemsSelected() { + return &types.DisabledReason{Text: self.c.Tr.RangeSelectNotSupported} + } + + var zeroValue T + item := self.getSelected() + if item == zeroValue { + return &types.DisabledReason{Text: self.c.Tr.NoItemSelected} + } + + for _, callback := range callbacks { + if reason := callback(item); reason != nil { + return reason + } + } + + return nil + } +} + +// Passes the selected item to the callback. Used for handler functions. +func (self *ListControllerTrait[T]) withItem(callback func(T) error) func() error { + return func() error { + var zeroValue T + commit := self.getSelected() + if commit == zeroValue { + return self.c.ErrorMsg(self.c.Tr.NoItemSelected) + } + + return callback(commit) + } +} + +// Like withItem, but doesn't show an error message if no item is selected. +// Use this for click actions (it's a no-op to click empty space) +func (self *ListControllerTrait[T]) withItemGraceful(callback func(T) error) func() error { + return func() error { + var zeroValue T + commit := self.getSelected() + if commit == zeroValue { + return nil + } + + return callback(commit) + } +} + +// All controllers must implement this method so we're defining it here for convenience +func (self *ListControllerTrait[T]) Context() types.Context { + return self.context +} |