1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-05 15:15:49 +02:00
This commit is contained in:
Jesse Duffield 2021-03-21 15:58:15 +11:00
parent 9e67f74ca3
commit d5639e6e95
9 changed files with 61 additions and 57 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/mgutz/str"
)
@ -137,12 +138,12 @@ func (c *GitCommand) DiscardAllFileChanges(file *models.File) error {
return c.DiscardUnstagedFileChanges(file)
}
func (c *GitCommand) DiscardAllDirChanges(node *models.FileChangeNode) error {
func (c *GitCommand) DiscardAllDirChanges(node *filetree.FileChangeNode) error {
// this could be more efficient but we would need to handle all the edge cases
return node.ForEachFile(c.DiscardAllFileChanges)
}
func (c *GitCommand) DiscardUnstagedDirChanges(node *models.FileChangeNode) error {
func (c *GitCommand) DiscardUnstagedDirChanges(node *filetree.FileChangeNode) error {
if err := c.RemoveUntrackedDirFiles(node); err != nil {
return err
}
@ -155,9 +156,9 @@ func (c *GitCommand) DiscardUnstagedDirChanges(node *models.FileChangeNode) erro
return nil
}
func (c *GitCommand) RemoveUntrackedDirFiles(node *models.FileChangeNode) error {
func (c *GitCommand) RemoveUntrackedDirFiles(node *filetree.FileChangeNode) error {
untrackedFilePaths := node.GetPathsMatching(
func(n *models.FileChangeNode) bool { return n.File != nil && !n.File.GetIsTracked() },
func(n *filetree.FileChangeNode) bool { return n.File != nil && !n.File.GetIsTracked() },
)
for _, path := range untrackedFilePaths {

View File

@ -21,6 +21,14 @@ type File struct {
ShortStatus string // e.g. 'AD', ' A', 'M ', '??'
}
// sometimes we need to deal with either a node (which contains a file) or an actual file
type IFileChange interface {
GetHasUnstagedChanges() bool
GetHasStagedChanges() bool
GetIsTracked() bool
GetPath() string
}
const RENAME_SEPARATOR = " -> "
func (f *File) IsRename() bool {

View File

@ -1,9 +0,0 @@
package models
// sometimes we need to deal with either a node (which contains a file) or an actual file
type IFileChange interface {
GetHasUnstagedChanges() bool
GetHasStagedChanges() bool
GetIsTracked() bool
GetPath() string
}

View File

@ -15,13 +15,14 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/mgutz/str"
)
// list panel functions
func (gui *Gui) getSelectedFileChangeNode() *models.FileChangeNode {
func (gui *Gui) getSelectedFileChangeNode() *filetree.FileChangeNode {
selectedLine := gui.State.Panels.Files.SelectedLineIdx
if selectedLine == -1 {
return nil
@ -557,8 +558,8 @@ func (gui *Gui) refreshStateFiles() error {
// nodes until we find one that exists in the new set of nodes, then move the cursor
// to that.
// prevNodes starts from our previously selected node because we don't need to consider anything above that
func (gui *Gui) findNewSelectedIdx(prevNodes []*models.FileChangeNode, currNodes []*models.FileChangeNode) int {
getPaths := func(node *models.FileChangeNode) []string {
func (gui *Gui) findNewSelectedIdx(prevNodes []*filetree.FileChangeNode, currNodes []*filetree.FileChangeNode) int {
getPaths := func(node *filetree.FileChangeNode) []string {
if node == nil {
return nil
}

View File

@ -9,10 +9,10 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
func BuildTreeFromFiles(files []*models.File) *models.FileChangeNode {
root := &models.FileChangeNode{}
func BuildTreeFromFiles(files []*models.File) *FileChangeNode {
root := &FileChangeNode{}
var curr *models.FileChangeNode
var curr *FileChangeNode
for _, file := range files {
split := strings.Split(file.Name, string(os.PathSeparator))
curr = root
@ -33,7 +33,7 @@ func BuildTreeFromFiles(files []*models.File) *models.FileChangeNode {
}
}
newChild := &models.FileChangeNode{
newChild := &FileChangeNode{
Path: path,
File: setFile,
}
@ -49,7 +49,7 @@ func BuildTreeFromFiles(files []*models.File) *models.FileChangeNode {
return root
}
func BuildFlatTreeFromFiles(files []*models.File) *models.FileChangeNode {
func BuildFlatTreeFromFiles(files []*models.File) *FileChangeNode {
rootAux := BuildTreeFromFiles(files)
sortedFiles := rootAux.GetLeaves()
@ -59,5 +59,5 @@ func BuildFlatTreeFromFiles(files []*models.File) *models.FileChangeNode {
return sortedFiles[i].File != nil && sortedFiles[i].File.HasMergeConflicts && !(sortedFiles[j].File != nil && sortedFiles[j].File.HasMergeConflicts)
})
return &models.FileChangeNode{Children: sortedFiles}
return &FileChangeNode{Children: sortedFiles}
}

View File

@ -19,7 +19,7 @@ const NOTHING = " "
type FileChangeManager struct {
files []*models.File
tree *models.FileChangeNode
tree *FileChangeNode
showTree bool
log *logrus.Entry
collapsedPaths map[string]bool
@ -39,7 +39,7 @@ func (m *FileChangeManager) ToggleShowTree() {
m.SetTree()
}
func (m *FileChangeManager) GetItemAtIndex(index int) *models.FileChangeNode {
func (m *FileChangeManager) GetItemAtIndex(index int) *FileChangeNode {
// need to traverse the three depth first until we get to the index.
return m.tree.GetNodeAtIndex(index+1, m.collapsedPaths) // ignoring root
}
@ -49,7 +49,7 @@ func (m *FileChangeManager) GetIndexForPath(path string) (int, bool) {
return index - 1, found
}
func (m *FileChangeManager) GetAllItems() []*models.FileChangeNode {
func (m *FileChangeManager) GetAllItems() []*FileChangeNode {
if m.tree == nil {
return nil
}
@ -83,15 +83,15 @@ func (m *FileChangeManager) Render(diffName string, submoduleConfigs []*models.S
return m.renderAux(m.tree, "", -1, diffName, submoduleConfigs)
}
func (m *FileChangeManager) IsCollapsed(s *models.FileChangeNode) bool {
func (m *FileChangeManager) IsCollapsed(s *FileChangeNode) bool {
return m.collapsedPaths[s.GetPath()]
}
func (m *FileChangeManager) ToggleCollapsed(s *models.FileChangeNode) {
func (m *FileChangeManager) ToggleCollapsed(s *FileChangeNode) {
m.collapsedPaths[s.GetPath()] = !m.collapsedPaths[s.GetPath()]
}
func (m *FileChangeManager) renderAux(s *models.FileChangeNode, prefix string, depth int, diffName string, submoduleConfigs []*models.SubmoduleConfig) []string {
func (m *FileChangeManager) renderAux(s *FileChangeNode, prefix string, depth int, diffName string, submoduleConfigs []*models.SubmoduleConfig) []string {
isRoot := depth == -1
if s == nil {
return []string{}

View File

@ -10,7 +10,7 @@ import (
func TestRender(t *testing.T) {
scenarios := []struct {
name string
root *models.FileChangeNode
root *FileChangeNode
collapsedPaths map[string]bool
expected []string
}{
@ -21,9 +21,9 @@ func TestRender(t *testing.T) {
},
{
name: "leaf node",
root: &models.FileChangeNode{
root: &FileChangeNode{
Path: "",
Children: []*models.FileChangeNode{
Children: []*FileChangeNode{
{File: &models.File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
},
},
@ -31,12 +31,12 @@ func TestRender(t *testing.T) {
},
{
name: "big example",
root: &models.FileChangeNode{
root: &FileChangeNode{
Path: "",
Children: []*models.FileChangeNode{
Children: []*FileChangeNode{
{
Path: "dir1",
Children: []*models.FileChangeNode{
Children: []*FileChangeNode{
{
File: &models.File{Name: "dir1/file2", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "dir1/file2",
@ -49,10 +49,10 @@ func TestRender(t *testing.T) {
},
{
Path: "dir2",
Children: []*models.FileChangeNode{
Children: []*FileChangeNode{
{
Path: "dir2/dir2",
Children: []*models.FileChangeNode{
Children: []*FileChangeNode{
{
File: &models.File{Name: "dir2/dir2/file3", ShortStatus: " M", HasStagedChanges: true},
Path: "dir2/dir2/file3",

View File

@ -1,4 +1,4 @@
package models
package filetree
import (
"fmt"
@ -6,28 +6,30 @@ import (
"path/filepath"
"sort"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
type FileChangeNode struct {
Children []*FileChangeNode
File *File
File *models.File
Path string // e.g. '/path/to/mydir'
CompressionLevel int // equal to the number of forward slashes you'll see in the path when it's rendered in tree mode
}
func (s *FileChangeNode) GetHasUnstagedChanges() bool {
return s.AnyFile(func(file *File) bool { return file.HasUnstagedChanges })
return s.AnyFile(func(file *models.File) bool { return file.HasUnstagedChanges })
}
func (s *FileChangeNode) GetHasStagedChanges() bool {
return s.AnyFile(func(file *File) bool { return file.HasStagedChanges })
return s.AnyFile(func(file *models.File) bool { return file.HasStagedChanges })
}
func (s *FileChangeNode) GetHasInlineMergeConflicts() bool {
return s.AnyFile(func(file *File) bool { return file.HasInlineMergeConflicts })
return s.AnyFile(func(file *models.File) bool { return file.HasInlineMergeConflicts })
}
func (s *FileChangeNode) AnyFile(test func(file *File) bool) bool {
func (s *FileChangeNode) AnyFile(test func(file *models.File) bool) bool {
return s.Any(func(node *FileChangeNode) bool {
return node.IsLeaf() && test(node.File)
})
@ -39,7 +41,7 @@ func (s *FileChangeNode) Any(test func(node *FileChangeNode) bool) bool {
}
for _, child := range s.Children {
if test(child) {
if child.Any(test) {
return true
}
}
@ -231,7 +233,7 @@ func (s *FileChangeNode) Description() string {
return s.GetPath()
}
func (s *FileChangeNode) ForEachFile(cb func(*File) error) error {
func (s *FileChangeNode) ForEachFile(cb func(*models.File) error) error {
if s.File != nil {
if err := cb(s.File); err != nil {
return err

View File

@ -1,8 +1,9 @@
package models
package filetree
import (
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/stretchr/testify/assert"
)
@ -22,13 +23,13 @@ func TestCompress(t *testing.T) {
root: &FileChangeNode{
Path: "",
Children: []*FileChangeNode{
{File: &File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
{File: &models.File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
},
},
expected: &FileChangeNode{
Path: "",
Children: []*FileChangeNode{
{File: &File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
{File: &models.File{Name: "test", ShortStatus: " M", HasStagedChanges: true}, Path: "test"},
},
},
},
@ -41,7 +42,7 @@ func TestCompress(t *testing.T) {
Path: "dir1",
Children: []*FileChangeNode{
{
File: &File{Name: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "dir1/file2",
},
},
@ -50,11 +51,11 @@ func TestCompress(t *testing.T) {
Path: "dir2",
Children: []*FileChangeNode{
{
File: &File{Name: "file3", ShortStatus: " M", HasStagedChanges: true},
File: &models.File{Name: "file3", ShortStatus: " M", HasStagedChanges: true},
Path: "dir2/file3",
},
{
File: &File{Name: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "dir2/file4",
},
},
@ -66,7 +67,7 @@ func TestCompress(t *testing.T) {
Path: "dir3/dir3-1",
Children: []*FileChangeNode{
{
File: &File{Name: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "dir3/dir3-1/file5",
},
},
@ -74,7 +75,7 @@ func TestCompress(t *testing.T) {
},
},
{
File: &File{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "file1",
},
},
@ -84,29 +85,29 @@ func TestCompress(t *testing.T) {
Children: []*FileChangeNode{
{
Path: "dir1/file2",
File: &File{Name: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file2", ShortStatus: "M ", HasUnstagedChanges: true},
CompressionLevel: 1,
},
{
Path: "dir2",
Children: []*FileChangeNode{
{
File: &File{Name: "file3", ShortStatus: " M", HasStagedChanges: true},
File: &models.File{Name: "file3", ShortStatus: " M", HasStagedChanges: true},
Path: "dir2/file3",
},
{
File: &File{Name: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file4", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "dir2/file4",
},
},
},
{
Path: "dir3/dir3-1/file5",
File: &File{Name: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file5", ShortStatus: "M ", HasUnstagedChanges: true},
CompressionLevel: 2,
},
{
File: &File{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
File: &models.File{Name: "file1", ShortStatus: "M ", HasUnstagedChanges: true},
Path: "file1",
},
},