1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
package controllers
import (
"errors"
"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
getSelectedItem func() T
getSelectedItems func() ([]T, int, int)
}
func NewListControllerTrait[T comparable](
c *ControllerCommon,
context types.IListContext,
getSelected func() T,
getSelectedItems func() ([]T, int, int),
) *ListControllerTrait[T] {
return &ListControllerTrait[T]{
c: c,
context: context,
getSelectedItem: getSelected,
getSelectedItems: getSelectedItems,
}
}
// 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.getSelectedItem()
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
}
}
// Ensures that at least one item is selected.
func (self *ListControllerTrait[T]) itemRangeSelected(callbacks ...func([]T, int, int) *types.DisabledReason) func() *types.DisabledReason {
return func() *types.DisabledReason {
items, startIdx, endIdx := self.getSelectedItems()
if len(items) == 0 {
return &types.DisabledReason{Text: self.c.Tr.NoItemSelected}
}
for _, callback := range callbacks {
if reason := callback(items, startIdx, endIdx); reason != nil {
return reason
}
}
return nil
}
}
func (self *ListControllerTrait[T]) itemsSelected(callbacks ...func([]T) *types.DisabledReason) func() *types.DisabledReason { //nolint:unused
return func() *types.DisabledReason {
items, _, _ := self.getSelectedItems()
if len(items) == 0 {
return &types.DisabledReason{Text: self.c.Tr.NoItemSelected}
}
for _, callback := range callbacks {
if reason := callback(items); 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.getSelectedItem()
if commit == zeroValue {
return errors.New(self.c.Tr.NoItemSelected)
}
return callback(commit)
}
}
func (self *ListControllerTrait[T]) withItems(callback func([]T) error) func() error {
return func() error {
items, _, _ := self.getSelectedItems()
if len(items) == 0 {
return errors.New(self.c.Tr.NoItemSelected)
}
return callback(items)
}
}
// like withItems but also passes the start and end index of the selection
func (self *ListControllerTrait[T]) withItemsRange(callback func([]T, int, int) error) func() error {
return func() error {
items, startIdx, endIdx := self.getSelectedItems()
if len(items) == 0 {
return errors.New(self.c.Tr.NoItemSelected)
}
return callback(items, startIdx, endIdx)
}
}
// 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.getSelectedItem()
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
}
|