From b726fd44e794d5260e4d14dca2e6426b7885133a Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 2 Oct 2023 11:41:11 +1100 Subject: Use universal resource names to identify items Refactoring the code to allow for any list item, not just branches/tags, to have an inline status. --- pkg/commands/models/branch.go | 4 ++++ pkg/commands/models/tag.go | 4 ++++ pkg/gui/context/branches_context.go | 4 +--- pkg/gui/context/tags_context.go | 4 +--- pkg/gui/controllers/branches_controller.go | 8 +++---- pkg/gui/controllers/helpers/refresh_helper.go | 2 +- pkg/gui/controllers/status_controller.go | 2 +- pkg/gui/controllers/sync_controller.go | 12 +++++----- pkg/gui/controllers/tags_controller.go | 8 +++---- pkg/gui/gui.go | 32 +++++++++++++-------------- pkg/gui/presentation/branches.go | 12 +++++----- pkg/gui/presentation/ref_operations.go | 12 +++++----- pkg/gui/presentation/status.go | 2 +- pkg/gui/presentation/tags.go | 6 ++--- pkg/gui/types/common.go | 28 ++++++++++++++--------- 15 files changed, 75 insertions(+), 65 deletions(-) diff --git a/pkg/commands/models/branch.go b/pkg/commands/models/branch.go index 5fc887f87..c5fcfdaed 100644 --- a/pkg/commands/models/branch.go +++ b/pkg/commands/models/branch.go @@ -65,6 +65,10 @@ func (b *Branch) ID() string { return b.RefName() } +func (b *Branch) URN() string { + return "branch-" + b.ID() +} + func (b *Branch) Description() string { return b.RefName() } diff --git a/pkg/commands/models/tag.go b/pkg/commands/models/tag.go index ab6076a7a..24cb83254 100644 --- a/pkg/commands/models/tag.go +++ b/pkg/commands/models/tag.go @@ -24,6 +24,10 @@ func (t *Tag) ID() string { return t.RefName() } +func (t *Tag) URN() string { + return "tag-" + t.ID() +} + func (t *Tag) Description() string { return t.Message } diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go index 16bd58709..68324d020 100644 --- a/pkg/gui/context/branches_context.go +++ b/pkg/gui/context/branches_context.go @@ -27,9 +27,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext { getDisplayStrings := func(_ int, _ int) [][]string { return presentation.GetBranchListDisplayStrings( viewModel.GetItems(), - func(branch *models.Branch) types.RefOperation { - return c.State().GetRefOperation(branch.FullRefName()) - }, + c.State().GetItemOperation, c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL, c.Modes().Diffing.Ref, c.Tr, diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index c9df8c853..3da5a9576 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -29,9 +29,7 @@ func NewTagsContext( getDisplayStrings := func(_ int, _ int) [][]string { return presentation.GetTagListDisplayStrings( viewModel.GetItems(), - func(tag *models.Tag) types.RefOperation { - return c.State().GetRefOperation(tag.FullRefName()) - }, + c.State().GetItemOperation, c.Modes().Diffing.Ref, c.Tr) } diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 119381f63..171f07373 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -303,8 +303,8 @@ func (self *BranchesController) press(selectedBranch *models.Branch) error { func (self *BranchesController) getDisabledReasonForPress() string { currentBranch := self.c.Helpers().Refs.GetCheckedOutRef() if currentBranch != nil { - op := self.c.State().GetRefOperation(currentBranch.FullRefName()) - if op == types.RefOperationFastForwarding || op == types.RefOperationPulling { + op := self.c.State().GetItemOperation(currentBranch) + if op == types.ItemOperationFastForwarding || op == types.ItemOperationPulling { return self.c.Tr.CantCheckoutBranchWhilePulling } } @@ -584,8 +584,8 @@ func (self *BranchesController) fastForward(branch *models.Branch) error { ) return self.c.WithWaitingStatus(message, func(task gocui.Task) error { - self.c.State().SetRefOperation(branch.FullRefName(), types.RefOperationFastForwarding, context.LOCAL_BRANCHES_CONTEXT_KEY) - defer func() { self.c.State().ClearRefOperation(branch.FullRefName(), context.LOCAL_BRANCHES_CONTEXT_KEY) }() + self.c.State().SetItemOperation(branch, types.ItemOperationFastForwarding, context.LOCAL_BRANCHES_CONTEXT_KEY) + defer func() { self.c.State().ClearItemOperation(branch, context.LOCAL_BRANCHES_CONTEXT_KEY) }() worktree, ok := self.worktreeForBranch(branch) if ok { diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index ca514e935..d84d0658c 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -689,7 +689,7 @@ func (self *RefreshHelper) refreshStatus() { repoName := self.c.Git().RepoPaths.RepoName() - status := presentation.FormatStatus(repoName, currentBranch, types.RefOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr) + status := presentation.FormatStatus(repoName, currentBranch, types.ItemOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr) self.c.SetViewContent(self.c.Views().Status, status) } diff --git a/pkg/gui/controllers/status_controller.go b/pkg/gui/controllers/status_controller.go index efa893340..2a186670b 100644 --- a/pkg/gui/controllers/status_controller.go +++ b/pkg/gui/controllers/status_controller.go @@ -106,7 +106,7 @@ func (self *StatusController) onClick() error { } cx, _ := self.c.Views().Status.Cursor() - upstreamStatus := presentation.BranchStatus(currentBranch, types.RefOperationNone, self.c.Tr) + upstreamStatus := presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr) repoName := self.c.Git().RepoPaths.RepoName() workingTreeState := self.c.Git().Status.WorkingTreeState() switch workingTreeState { diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index d72cbbd91..e25252733 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -62,8 +62,8 @@ func (self *SyncController) HandlePull() error { func (self *SyncController) getDisabledReasonForPushOrPull() string { currentBranch := self.c.Helpers().Refs.GetCheckedOutRef() if currentBranch != nil { - op := self.c.State().GetRefOperation(currentBranch.FullRefName()) - if op != types.RefOperationNone { + op := self.c.State().GetItemOperation(currentBranch) + if op != types.ItemOperationNone { return self.c.Tr.CantPullOrPushSameBranchTwice } } @@ -156,9 +156,9 @@ type PullFilesOptions struct { func (self *SyncController) PullAux(currentBranch *models.Branch, opts PullFilesOptions) error { return self.c.WithWaitingStatus(self.c.Tr.PullingStatus, func(task gocui.Task) error { - self.c.State().SetRefOperation(currentBranch.FullRefName(), types.RefOperationPulling, context.LOCAL_BRANCHES_CONTEXT_KEY) + self.c.State().SetItemOperation(currentBranch, types.ItemOperationPulling, context.LOCAL_BRANCHES_CONTEXT_KEY) defer func() { - self.c.State().ClearRefOperation(currentBranch.FullRefName(), context.LOCAL_BRANCHES_CONTEXT_KEY) + self.c.State().ClearItemOperation(currentBranch, context.LOCAL_BRANCHES_CONTEXT_KEY) }() return self.pullWithLock(task, opts) @@ -189,9 +189,9 @@ type pushOpts struct { func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts) error { return self.c.WithWaitingStatus(self.c.Tr.PushingStatus, func(task gocui.Task) error { - self.c.State().SetRefOperation(currentBranch.FullRefName(), types.RefOperationPushing, context.LOCAL_BRANCHES_CONTEXT_KEY) + self.c.State().SetItemOperation(currentBranch, types.ItemOperationPushing, context.LOCAL_BRANCHES_CONTEXT_KEY) defer func() { - self.c.State().ClearRefOperation(currentBranch.FullRefName(), context.LOCAL_BRANCHES_CONTEXT_KEY) + self.c.State().ClearItemOperation(currentBranch, context.LOCAL_BRANCHES_CONTEXT_KEY) }() self.c.LogAction(self.c.Tr.Actions.Push) diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index bec53dc0a..0c02147ae 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -131,8 +131,8 @@ func (self *TagsController) remoteDelete(tag *models.Tag) error { Prompt: confirmPrompt, HandleConfirm: func() error { return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(t gocui.Task) error { - self.c.State().SetRefOperation(tag.FullRefName(), types.RefOperationDeleting, context.TAGS_CONTEXT_KEY) - defer func() { self.c.State().ClearRefOperation(tag.FullRefName(), context.TAGS_CONTEXT_KEY) }() + self.c.State().SetItemOperation(tag, types.ItemOperationDeleting, context.TAGS_CONTEXT_KEY) + defer func() { self.c.State().ClearItemOperation(tag, context.TAGS_CONTEXT_KEY) }() self.c.LogAction(self.c.Tr.Actions.DeleteRemoteTag) if err := self.c.Git().Remote.DeleteRemoteTag(t, upstream, tag.Name); err != nil { @@ -193,9 +193,9 @@ func (self *TagsController) push(tag *models.Tag) error { FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(), HandleConfirm: func(response string) error { return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func(task gocui.Task) error { - self.c.State().SetRefOperation(tag.FullRefName(), types.RefOperationPushing, context.TAGS_CONTEXT_KEY) + self.c.State().SetItemOperation(tag, types.ItemOperationPushing, context.TAGS_CONTEXT_KEY) defer func() { - self.c.State().ClearRefOperation(tag.FullRefName(), context.TAGS_CONTEXT_KEY) + self.c.State().ClearItemOperation(tag, context.TAGS_CONTEXT_KEY) // Render again to remove the inline status: self.c.OnUIThread(func() error { _ = self.c.Contexts().Tags.HandleRender() diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 05bbee1e6..1ca03fc31 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -110,8 +110,8 @@ type Gui struct { // lazygit was opened in, or if we'll retain the one we're currently in. RetainOriginalDir bool - refOperations map[string]types.RefOperation - refOperationsMutex *deadlock.Mutex + itemOperations map[string]types.ItemOperation + itemOperationsMutex *deadlock.Mutex contextsWithInlineStatus map[types.ContextKey]*inlineStatusInfo PrevLayout PrevLayout @@ -184,27 +184,27 @@ func (self *StateAccessor) SetRetainOriginalDir(value bool) { self.gui.RetainOriginalDir = value } -func (self *StateAccessor) GetRefOperation(ref string) types.RefOperation { - self.gui.refOperationsMutex.Lock() - defer self.gui.refOperationsMutex.Unlock() +func (self *StateAccessor) GetItemOperation(item types.HasUrn) types.ItemOperation { + self.gui.itemOperationsMutex.Lock() + defer self.gui.itemOperationsMutex.Unlock() - return self.gui.refOperations[ref] + return self.gui.itemOperations[item.URN()] } -func (self *StateAccessor) SetRefOperation(ref string, operation types.RefOperation, contextKey types.ContextKey) { - self.gui.refOperationsMutex.Lock() - defer self.gui.refOperationsMutex.Unlock() +func (self *StateAccessor) SetItemOperation(item types.HasUrn, operation types.ItemOperation, contextKey types.ContextKey) { + self.gui.itemOperationsMutex.Lock() + defer self.gui.itemOperationsMutex.Unlock() - self.gui.refOperations[ref] = operation + self.gui.itemOperations[item.URN()] = operation self.gui.startRenderingInlineStatus(contextKey) } -func (self *StateAccessor) ClearRefOperation(ref string, contextKey types.ContextKey) { - self.gui.refOperationsMutex.Lock() - defer self.gui.refOperationsMutex.Unlock() +func (self *StateAccessor) ClearItemOperation(item types.HasUrn, contextKey types.ContextKey) { + self.gui.itemOperationsMutex.Lock() + defer self.gui.itemOperationsMutex.Unlock() self.gui.stopRenderingInlineStatus(contextKey) - delete(self.gui.refOperations, ref) + delete(self.gui.itemOperations, item.URN()) } // we keep track of some stuff from one render to the next to see if certain @@ -499,8 +499,8 @@ func NewGui( InitialDir: initialDir, afterLayoutFuncs: make(chan func() error, 1000), - refOperations: make(map[string]types.RefOperation), - refOperationsMutex: &deadlock.Mutex{}, + itemOperations: make(map[string]types.ItemOperation), + itemOperationsMutex: &deadlock.Mutex{}, contextsWithInlineStatus: make(map[types.ContextKey]*inlineStatusInfo), } diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go index d550fcd9f..004890363 100644 --- a/pkg/gui/presentation/branches.go +++ b/pkg/gui/presentation/branches.go @@ -20,7 +20,7 @@ var branchPrefixColorCache = make(map[string]style.TextStyle) func GetBranchListDisplayStrings( branches []*models.Branch, - getRefOperation func(branch *models.Branch) types.RefOperation, + getItemOperation func(item types.HasUrn) types.ItemOperation, fullDescription bool, diffName string, tr *i18n.TranslationSet, @@ -29,14 +29,14 @@ func GetBranchListDisplayStrings( ) [][]string { return lo.Map(branches, func(branch *models.Branch, _ int) []string { diffed := branch.Name == diffName - return getBranchDisplayStrings(branch, getRefOperation(branch), fullDescription, diffed, tr, userConfig, worktrees) + return getBranchDisplayStrings(branch, getItemOperation(branch), fullDescription, diffed, tr, userConfig, worktrees) }) } // getBranchDisplayStrings returns the display string of branch func getBranchDisplayStrings( b *models.Branch, - refOperation types.RefOperation, + refOperation types.ItemOperation, fullDescription bool, diffed bool, tr *i18n.TranslationSet, @@ -112,9 +112,9 @@ func GetBranchTextStyle(name string) style.TextStyle { } } -func ColoredBranchStatus(branch *models.Branch, refOperation types.RefOperation, tr *i18n.TranslationSet) string { +func ColoredBranchStatus(branch *models.Branch, refOperation types.ItemOperation, tr *i18n.TranslationSet) string { colour := style.FgYellow - if refOperation != types.RefOperationNone { + if refOperation != types.ItemOperationNone { colour = style.FgCyan } else if branch.UpstreamGone { colour = style.FgRed @@ -127,7 +127,7 @@ func ColoredBranchStatus(branch *models.Branch, refOperation types.RefOperation, return colour.Sprint(BranchStatus(branch, refOperation, tr)) } -func BranchStatus(branch *models.Branch, refOperation types.RefOperation, tr *i18n.TranslationSet) string { +func BranchStatus(branch *models.Branch, refOperation types.ItemOperation, tr *i18n.TranslationSet) string { refOperationStr := refOperationToString(refOperation, tr) if refOperationStr != "" { return refOperationStr + " " + utils.Loader() diff --git a/pkg/gui/presentation/ref_operations.go b/pkg/gui/presentation/ref_operations.go index 0d7331569..32703eaf1 100644 --- a/pkg/gui/presentation/ref_operations.go +++ b/pkg/gui/presentation/ref_operations.go @@ -5,17 +5,17 @@ import ( "github.com/jesseduffield/lazygit/pkg/i18n" ) -func refOperationToString(refOperation types.RefOperation, tr *i18n.TranslationSet) string { +func refOperationToString(refOperation types.ItemOperation, tr *i18n.TranslationSet) string { switch refOperation { - case types.RefOperationNone: + case types.ItemOperationNone: return "" - case types.RefOperationPushing: + case types.ItemOperationPushing: return tr.PushingStatus - case types.RefOperationPulling: + case types.ItemOperationPulling: return tr.PullingStatus - case types.RefOperationFastForwarding: + case types.ItemOperationFastForwarding: return tr.FastForwardingOperation - case types.RefOperationDeleting: + case types.ItemOperationDeleting: return tr.DeletingStatus } diff --git a/pkg/gui/presentation/status.go b/pkg/gui/presentation/status.go index af7099ac9..489d10841 100644 --- a/pkg/gui/presentation/status.go +++ b/pkg/gui/presentation/status.go @@ -11,7 +11,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/i18n" ) -func FormatStatus(repoName string, currentBranch *models.Branch, refOperation types.RefOperation, linkedWorktreeName string, workingTreeState enums.RebaseMode, tr *i18n.TranslationSet) string { +func FormatStatus(repoName string, currentBranch *models.Branch, refOperation types.ItemOperation, linkedWorktreeName string, workingTreeState enums.RebaseMode, tr *i18n.TranslationSet) string { status := "" if currentBranch.IsRealBranch() { diff --git a/pkg/gui/presentation/tags.go b/pkg/gui/presentation/tags.go index ed6cad392..b4203d0d0 100644 --- a/pkg/gui/presentation/tags.go +++ b/pkg/gui/presentation/tags.go @@ -13,18 +13,18 @@ import ( func GetTagListDisplayStrings( tags []*models.Tag, - getRefOperation func(branch *models.Tag) types.RefOperation, + getItemOperation func(item types.HasUrn) types.ItemOperation, diffName string, tr *i18n.TranslationSet, ) [][]string { return lo.Map(tags, func(tag *models.Tag, _ int) []string { diffed := tag.Name == diffName - return getTagDisplayStrings(tag, getRefOperation(tag), diffed, tr) + return getTagDisplayStrings(tag, getItemOperation(tag), diffed, tr) }) } // getTagDisplayStrings returns the display string of branch -func getTagDisplayStrings(t *models.Tag, refOperation types.RefOperation, diffed bool, tr *i18n.TranslationSet) []string { +func getTagDisplayStrings(t *models.Tag, refOperation types.ItemOperation, diffed bool, tr *i18n.TranslationSet) []string { textStyle := theme.DefaultTextColor if diffed { textStyle = theme.DiffTerminalColor diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 7f1dc2f40..7f2337b24 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -264,18 +264,24 @@ type Mutexes struct { PtyMutex *deadlock.Mutex } -type RefOperation int +// A long-running operation associated with an item. For example, we'll show +// that a branch is being pushed from so that there's visual feedback about +// what's happening and so that you can see multiple branches' concurrent +// operations +type ItemOperation int -// An long-running operation on a ref (branch or tag). We display these in the -// list of branches or tags so that there's better feedback of what's happening. const ( - RefOperationNone RefOperation = iota - RefOperationPushing - RefOperationPulling - RefOperationFastForwarding - RefOperationDeleting + ItemOperationNone ItemOperation = iota + ItemOperationPushing + ItemOperationPulling + ItemOperationFastForwarding + ItemOperationDeleting ) +type HasUrn interface { + URN() string +} + type IStateAccessor interface { GetRepoPathStack() *utils.StringStack GetRepoState() IRepoStateAccessor @@ -288,9 +294,9 @@ type IStateAccessor interface { SetShowExtrasWindow(bool) GetRetainOriginalDir() bool SetRetainOriginalDir(bool) - GetRefOperation(ref string) RefOperation - SetRefOperation(ref string, operation RefOperation, contextKey ContextKey) - ClearRefOperation(ref string, contextKey ContextKey) + GetItemOperation(item HasUrn) ItemOperation + SetItemOperation(item HasUrn, operation ItemOperation, contextKey ContextKey) + ClearItemOperation(item HasUrn, contextKey ContextKey) } type IRepoStateAccessor interface { -- cgit v1.2.3