summaryrefslogtreecommitdiffstats
path: root/pkg/gui/controllers/list_controller_trait.go
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2024-01-14 13:51:20 +1100
committerJesse Duffield <jessedduffield@gmail.com>2024-01-19 10:50:49 +1100
commit51fb82d6bf26153f294477883a1b2abd592441f9 (patch)
tree1be91ee6e52592f6d1eec311e26b22725237a200 /pkg/gui/controllers/list_controller_trait.go
parent280b4d60f893a0e20897091ab02617c32180b45d (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.go95
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
+}