1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-12 11:15:00 +02:00
lazygit/pkg/gui/presentation/files.go

223 lines
5.9 KiB
Go
Raw Normal View History

2022-01-21 15:13:51 +02:00
package presentation
import (
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
2022-04-23 03:14:42 +02:00
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
2022-01-21 15:13:51 +02:00
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
)
2022-03-19 00:38:49 +02:00
const (
EXPANDED_ARROW = "▼"
COLLAPSED_ARROW = "►"
)
2022-01-21 15:13:51 +02:00
// keeping these here as individual constants in case later on people want the old tree shape
2022-03-19 00:38:49 +02:00
const (
INNER_ITEM = " "
LAST_ITEM = " "
NESTED = " "
NOTHING = " "
2022-03-19 00:38:49 +02:00
)
2022-01-21 15:13:51 +02:00
func RenderFileTree(
tree filetree.IFileTree,
2022-01-21 15:13:51 +02:00
diffName string,
submoduleConfigs []*models.SubmoduleConfig,
) []string {
return renderAux(tree.Tree(), tree.CollapsedPaths(), "", -1, func(n filetree.INode, depth int) string {
2022-01-21 15:13:51 +02:00
castN := n.(*filetree.FileNode)
return getFileLine(castN.GetHasUnstagedChanges(), castN.GetHasStagedChanges(), castN.NameAtDepth(depth), diffName, submoduleConfigs, castN.File)
})
}
func RenderCommitFileTree(
tree *filetree.CommitFileTreeViewModel,
2022-01-21 15:13:51 +02:00
diffName string,
patchManager *patch.PatchManager,
) []string {
return renderAux(tree.Tree(), tree.CollapsedPaths(), "", -1, func(n filetree.INode, depth int) string {
2022-01-21 15:13:51 +02:00
castN := n.(*filetree.CommitFileNode)
// This is a little convoluted because we're dealing with either a leaf or a non-leaf.
// But this code actually applies to both. If it's a leaf, the status will just
// be whatever status it is, but if it's a non-leaf it will determine its status
// based on the leaves of that subtree
var status patch.PatchStatus
if castN.EveryFile(func(file *models.CommitFile) bool {
2022-03-26 15:18:08 +02:00
return patchManager.GetFileStatus(file.Name, tree.GetRef().RefName()) == patch.WHOLE
2022-01-21 15:13:51 +02:00
}) {
status = patch.WHOLE
} else if castN.EveryFile(func(file *models.CommitFile) bool {
2022-03-26 15:18:08 +02:00
return patchManager.GetFileStatus(file.Name, tree.GetRef().RefName()) == patch.UNSELECTED
2022-01-21 15:13:51 +02:00
}) {
status = patch.UNSELECTED
} else {
status = patch.PART
}
return getCommitFileLine(castN.NameAtDepth(depth), diffName, castN.File, status)
})
}
func renderAux(
s filetree.INode,
2022-03-19 03:26:30 +02:00
collapsedPaths *filetree.CollapsedPaths,
2022-01-21 15:13:51 +02:00
prefix string,
depth int,
renderLine func(filetree.INode, int) string,
) []string {
if s == nil || s.IsNil() {
return []string{}
}
isRoot := depth == -1
if s.IsLeaf() {
if isRoot {
return []string{}
}
return []string{prefix + renderLine(s, depth)}
2022-01-21 15:13:51 +02:00
}
if collapsedPaths.IsCollapsed(s.GetPath()) {
return []string{prefix + COLLAPSED_ARROW + " " + renderLine(s, depth)}
2022-01-21 15:13:51 +02:00
}
arr := []string{}
if !isRoot {
arr = append(arr, prefix+EXPANDED_ARROW+" "+renderLine(s, depth))
2022-01-21 15:13:51 +02:00
}
newPrefix := prefix
if strings.HasSuffix(prefix, LAST_ITEM) {
newPrefix = strings.TrimSuffix(prefix, LAST_ITEM) + NOTHING
} else if strings.HasSuffix(prefix, INNER_ITEM) {
newPrefix = strings.TrimSuffix(prefix, INNER_ITEM) + NESTED
}
for i, child := range s.GetChildren() {
isLast := i == len(s.GetChildren())-1
var childPrefix string
if isRoot {
childPrefix = newPrefix
} else if isLast {
childPrefix = newPrefix + LAST_ITEM
} else {
childPrefix = newPrefix + INNER_ITEM
}
arr = append(arr, renderAux(child, collapsedPaths, childPrefix, depth+1+s.GetCompressionLevel(), renderLine)...)
}
return arr
}
func getFileLine(hasUnstagedChanges bool, hasStagedChanges bool, name string, diffName string, submoduleConfigs []*models.SubmoduleConfig, file *models.File) string {
// potentially inefficient to be instantiating these color
// objects with each render
partiallyModifiedColor := style.FgYellow
restColor := style.FgGreen
if name == diffName {
restColor = theme.DiffTerminalColor
} else if file == nil && hasStagedChanges && hasUnstagedChanges {
restColor = partiallyModifiedColor
} else if hasUnstagedChanges {
2022-01-29 01:15:55 +02:00
restColor = theme.UnstagedChangesColor
2022-01-21 15:13:51 +02:00
}
output := ""
if file != nil {
// this is just making things look nice when the background attribute is 'reverse'
firstChar := file.ShortStatus[0:1]
firstCharCl := style.FgGreen
if firstChar == "?" {
2022-01-29 01:15:55 +02:00
firstCharCl = theme.UnstagedChangesColor
2022-01-21 15:13:51 +02:00
} else if firstChar == " " {
firstCharCl = restColor
}
secondChar := file.ShortStatus[1:2]
2022-01-29 01:15:55 +02:00
secondCharCl := theme.UnstagedChangesColor
2022-01-21 15:13:51 +02:00
if secondChar == " " {
secondCharCl = restColor
}
output = firstCharCl.Sprint(firstChar)
output += secondCharCl.Sprint(secondChar)
output += restColor.Sprint(" ")
}
2022-04-23 03:14:42 +02:00
isSubmodule := file != nil && file.IsSubmodule(submoduleConfigs)
isDirectory := file == nil
2022-04-23 03:41:40 +02:00
if icons.IsIconEnabled() {
2022-04-23 03:14:42 +02:00
output += restColor.Sprintf("%s ", icons.IconForFile(name, isSubmodule, isDirectory))
}
2022-01-21 15:13:51 +02:00
output += restColor.Sprint(utils.EscapeSpecialChars(name))
2022-04-23 03:14:42 +02:00
if isSubmodule {
2022-01-21 15:13:51 +02:00
output += theme.DefaultTextColor.Sprint(" (submodule)")
}
return output
}
func getCommitFileLine(name string, diffName string, commitFile *models.CommitFile, status patch.PatchStatus) string {
var colour style.TextStyle
if diffName == name {
colour = theme.DiffTerminalColor
} else {
switch status {
case patch.WHOLE:
colour = style.FgGreen
case patch.PART:
colour = style.FgYellow
case patch.UNSELECTED:
colour = theme.DefaultTextColor
}
}
2022-04-23 03:14:42 +02:00
output := ""
2022-01-21 15:13:51 +02:00
name = utils.EscapeSpecialChars(name)
2022-04-23 03:14:42 +02:00
if commitFile != nil {
output += getColorForChangeStatus(commitFile.ChangeStatus).Sprint(commitFile.ChangeStatus) + " "
2022-01-21 15:13:51 +02:00
}
2022-04-29 10:53:43 +02:00
isSubmodule := false
2022-04-23 03:14:42 +02:00
isDirectory := commitFile == nil
2022-04-23 03:41:40 +02:00
if icons.IsIconEnabled() {
2022-04-23 03:14:42 +02:00
output += colour.Sprintf("%s ", icons.IconForFile(name, isSubmodule, isDirectory))
}
output += colour.Sprint(name)
return output
2022-01-21 15:13:51 +02:00
}
func getColorForChangeStatus(changeStatus string) style.TextStyle {
switch changeStatus {
case "A":
return style.FgGreen
case "M", "R":
return style.FgYellow
case "D":
2022-01-29 01:15:55 +02:00
return theme.UnstagedChangesColor
2022-01-21 15:13:51 +02:00
case "C":
return style.FgCyan
case "T":
return style.FgMagenta
default:
return theme.DefaultTextColor
}
}