2020-02-25 11:11:07 +02:00
|
|
|
package presentation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
2021-11-02 07:39:15 +02:00
|
|
|
"sync"
|
2020-02-25 11:11:07 +02:00
|
|
|
|
2022-01-19 09:32:27 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
2020-09-29 12:28:39 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
2021-10-30 08:42:43 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/authors"
|
2021-11-02 07:39:15 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/graph"
|
2021-07-27 15:00:37 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
2020-02-25 11:11:07 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/theme"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
2021-07-16 14:06:01 +02:00
|
|
|
"github.com/kyokomi/emoji/v2"
|
2020-02-25 11:11:07 +02:00
|
|
|
)
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
type pipeSetCacheKey struct {
|
|
|
|
commitSha string
|
|
|
|
commitCount int
|
|
|
|
}
|
2020-02-25 11:11:07 +02:00
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
var pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe)
|
|
|
|
var mutex sync.Mutex
|
|
|
|
|
2022-01-19 09:32:27 +02:00
|
|
|
type BisectProgress int
|
|
|
|
|
|
|
|
const (
|
|
|
|
BeforeNewCommit BisectProgress = iota
|
|
|
|
InbetweenCommits
|
|
|
|
AfterOldCommit
|
|
|
|
)
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
func GetCommitListDisplayStrings(
|
|
|
|
commits []*models.Commit,
|
|
|
|
fullDescription bool,
|
|
|
|
cherryPickedCommitShaMap map[string]bool,
|
|
|
|
diffName string,
|
|
|
|
parseEmoji bool,
|
|
|
|
selectedCommitSha string,
|
|
|
|
startIdx int,
|
|
|
|
length int,
|
2021-11-02 11:05:23 +02:00
|
|
|
showGraph bool,
|
2022-01-19 09:32:27 +02:00
|
|
|
bisectInfo *git_commands.BisectInfo,
|
2021-11-02 07:39:15 +02:00
|
|
|
) [][]string {
|
|
|
|
mutex.Lock()
|
|
|
|
defer mutex.Unlock()
|
|
|
|
|
|
|
|
if len(commits) == 0 {
|
|
|
|
return nil
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
// given that our cache key is a commit sha and a commit count, it's very important that we don't actually try to render pipes
|
|
|
|
// when dealing with things like filtered commits.
|
|
|
|
cacheKey := pipeSetCacheKey{
|
|
|
|
commitSha: commits[0].Sha,
|
|
|
|
commitCount: len(commits),
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
pipeSets, ok := pipeSetCache[cacheKey]
|
|
|
|
if !ok {
|
|
|
|
// pipe sets are unique to a commit head. and a commit count. Sometimes we haven't loaded everything for that.
|
|
|
|
// so let's just cache it based on that.
|
|
|
|
getStyle := func(commit *models.Commit) style.TextStyle {
|
|
|
|
return authors.AuthorStyle(commit.Author)
|
|
|
|
}
|
|
|
|
pipeSets = graph.GetPipeSets(commits, getStyle)
|
|
|
|
pipeSetCache[cacheKey] = pipeSets
|
|
|
|
}
|
|
|
|
|
2021-11-02 12:33:22 +02:00
|
|
|
if startIdx > len(commits) {
|
|
|
|
return nil
|
|
|
|
}
|
2021-11-02 07:39:15 +02:00
|
|
|
end := startIdx + length
|
|
|
|
if end > len(commits)-1 {
|
|
|
|
end = len(commits) - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
filteredCommits := commits[startIdx : end+1]
|
|
|
|
|
2021-11-02 11:05:23 +02:00
|
|
|
var getGraphLine func(int) string
|
|
|
|
if showGraph {
|
|
|
|
filteredPipeSets := pipeSets[startIdx : end+1]
|
|
|
|
graphLines := graph.RenderAux(filteredPipeSets, filteredCommits, selectedCommitSha)
|
|
|
|
getGraphLine = func(idx int) string { return graphLines[idx] }
|
|
|
|
} else {
|
|
|
|
getGraphLine = func(idx int) string { return "" }
|
|
|
|
}
|
|
|
|
|
|
|
|
lines := make([][]string, 0, len(filteredCommits))
|
2022-01-19 09:32:27 +02:00
|
|
|
bisectProgress := BeforeNewCommit
|
|
|
|
var bisectStatus BisectStatus
|
2021-11-02 07:39:15 +02:00
|
|
|
for i, commit := range filteredCommits {
|
2022-01-19 09:32:27 +02:00
|
|
|
bisectStatus, bisectProgress = getBisectStatus(commit.Sha, bisectInfo, bisectProgress)
|
|
|
|
lines = append(lines, displayCommit(
|
|
|
|
commit,
|
|
|
|
cherryPickedCommitShaMap,
|
|
|
|
diffName,
|
|
|
|
parseEmoji,
|
|
|
|
getGraphLine(i),
|
|
|
|
fullDescription,
|
|
|
|
bisectStatus,
|
|
|
|
bisectInfo,
|
|
|
|
))
|
2021-11-02 07:39:15 +02:00
|
|
|
}
|
2020-02-25 11:11:07 +02:00
|
|
|
return lines
|
|
|
|
}
|
|
|
|
|
2022-01-19 09:32:27 +02:00
|
|
|
// similar to the git_commands.BisectStatus but more gui-focused
|
|
|
|
type BisectStatus int
|
|
|
|
|
|
|
|
const (
|
|
|
|
BisectStatusNone BisectStatus = iota
|
|
|
|
BisectStatusOld
|
|
|
|
BisectStatusNew
|
|
|
|
BisectStatusSkipped
|
|
|
|
// adding candidate here which isn't present in the commands package because
|
|
|
|
// we need to actually go through the commits to get this info
|
|
|
|
BisectStatusCandidate
|
|
|
|
// also adding this
|
|
|
|
BisectStatusCurrent
|
|
|
|
)
|
|
|
|
|
|
|
|
func getBisectStatus(commitSha string, bisectInfo *git_commands.BisectInfo, bisectProgress BisectProgress) (BisectStatus, BisectProgress) {
|
|
|
|
if !bisectInfo.Started() {
|
|
|
|
return BisectStatusNone, bisectProgress
|
|
|
|
}
|
|
|
|
|
|
|
|
if bisectInfo.GetCurrentSha() == commitSha {
|
|
|
|
return BisectStatusCurrent, bisectProgress
|
|
|
|
}
|
|
|
|
|
|
|
|
status, ok := bisectInfo.Status(commitSha)
|
|
|
|
if ok {
|
|
|
|
switch status {
|
|
|
|
case git_commands.BisectStatusNew:
|
|
|
|
return BisectStatusNew, InbetweenCommits
|
|
|
|
case git_commands.BisectStatusOld:
|
|
|
|
return BisectStatusOld, AfterOldCommit
|
|
|
|
case git_commands.BisectStatusSkipped:
|
|
|
|
return BisectStatusSkipped, bisectProgress
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if bisectProgress == InbetweenCommits {
|
|
|
|
return BisectStatusCandidate, bisectProgress
|
|
|
|
} else {
|
|
|
|
return BisectStatusNone, bisectProgress
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// should never land here
|
|
|
|
return BisectStatusNone, bisectProgress
|
|
|
|
}
|
|
|
|
|
|
|
|
func getBisectStatusText(bisectStatus BisectStatus, bisectInfo *git_commands.BisectInfo) string {
|
|
|
|
if bisectStatus == BisectStatusNone {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
style := getBisectStatusColor(bisectStatus)
|
|
|
|
|
|
|
|
switch bisectStatus {
|
|
|
|
case BisectStatusNew:
|
|
|
|
return style.Sprintf("<-- " + bisectInfo.NewTerm())
|
|
|
|
case BisectStatusOld:
|
|
|
|
return style.Sprintf("<-- " + bisectInfo.OldTerm())
|
|
|
|
case BisectStatusCurrent:
|
|
|
|
// TODO: i18n
|
|
|
|
return style.Sprintf("<-- current")
|
|
|
|
case BisectStatusSkipped:
|
|
|
|
return style.Sprintf("<-- skipped")
|
|
|
|
case BisectStatusCandidate:
|
|
|
|
return style.Sprintf("?")
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
func displayCommit(
|
|
|
|
commit *models.Commit,
|
|
|
|
cherryPickedCommitShaMap map[string]bool,
|
|
|
|
diffName string,
|
|
|
|
parseEmoji bool,
|
|
|
|
graphLine string,
|
|
|
|
fullDescription bool,
|
2022-01-19 09:32:27 +02:00
|
|
|
bisectStatus BisectStatus,
|
|
|
|
bisectInfo *git_commands.BisectInfo,
|
2021-11-02 07:39:15 +02:00
|
|
|
) []string {
|
2022-01-19 09:32:27 +02:00
|
|
|
shaColor := getShaColor(commit, diffName, cherryPickedCommitShaMap, bisectStatus, bisectInfo)
|
|
|
|
bisectString := getBisectStatusText(bisectStatus, bisectInfo)
|
2021-11-02 07:39:15 +02:00
|
|
|
|
|
|
|
actionString := ""
|
|
|
|
if commit.Action != "" {
|
|
|
|
actionString = actionColorMap(commit.Action).Sprint(commit.Action) + " "
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tagString := ""
|
2021-11-02 07:39:15 +02:00
|
|
|
if fullDescription {
|
|
|
|
if commit.ExtraInfo != "" {
|
|
|
|
tagString = style.FgMagenta.SetBold().Sprint(commit.ExtraInfo) + " "
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if len(commit.Tags) > 0 {
|
|
|
|
tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(commit.Tags, " ")) + " "
|
|
|
|
}
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
name := commit.Name
|
2021-07-16 14:06:01 +02:00
|
|
|
if parseEmoji {
|
|
|
|
name = emoji.Sprint(name)
|
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
authorFunc := authors.ShortAuthor
|
|
|
|
if fullDescription {
|
|
|
|
authorFunc = authors.LongAuthor
|
2021-07-27 15:00:37 +02:00
|
|
|
}
|
2021-11-02 07:39:15 +02:00
|
|
|
|
|
|
|
cols := make([]string, 0, 5)
|
|
|
|
cols = append(cols, shaColor.Sprint(commit.ShortSha()))
|
2022-01-19 09:32:27 +02:00
|
|
|
cols = append(cols, bisectString)
|
2021-11-02 07:39:15 +02:00
|
|
|
if fullDescription {
|
|
|
|
cols = append(cols, style.FgBlue.Sprint(utils.UnixToDate(commit.UnixTimestamp)))
|
|
|
|
}
|
|
|
|
cols = append(
|
|
|
|
cols,
|
|
|
|
actionString,
|
|
|
|
authorFunc(commit.Author),
|
|
|
|
graphLine+tagString+theme.DefaultTextColor.Sprint(name),
|
|
|
|
)
|
|
|
|
|
|
|
|
return cols
|
2022-01-19 09:32:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func getBisectStatusColor(status BisectStatus) style.TextStyle {
|
|
|
|
switch status {
|
|
|
|
case BisectStatusNone:
|
|
|
|
return style.FgBlack
|
|
|
|
case BisectStatusNew:
|
|
|
|
return style.FgRed
|
|
|
|
case BisectStatusOld:
|
|
|
|
return style.FgGreen
|
|
|
|
case BisectStatusSkipped:
|
|
|
|
return style.FgYellow
|
|
|
|
case BisectStatusCurrent:
|
|
|
|
return style.FgMagenta
|
|
|
|
case BisectStatusCandidate:
|
|
|
|
return style.FgBlue
|
|
|
|
}
|
2021-11-02 07:39:15 +02:00
|
|
|
|
2022-01-19 09:32:27 +02:00
|
|
|
// shouldn't land here
|
|
|
|
return style.FgWhite
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
2022-01-19 09:32:27 +02:00
|
|
|
func getShaColor(
|
|
|
|
commit *models.Commit,
|
|
|
|
diffName string,
|
|
|
|
cherryPickedCommitShaMap map[string]bool,
|
|
|
|
bisectStatus BisectStatus,
|
|
|
|
bisectInfo *git_commands.BisectInfo,
|
|
|
|
) style.TextStyle {
|
|
|
|
if bisectInfo.Started() {
|
|
|
|
return getBisectStatusColor(bisectStatus)
|
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
diffed := commit.Sha == diffName
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor := theme.DefaultTextColor
|
2021-11-02 07:39:15 +02:00
|
|
|
switch commit.Status {
|
2020-02-25 11:11:07 +02:00
|
|
|
case "unpushed":
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor = style.FgRed
|
2020-02-25 11:11:07 +02:00
|
|
|
case "pushed":
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor = style.FgYellow
|
2020-02-25 11:11:07 +02:00
|
|
|
case "merged":
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor = style.FgGreen
|
2020-02-25 11:11:07 +02:00
|
|
|
case "rebasing":
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor = style.FgBlue
|
2020-02-25 11:11:07 +02:00
|
|
|
case "reflog":
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor = style.FgBlue
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
2020-03-29 05:34:17 +02:00
|
|
|
if diffed {
|
2021-07-27 15:00:37 +02:00
|
|
|
shaColor = theme.DiffTerminalColor
|
2021-11-02 07:39:15 +02:00
|
|
|
} else if cherryPickedCommitShaMap[commit.Sha] {
|
2021-09-29 13:53:31 +02:00
|
|
|
shaColor = theme.CherryPickedCommitTextStyle
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
|
|
|
|
2021-11-02 07:39:15 +02:00
|
|
|
return shaColor
|
2020-02-25 11:11:07 +02:00
|
|
|
}
|
2020-08-27 09:00:43 +02:00
|
|
|
|
2021-07-27 15:00:37 +02:00
|
|
|
func actionColorMap(str string) style.TextStyle {
|
2020-08-27 09:00:43 +02:00
|
|
|
switch str {
|
|
|
|
case "pick":
|
2021-07-27 15:00:37 +02:00
|
|
|
return style.FgCyan
|
2020-08-27 09:00:43 +02:00
|
|
|
case "drop":
|
2021-07-27 15:00:37 +02:00
|
|
|
return style.FgRed
|
2020-08-27 09:00:43 +02:00
|
|
|
case "edit":
|
2021-07-27 15:00:37 +02:00
|
|
|
return style.FgGreen
|
2020-08-27 09:00:43 +02:00
|
|
|
case "fixup":
|
2021-07-27 15:00:37 +02:00
|
|
|
return style.FgMagenta
|
2020-08-27 09:00:43 +02:00
|
|
|
default:
|
2021-07-27 15:00:37 +02:00
|
|
|
return style.FgYellow
|
2020-08-27 09:00:43 +02:00
|
|
|
}
|
|
|
|
}
|