diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2022-01-19 18:32:27 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2022-01-22 10:48:51 +1100 |
commit | 4ab5e5413944a92699a9540148666f0de26aa44b (patch) | |
tree | 58a4b648b5a4e5a6ed5f01b4e40ae5ba3c3ebad7 /pkg/gui | |
parent | ab84410b4155bcee73ead0e2a7510924575b1323 (diff) |
add support for git bisect
Diffstat (limited to 'pkg/gui')
-rw-r--r-- | pkg/gui/bisect.go | 204 | ||||
-rw-r--r-- | pkg/gui/commits_panel.go | 9 | ||||
-rw-r--r-- | pkg/gui/custom_commands.go | 6 | ||||
-rw-r--r-- | pkg/gui/filetree/commit_file_manager.go | 3 | ||||
-rw-r--r-- | pkg/gui/filetree/file_manager.go | 3 | ||||
-rw-r--r-- | pkg/gui/filetree/presentation.go (renamed from pkg/gui/presentation/files.go) | 47 | ||||
-rw-r--r-- | pkg/gui/gui.go | 3 | ||||
-rw-r--r-- | pkg/gui/keybindings.go | 8 | ||||
-rw-r--r-- | pkg/gui/list_context_config.go | 3 | ||||
-rw-r--r-- | pkg/gui/modes.go | 65 | ||||
-rw-r--r-- | pkg/gui/presentation/commit_files.go | 49 | ||||
-rw-r--r-- | pkg/gui/presentation/commits.go | 132 | ||||
-rw-r--r-- | pkg/gui/view_helpers.go | 6 |
13 files changed, 452 insertions, 86 deletions
diff --git a/pkg/gui/bisect.go b/pkg/gui/bisect.go new file mode 100644 index 000000000..ca00ce87f --- /dev/null +++ b/pkg/gui/bisect.go @@ -0,0 +1,204 @@ +package gui + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" +) + +func (gui *Gui) handleOpenBisectMenu() error { + if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { + return err + } + + // no shame in getting this directly rather than using the cached value + // given how cheap it is to obtain + info := gui.Git.Bisect.GetInfo() + commit := gui.getSelectedLocalCommit() + if info.Started() { + return gui.openMidBisectMenu(info, commit) + } else { + return gui.openStartBisectMenu(info, commit) + } +} + +func (gui *Gui) openMidBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { + // if there is not yet a 'current' bisect commit, or if we have + // selected the current commit, we need to jump to the next 'current' commit + // after we perform a bisect action. The reason we don't unconditionally jump + // is that sometimes the user will want to go and mark a few commits as skipped + // in a row and they wouldn't want to be jumped back to the current bisect + // commit each time. + // Originally we were allowing the user to, from the bisect menu, select whether + // they were talking about the selected commit or the current bisect commit, + // and that was a bit confusing (and required extra keypresses). + selectCurrentAfter := info.GetCurrentSha() == "" || info.GetCurrentSha() == commit.Sha + + menuItems := []*menuItem{ + { + displayString: fmt.Sprintf(gui.Tr.Bisect.Mark, commit.ShortSha(), info.NewTerm()), + onPress: func() error { + gui.logAction(gui.Tr.Actions.BisectMark) + if err := gui.Git.Bisect.Mark(commit.Sha, info.NewTerm()); err != nil { + return gui.surfaceError(err) + } + + return gui.afterMark(selectCurrentAfter) + }, + }, + { + displayString: fmt.Sprintf(gui.Tr.Bisect.Mark, commit.ShortSha(), info.OldTerm()), + onPress: func() error { + gui.logAction(gui.Tr.Actions.BisectMark) + if err := gui.Git.Bisect.Mark(commit.Sha, info.OldTerm()); err != nil { + return gui.surfaceError(err) + } + + return gui.afterMark(selectCurrentAfter) + }, + }, + { + displayString: fmt.Sprintf(gui.Tr.Bisect.Skip, commit.ShortSha()), + onPress: func() error { + gui.logAction(gui.Tr.Actions.BisectSkip) + if err := gui.Git.Bisect.Skip(commit.Sha); err != nil { + return gui.surfaceError(err) + } + + return gui.afterMark(selectCurrentAfter) + }, + }, + { + displayString: gui.Tr.Bisect.ResetOption, + onPress: func() error { + return gui.resetBisect() + }, + }, + } + + return gui.createMenu( + gui.Tr.Bisect.BisectMenuTitle, + menuItems, + createMenuOptions{showCancel: true}, + ) +} + +func (gui *Gui) openStartBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { + return gui.createMenu( + gui.Tr.Bisect.BisectMenuTitle, + []*menuItem{ + { + displayString: fmt.Sprintf(gui.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()), + onPress: func() error { + gui.logAction(gui.Tr.Actions.StartBisect) + if err := gui.Git.Bisect.Start(); err != nil { + return gui.surfaceError(err) + } + + if err := gui.Git.Bisect.Mark(commit.Sha, info.NewTerm()); err != nil { + return gui.surfaceError(err) + } + + return gui.postBisectCommandRefresh() + }, + }, + { + displayString: fmt.Sprintf(gui.Tr.Bisect.MarkStart, commit.ShortSha(), info.OldTerm()), + onPress: func() error { + gui.logAction(gui.Tr.Actions.StartBisect) + if err := gui.Git.Bisect.Start(); err != nil { + return gui.surfaceError(err) + } + + if err := gui.Git.Bisect.Mark(commit.Sha, info.OldTerm()); err != nil { + return gui.surfaceError(err) + } + + return gui.postBisectCommandRefresh() + }, + }, + }, + createMenuOptions{showCancel: true}, + ) +} + +func (gui *Gui) resetBisect() error { + return gui.ask(askOpts{ + title: gui.Tr.Bisect.ResetTitle, + prompt: gui.Tr.Bisect.ResetPrompt, + handleConfirm: func() error { + gui.logAction(gui.Tr.Actions.ResetBisect) + if err := gui.Git.Bisect.Reset(); err != nil { + return gui.surfaceError(err) + } + + return gui.postBisectCommandRefresh() + }, + }) +} + +func (gui *Gui) showBisectCompleteMessage(candidateShas []string) error { + prompt := gui.Tr.Bisect.CompletePrompt + if len(candidateShas) > 1 { + prompt = gui.Tr.Bisect.CompletePromptIndeterminate + } + + formattedCommits, err := gui.Git.Commit.GetCommitsOneline(candidateShas) + if err != nil { + return gui.surfaceError(err) + } + + return gui.ask(askOpts{ + title: gui.Tr.Bisect.CompleteTitle, + prompt: fmt.Sprintf(prompt, strings.TrimSpace(formattedCommits)), + handleConfirm: func() error { + gui.logAction(gui.Tr.Actions.ResetBisect) + if err := gui.Git.Bisect.Reset(); err != nil { + return gui.surfaceError(err) + } + + return gui.postBisectCommandRefresh() + }, + }) +} + +func (gui *Gui) afterMark(selectCurrent bool) error { + done, candidateShas, err := gui.Git.Bisect.IsDone() + if err != nil { + return gui.surfaceError(err) + } + + if err := gui.postBisectCommandRefresh(); err != nil { + return gui.surfaceError(err) + } + + if done { + return gui.showBisectCompleteMessage(candidateShas) + } + + if selectCurrent { + gui.selectCurrentBisectCommit() + } + + return nil +} + +func (gui *Gui) selectCurrentBisectCommit() { + info := gui.Git.Bisect.GetInfo() + if info.GetCurrentSha() != "" { + // find index of commit with that sha, move cursor to that. + for i, commit := range gui.State.Commits { + if commit.Sha == info.GetCurrentSha() { + gui.State.Contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(i) + _ = gui.State.Contexts.BranchCommits.HandleFocus() + break + } + } + } +} + +func (gui *Gui) postBisectCommandRefresh() error { + return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{}}) +} diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 0f63e4157..d568caf88 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -116,12 +116,19 @@ func (gui *Gui) refreshCommitsWithLimit() error { gui.Mutexes.BranchCommitsMutex.Lock() defer gui.Mutexes.BranchCommitsMutex.Unlock() + refName := "HEAD" + bisectInfo := gui.Git.Bisect.GetInfo() + gui.State.BisectInfo = bisectInfo + if bisectInfo.Started() { + refName = bisectInfo.StartSha() + } + commits, err := gui.Git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ Limit: gui.State.Panels.Commits.LimitCommits, FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: true, - RefName: "HEAD", + RefName: refName, All: gui.State.ShowWholeGitGraph, }, ) diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index c55b58a02..02293dd65 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -254,7 +254,11 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand } return gui.WithWaitingStatus(loadingText, func() error { gui.logAction(gui.Tr.Actions.CustomCommand) - err := gui.OSCommand.Cmd.NewShell(cmdStr).Run() + cmdObj := gui.OSCommand.Cmd.NewShell(cmdStr) + if customCommand.Stream { + cmdObj.StreamOutput() + } + err := cmdObj.Run() if err != nil { return gui.surfaceError(err) } diff --git a/pkg/gui/filetree/commit_file_manager.go b/pkg/gui/filetree/commit_file_manager.go index e80528bcb..852a67b09 100644 --- a/pkg/gui/filetree/commit_file_manager.go +++ b/pkg/gui/filetree/commit_file_manager.go @@ -3,7 +3,6 @@ package filetree import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/patch" - "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/sirupsen/logrus" ) @@ -114,6 +113,6 @@ func (m *CommitFileManager) Render(diffName string, patchManager *patch.PatchMan status = patch.PART } - return presentation.GetCommitFileLine(castN.NameAtDepth(depth), diffName, castN.File, status) + return getCommitFileLine(castN.NameAtDepth(depth), diffName, castN.File, status) }) } diff --git a/pkg/gui/filetree/file_manager.go b/pkg/gui/filetree/file_manager.go index 699e20332..b028ef961 100644 --- a/pkg/gui/filetree/file_manager.go +++ b/pkg/gui/filetree/file_manager.go @@ -4,7 +4,6 @@ import ( "sync" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/sirupsen/logrus" ) @@ -136,6 +135,6 @@ func (m *FileManager) Render(diffName string, submoduleConfigs []*models.Submodu return renderAux(m.tree, m.collapsedPaths, "", -1, func(n INode, depth int) string { castN := n.(*FileNode) - return presentation.GetFileLine(castN.GetHasUnstagedChanges(), castN.GetHasStagedChanges(), castN.NameAtDepth(depth), diffName, submoduleConfigs, castN.File) + return getFileLine(castN.GetHasUnstagedChanges(), castN.GetHasStagedChanges(), castN.NameAtDepth(depth), diffName, submoduleConfigs, castN.File) }) } diff --git a/pkg/gui/presentation/files.go b/pkg/gui/filetree/presentation.go index 4d00b7e84..6cecb78ad 100644 --- a/pkg/gui/presentation/files.go +++ b/pkg/gui/filetree/presentation.go @@ -1,13 +1,16 @@ -package presentation +package filetree import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" ) -func GetFileLine(hasUnstagedChanges bool, hasStagedChanges bool, name string, diffName string, submoduleConfigs []*models.SubmoduleConfig, file *models.File) string { +// TODO: move this back into presentation package and fix the import cycle + +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 @@ -51,3 +54,43 @@ func GetFileLine(hasUnstagedChanges bool, hasStagedChanges bool, name string, di 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 + } + } + + name = utils.EscapeSpecialChars(name) + if commitFile == nil { + return colour.Sprint(name) + } + + return getColorForChangeStatus(commitFile.ChangeStatus).Sprint(commitFile.ChangeStatus) + " " + colour.Sprint(name) +} + +func getColorForChangeStatus(changeStatus string) style.TextStyle { + switch changeStatus { + case "A": + return style.FgGreen + case "M", "R": + return style.FgYellow + case "D": + return style.FgRed + case "C": + return style.FgCyan + case "T": + return style.FgMagenta + default: + return theme.DefaultTextColor + } +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 50291c8bf..731e56b5b 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -12,6 +12,7 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" @@ -309,6 +310,7 @@ type guiState struct { RemoteBranches []*models.RemoteBranch Tags []*models.Tag MenuItems []*menuItem + BisectInfo *git_commands.BisectInfo Updating bool Panels *panelStates SplitMainPanel bool @@ -394,6 +396,7 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { FilteredReflogCommits: make([]*models.Commit, 0), ReflogCommits: make([]*models.Commit, 0), StashEntries: make([]*models.StashEntry, 0), + BisectInfo: gui.Git.Bisect.GetInfo(), Panels: &panelStates{ // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now Files: &filePanelState{listPanelState{SelectedLineIdx: -1}}, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index a3e998416..584a276bb 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -910,6 +910,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, { ViewName: "commits", + Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, + Key: gui.getKey(config.Commits.ViewBisectOptions), + Handler: gui.handleOpenBisectMenu, + Description: gui.Tr.LcViewBisectOptions, + OpensMenu: true, + }, + { + ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleViewReflogCommitFiles, diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index e5ad6c034..f05375b67 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -4,6 +4,7 @@ import ( "log" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" ) @@ -177,6 +178,7 @@ func (gui *Gui) branchCommitsListContext() IListContext { startIdx, length, gui.shouldShowGraph(), + gui.State.BisectInfo, ) }, SelectedItem: func() (ListItem, bool) { @@ -218,6 +220,7 @@ func (gui *Gui) subCommitsListContext() IListContext { startIdx, length, gui.shouldShowGraph(), + git_commands.NewNullBisectInfo(), ) }, SelectedItem: func() (ListItem, bool) { diff --git a/pkg/gui/modes.go b/pkg/gui/modes.go index 1f92d1c84..b60fafc8a 100644 --- a/pkg/gui/modes.go +++ b/pkg/gui/modes.go @@ -1,6 +1,8 @@ package gui import ( + "fmt" + "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/gui/style" ) @@ -16,11 +18,13 @@ func (gui *Gui) modeStatuses() []modeStatus { { isActive: gui.State.Modes.Diffing.Active, description: func() string { - return style.FgMagenta.Sprintf( - "%s %s %s", - gui.Tr.LcShowingGitDiff, - "git diff "+gui.diffStr(), - style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), + return gui.withResetButton( + fmt.Sprintf( + "%s %s", + gui.Tr.LcShowingGitDiff, + "git diff "+gui.diffStr(), + ), + style.FgMagenta, ) }, reset: gui.exitDiffMode, @@ -28,22 +32,20 @@ func (gui *Gui) modeStatuses() []modeStatus { { isActive: gui.Git.Patch.PatchManager.Active, description: func() string { - return style.FgYellow.SetBold().Sprintf( - "%s %s", - gui.Tr.LcBuildingPatch, - style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), - ) + return gui.withResetButton(gui.Tr.LcBuildingPatch, style.FgYellow.SetBold()) }, reset: gui.handleResetPatch, }, { isActive: gui.State.Modes.Filtering.Active, description: func() string { - return style.FgRed.SetBold().Sprintf( - "%s '%s' %s", - gui.Tr.LcFilteringBy, - gui.State.Modes.Filtering.GetPath(), - style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), + return gui.withResetButton( + fmt.Sprintf( + "%s '%s'", + gui.Tr.LcFilteringBy, + gui.State.Modes.Filtering.GetPath(), + ), + style.FgRed, ) }, reset: gui.exitFilterMode, @@ -51,10 +53,12 @@ func (gui *Gui) modeStatuses() []modeStatus { { isActive: gui.State.Modes.CherryPicking.Active, description: func() string { - return style.FgCyan.Sprintf( - "%d commits copied %s", - len(gui.State.Modes.CherryPicking.CherryPickedCommits), - style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), + return gui.withResetButton( + fmt.Sprintf( + "%d commits copied", + len(gui.State.Modes.CherryPicking.CherryPickedCommits), + ), + style.FgCyan, ) }, reset: gui.exitCherryPickingMode, @@ -65,13 +69,28 @@ func (gui *Gui) modeStatuses() []modeStatus { }, description: func() string { workingTreeState := gui.Git.Status.WorkingTreeState() - return style.FgYellow.Sprintf( - "%s %s", - formatWorkingTreeState(workingTreeState), - style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), + return gui.withResetButton( + formatWorkingTreeState(workingTreeState), style.FgYellow, ) }, reset: gui.abortMergeOrRebaseWithConfirm, }, + { + isActive: func() bool { + return gui.State.BisectInfo.Started() + }, + description: func() string { + return gui.withResetButton("bisecting", style.FgGreen) + }, + reset: gui.resetBisect, + }, } } + +func (gui *Gui) withResetButton(content string, textStyle style.TextStyle) string { + return textStyle.Sprintf( + "%s %s", + content, + style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), + ) +} diff --git a/pkg/gui/presentation/commit_files.go b/pkg/gui/presentation/commit_files.go deleted file mode 100644 index 6a351be48..000000000 --- a/pkg/gui/presentation/commit_files.go +++ /dev/null @@ -1,49 +0,0 @@ -package presentation - -import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/commands/patch" - "github.com/jesseduffield/lazygit/pkg/gui/style" - "github.com/jesseduffield/lazygit/pkg/theme" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -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 - } - } - - name = utils.EscapeSpecialChars(name) - if commitFile == nil { - return colour.Sprint(name) - } - - return getColorForChangeStatus(commitFile.ChangeStatus).Sprint(commitFile.ChangeStatus) + " " + colour.Sprint(name) -} - -func getColorForChangeStatus(changeStatus string) style.TextStyle { - switch changeStatus { - case "A": - return style.FgGreen - case "M", "R": - return style.FgYellow - case "D": - return style.FgRed - case "C": - return style.FgCyan - case "T": - return style.FgMagenta - default: - return theme.DefaultTextColor - } -} diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 68cd554fa..0bc84d5e8 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -4,6 +4,7 @@ import ( "strings" "sync" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/presentation/authors" "github.com/jesseduffield/lazygit/pkg/gui/presentation/graph" @@ -21,6 +22,14 @@ type pipeSetCacheKey struct { var pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe) var mutex sync.Mutex +type BisectProgress int + +const ( + BeforeNewCommit BisectProgress = iota + InbetweenCommits + AfterOldCommit +) + func GetCommitListDisplayStrings( commits []*models.Commit, fullDescription bool, @@ -31,6 +40,7 @@ func GetCommitListDisplayStrings( startIdx int, length int, showGraph bool, + bisectInfo *git_commands.BisectInfo, ) [][]string { mutex.Lock() defer mutex.Unlock() @@ -77,12 +87,94 @@ func GetCommitListDisplayStrings( } lines := make([][]string, 0, len(filteredCommits)) + bisectProgress := BeforeNewCommit + var bisectStatus BisectStatus for i, commit := range filteredCommits { - lines = append(lines, displayCommit(commit, cherryPickedCommitShaMap, diffName, parseEmoji, getGraphLine(i), fullDescription)) + bisectStatus, bisectProgress = getBisectStatus(commit.Sha, bisectInfo, bisectProgress) + lines = append(lines, displayCommit( + commit, + cherryPickedCommitShaMap, + diffName, + parseEmoji, + getGraphLine(i), + fullDescription, + bisectStatus, + bisectInfo, + )) } return lines } +// 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 "" +} + func displayCommit( commit *models.Commit, cherryPickedCommitShaMap map[string]bool, @@ -90,9 +182,11 @@ func displayCommit( parseEmoji bool, graphLine string, fullDescription bool, + bisectStatus BisectStatus, + bisectInfo *git_commands.BisectInfo, ) []string { - - shaColor := getShaColor(commit, diffName, cherryPickedCommitShaMap) + shaColor := getShaColor(commit, diffName, cherryPickedCommitShaMap, bisectStatus, bisectInfo) + bisectString := getBisectStatusText(bisectStatus, bisectInfo) actionString := "" if commit.Action != "" { @@ -122,6 +216,7 @@ func displayCommit( cols := make([]string, 0, 5) cols = append(cols, shaColor.Sprint(commit.ShortSha())) + cols = append(cols, bisectString) if fullDescription { cols = append(cols, style.FgBlue.Sprint(utils.UnixToDate(commit.UnixTimestamp))) } @@ -133,10 +228,39 @@ func displayCommit( ) return cols +} + +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 + } + // shouldn't land here + return style.FgWhite } -func getShaColor(commit *models.Commit, diffName string, cherryPickedCommitShaMap map[string]bool) style.TextStyle { +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) + } + diffed := commit.Sha == diffName shaColor := theme.DefaultTextColor switch commit.Status { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 3f559b400..300571ad3 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -28,6 +28,8 @@ const ( REMOTES STATUS SUBMODULES + // not actually a view. Will refactor this later + BISECT_INFO ) func getScopeNames(scopes []RefreshableView) []string { @@ -105,12 +107,12 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { f := func() { var scopeMap map[RefreshableView]bool if len(options.scope) == 0 { - scopeMap = arrToMap([]RefreshableView{COMMITS, BRANCHES, FILES, STASH, REFLOG, TAGS, REMOTES, STATUS}) + scopeMap = arrToMap([]RefreshableView{COMMITS, BRANCHES, FILES, STASH, REFLOG, TAGS, REMOTES, STATUS, BISECT_INFO}) } else { scopeMap = arrToMap(options.scope) } - if scopeMap[COMMITS] || scopeMap[BRANCHES] || scopeMap[REFLOG] { + if scopeMap[COMMITS] || scopeMap[BRANCHES] || scopeMap[REFLOG] || scopeMap[BISECT_INFO] { wg.Add(1) func() { if options.mode == ASYNC { |