Set groundwork for better disabled reasons with range select
Something dumb that we're currently doing is expecting list items to define an ID method which returns a string. We use that when copying items to clipboard with ctrl+o and when getting a ref name for diffing. This commit gets us a little deeper into that hole by explicitly requiring list items to implement that method so that we can easily use the new helper functions in list_controller_trait.go. In future we need to just remove the whole ID thing entirely but I'm too lazy to do that right now.
This commit is contained in:
@@ -59,15 +59,6 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *BranchesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *BranchesContext) GetSelectedRef() types.Ref {
|
||||
branch := self.GetSelected()
|
||||
if branch == nil {
|
||||
|
||||
@@ -72,15 +72,6 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (self *CommitFilesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *CommitFilesContext) GetDiffTerminals() []string {
|
||||
return []string{self.GetRef().RefName()}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package context
|
||||
|
||||
type FilteredListViewModel[T any] struct {
|
||||
type FilteredListViewModel[T HasID] struct {
|
||||
*FilteredList[T]
|
||||
*ListViewModel[T]
|
||||
*SearchHistory
|
||||
}
|
||||
|
||||
func NewFilteredListViewModel[T any](getList func() []T, getFilterFields func(T) []string) *FilteredListViewModel[T] {
|
||||
func NewFilteredListViewModel[T HasID](getList func() []T, getFilterFields func(T) []string) *FilteredListViewModel[T] {
|
||||
filteredList := NewFilteredList(getList, getFilterFields)
|
||||
|
||||
self := &FilteredListViewModel[T]{
|
||||
|
||||
@@ -9,10 +9,17 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// wrapping string in my own type to give it an ID method which is required for list items
|
||||
type mystring string
|
||||
|
||||
func (self mystring) ID() string {
|
||||
return string(self)
|
||||
}
|
||||
|
||||
func TestListRenderer_renderLines(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
modelStrings []string
|
||||
modelStrings []mystring
|
||||
nonModelIndices []int
|
||||
startIdx int
|
||||
endIdx int
|
||||
@@ -20,7 +27,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Render whole list",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
startIdx: 0,
|
||||
endIdx: 3,
|
||||
expectedOutput: `
|
||||
@@ -30,7 +37,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Partial list, beginning",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
startIdx: 0,
|
||||
endIdx: 2,
|
||||
expectedOutput: `
|
||||
@@ -39,7 +46,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Partial list, end",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
startIdx: 1,
|
||||
endIdx: 3,
|
||||
expectedOutput: `
|
||||
@@ -48,7 +55,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Pass an endIdx greater than the model length",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
startIdx: 2,
|
||||
endIdx: 5,
|
||||
expectedOutput: `
|
||||
@@ -56,7 +63,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Whole list with section headers",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
nonModelIndices: []int{1, 3},
|
||||
startIdx: 0,
|
||||
endIdx: 5,
|
||||
@@ -69,7 +76,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Multiple consecutive headers",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
nonModelIndices: []int{0, 0, 2, 2, 2},
|
||||
startIdx: 0,
|
||||
endIdx: 8,
|
||||
@@ -85,7 +92,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Partial list with headers, beginning",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
nonModelIndices: []int{1, 3},
|
||||
startIdx: 0,
|
||||
endIdx: 3,
|
||||
@@ -96,7 +103,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Partial list with headers, end (beyond end index)",
|
||||
modelStrings: []string{"a", "b", "c"},
|
||||
modelStrings: []mystring{"a", "b", "c"},
|
||||
nonModelIndices: []int{1, 3},
|
||||
startIdx: 2,
|
||||
endIdx: 7,
|
||||
@@ -108,7 +115,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
}
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
viewModel := NewListViewModel[string](func() []string { return s.modelStrings })
|
||||
viewModel := NewListViewModel[mystring](func() []mystring { return s.modelStrings })
|
||||
var getNonModelItems func() []*NonModelItem
|
||||
if s.nonModelIndices != nil {
|
||||
getNonModelItems = func() []*NonModelItem {
|
||||
@@ -124,7 +131,7 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
list: viewModel,
|
||||
getDisplayStrings: func(startIdx int, endIdx int) [][]string {
|
||||
return lo.Map(s.modelStrings[startIdx:endIdx],
|
||||
func(s string, _ int) []string { return []string{s} })
|
||||
func(s mystring, _ int) []string { return []string{string(s)} })
|
||||
},
|
||||
getNonModelItems: getNonModelItems,
|
||||
}
|
||||
@@ -138,6 +145,12 @@ func TestListRenderer_renderLines(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type myint int
|
||||
|
||||
func (self myint) ID() string {
|
||||
return fmt.Sprint(int(self))
|
||||
}
|
||||
|
||||
func TestListRenderer_ModelIndexToViewIndex_and_back(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
@@ -222,8 +235,8 @@ func TestListRenderer_ModelIndexToViewIndex_and_back(t *testing.T) {
|
||||
assert.Equal(t, len(s.modelIndices), len(s.expectedViewIndices))
|
||||
assert.Equal(t, len(s.viewIndices), len(s.expectedModelIndices))
|
||||
|
||||
modelInts := lo.Range(s.numModelItems)
|
||||
viewModel := NewListViewModel[int](func() []int { return modelInts })
|
||||
modelInts := lo.Map(lo.Range(s.numModelItems), func(i int, _ int) myint { return myint(i) })
|
||||
viewModel := NewListViewModel[myint](func() []myint { return modelInts })
|
||||
var getNonModelItems func() []*NonModelItem
|
||||
if s.nonModelIndices != nil {
|
||||
getNonModelItems = func() []*NonModelItem {
|
||||
@@ -236,7 +249,7 @@ func TestListRenderer_ModelIndexToViewIndex_and_back(t *testing.T) {
|
||||
list: viewModel,
|
||||
getDisplayStrings: func(startIdx int, endIdx int) [][]string {
|
||||
return lo.Map(modelInts[startIdx:endIdx],
|
||||
func(i int, _ int) []string { return []string{fmt.Sprint(i)} })
|
||||
func(i myint, _ int) []string { return []string{fmt.Sprint(i)} })
|
||||
},
|
||||
getNonModelItems: getNonModelItems,
|
||||
}
|
||||
|
||||
@@ -3,14 +3,19 @@ package context
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type ListViewModel[T any] struct {
|
||||
type HasID interface {
|
||||
ID() string
|
||||
}
|
||||
|
||||
type ListViewModel[T HasID] struct {
|
||||
*traits.ListCursor
|
||||
getModel func() []T
|
||||
}
|
||||
|
||||
func NewListViewModel[T any](getModel func() []T) *ListViewModel[T] {
|
||||
func NewListViewModel[T HasID](getModel func() []T) *ListViewModel[T] {
|
||||
self := &ListViewModel[T]{
|
||||
getModel: getModel,
|
||||
}
|
||||
@@ -32,6 +37,34 @@ func (self *ListViewModel[T]) GetSelected() T {
|
||||
return self.getModel()[self.GetSelectedLineIdx()]
|
||||
}
|
||||
|
||||
func (self *ListViewModel[T]) GetSelectedItemId() string {
|
||||
if self.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return self.GetSelected().ID()
|
||||
}
|
||||
|
||||
func (self *ListViewModel[T]) GetSelectedItems() ([]T, int, int) {
|
||||
if self.Len() == 0 {
|
||||
return nil, -1, -1
|
||||
}
|
||||
|
||||
startIdx, endIdx := self.GetSelectionRange()
|
||||
|
||||
return self.getModel()[startIdx : endIdx+1], startIdx, endIdx
|
||||
}
|
||||
|
||||
func (self *ListViewModel[T]) GetSelectedItemIds() ([]string, int, int) {
|
||||
selectedItems, startIdx, endIdx := self.GetSelectedItems()
|
||||
|
||||
ids := lo.Map(selectedItems, func(item T, _ int) string {
|
||||
return item.ID()
|
||||
})
|
||||
|
||||
return ids, startIdx, endIdx
|
||||
}
|
||||
|
||||
func (self *ListViewModel[T]) GetItems() []T {
|
||||
return self.getModel()
|
||||
}
|
||||
|
||||
@@ -92,15 +92,6 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (self *LocalCommitsContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
type LocalCommitsViewModel struct {
|
||||
*ListViewModel[*models.Commit]
|
||||
|
||||
|
||||
@@ -45,16 +45,6 @@ func NewMenuContext(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this thing.
|
||||
func (self *MenuContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.Label
|
||||
}
|
||||
|
||||
type MenuViewModel struct {
|
||||
c *ContextCommon
|
||||
menuItems []*types.MenuItem
|
||||
|
||||
@@ -59,15 +59,6 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ReflogCommitsContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *ReflogCommitsContext) CanRebase() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type RemoteBranchesContext struct {
|
||||
@@ -53,15 +54,6 @@ func NewRemoteBranchesContext(
|
||||
}
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesContext) GetSelectedRef() types.Ref {
|
||||
remoteBranch := self.GetSelected()
|
||||
if remoteBranch == nil {
|
||||
@@ -70,6 +62,16 @@ func (self *RemoteBranchesContext) GetSelectedRef() types.Ref {
|
||||
return remoteBranch
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesContext) GetSelectedRefs() ([]types.Ref, int, int) {
|
||||
items, startIdx, endIdx := self.GetSelectedItems()
|
||||
|
||||
refs := lo.Map(items, func(item *models.RemoteBranch, _ int) types.Ref {
|
||||
return item
|
||||
})
|
||||
|
||||
return refs, startIdx, endIdx
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesContext) GetDiffTerminals() []string {
|
||||
itemId := self.GetSelectedItemId()
|
||||
|
||||
|
||||
@@ -47,15 +47,6 @@ func NewRemotesContext(c *ContextCommon) *RemotesContext {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *RemotesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *RemotesContext) GetDiffTerminals() []string {
|
||||
itemId := self.GetSelectedItemId()
|
||||
|
||||
|
||||
@@ -49,15 +49,6 @@ func NewStashContext(
|
||||
}
|
||||
}
|
||||
|
||||
func (self *StashContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *StashContext) CanRebase() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -175,15 +175,6 @@ func (self *SubCommitsViewModel) GetShowBranchHeads() bool {
|
||||
return self.showBranchHeads
|
||||
}
|
||||
|
||||
func (self *SubCommitsContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *SubCommitsContext) CanRebase() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -43,12 +43,3 @@ func NewSubmodulesContext(c *ContextCommon) *SubmodulesContext {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SubmodulesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
@@ -63,15 +63,6 @@ func NewSuggestionsContext(
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SuggestionsContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.Value
|
||||
}
|
||||
|
||||
func (self *SuggestionsContext) SetSuggestions(suggestions []*types.Suggestion) {
|
||||
self.State.Suggestions = suggestions
|
||||
self.SetSelection(0)
|
||||
|
||||
@@ -52,15 +52,6 @@ func NewTagsContext(
|
||||
}
|
||||
}
|
||||
|
||||
func (self *TagsContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
func (self *TagsContext) GetSelectedRef() types.Ref {
|
||||
tag := self.GetSelected()
|
||||
if tag == nil {
|
||||
|
||||
@@ -58,12 +58,3 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext {
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (self *WorkingTreeContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
@@ -46,12 +46,3 @@ func NewWorktreesContext(c *ContextCommon) *WorktreesContext {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user