mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-30 03:23:08 +03:00
Add a mechanism to insert non-model items into list contexts
Not used by anything yet.
This commit is contained in:
@ -5,26 +5,120 @@ import (
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type NonModelItem struct {
|
||||
// Where in the model this should be inserted
|
||||
Index int
|
||||
// Content to render
|
||||
Content string
|
||||
// The column from which to render the item
|
||||
Column int
|
||||
}
|
||||
|
||||
type ListRenderer struct {
|
||||
list types.IList
|
||||
list types.IList
|
||||
// Function to get the display strings for each model item in the given
|
||||
// range. startIdx and endIdx are model indices. For each model item, return
|
||||
// an array of strings, one for each column; the list renderer will take
|
||||
// care of aligning the columns appropriately.
|
||||
getDisplayStrings func(startIdx int, endIdx int) [][]string
|
||||
// Alignment for each column. If nil, the default is left alignment
|
||||
getColumnAlignments func() []utils.Alignment
|
||||
// Function to insert non-model items (e.g. section headers). If nil, no
|
||||
// such items are inserted
|
||||
getNonModelItems func() []*NonModelItem
|
||||
|
||||
// The remaining fields are private and shouldn't be initialized by clients
|
||||
numNonModelItems int
|
||||
viewIndicesByModelIndex []int
|
||||
modelIndicesByViewIndex []int
|
||||
}
|
||||
|
||||
func (self *ListRenderer) GetList() types.IList {
|
||||
return self.list
|
||||
}
|
||||
|
||||
func (self *ListRenderer) ModelIndexToViewIndex(modelIndex int) int {
|
||||
modelIndex = lo.Clamp(modelIndex, 0, self.list.Len())
|
||||
if self.viewIndicesByModelIndex != nil {
|
||||
return self.viewIndicesByModelIndex[modelIndex]
|
||||
}
|
||||
|
||||
return modelIndex
|
||||
}
|
||||
|
||||
func (self *ListRenderer) ViewIndexToModelIndex(viewIndex int) int {
|
||||
viewIndex = utils.Clamp(viewIndex, 0, self.list.Len()+self.numNonModelItems)
|
||||
if self.modelIndicesByViewIndex != nil {
|
||||
return self.modelIndicesByViewIndex[viewIndex]
|
||||
}
|
||||
|
||||
return viewIndex
|
||||
}
|
||||
|
||||
// startIdx and endIdx are view indices, not model indices. If you want to
|
||||
// render the whole list, pass -1 for both.
|
||||
func (self *ListRenderer) renderLines(startIdx int, endIdx int) string {
|
||||
var columnAlignments []utils.Alignment
|
||||
if self.getColumnAlignments != nil {
|
||||
columnAlignments = self.getColumnAlignments()
|
||||
}
|
||||
lines, _ := utils.RenderDisplayStrings(
|
||||
self.getDisplayStrings(startIdx, utils.Min(endIdx, self.list.Len())),
|
||||
nonModelItems := []*NonModelItem{}
|
||||
self.numNonModelItems = 0
|
||||
if self.getNonModelItems != nil {
|
||||
nonModelItems = self.getNonModelItems()
|
||||
self.prepareConversionArrays(nonModelItems)
|
||||
}
|
||||
startModelIdx := 0
|
||||
if startIdx == -1 {
|
||||
startIdx = 0
|
||||
} else {
|
||||
startModelIdx = self.ViewIndexToModelIndex(startIdx)
|
||||
}
|
||||
endModelIdx := self.list.Len()
|
||||
if endIdx == -1 {
|
||||
endIdx = endModelIdx + len(nonModelItems)
|
||||
} else {
|
||||
endModelIdx = self.ViewIndexToModelIndex(endIdx)
|
||||
}
|
||||
lines, columnPositions := utils.RenderDisplayStrings(
|
||||
self.getDisplayStrings(startModelIdx, endModelIdx),
|
||||
columnAlignments)
|
||||
lines = self.insertNonModelItems(nonModelItems, endIdx, startIdx, lines, columnPositions)
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func (self *ListRenderer) prepareConversionArrays(nonModelItems []*NonModelItem) {
|
||||
self.numNonModelItems = len(nonModelItems)
|
||||
self.viewIndicesByModelIndex = lo.Range(self.list.Len() + 1)
|
||||
self.modelIndicesByViewIndex = lo.Range(self.list.Len() + 1)
|
||||
offset := 0
|
||||
for _, item := range nonModelItems {
|
||||
for i := item.Index; i <= self.list.Len(); i++ {
|
||||
self.viewIndicesByModelIndex[i]++
|
||||
}
|
||||
self.modelIndicesByViewIndex = slices.Insert(
|
||||
self.modelIndicesByViewIndex, item.Index+offset, self.modelIndicesByViewIndex[item.Index+offset])
|
||||
offset++
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ListRenderer) insertNonModelItems(
|
||||
nonModelItems []*NonModelItem, endIdx int, startIdx int, lines []string, columnPositions []int,
|
||||
) []string {
|
||||
offset := 0
|
||||
for _, item := range nonModelItems {
|
||||
if item.Index+offset >= endIdx {
|
||||
break
|
||||
}
|
||||
if item.Index+offset >= startIdx {
|
||||
padding := strings.Repeat(" ", columnPositions[item.Column])
|
||||
lines = slices.Insert(lines, item.Index+offset-startIdx, padding+item.Content)
|
||||
}
|
||||
offset++
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
Reference in New Issue
Block a user