mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-21 22:43:27 +02:00
Show sync status in branches list (#3021)
This commit is contained in:
commit
013cfc77a1
@ -7,7 +7,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/sasha-s/go-deadlock"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
gogit "github.com/jesseduffield/go-git/v5"
|
gogit "github.com/jesseduffield/go-git/v5"
|
||||||
@ -63,7 +62,6 @@ func NewGitCommand(
|
|||||||
version *git_commands.GitVersion,
|
version *git_commands.GitVersion,
|
||||||
osCommand *oscommands.OSCommand,
|
osCommand *oscommands.OSCommand,
|
||||||
gitConfig git_config.IGitConfig,
|
gitConfig git_config.IGitConfig,
|
||||||
syncMutex *deadlock.Mutex,
|
|
||||||
) (*GitCommand, error) {
|
) (*GitCommand, error) {
|
||||||
currentPath, err := os.Getwd()
|
currentPath, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -118,7 +116,6 @@ func NewGitCommand(
|
|||||||
gitConfig,
|
gitConfig,
|
||||||
repoPaths,
|
repoPaths,
|
||||||
repository,
|
repository,
|
||||||
syncMutex,
|
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +126,6 @@ func NewGitCommandAux(
|
|||||||
gitConfig git_config.IGitConfig,
|
gitConfig git_config.IGitConfig,
|
||||||
repoPaths *git_commands.RepoPaths,
|
repoPaths *git_commands.RepoPaths,
|
||||||
repo *gogit.Repository,
|
repo *gogit.Repository,
|
||||||
syncMutex *deadlock.Mutex,
|
|
||||||
) *GitCommand {
|
) *GitCommand {
|
||||||
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
|
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
|
||||||
|
|
||||||
@ -140,7 +136,7 @@ func NewGitCommandAux(
|
|||||||
// common ones are: cmn, osCommand, dotGitDir, configCommands
|
// common ones are: cmn, osCommand, dotGitDir, configCommands
|
||||||
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
|
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
|
||||||
|
|
||||||
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands, syncMutex)
|
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands)
|
||||||
|
|
||||||
fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
|
fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
|
||||||
statusCommands := git_commands.NewStatusCommands(gitCommon)
|
statusCommands := git_commands.NewStatusCommands(gitCommon)
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
gogit "github.com/jesseduffield/go-git/v5"
|
gogit "github.com/jesseduffield/go-git/v5"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/sasha-s/go-deadlock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GitCommon struct {
|
type GitCommon struct {
|
||||||
@ -15,8 +14,6 @@ type GitCommon struct {
|
|||||||
repoPaths *RepoPaths
|
repoPaths *RepoPaths
|
||||||
repo *gogit.Repository
|
repo *gogit.Repository
|
||||||
config *ConfigCommands
|
config *ConfigCommands
|
||||||
// mutex for doing things like push/pull/fetch
|
|
||||||
syncMutex *deadlock.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGitCommon(
|
func NewGitCommon(
|
||||||
@ -27,7 +24,6 @@ func NewGitCommon(
|
|||||||
repoPaths *RepoPaths,
|
repoPaths *RepoPaths,
|
||||||
repo *gogit.Repository,
|
repo *gogit.Repository,
|
||||||
config *ConfigCommands,
|
config *ConfigCommands,
|
||||||
syncMutex *deadlock.Mutex,
|
|
||||||
) *GitCommon {
|
) *GitCommon {
|
||||||
return &GitCommon{
|
return &GitCommon{
|
||||||
Common: cmn,
|
Common: cmn,
|
||||||
@ -37,6 +33,5 @@ func NewGitCommon(
|
|||||||
repoPaths: repoPaths,
|
repoPaths: repoPaths,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
config: config,
|
config: config,
|
||||||
syncMutex: syncMutex,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName strin
|
|||||||
Arg(remoteName, "--delete", branchName).
|
Arg(remoteName, "--delete", branchName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string, tagName string) error {
|
func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string, tagName string) error {
|
||||||
@ -61,7 +61,7 @@ func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string,
|
|||||||
Arg(remoteName, "--delete", tagName).
|
Arg(remoteName, "--delete", tagName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRemoteBranchExists Returns remote branch
|
// CheckRemoteBranchExists Returns remote branch
|
||||||
|
@ -36,7 +36,7 @@ func (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (oscommands
|
|||||||
ArgIf(opts.UpstreamBranch != "", opts.UpstreamBranch).
|
ArgIf(opts.UpstreamBranch != "", opts.UpstreamBranch).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex)
|
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
|
||||||
return cmdObj, nil
|
return cmdObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,6 @@ func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
|
|||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs)
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
cmdObj.DontLog().FailOnCredentialRequest()
|
cmdObj.DontLog().FailOnCredentialRequest()
|
||||||
cmdObj.WithMutex(self.syncMutex)
|
|
||||||
return cmdObj
|
return cmdObj
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +95,7 @@ func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
|||||||
|
|
||||||
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
|
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
|
||||||
// has 'pull.rebase = interactive' configured.
|
// has 'pull.rebase = interactive' configured.
|
||||||
return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FastForward(
|
func (self *SyncCommands) FastForward(
|
||||||
@ -110,7 +109,7 @@ func (self *SyncCommands) FastForward(
|
|||||||
Arg(remoteBranchName + ":" + branchName).
|
Arg(remoteBranchName + ":" + branchName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
|
func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
|
||||||
@ -118,5 +117,5 @@ func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error
|
|||||||
Arg(remoteName).
|
Arg(remoteName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
@ -52,5 +52,5 @@ func (self *TagCommands) Push(task gocui.Task, remoteName string, tagName string
|
|||||||
cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
|
cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,10 @@ func (b *Branch) ID() string {
|
|||||||
return b.RefName()
|
return b.RefName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Branch) URN() string {
|
||||||
|
return "branch-" + b.ID()
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Branch) Description() string {
|
func (b *Branch) Description() string {
|
||||||
return b.RefName()
|
return b.RefName()
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@ func (t *Tag) ID() string {
|
|||||||
return t.RefName()
|
return t.RefName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tag) URN() string {
|
||||||
|
return "tag-" + t.ID()
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tag) Description() string {
|
func (t *Tag) Description() string {
|
||||||
return t.Message
|
return t.Message
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
|
|||||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||||
return presentation.GetBranchListDisplayStrings(
|
return presentation.GetBranchListDisplayStrings(
|
||||||
viewModel.GetItems(),
|
viewModel.GetItems(),
|
||||||
|
c.State().GetItemOperation,
|
||||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
c.Tr,
|
c.Tr,
|
||||||
|
@ -27,7 +27,10 @@ func NewTagsContext(
|
|||||||
)
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||||
return presentation.GetTagListDisplayStrings(viewModel.GetItems(), c.Modes().Diffing.Ref)
|
return presentation.GetTagListDisplayStrings(
|
||||||
|
viewModel.GetItems(),
|
||||||
|
c.State().GetItemOperation,
|
||||||
|
c.Modes().Diffing.Ref, c.Tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &TagsContext{
|
return &TagsContext{
|
||||||
|
@ -112,6 +112,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
|||||||
Confirmation: helpers.NewConfirmationHelper(helperCommon),
|
Confirmation: helpers.NewConfirmationHelper(helperCommon),
|
||||||
Mode: modeHelper,
|
Mode: modeHelper,
|
||||||
AppStatus: appStatusHelper,
|
AppStatus: appStatusHelper,
|
||||||
|
InlineStatus: helpers.NewInlineStatusHelper(helperCommon),
|
||||||
WindowArrangement: helpers.NewWindowArrangementHelper(
|
WindowArrangement: helpers.NewWindowArrangementHelper(
|
||||||
gui.c,
|
gui.c,
|
||||||
windowHelper,
|
windowHelper,
|
||||||
|
@ -34,9 +34,10 @@ func NewBranchesController(
|
|||||||
func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
return []*types.Binding{
|
return []*types.Binding{
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||||
Handler: self.checkSelected(self.press),
|
Handler: self.checkSelected(self.press),
|
||||||
Description: self.c.Tr.Checkout,
|
GetDisabledReason: self.getDisabledReasonForPress,
|
||||||
|
Description: self.c.Tr.Checkout,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.New),
|
Key: opts.GetKey(opts.Config.Universal.New),
|
||||||
@ -299,6 +300,18 @@ func (self *BranchesController) press(selectedBranch *models.Branch) error {
|
|||||||
return self.c.Helpers().Refs.CheckoutRef(selectedBranch.Name, types.CheckoutRefOptions{})
|
return self.c.Helpers().Refs.CheckoutRef(selectedBranch.Name, types.CheckoutRefOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *BranchesController) getDisabledReasonForPress() string {
|
||||||
|
currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
||||||
|
if currentBranch != nil {
|
||||||
|
op := self.c.State().GetItemOperation(currentBranch)
|
||||||
|
if op == types.ItemOperationFastForwarding || op == types.ItemOperationPulling {
|
||||||
|
return self.c.Tr.CantCheckoutBranchWhilePulling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (self *BranchesController) worktreeForBranch(branch *models.Branch) (*models.Worktree, bool) {
|
func (self *BranchesController) worktreeForBranch(branch *models.Branch) (*models.Worktree, bool) {
|
||||||
return git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees)
|
return git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees)
|
||||||
}
|
}
|
||||||
@ -563,14 +576,7 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
|
|||||||
|
|
||||||
action := self.c.Tr.Actions.FastForwardBranch
|
action := self.c.Tr.Actions.FastForwardBranch
|
||||||
|
|
||||||
message := utils.ResolvePlaceholderString(
|
return self.c.WithInlineStatus(branch, types.ItemOperationFastForwarding, context.LOCAL_BRANCHES_CONTEXT_KEY, func(task gocui.Task) error {
|
||||||
self.c.Tr.FastForwarding,
|
|
||||||
map[string]string{
|
|
||||||
"branch": branch.Name,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.c.WithWaitingStatus(message, func(task gocui.Task) error {
|
|
||||||
worktree, ok := self.worktreeForBranch(branch)
|
worktree, ok := self.worktreeForBranch(branch)
|
||||||
if ok {
|
if ok {
|
||||||
self.c.LogAction(action)
|
self.c.LogAction(action)
|
||||||
@ -590,24 +596,17 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
|
|||||||
WorktreeGitDir: worktreeGitDir,
|
WorktreeGitDir: worktreeGitDir,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
_ = self.c.Error(err)
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
||||||
} else {
|
} else {
|
||||||
self.c.LogAction(action)
|
self.c.LogAction(action)
|
||||||
|
|
||||||
err := self.c.Git().Sync.FastForward(
|
err := self.c.Git().Sync.FastForward(
|
||||||
task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch,
|
task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch,
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
_ = self.c.Error(err)
|
|
||||||
}
|
|
||||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ type Helpers struct {
|
|||||||
Confirmation *ConfirmationHelper
|
Confirmation *ConfirmationHelper
|
||||||
Mode *ModeHelper
|
Mode *ModeHelper
|
||||||
AppStatus *AppStatusHelper
|
AppStatus *AppStatusHelper
|
||||||
|
InlineStatus *InlineStatusHelper
|
||||||
WindowArrangement *WindowArrangementHelper
|
WindowArrangement *WindowArrangementHelper
|
||||||
Search *SearchHelper
|
Search *SearchHelper
|
||||||
Worktree *WorktreeHelper
|
Worktree *WorktreeHelper
|
||||||
@ -81,6 +82,7 @@ func NewStubHelpers() *Helpers {
|
|||||||
Confirmation: &ConfirmationHelper{},
|
Confirmation: &ConfirmationHelper{},
|
||||||
Mode: &ModeHelper{},
|
Mode: &ModeHelper{},
|
||||||
AppStatus: &AppStatusHelper{},
|
AppStatus: &AppStatusHelper{},
|
||||||
|
InlineStatus: &InlineStatusHelper{},
|
||||||
WindowArrangement: &WindowArrangementHelper{},
|
WindowArrangement: &WindowArrangementHelper{},
|
||||||
Search: &SearchHelper{},
|
Search: &SearchHelper{},
|
||||||
Worktree: &WorktreeHelper{},
|
Worktree: &WorktreeHelper{},
|
||||||
|
129
pkg/gui/controllers/helpers/inline_status_helper.go
Normal file
129
pkg/gui/controllers/helpers/inline_status_helper.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/sasha-s/go-deadlock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InlineStatusHelper struct {
|
||||||
|
c *HelperCommon
|
||||||
|
|
||||||
|
contextsWithInlineStatus map[types.ContextKey]*inlineStatusInfo
|
||||||
|
mutex *deadlock.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInlineStatusHelper(c *HelperCommon) *InlineStatusHelper {
|
||||||
|
return &InlineStatusHelper{
|
||||||
|
c: c,
|
||||||
|
contextsWithInlineStatus: make(map[types.ContextKey]*inlineStatusInfo),
|
||||||
|
mutex: &deadlock.Mutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type InlineStatusOpts struct {
|
||||||
|
Item types.HasUrn
|
||||||
|
Operation types.ItemOperation
|
||||||
|
ContextKey types.ContextKey
|
||||||
|
}
|
||||||
|
|
||||||
|
type inlineStatusInfo struct {
|
||||||
|
refCount int
|
||||||
|
stop chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A custom task for WithInlineStatus calls; it wraps the original one and
|
||||||
|
// hides the status whenever the task is paused, and shows it again when
|
||||||
|
// continued.
|
||||||
|
type inlineStatusHelperTask struct {
|
||||||
|
gocui.Task
|
||||||
|
|
||||||
|
inlineStatusHelper *InlineStatusHelper
|
||||||
|
opts InlineStatusOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// poor man's version of explicitly saying that struct X implements interface Y
|
||||||
|
var _ gocui.Task = inlineStatusHelperTask{}
|
||||||
|
|
||||||
|
func (self inlineStatusHelperTask) Pause() {
|
||||||
|
self.inlineStatusHelper.stop(self.opts)
|
||||||
|
self.Task.Pause()
|
||||||
|
|
||||||
|
self.inlineStatusHelper.renderContext(self.opts.ContextKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self inlineStatusHelperTask) Continue() {
|
||||||
|
self.Task.Continue()
|
||||||
|
self.inlineStatusHelper.start(self.opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *InlineStatusHelper) WithInlineStatus(opts InlineStatusOpts, f func(gocui.Task) error) {
|
||||||
|
self.c.OnWorker(func(task gocui.Task) {
|
||||||
|
self.start(opts)
|
||||||
|
|
||||||
|
err := f(inlineStatusHelperTask{task, self, opts})
|
||||||
|
if err != nil {
|
||||||
|
self.c.OnUIThread(func() error {
|
||||||
|
return self.c.Error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
self.stop(opts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *InlineStatusHelper) start(opts InlineStatusOpts) {
|
||||||
|
self.c.State().SetItemOperation(opts.Item, opts.Operation)
|
||||||
|
|
||||||
|
self.mutex.Lock()
|
||||||
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
|
info := self.contextsWithInlineStatus[opts.ContextKey]
|
||||||
|
if info == nil {
|
||||||
|
info = &inlineStatusInfo{refCount: 0, stop: make(chan struct{})}
|
||||||
|
self.contextsWithInlineStatus[opts.ContextKey] = info
|
||||||
|
|
||||||
|
go utils.Safe(func() {
|
||||||
|
ticker := time.NewTicker(time.Millisecond * utils.LoaderAnimationInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
outer:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
self.renderContext(opts.ContextKey)
|
||||||
|
case <-info.stop:
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
info.refCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *InlineStatusHelper) stop(opts InlineStatusOpts) {
|
||||||
|
self.mutex.Lock()
|
||||||
|
|
||||||
|
if info := self.contextsWithInlineStatus[opts.ContextKey]; info != nil {
|
||||||
|
info.refCount--
|
||||||
|
if info.refCount <= 0 {
|
||||||
|
info.stop <- struct{}{}
|
||||||
|
delete(self.contextsWithInlineStatus, opts.ContextKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mutex.Unlock()
|
||||||
|
|
||||||
|
self.c.State().ClearItemOperation(opts.Item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *InlineStatusHelper) renderContext(contextKey types.ContextKey) {
|
||||||
|
self.c.OnUIThread(func() error {
|
||||||
|
_ = self.c.ContextForKey(contextKey).HandleRender()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
@ -115,12 +115,15 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
includeWorktreesWithBranches := false
|
||||||
if scopeSet.Includes(types.COMMITS) || scopeSet.Includes(types.BRANCHES) || scopeSet.Includes(types.REFLOG) || scopeSet.Includes(types.BISECT_INFO) {
|
if scopeSet.Includes(types.COMMITS) || scopeSet.Includes(types.BRANCHES) || scopeSet.Includes(types.REFLOG) || scopeSet.Includes(types.BISECT_INFO) {
|
||||||
// whenever we change commits, we should update branches because the upstream/downstream
|
// whenever we change commits, we should update branches because the upstream/downstream
|
||||||
// counts can change. Whenever we change branches we should also change commits
|
// counts can change. Whenever we change branches we should also change commits
|
||||||
// e.g. in the case of switching branches.
|
// e.g. in the case of switching branches.
|
||||||
refresh("commits and commit files", self.refreshCommitsAndCommitFiles)
|
refresh("commits and commit files", self.refreshCommitsAndCommitFiles)
|
||||||
refresh("reflog and branches", self.refreshReflogAndBranches)
|
|
||||||
|
includeWorktreesWithBranches = scopeSet.Includes(types.WORKTREES)
|
||||||
|
refresh("reflog and branches", func() { self.refreshReflogAndBranches(includeWorktreesWithBranches) })
|
||||||
} else if scopeSet.Includes(types.REBASE_COMMITS) {
|
} else if scopeSet.Includes(types.REBASE_COMMITS) {
|
||||||
// the above block handles rebase commits so we only need to call this one
|
// the above block handles rebase commits so we only need to call this one
|
||||||
// if we've asked specifically for rebase commits and not those other things
|
// if we've asked specifically for rebase commits and not those other things
|
||||||
@ -157,7 +160,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
|||||||
refresh("remotes", func() { _ = self.refreshRemotes() })
|
refresh("remotes", func() { _ = self.refreshRemotes() })
|
||||||
}
|
}
|
||||||
|
|
||||||
if scopeSet.Includes(types.WORKTREES) {
|
if scopeSet.Includes(types.WORKTREES) && !includeWorktreesWithBranches {
|
||||||
refresh("worktrees", func() { _ = self.refreshWorktrees() })
|
refresh("worktrees", func() { _ = self.refreshWorktrees() })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +245,7 @@ func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
|
|||||||
case types.INITIAL:
|
case types.INITIAL:
|
||||||
self.c.OnWorker(func(_ gocui.Task) {
|
self.c.OnWorker(func(_ gocui.Task) {
|
||||||
_ = self.refreshReflogCommits()
|
_ = self.refreshReflogCommits()
|
||||||
self.refreshBranches()
|
self.refreshBranches(false)
|
||||||
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE)
|
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -251,10 +254,10 @@ func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RefreshHelper) refreshReflogAndBranches() {
|
func (self *RefreshHelper) refreshReflogAndBranches(refreshWorktrees bool) {
|
||||||
self.refreshReflogCommitsConsideringStartup()
|
self.refreshReflogCommitsConsideringStartup()
|
||||||
|
|
||||||
self.refreshBranches()
|
self.refreshBranches(refreshWorktrees)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RefreshHelper) refreshCommitsAndCommitFiles() {
|
func (self *RefreshHelper) refreshCommitsAndCommitFiles() {
|
||||||
@ -419,7 +422,7 @@ func (self *RefreshHelper) refreshStateSubmoduleConfigs() error {
|
|||||||
|
|
||||||
// self.refreshStatus is called at the end of this because that's when we can
|
// self.refreshStatus is called at the end of this because that's when we can
|
||||||
// be sure there is a State.Model.Branches array to pick the current branch from
|
// be sure there is a State.Model.Branches array to pick the current branch from
|
||||||
func (self *RefreshHelper) refreshBranches() {
|
func (self *RefreshHelper) refreshBranches(refreshWorktrees bool) {
|
||||||
self.c.Mutexes().RefreshingBranchesMutex.Lock()
|
self.c.Mutexes().RefreshingBranchesMutex.Lock()
|
||||||
defer self.c.Mutexes().RefreshingBranchesMutex.Unlock()
|
defer self.c.Mutexes().RefreshingBranchesMutex.Unlock()
|
||||||
|
|
||||||
@ -443,6 +446,13 @@ func (self *RefreshHelper) refreshBranches() {
|
|||||||
|
|
||||||
self.c.Model().Branches = branches
|
self.c.Model().Branches = branches
|
||||||
|
|
||||||
|
if refreshWorktrees {
|
||||||
|
self.loadWorktrees()
|
||||||
|
if err := self.c.PostRefreshUpdate(self.c.Contexts().Worktrees); err != nil {
|
||||||
|
self.c.Log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := self.c.PostRefreshUpdate(self.c.Contexts().Branches); err != nil {
|
if err := self.c.PostRefreshUpdate(self.c.Contexts().Branches); err != nil {
|
||||||
self.c.Log.Error(err)
|
self.c.Log.Error(err)
|
||||||
}
|
}
|
||||||
@ -636,15 +646,18 @@ func (self *RefreshHelper) refreshRemotes() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RefreshHelper) refreshWorktrees() error {
|
func (self *RefreshHelper) loadWorktrees() {
|
||||||
worktrees, err := self.c.Git().Loaders.Worktrees.GetWorktrees()
|
worktrees, err := self.c.Git().Loaders.Worktrees.GetWorktrees()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.c.Log.Error(err)
|
self.c.Log.Error(err)
|
||||||
self.c.Model().Worktrees = []*models.Worktree{}
|
self.c.Model().Worktrees = []*models.Worktree{}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.c.Model().Worktrees = worktrees
|
self.c.Model().Worktrees = worktrees
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RefreshHelper) refreshWorktrees() error {
|
||||||
|
self.loadWorktrees()
|
||||||
|
|
||||||
// need to refresh branches because the branches view shows worktrees against
|
// need to refresh branches because the branches view shows worktrees against
|
||||||
// branches
|
// branches
|
||||||
@ -678,7 +691,7 @@ func (self *RefreshHelper) refreshStatus() {
|
|||||||
|
|
||||||
repoName := self.c.Git().RepoPaths.RepoName()
|
repoName := self.c.Git().RepoPaths.RepoName()
|
||||||
|
|
||||||
status := presentation.FormatStatus(repoName, currentBranch, 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)
|
self.c.SetViewContent(self.c.Views().Status, status)
|
||||||
}
|
}
|
||||||
|
@ -173,11 +173,6 @@ func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// these two mutexes are used by our background goroutines (triggered via `self.goEvery`. We don't want to
|
|
||||||
// switch to a repo while one of these goroutines is in the process of updating something
|
|
||||||
self.c.Mutexes().SyncMutex.Lock()
|
|
||||||
defer self.c.Mutexes().SyncMutex.Unlock()
|
|
||||||
|
|
||||||
self.c.Mutexes().RefreshingFilesMutex.Lock()
|
self.c.Mutexes().RefreshingFilesMutex.Lock()
|
||||||
defer self.c.Mutexes().RefreshingFilesMutex.Unlock()
|
defer self.c.Mutexes().RefreshingFilesMutex.Unlock()
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ func (self *StatusController) onClick() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cx, _ := self.c.Views().Status.Cursor()
|
cx, _ := self.c.Views().Status.Cursor()
|
||||||
upstreamStatus := presentation.BranchStatus(currentBranch, self.c.Tr)
|
upstreamStatus := presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr)
|
||||||
repoName := self.c.Git().RepoPaths.RepoName()
|
repoName := self.c.Git().RepoPaths.RepoName()
|
||||||
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
||||||
switch workingTreeState {
|
switch workingTreeState {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
@ -30,14 +31,16 @@ func NewSyncController(
|
|||||||
func (self *SyncController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
func (self *SyncController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
bindings := []*types.Binding{
|
bindings := []*types.Binding{
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.Push),
|
Key: opts.GetKey(opts.Config.Universal.Push),
|
||||||
Handler: opts.Guards.NoPopupPanel(self.HandlePush),
|
Handler: opts.Guards.NoPopupPanel(self.HandlePush),
|
||||||
Description: self.c.Tr.Push,
|
GetDisabledReason: self.getDisabledReasonForPushOrPull,
|
||||||
|
Description: self.c.Tr.Push,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.Pull),
|
Key: opts.GetKey(opts.Config.Universal.Pull),
|
||||||
Handler: opts.Guards.NoPopupPanel(self.HandlePull),
|
Handler: opts.Guards.NoPopupPanel(self.HandlePull),
|
||||||
Description: self.c.Tr.Pull,
|
GetDisabledReason: self.getDisabledReasonForPushOrPull,
|
||||||
|
Description: self.c.Tr.Pull,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +59,18 @@ func (self *SyncController) HandlePull() error {
|
|||||||
return self.branchCheckedOut(self.pull)()
|
return self.branchCheckedOut(self.pull)()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *SyncController) getDisabledReasonForPushOrPull() string {
|
||||||
|
currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
||||||
|
if currentBranch != nil {
|
||||||
|
op := self.c.State().GetItemOperation(currentBranch)
|
||||||
|
if op != types.ItemOperationNone {
|
||||||
|
return self.c.Tr.CantPullOrPushSameBranchTwice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func() error {
|
func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
||||||
@ -73,13 +88,13 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
|
|||||||
if currentBranch.IsTrackingRemote() {
|
if currentBranch.IsTrackingRemote() {
|
||||||
opts := pushOpts{}
|
opts := pushOpts{}
|
||||||
if currentBranch.HasCommitsToPull() {
|
if currentBranch.HasCommitsToPull() {
|
||||||
return self.requestToForcePush(opts)
|
return self.requestToForcePush(currentBranch, opts)
|
||||||
} else {
|
} else {
|
||||||
return self.pushAux(opts)
|
return self.pushAux(currentBranch, opts)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.c.Git().Config.GetPushToCurrent() {
|
if self.c.Git().Config.GetPushToCurrent() {
|
||||||
return self.pushAux(pushOpts{setUpstream: true})
|
return self.pushAux(currentBranch, pushOpts{setUpstream: true})
|
||||||
} else {
|
} else {
|
||||||
return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error {
|
return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error {
|
||||||
upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream)
|
upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream)
|
||||||
@ -87,7 +102,7 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
|
|||||||
return self.c.Error(err)
|
return self.c.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.pushAux(pushOpts{
|
return self.pushAux(currentBranch, pushOpts{
|
||||||
setUpstream: true,
|
setUpstream: true,
|
||||||
upstreamRemote: upstreamRemote,
|
upstreamRemote: upstreamRemote,
|
||||||
upstreamBranch: upstreamBranch,
|
upstreamBranch: upstreamBranch,
|
||||||
@ -107,11 +122,11 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
|
|||||||
return self.c.Error(err)
|
return self.c.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.PullAux(PullFilesOptions{Action: action})
|
return self.PullAux(currentBranch, PullFilesOptions{Action: action})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.PullAux(PullFilesOptions{Action: action})
|
return self.PullAux(currentBranch, PullFilesOptions{Action: action})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncController) setCurrentBranchUpstream(upstream string) error {
|
func (self *SyncController) setCurrentBranchUpstream(upstream string) error {
|
||||||
@ -139,8 +154,8 @@ type PullFilesOptions struct {
|
|||||||
Action string
|
Action string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncController) PullAux(opts PullFilesOptions) error {
|
func (self *SyncController) PullAux(currentBranch *models.Branch, opts PullFilesOptions) error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.PullingStatus, func(task gocui.Task) error {
|
return self.c.WithInlineStatus(currentBranch, types.ItemOperationPulling, context.LOCAL_BRANCHES_CONTEXT_KEY, func(task gocui.Task) error {
|
||||||
return self.pullWithLock(task, opts)
|
return self.pullWithLock(task, opts)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -167,8 +182,8 @@ type pushOpts struct {
|
|||||||
setUpstream bool
|
setUpstream bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncController) pushAux(opts pushOpts) error {
|
func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts) error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.PushingStatus, func(task gocui.Task) error {
|
return self.c.WithInlineStatus(currentBranch, types.ItemOperationPushing, context.LOCAL_BRANCHES_CONTEXT_KEY, func(task gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.Push)
|
self.c.LogAction(self.c.Tr.Actions.Push)
|
||||||
err := self.c.Git().Sync.Push(
|
err := self.c.Git().Sync.Push(
|
||||||
task,
|
task,
|
||||||
@ -192,18 +207,18 @@ func (self *SyncController) pushAux(opts pushOpts) error {
|
|||||||
newOpts := opts
|
newOpts := opts
|
||||||
newOpts.force = true
|
newOpts.force = true
|
||||||
|
|
||||||
return self.pushAux(newOpts)
|
return self.pushAux(currentBranch, newOpts)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_ = self.c.Error(err)
|
return err
|
||||||
}
|
}
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncController) requestToForcePush(opts pushOpts) error {
|
func (self *SyncController) requestToForcePush(currentBranch *models.Branch, opts pushOpts) error {
|
||||||
forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing
|
forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing
|
||||||
if forcePushDisabled {
|
if forcePushDisabled {
|
||||||
return self.c.ErrorMsg(self.c.Tr.ForcePushDisabled)
|
return self.c.ErrorMsg(self.c.Tr.ForcePushDisabled)
|
||||||
@ -214,7 +229,7 @@ func (self *SyncController) requestToForcePush(opts pushOpts) error {
|
|||||||
Prompt: self.forcePushPrompt(),
|
Prompt: self.forcePushPrompt(),
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
opts.force = true
|
opts.force = true
|
||||||
return self.pushAux(opts)
|
return self.pushAux(currentBranch, opts)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -92,10 +92,9 @@ func (self *TagsController) checkout(tag *models.Tag) error {
|
|||||||
func (self *TagsController) localDelete(tag *models.Tag) error {
|
func (self *TagsController) localDelete(tag *models.Tag) error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(gocui.Task) error {
|
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.DeleteLocalTag)
|
self.c.LogAction(self.c.Tr.Actions.DeleteLocalTag)
|
||||||
if err := self.c.Git().Tag.LocalDelete(tag.Name); err != nil {
|
err := self.c.Git().Tag.LocalDelete(tag.Name)
|
||||||
return self.c.Error(err)
|
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
|
||||||
}
|
return err
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,10 +129,10 @@ func (self *TagsController) remoteDelete(tag *models.Tag) error {
|
|||||||
Title: confirmTitle,
|
Title: confirmTitle,
|
||||||
Prompt: confirmPrompt,
|
Prompt: confirmPrompt,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(t gocui.Task) error {
|
return self.c.WithInlineStatus(tag, types.ItemOperationDeleting, context.TAGS_CONTEXT_KEY, func(task gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteTag)
|
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteTag)
|
||||||
if err := self.c.Git().Remote.DeleteRemoteTag(t, upstream, tag.Name); err != nil {
|
if err := self.c.Git().Remote.DeleteRemoteTag(task, upstream, tag.Name); err != nil {
|
||||||
return self.c.Error(err)
|
return err
|
||||||
}
|
}
|
||||||
self.c.Toast(self.c.Tr.RemoteTagDeletedMessage)
|
self.c.Toast(self.c.Tr.RemoteTagDeletedMessage)
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
|
||||||
@ -189,14 +188,17 @@ func (self *TagsController) push(tag *models.Tag) error {
|
|||||||
InitialContent: "origin",
|
InitialContent: "origin",
|
||||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
|
||||||
HandleConfirm: func(response string) error {
|
HandleConfirm: func(response string) error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func(task gocui.Task) error {
|
return self.c.WithInlineStatus(tag, types.ItemOperationPushing, context.TAGS_CONTEXT_KEY, func(task gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.PushTag)
|
self.c.LogAction(self.c.Tr.Actions.PushTag)
|
||||||
err := self.c.Git().Tag.Push(task, response, tag.Name)
|
err := self.c.Git().Tag.Push(task, response, tag.Name)
|
||||||
if err != nil {
|
|
||||||
_ = self.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
// Render again to remove the inline status:
|
||||||
|
self.c.OnUIThread(func() error {
|
||||||
|
_ = self.c.Contexts().Tags.HandleRender()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -110,6 +110,12 @@ type Gui struct {
|
|||||||
// lazygit was opened in, or if we'll retain the one we're currently in.
|
// lazygit was opened in, or if we'll retain the one we're currently in.
|
||||||
RetainOriginalDir bool
|
RetainOriginalDir bool
|
||||||
|
|
||||||
|
// stores long-running operations associated with items (e.g. when a branch
|
||||||
|
// is being pushed). At the moment the rule is to use an item operation when
|
||||||
|
// we need to talk to the remote.
|
||||||
|
itemOperations map[string]types.ItemOperation
|
||||||
|
itemOperationsMutex *deadlock.Mutex
|
||||||
|
|
||||||
PrevLayout PrevLayout
|
PrevLayout PrevLayout
|
||||||
|
|
||||||
// this is the initial dir we are in upon opening lazygit. We hold onto this
|
// this is the initial dir we are in upon opening lazygit. We hold onto this
|
||||||
@ -180,6 +186,27 @@ func (self *StateAccessor) SetRetainOriginalDir(value bool) {
|
|||||||
self.gui.RetainOriginalDir = value
|
self.gui.RetainOriginalDir = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StateAccessor) GetItemOperation(item types.HasUrn) types.ItemOperation {
|
||||||
|
self.gui.itemOperationsMutex.Lock()
|
||||||
|
defer self.gui.itemOperationsMutex.Unlock()
|
||||||
|
|
||||||
|
return self.gui.itemOperations[item.URN()]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *StateAccessor) SetItemOperation(item types.HasUrn, operation types.ItemOperation) {
|
||||||
|
self.gui.itemOperationsMutex.Lock()
|
||||||
|
defer self.gui.itemOperationsMutex.Unlock()
|
||||||
|
|
||||||
|
self.gui.itemOperations[item.URN()] = operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *StateAccessor) ClearItemOperation(item types.HasUrn) {
|
||||||
|
self.gui.itemOperationsMutex.Lock()
|
||||||
|
defer self.gui.itemOperationsMutex.Unlock()
|
||||||
|
|
||||||
|
delete(self.gui.itemOperations, item.URN())
|
||||||
|
}
|
||||||
|
|
||||||
// we keep track of some stuff from one render to the next to see if certain
|
// we keep track of some stuff from one render to the next to see if certain
|
||||||
// things have changed
|
// things have changed
|
||||||
type PrevLayout struct {
|
type PrevLayout struct {
|
||||||
@ -273,7 +300,6 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
|
|||||||
gui.gitVersion,
|
gui.gitVersion,
|
||||||
gui.os,
|
gui.os,
|
||||||
git_config.NewStdCachedGitConfig(gui.Log),
|
git_config.NewStdCachedGitConfig(gui.Log),
|
||||||
gui.Mutexes.SyncMutex,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -463,7 +489,6 @@ func NewGui(
|
|||||||
RefreshingFilesMutex: &deadlock.Mutex{},
|
RefreshingFilesMutex: &deadlock.Mutex{},
|
||||||
RefreshingBranchesMutex: &deadlock.Mutex{},
|
RefreshingBranchesMutex: &deadlock.Mutex{},
|
||||||
RefreshingStatusMutex: &deadlock.Mutex{},
|
RefreshingStatusMutex: &deadlock.Mutex{},
|
||||||
SyncMutex: &deadlock.Mutex{},
|
|
||||||
LocalCommitsMutex: &deadlock.Mutex{},
|
LocalCommitsMutex: &deadlock.Mutex{},
|
||||||
SubCommitsMutex: &deadlock.Mutex{},
|
SubCommitsMutex: &deadlock.Mutex{},
|
||||||
AuthorsMutex: &deadlock.Mutex{},
|
AuthorsMutex: &deadlock.Mutex{},
|
||||||
@ -473,6 +498,9 @@ func NewGui(
|
|||||||
},
|
},
|
||||||
InitialDir: initialDir,
|
InitialDir: initialDir,
|
||||||
afterLayoutFuncs: make(chan func() error, 1000),
|
afterLayoutFuncs: make(chan func() error, 1000),
|
||||||
|
|
||||||
|
itemOperations: make(map[string]types.ItemOperation),
|
||||||
|
itemOperationsMutex: &deadlock.Mutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.PopupHandler = popup.NewPopupHandler(
|
gui.PopupHandler = popup.NewPopupHandler(
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -199,3 +200,8 @@ func (self *guiCommon) RunningIntegrationTest() bool {
|
|||||||
func (self *guiCommon) InDemo() bool {
|
func (self *guiCommon) InDemo() bool {
|
||||||
return self.gui.integrationTest != nil && self.gui.integrationTest.IsDemo()
|
return self.gui.integrationTest != nil && self.gui.integrationTest.IsDemo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *guiCommon) WithInlineStatus(item types.HasUrn, operation types.ItemOperation, contextKey types.ContextKey, f func(gocui.Task) error) error {
|
||||||
|
self.gui.helpers.InlineStatus.WithInlineStatus(helpers.InlineStatusOpts{Item: item, Operation: operation, ContextKey: contextKey}, f)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
@ -19,6 +20,7 @@ var branchPrefixColorCache = make(map[string]style.TextStyle)
|
|||||||
|
|
||||||
func GetBranchListDisplayStrings(
|
func GetBranchListDisplayStrings(
|
||||||
branches []*models.Branch,
|
branches []*models.Branch,
|
||||||
|
getItemOperation func(item types.HasUrn) types.ItemOperation,
|
||||||
fullDescription bool,
|
fullDescription bool,
|
||||||
diffName string,
|
diffName string,
|
||||||
tr *i18n.TranslationSet,
|
tr *i18n.TranslationSet,
|
||||||
@ -27,13 +29,14 @@ func GetBranchListDisplayStrings(
|
|||||||
) [][]string {
|
) [][]string {
|
||||||
return lo.Map(branches, func(branch *models.Branch, _ int) []string {
|
return lo.Map(branches, func(branch *models.Branch, _ int) []string {
|
||||||
diffed := branch.Name == diffName
|
diffed := branch.Name == diffName
|
||||||
return getBranchDisplayStrings(branch, fullDescription, diffed, tr, userConfig, worktrees)
|
return getBranchDisplayStrings(branch, getItemOperation(branch), fullDescription, diffed, tr, userConfig, worktrees)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getBranchDisplayStrings returns the display string of branch
|
// getBranchDisplayStrings returns the display string of branch
|
||||||
func getBranchDisplayStrings(
|
func getBranchDisplayStrings(
|
||||||
b *models.Branch,
|
b *models.Branch,
|
||||||
|
itemOperation types.ItemOperation,
|
||||||
fullDescription bool,
|
fullDescription bool,
|
||||||
diffed bool,
|
diffed bool,
|
||||||
tr *i18n.TranslationSet,
|
tr *i18n.TranslationSet,
|
||||||
@ -51,7 +54,7 @@ func getBranchDisplayStrings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
coloredName := nameTextStyle.Sprint(displayName)
|
coloredName := nameTextStyle.Sprint(displayName)
|
||||||
branchStatus := utils.WithPadding(ColoredBranchStatus(b, tr), 2, utils.AlignLeft)
|
branchStatus := utils.WithPadding(ColoredBranchStatus(b, itemOperation, tr), 2, utils.AlignLeft)
|
||||||
if git_commands.CheckedOutByOtherWorktree(b, worktrees) {
|
if git_commands.CheckedOutByOtherWorktree(b, worktrees) {
|
||||||
worktreeIcon := lo.Ternary(icons.IsIconEnabled(), icons.LINKED_WORKTREE_ICON, fmt.Sprintf("(%s)", tr.LcWorktree))
|
worktreeIcon := lo.Ternary(icons.IsIconEnabled(), icons.LINKED_WORKTREE_ICON, fmt.Sprintf("(%s)", tr.LcWorktree))
|
||||||
coloredName = fmt.Sprintf("%s %s", coloredName, style.FgDefault.Sprint(worktreeIcon))
|
coloredName = fmt.Sprintf("%s %s", coloredName, style.FgDefault.Sprint(worktreeIcon))
|
||||||
@ -109,9 +112,11 @@ func GetBranchTextStyle(name string) style.TextStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ColoredBranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string {
|
func ColoredBranchStatus(branch *models.Branch, itemOperation types.ItemOperation, tr *i18n.TranslationSet) string {
|
||||||
colour := style.FgYellow
|
colour := style.FgYellow
|
||||||
if branch.UpstreamGone {
|
if itemOperation != types.ItemOperationNone {
|
||||||
|
colour = style.FgCyan
|
||||||
|
} else if branch.UpstreamGone {
|
||||||
colour = style.FgRed
|
colour = style.FgRed
|
||||||
} else if branch.MatchesUpstream() {
|
} else if branch.MatchesUpstream() {
|
||||||
colour = style.FgGreen
|
colour = style.FgGreen
|
||||||
@ -119,10 +124,15 @@ func ColoredBranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string
|
|||||||
colour = style.FgMagenta
|
colour = style.FgMagenta
|
||||||
}
|
}
|
||||||
|
|
||||||
return colour.Sprint(BranchStatus(branch, tr))
|
return colour.Sprint(BranchStatus(branch, itemOperation, tr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func BranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string {
|
func BranchStatus(branch *models.Branch, itemOperation types.ItemOperation, tr *i18n.TranslationSet) string {
|
||||||
|
itemOperationStr := itemOperationToString(itemOperation, tr)
|
||||||
|
if itemOperationStr != "" {
|
||||||
|
return itemOperationStr + " " + utils.Loader()
|
||||||
|
}
|
||||||
|
|
||||||
if !branch.IsTrackingRemote() {
|
if !branch.IsTrackingRemote() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
23
pkg/gui/presentation/item_operations.go
Normal file
23
pkg/gui/presentation/item_operations.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package presentation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
func itemOperationToString(itemOperation types.ItemOperation, tr *i18n.TranslationSet) string {
|
||||||
|
switch itemOperation {
|
||||||
|
case types.ItemOperationNone:
|
||||||
|
return ""
|
||||||
|
case types.ItemOperationPushing:
|
||||||
|
return tr.PushingStatus
|
||||||
|
case types.ItemOperationPulling:
|
||||||
|
return tr.PullingStatus
|
||||||
|
case types.ItemOperationFastForwarding:
|
||||||
|
return tr.FastForwarding
|
||||||
|
case types.ItemOperationDeleting:
|
||||||
|
return tr.DeletingStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
@ -7,14 +7,15 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FormatStatus(repoName string, currentBranch *models.Branch, linkedWorktreeName string, workingTreeState enums.RebaseMode, tr *i18n.TranslationSet) string {
|
func FormatStatus(repoName string, currentBranch *models.Branch, itemOperation types.ItemOperation, linkedWorktreeName string, workingTreeState enums.RebaseMode, tr *i18n.TranslationSet) string {
|
||||||
status := ""
|
status := ""
|
||||||
|
|
||||||
if currentBranch.IsRealBranch() {
|
if currentBranch.IsRealBranch() {
|
||||||
status += ColoredBranchStatus(currentBranch, tr) + " "
|
status += ColoredBranchStatus(currentBranch, itemOperation, tr) + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
if workingTreeState != enums.REBASE_MODE_NONE {
|
if workingTreeState != enums.REBASE_MODE_NONE {
|
||||||
|
@ -4,19 +4,27 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetTagListDisplayStrings(tags []*models.Tag, diffName string) [][]string {
|
func GetTagListDisplayStrings(
|
||||||
|
tags []*models.Tag,
|
||||||
|
getItemOperation func(item types.HasUrn) types.ItemOperation,
|
||||||
|
diffName string,
|
||||||
|
tr *i18n.TranslationSet,
|
||||||
|
) [][]string {
|
||||||
return lo.Map(tags, func(tag *models.Tag, _ int) []string {
|
return lo.Map(tags, func(tag *models.Tag, _ int) []string {
|
||||||
diffed := tag.Name == diffName
|
diffed := tag.Name == diffName
|
||||||
return getTagDisplayStrings(tag, diffed)
|
return getTagDisplayStrings(tag, getItemOperation(tag), diffed, tr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTagDisplayStrings returns the display string of branch
|
// getTagDisplayStrings returns the display string of branch
|
||||||
func getTagDisplayStrings(t *models.Tag, diffed bool) []string {
|
func getTagDisplayStrings(t *models.Tag, itemOperation types.ItemOperation, diffed bool, tr *i18n.TranslationSet) []string {
|
||||||
textStyle := theme.DefaultTextColor
|
textStyle := theme.DefaultTextColor
|
||||||
if diffed {
|
if diffed {
|
||||||
textStyle = theme.DiffTerminalColor
|
textStyle = theme.DiffTerminalColor
|
||||||
@ -26,6 +34,11 @@ func getTagDisplayStrings(t *models.Tag, diffed bool) []string {
|
|||||||
res = append(res, textStyle.Sprint(icons.IconForTag(t)))
|
res = append(res, textStyle.Sprint(icons.IconForTag(t)))
|
||||||
}
|
}
|
||||||
descriptionColor := style.FgYellow
|
descriptionColor := style.FgYellow
|
||||||
res = append(res, textStyle.Sprint(t.Name), descriptionColor.Sprint(t.Description()))
|
descriptionStr := descriptionColor.Sprint(t.Description())
|
||||||
|
itemOperationStr := itemOperationToString(itemOperation, tr)
|
||||||
|
if itemOperationStr != "" {
|
||||||
|
descriptionStr = style.FgCyan.Sprint(itemOperationStr+" "+utils.Loader()) + " " + descriptionStr
|
||||||
|
}
|
||||||
|
res = append(res, textStyle.Sprint(t.Name), descriptionStr)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,12 @@ type IGuiCommon interface {
|
|||||||
// resized, if in accordion mode.
|
// resized, if in accordion mode.
|
||||||
AfterLayout(f func() error)
|
AfterLayout(f func() error)
|
||||||
|
|
||||||
|
// Wraps a function, attaching the given operation to the given item while
|
||||||
|
// the function is executing, and also causes the given context to be
|
||||||
|
// redrawn periodically. This allows the operation to be visualized with a
|
||||||
|
// spinning loader animation (e.g. when a branch is being pushed).
|
||||||
|
WithInlineStatus(item HasUrn, operation ItemOperation, contextKey ContextKey, f func(gocui.Task) error) error
|
||||||
|
|
||||||
// returns the gocui Gui struct. There is a good chance you don't actually want to use
|
// returns the gocui Gui struct. There is a good chance you don't actually want to use
|
||||||
// this struct and instead want to use another method above
|
// this struct and instead want to use another method above
|
||||||
GocuiGui() *gocui.Gui
|
GocuiGui() *gocui.Gui
|
||||||
@ -256,7 +262,6 @@ type Mutexes struct {
|
|||||||
RefreshingFilesMutex *deadlock.Mutex
|
RefreshingFilesMutex *deadlock.Mutex
|
||||||
RefreshingBranchesMutex *deadlock.Mutex
|
RefreshingBranchesMutex *deadlock.Mutex
|
||||||
RefreshingStatusMutex *deadlock.Mutex
|
RefreshingStatusMutex *deadlock.Mutex
|
||||||
SyncMutex *deadlock.Mutex
|
|
||||||
LocalCommitsMutex *deadlock.Mutex
|
LocalCommitsMutex *deadlock.Mutex
|
||||||
SubCommitsMutex *deadlock.Mutex
|
SubCommitsMutex *deadlock.Mutex
|
||||||
AuthorsMutex *deadlock.Mutex
|
AuthorsMutex *deadlock.Mutex
|
||||||
@ -265,6 +270,24 @@ type Mutexes struct {
|
|||||||
PtyMutex *deadlock.Mutex
|
PtyMutex *deadlock.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
const (
|
||||||
|
ItemOperationNone ItemOperation = iota
|
||||||
|
ItemOperationPushing
|
||||||
|
ItemOperationPulling
|
||||||
|
ItemOperationFastForwarding
|
||||||
|
ItemOperationDeleting
|
||||||
|
)
|
||||||
|
|
||||||
|
type HasUrn interface {
|
||||||
|
URN() string
|
||||||
|
}
|
||||||
|
|
||||||
type IStateAccessor interface {
|
type IStateAccessor interface {
|
||||||
GetRepoPathStack() *utils.StringStack
|
GetRepoPathStack() *utils.StringStack
|
||||||
GetRepoState() IRepoStateAccessor
|
GetRepoState() IRepoStateAccessor
|
||||||
@ -277,6 +300,9 @@ type IStateAccessor interface {
|
|||||||
SetShowExtrasWindow(bool)
|
SetShowExtrasWindow(bool)
|
||||||
GetRetainOriginalDir() bool
|
GetRetainOriginalDir() bool
|
||||||
SetRetainOriginalDir(bool)
|
SetRetainOriginalDir(bool)
|
||||||
|
GetItemOperation(item HasUrn) ItemOperation
|
||||||
|
SetItemOperation(item HasUrn, operation ItemOperation)
|
||||||
|
ClearItemOperation(item HasUrn)
|
||||||
}
|
}
|
||||||
|
|
||||||
type IRepoStateAccessor interface {
|
type IRepoStateAccessor interface {
|
||||||
|
@ -169,7 +169,7 @@ func chineseTranslationSet() TranslationSet {
|
|||||||
ToggleStagingPanel: `切换到其他面板`,
|
ToggleStagingPanel: `切换到其他面板`,
|
||||||
ReturnToFilesPanel: `返回文件面板`,
|
ReturnToFilesPanel: `返回文件面板`,
|
||||||
FastForward: `从上游快进此分支`,
|
FastForward: `从上游快进此分支`,
|
||||||
FastForwarding: "抓取并快进 {{.branch}} ...",
|
FastForwarding: "抓取并快进",
|
||||||
FoundConflictsTitle: "自动合并失败",
|
FoundConflictsTitle: "自动合并失败",
|
||||||
ViewMergeRebaseOptions: "查看 合并/变基 选项",
|
ViewMergeRebaseOptions: "查看 合并/变基 选项",
|
||||||
NotMergingOrRebasing: "您目前既不进行变基也不进行合并",
|
NotMergingOrRebasing: "您目前既不进行变基也不进行合并",
|
||||||
|
@ -134,7 +134,7 @@ func dutchTranslationSet() TranslationSet {
|
|||||||
ToggleStagingPanel: `Ga naar een ander paneel`,
|
ToggleStagingPanel: `Ga naar een ander paneel`,
|
||||||
ReturnToFilesPanel: `Ga terug naar het bestanden paneel`,
|
ReturnToFilesPanel: `Ga terug naar het bestanden paneel`,
|
||||||
FastForward: `Fast-forward deze branch vanaf zijn upstream`,
|
FastForward: `Fast-forward deze branch vanaf zijn upstream`,
|
||||||
FastForwarding: "Fast-forwarding {{.branch}} ...",
|
FastForwarding: "Fast-forwarding",
|
||||||
FoundConflictsTitle: "Conflicten!",
|
FoundConflictsTitle: "Conflicten!",
|
||||||
ViewMergeRebaseOptions: "Bekijk merge/rebase opties",
|
ViewMergeRebaseOptions: "Bekijk merge/rebase opties",
|
||||||
NotMergingOrRebasing: "Je bent momenteel niet aan het rebasen of mergen",
|
NotMergingOrRebasing: "Je bent momenteel niet aan het rebasen of mergen",
|
||||||
|
@ -57,6 +57,8 @@ type TranslationSet struct {
|
|||||||
ResetFilter string
|
ResetFilter string
|
||||||
MergeConflictsTitle string
|
MergeConflictsTitle string
|
||||||
Checkout string
|
Checkout string
|
||||||
|
CantCheckoutBranchWhilePulling string
|
||||||
|
CantPullOrPushSameBranchTwice string
|
||||||
NoChangedFiles string
|
NoChangedFiles string
|
||||||
SoftReset string
|
SoftReset string
|
||||||
AlreadyCheckedOutBranch string
|
AlreadyCheckedOutBranch string
|
||||||
@ -846,6 +848,8 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
Scroll: "Scroll",
|
Scroll: "Scroll",
|
||||||
MergeConflictsTitle: "Merge conflicts",
|
MergeConflictsTitle: "Merge conflicts",
|
||||||
Checkout: "Checkout",
|
Checkout: "Checkout",
|
||||||
|
CantCheckoutBranchWhilePulling: "You cannot checkout another branch while pulling the current branch",
|
||||||
|
CantPullOrPushSameBranchTwice: "You cannot push or pull a branch while it is already being pushed or pulled",
|
||||||
FileFilter: "Filter files by status",
|
FileFilter: "Filter files by status",
|
||||||
FilterStagedFiles: "Show only staged files",
|
FilterStagedFiles: "Show only staged files",
|
||||||
FilterUnstagedFiles: "Show only unstaged files",
|
FilterUnstagedFiles: "Show only unstaged files",
|
||||||
@ -980,7 +984,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
ToggleStagingPanel: `Switch to other panel (staged/unstaged changes)`,
|
ToggleStagingPanel: `Switch to other panel (staged/unstaged changes)`,
|
||||||
ReturnToFilesPanel: `Return to files panel`,
|
ReturnToFilesPanel: `Return to files panel`,
|
||||||
FastForward: `Fast-forward this branch from its upstream`,
|
FastForward: `Fast-forward this branch from its upstream`,
|
||||||
FastForwarding: "Fast-forwarding {{.branch}}",
|
FastForwarding: "Fast-forwarding",
|
||||||
FoundConflictsTitle: "Conflicts!",
|
FoundConflictsTitle: "Conflicts!",
|
||||||
ViewConflictsMenuItem: "View conflicts",
|
ViewConflictsMenuItem: "View conflicts",
|
||||||
AbortMenuItem: "Abort the %s",
|
AbortMenuItem: "Abort the %s",
|
||||||
|
@ -170,7 +170,7 @@ func koreanTranslationSet() TranslationSet {
|
|||||||
ToggleStagingPanel: `패널 전환`,
|
ToggleStagingPanel: `패널 전환`,
|
||||||
ReturnToFilesPanel: `파일 목록으로 돌아가기`,
|
ReturnToFilesPanel: `파일 목록으로 돌아가기`,
|
||||||
FastForward: `Fast-forward this branch from its upstream`,
|
FastForward: `Fast-forward this branch from its upstream`,
|
||||||
FastForwarding: "Fast-forwarding {{.branch}} ...",
|
FastForwarding: "Fast-forwarding",
|
||||||
FoundConflictsTitle: "Auto-merge failed",
|
FoundConflictsTitle: "Auto-merge failed",
|
||||||
ViewMergeRebaseOptions: "View merge/rebase options",
|
ViewMergeRebaseOptions: "View merge/rebase options",
|
||||||
NotMergingOrRebasing: "You are currently neither rebasing nor merging",
|
NotMergingOrRebasing: "You are currently neither rebasing nor merging",
|
||||||
|
@ -201,7 +201,7 @@ func RussianTranslationSet() TranslationSet {
|
|||||||
ToggleStagingPanel: `Переключиться на другую панель (проиндексированные/непроиндексированные изменения)`,
|
ToggleStagingPanel: `Переключиться на другую панель (проиндексированные/непроиндексированные изменения)`,
|
||||||
ReturnToFilesPanel: `Вернуться к панели файлов`,
|
ReturnToFilesPanel: `Вернуться к панели файлов`,
|
||||||
FastForward: `Перемотать эту ветку вперёд из её upstream-ветки`,
|
FastForward: `Перемотать эту ветку вперёд из её upstream-ветки`,
|
||||||
FastForwarding: "Получить изменения и перемотать вперёд {{.branch}} ...",
|
FastForwarding: "Получить изменения и перемотать вперёд",
|
||||||
FoundConflictsTitle: "Конфликты!",
|
FoundConflictsTitle: "Конфликты!",
|
||||||
ViewConflictsMenuItem: "Просмотр конфликтов",
|
ViewConflictsMenuItem: "Просмотр конфликтов",
|
||||||
AbortMenuItem: "Прервать %s",
|
AbortMenuItem: "Прервать %s",
|
||||||
|
@ -234,7 +234,7 @@ func traditionalChineseTranslationSet() TranslationSet {
|
|||||||
ToggleStagingPanel: `切換至另一個面板 (已預存/未預存更改)`,
|
ToggleStagingPanel: `切換至另一個面板 (已預存/未預存更改)`,
|
||||||
ReturnToFilesPanel: `返回檔案面板`,
|
ReturnToFilesPanel: `返回檔案面板`,
|
||||||
FastForward: `從上游快進此分支`,
|
FastForward: `從上游快進此分支`,
|
||||||
FastForwarding: "{{.branch}} 的擷取和快進中...",
|
FastForwarding: "的擷取和快進中",
|
||||||
FoundConflictsTitle: "自動合併失敗",
|
FoundConflictsTitle: "自動合併失敗",
|
||||||
ViewMergeRebaseOptions: "查看合併/變基選項",
|
ViewMergeRebaseOptions: "查看合併/變基選項",
|
||||||
NotMergingOrRebasing: "你當前既不在變基也不在合併中",
|
NotMergingOrRebasing: "你當前既不在變基也不在合併中",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user