mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 15:46:26 -04:00
The only menu that ever asked for it was the keybindings menu, which now filters as you type and doesn't use the prompt at all. That leaves every filterable context with the same prompt, so the whole hook can go, and with it the two implementations that only existed to satisfy it. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
268 lines
7.1 KiB
Go
268 lines
7.1 KiB
Go
package filetree
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
|
"github.com/jesseduffield/lazygit/pkg/common"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
type ICommitFileTreeViewModel interface {
|
|
ICommitFileTree
|
|
types.IListCursor
|
|
|
|
GetRef() models.Ref
|
|
SetRef(models.Ref)
|
|
GetRefRange() *types.RefRange // can be nil, in which case GetRef should be used
|
|
SetRefRange(*types.RefRange) // should be set to nil when selection is not a range
|
|
GetCanRebase() bool
|
|
SetCanRebase(bool)
|
|
}
|
|
|
|
type CommitFileTreeViewModel struct {
|
|
types.IListCursor
|
|
ICommitFileTree
|
|
|
|
// this is e.g. the commit for which we're viewing the files, if there is no
|
|
// range selection, or if the range selection can't be used for some reason
|
|
ref models.Ref
|
|
|
|
// this is a commit range for which we're viewing the files. Can be nil, in
|
|
// which case ref is used.
|
|
refRange *types.RefRange
|
|
|
|
// we set this to true when you're viewing the files within the checked-out branch's commits.
|
|
// If you're viewing the files of some random other branch we can't do any rebase stuff.
|
|
canRebase bool
|
|
|
|
searchHistory *utils.HistoryBuffer[string]
|
|
}
|
|
|
|
var _ ICommitFileTreeViewModel = &CommitFileTreeViewModel{}
|
|
|
|
func NewCommitFileTreeViewModel(getFiles func() []*models.CommitFile, common *common.Common, showTree bool) *CommitFileTreeViewModel {
|
|
fileTree := NewCommitFileTree(getFiles, common, showTree)
|
|
listCursor := traits.NewListCursor(fileTree.Len)
|
|
return &CommitFileTreeViewModel{
|
|
ICommitFileTree: fileTree,
|
|
IListCursor: listCursor,
|
|
ref: nil,
|
|
refRange: nil,
|
|
canRebase: false,
|
|
searchHistory: utils.NewHistoryBuffer[string](1000),
|
|
}
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetRef() models.Ref {
|
|
return self.ref
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) SetRef(ref models.Ref) {
|
|
self.ref = ref
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetRefRange() *types.RefRange {
|
|
return self.refRange
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) SetRefRange(refsForRange *types.RefRange) {
|
|
self.refRange = refsForRange
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetCanRebase() bool {
|
|
return self.canRebase
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) SetCanRebase(canRebase bool) {
|
|
self.canRebase = canRebase
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSelected() *CommitFileNode {
|
|
if self.Len() == 0 {
|
|
return nil
|
|
}
|
|
|
|
return self.Get(self.GetSelectedLineIdx())
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSelectedItemId() string {
|
|
item := self.GetSelected()
|
|
if item == nil {
|
|
return ""
|
|
}
|
|
|
|
return item.ID()
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSelectedItems() ([]*CommitFileNode, int, int) {
|
|
if self.Len() == 0 {
|
|
return nil, 0, 0
|
|
}
|
|
|
|
startIdx, endIdx := self.GetSelectionRange()
|
|
|
|
nodes := []*CommitFileNode{}
|
|
for i := startIdx; i <= endIdx; i++ {
|
|
nodes = append(nodes, self.Get(i))
|
|
}
|
|
|
|
return nodes, startIdx, endIdx
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSelectedItemIds() ([]string, int, int) {
|
|
selectedItems, startIdx, endIdx := self.GetSelectedItems()
|
|
|
|
ids := lo.Map(selectedItems, func(item *CommitFileNode, _ int) string {
|
|
return item.ID()
|
|
})
|
|
|
|
return ids, startIdx, endIdx
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSelectedFile() *models.CommitFile {
|
|
node := self.GetSelected()
|
|
if node == nil {
|
|
return nil
|
|
}
|
|
|
|
return node.File
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSelectedPath() string {
|
|
node := self.GetSelected()
|
|
if node == nil {
|
|
return ""
|
|
}
|
|
|
|
return node.GetPath()
|
|
}
|
|
|
|
// SetTree rebuilds the tree and clamps the selection so it stays in range. The
|
|
// embedded tree's SetTree only rebuilds the node list and doesn't touch the
|
|
// cursor, so after a shrinking rebuild (e.g. moving a patch out into the index)
|
|
// the selection index could be left past the end of the tree; GetSelectedItems
|
|
// would then return a nil node and crash callers such as canEditFiles when the
|
|
// options map is rendered during layout.
|
|
//
|
|
// Unlike FileTreeViewModel.SetTree we don't re-find the selected node by path
|
|
// afterwards: that walk lands on the containing directory when a file is removed
|
|
// from a dir that then collapses, whereas keeping the (clamped) index lands on
|
|
// the sibling file, which is what we want here.
|
|
func (self *CommitFileTreeViewModel) SetTree() {
|
|
self.ICommitFileTree.SetTree()
|
|
self.ClampSelection()
|
|
}
|
|
|
|
// duplicated from file_tree_view_model.go. Generics will help here
|
|
func (self *CommitFileTreeViewModel) ToggleShowTree() {
|
|
selectedNode := self.GetSelected()
|
|
|
|
self.ICommitFileTree.ToggleShowTree()
|
|
|
|
if selectedNode == nil {
|
|
return
|
|
}
|
|
path := selectedNode.path
|
|
|
|
if self.InTreeMode() {
|
|
self.ExpandToPath(path)
|
|
} else if len(selectedNode.Children) > 0 {
|
|
path = selectedNode.GetLeaves()[0].path
|
|
}
|
|
|
|
index, found := self.GetIndexForPath(path)
|
|
if found {
|
|
self.SetSelection(index)
|
|
}
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) CollapseAll() {
|
|
selectedNode := self.GetSelected()
|
|
|
|
self.ICommitFileTree.CollapseAll()
|
|
if selectedNode == nil {
|
|
return
|
|
}
|
|
|
|
topLevelPath := strings.Split(selectedNode.path, "/")[0]
|
|
index, found := self.GetIndexForPath(topLevelPath)
|
|
if found {
|
|
self.SetSelectedLineIdx(index)
|
|
}
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) ExpandAll() {
|
|
selectedNode := self.GetSelected()
|
|
|
|
self.ICommitFileTree.ExpandAll()
|
|
|
|
if selectedNode == nil {
|
|
return
|
|
}
|
|
|
|
index, found := self.GetIndexForPath(selectedNode.path)
|
|
if found {
|
|
self.SetSelectedLineIdx(index)
|
|
}
|
|
}
|
|
|
|
// Try to select the given path if present. If it doesn't exist, or one of the parent directories is
|
|
// collapsed, do nothing.
|
|
// Note that filepath is an actual file path, not an internal tree path as with e.g.
|
|
// ToggleCollapsed. It must be a relative path (relative to the repo root), and it must contain
|
|
// forward slashes rather than backslashes even on Windows.
|
|
func (self *CommitFileTreeViewModel) SelectPath(filepath string, showRootItem bool) {
|
|
index, found := self.GetIndexForPath(InternalTreePathForFilePath(filepath, showRootItem))
|
|
if found {
|
|
self.SetSelection(index)
|
|
}
|
|
}
|
|
|
|
// IFilterableContext methods
|
|
|
|
func (self *CommitFileTreeViewModel) SetFilter(filter string, useFuzzySearch bool) {
|
|
self.ICommitFileTree.SetTextFilter(filter, useFuzzySearch)
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) GetFilter() string {
|
|
return self.ICommitFileTree.GetTextFilter()
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) ClearFilter() {
|
|
selectedNode := self.GetSelected()
|
|
var selectedPath string
|
|
if selectedNode != nil {
|
|
selectedPath = selectedNode.GetInternalPath()
|
|
}
|
|
|
|
self.ICommitFileTree.SetTextFilter("", false)
|
|
|
|
if selectedPath != "" {
|
|
self.ExpandToPath(selectedPath)
|
|
if idx, found := self.GetIndexForPath(selectedPath); found {
|
|
self.SetSelection(idx)
|
|
return
|
|
}
|
|
}
|
|
self.ClampSelection()
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) ReApplyFilter(useFuzzySearch bool) {
|
|
self.ICommitFileTree.SetTextFilter(self.ICommitFileTree.GetTextFilter(), useFuzzySearch)
|
|
}
|
|
|
|
func (self *CommitFileTreeViewModel) IsFiltering() bool {
|
|
return self.ICommitFileTree.GetTextFilter() != ""
|
|
}
|
|
|
|
// used for type switch
|
|
func (self *CommitFileTreeViewModel) IsFilterableContext() {}
|
|
|
|
func (self *CommitFileTreeViewModel) GetSearchHistory() *utils.HistoryBuffer[string] {
|
|
return self.searchHistory
|
|
}
|