mirror of
https://github.com/wagoodman/dive
synced 2026-03-16 07:15:50 +01:00
203 lines
5.5 KiB
Go
203 lines
5.5 KiB
Go
package viewmodels
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"github.com/wagoodman/dive/dive/filetree"
|
|
"github.com/wagoodman/dive/dive/image"
|
|
"github.com/wagoodman/dive/internal/log"
|
|
)
|
|
|
|
//go:generate faux --interface FilterModel --output fakes/fake_filter_model.go
|
|
type FilterModel interface {
|
|
SetFilter(r *regexp.Regexp)
|
|
GetFilter() *regexp.Regexp
|
|
}
|
|
|
|
//go:generate faux --interface LayersModel --output fakes/fake_layers_model.go
|
|
type LayersModel interface {
|
|
SetLayerIndex(index int) bool
|
|
GetCompareIndicies() filetree.TreeIndexKey
|
|
GetCurrentLayer() *image.Layer
|
|
GetPrintableLayers() []fmt.Stringer
|
|
GetMode() LayerCompareMode
|
|
SwitchLayerMode() error
|
|
}
|
|
|
|
//go:generate faux --interface TreeCache --output fakes/fake_tree_cache.go
|
|
type TreeCache interface {
|
|
GetTree(key filetree.TreeIndexKey) (TreeModel, error)
|
|
}
|
|
|
|
//go:generate faux --interface TreeModel --output fakes/fake_tree_model.go
|
|
type TreeModel interface {
|
|
StringBetween(start, stop int, showAttributes bool) string
|
|
VisitDepthParentFirst(visitor filetree.Visitor, evaluator filetree.VisitEvaluator) error
|
|
VisitDepthChildFirst(visitor filetree.Visitor, evaluator filetree.VisitEvaluator) error
|
|
RemovePath(path string) error
|
|
VisibleSize() int
|
|
}
|
|
|
|
type TreeViewModel struct {
|
|
currentTree TreeModel
|
|
cache TreeCache
|
|
hiddenDiffTypes []bool
|
|
// Make this an interface that is composed with the FilterView
|
|
FilterModel
|
|
LayersModel
|
|
}
|
|
|
|
func NewTreeViewModel(cache TreeCache, lModel LayersModel, fModel FilterModel) (*TreeViewModel, error) {
|
|
curTreeIndex := filetree.NewTreeIndexKey(0, 0, 0, 0)
|
|
tree, err := cache.GetTree(curTreeIndex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &TreeViewModel{
|
|
currentTree: tree,
|
|
cache: cache,
|
|
hiddenDiffTypes: make([]bool, 4),
|
|
FilterModel: fModel,
|
|
LayersModel: lModel,
|
|
}, nil
|
|
}
|
|
|
|
func (tvm *TreeViewModel) StringBetween(startRow, stopRow int, showAttributes bool) string {
|
|
return tvm.currentTree.StringBetween(startRow, stopRow, showAttributes)
|
|
}
|
|
|
|
func (tvm *TreeViewModel) VisitDepthParentFirst(visitor filetree.Visitor, evaluator filetree.VisitEvaluator) error {
|
|
return tvm.currentTree.VisitDepthParentFirst(visitor, evaluator)
|
|
}
|
|
func (tvm *TreeViewModel) VisitDepthChildFirst(visitor filetree.Visitor, evaluator filetree.VisitEvaluator) error {
|
|
return tvm.currentTree.VisitDepthChildFirst(visitor, evaluator)
|
|
|
|
}
|
|
func (tvm *TreeViewModel) RemovePath(path string) error {
|
|
return tvm.currentTree.RemovePath(path)
|
|
}
|
|
func (tvm *TreeViewModel) VisibleSize() int {
|
|
return tvm.currentTree.VisibleSize()
|
|
}
|
|
|
|
func (tvm *TreeViewModel) SetFilter(filterRegex *regexp.Regexp) {
|
|
tvm.FilterModel.SetFilter(filterRegex)
|
|
if err := tvm.filterUpdate(); err != nil {
|
|
// TODO -Dan- handle panics
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// TODO: this seems like a very expensive operration, look for ways to optimize.
|
|
// TODO make type int a strongly typed argument
|
|
// TODO: handle errors correctly
|
|
func (tvm *TreeViewModel) ToggleHiddenFileType(filetype filetree.DiffType) bool {
|
|
tvm.hiddenDiffTypes[filetype] = !tvm.hiddenDiffTypes[filetype]
|
|
if err := tvm.filterUpdate(); err != nil {
|
|
//panic(err)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (tvm *TreeViewModel) GetHiddenFileType(filetype filetree.DiffType) bool {
|
|
return tvm.hiddenDiffTypes[filetype]
|
|
}
|
|
|
|
func (tvm *TreeViewModel) filterUpdate() error {
|
|
log.WithFields(
|
|
"model", "treeView",
|
|
).Trace("updating filter")
|
|
|
|
// keep the t selection in parity with the current DiffType selection
|
|
filter := tvm.GetFilter()
|
|
err := tvm.currentTree.VisitDepthChildFirst(func(node *filetree.FileNode) error {
|
|
node.Data.ViewInfo.Hidden = tvm.hiddenDiffTypes[node.Data.DiffType]
|
|
|
|
for _, child := range node.Children {
|
|
if !child.Data.ViewInfo.Hidden {
|
|
node.Data.ViewInfo.Hidden = false
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if len(node.Children) > 0 {
|
|
node.Data.ViewInfo.Hidden = true
|
|
}
|
|
|
|
if filter != nil && !node.Data.ViewInfo.Hidden { // hide nodes that do not match the current file filter regex (also don't unhide nodes that are already hidden)
|
|
match := filter.FindString(node.Path())
|
|
node.Data.ViewInfo.Hidden = len(match) == 0
|
|
}
|
|
return nil
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
log.Errorf("error updating filter on current tree: %s", err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Override functions
|
|
func (tvm *TreeViewModel) SetLayerIndex(index int) bool {
|
|
var err error
|
|
if tvm.LayersModel.SetLayerIndex(index) {
|
|
err = tvm.setCurrentTree(tvm.GetCompareIndicies())
|
|
}
|
|
return err == nil
|
|
}
|
|
|
|
func (tvm *TreeViewModel) setCurrentTree(key filetree.TreeIndexKey) error {
|
|
collapsedList := map[string]interface{}{}
|
|
|
|
newTree, err := tvm.cache.GetTree(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
evaluateFunc := func(node *filetree.FileNode) bool {
|
|
if node.Parent != nil && node.Parent.Data.ViewInfo.Hidden {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
if err = tvm.currentTree.VisitDepthParentFirst(func(node *filetree.FileNode) error {
|
|
if node.Data.ViewInfo.Collapsed {
|
|
collapsedList[node.Path()] = true
|
|
}
|
|
return nil
|
|
}, evaluateFunc); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = newTree.VisitDepthParentFirst(func(node *filetree.FileNode) error {
|
|
_, ok := collapsedList[node.Path()]
|
|
if ok {
|
|
node.Data.ViewInfo.Collapsed = true
|
|
}
|
|
return nil
|
|
}, evaluateFunc); err != nil {
|
|
return err
|
|
}
|
|
|
|
tvm.currentTree = newTree
|
|
if err := tvm.filterUpdate(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (tvm *TreeViewModel) SwitchLayerMode() error {
|
|
if err := tvm.LayersModel.SwitchLayerMode(); err != nil {
|
|
return err
|
|
}
|
|
// TODO: Handle this error
|
|
if err := tvm.setCurrentTree(tvm.GetCompareIndicies()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|