1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-27 12:32:37 +02:00

clean up interface for popup panels

This commit is contained in:
Jesse Duffield 2020-08-15 16:36:39 +10:00
parent c44ee71ad4
commit d9fa02c53b
34 changed files with 674 additions and 396 deletions

View File

@ -66,7 +66,7 @@ func (gui *Gui) WithWaitingStatus(name string, f func() error) error {
if appStatus == "" { if appStatus == "" {
return return
} }
gui.renderString(gui.g, "appStatus", appStatus) gui.renderString("appStatus", appStatus)
} }
}() }()

View File

@ -125,7 +125,7 @@ func (gui *Gui) handleCreatePullRequestPress(g *gocui.Gui, v *gocui.View) error
} }
func (gui *Gui) handleGitFetch(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleGitFetch(g *gocui.Gui, v *gocui.View) error {
if err := gui.createLoaderPanel(gui.g, v, gui.Tr.SLocalize("FetchWait")); err != nil { if err := gui.createLoaderPanel(v, gui.Tr.SLocalize("FetchWait")); err != nil {
return err return err
} }
go func() { go func() {
@ -140,12 +140,19 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch() branch := gui.getSelectedBranch()
message := gui.Tr.SLocalize("SureForceCheckout") message := gui.Tr.SLocalize("SureForceCheckout")
title := gui.Tr.SLocalize("ForceCheckoutBranch") title := gui.Tr.SLocalize("ForceCheckoutBranch")
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: title,
prompt: message,
handleConfirm: func() error {
if err := gui.GitCommand.Checkout(branch.Name, commands.CheckoutOptions{Force: true}); err != nil { if err := gui.GitCommand.Checkout(branch.Name, commands.CheckoutOptions{Force: true}); err != nil {
_ = gui.surfaceError(err) _ = gui.surfaceError(err)
} }
return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
}, nil) },
})
} }
type handleCheckoutRefOptions struct { type handleCheckoutRefOptions struct {
@ -179,8 +186,12 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions)
if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") {
// offer to autostash changes // offer to autostash changes
return gui.createConfirmationPanel(gui.g, gui.getBranchesView(), true, gui.Tr.SLocalize("AutoStashTitle"), gui.Tr.SLocalize("AutoStashPrompt"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getBranchesView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("AutoStashTitle"),
prompt: gui.Tr.SLocalize("AutoStashPrompt"),
handleConfirm: func() error {
if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + ref); err != nil { if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + ref); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
@ -196,7 +207,8 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions)
return gui.surfaceError(err) return gui.surfaceError(err)
} }
return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI})
}, nil) },
})
} }
if err := gui.surfaceError(err); err != nil { if err := gui.surfaceError(err); err != nil {
@ -210,12 +222,19 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions)
} }
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("BranchName")+":", "", func(response string) error {
return gui.handleCheckoutRef(gui.trimmedContent(v), handleCheckoutRefOptions{ return gui.handleCheckoutRef(response, handleCheckoutRefOptions{
onRefNotFound: func(ref string) error { onRefNotFound: func(ref string) error {
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("BranchNotFoundTitle"), fmt.Sprintf("%s %s%s", gui.Tr.SLocalize("BranchNotFoundPrompt"), ref, "?"), func(_g *gocui.Gui, _v *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("BranchNotFoundTitle"),
prompt: fmt.Sprintf("%s %s%s", gui.Tr.SLocalize("BranchNotFoundPrompt"), ref, "?"),
handleConfirm: func() error {
return gui.createNewBranchWithName(ref) return gui.createNewBranchWithName(ref)
}, nil) },
})
}, },
}) })
}) })
@ -240,8 +259,8 @@ func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
"branchName": branch.Name, "branchName": branch.Name,
}, },
) )
return gui.createPromptPanel(g, v, message, "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, message, "", func(response string) error {
return gui.createNewBranchWithName(gui.trimmedContent(v)) return gui.createNewBranchWithName(response)
}) })
} }
@ -288,7 +307,13 @@ func (gui *Gui) deleteNamedBranch(g *gocui.Gui, v *gocui.View, selectedBranch *c
"selectedBranchName": selectedBranch.Name, "selectedBranchName": selectedBranch.Name,
}, },
) )
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: title,
prompt: message,
handleConfirm: func() error {
if err := gui.GitCommand.DeleteBranch(selectedBranch.Name, force); err != nil { if err := gui.GitCommand.DeleteBranch(selectedBranch.Name, force); err != nil {
errMessage := err.Error() errMessage := err.Error()
if !force && strings.Contains(errMessage, "is not fully merged") { if !force && strings.Contains(errMessage, "is not fully merged") {
@ -297,7 +322,8 @@ func (gui *Gui) deleteNamedBranch(g *gocui.Gui, v *gocui.View, selectedBranch *c
return gui.createErrorPanel(errMessage) return gui.createErrorPanel(errMessage)
} }
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}})
}, nil) },
})
} }
func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error {
@ -319,12 +345,17 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error {
"selectedBranch": branchName, "selectedBranch": branchName,
}, },
) )
return gui.createConfirmationPanel(gui.g, gui.getBranchesView(), true, gui.Tr.SLocalize("MergingTitle"), prompt,
func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getBranchesView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("MergingTitle"),
prompt: prompt,
handleConfirm: func() error {
err := gui.GitCommand.Merge(branchName, commands.MergeOpts{}) err := gui.GitCommand.Merge(branchName, commands.MergeOpts{})
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}, nil) },
})
} }
func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
@ -357,11 +388,17 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error {
"selectedBranch": selectedBranchName, "selectedBranch": selectedBranchName,
}, },
) )
return gui.createConfirmationPanel(gui.g, gui.getBranchesView(), true, gui.Tr.SLocalize("RebasingTitle"), prompt,
func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getBranchesView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("RebasingTitle"),
prompt: prompt,
handleConfirm: func() error {
err := gui.GitCommand.RebaseBranch(selectedBranchName) err := gui.GitCommand.RebaseBranch(selectedBranchName)
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}, nil) },
})
} }
func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
@ -396,7 +433,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
}, },
) )
go func() { go func() {
_ = gui.createLoaderPanel(gui.g, v, message) _ = gui.createLoaderPanel(v, message)
if gui.State.Panels.Branches.SelectedLine == 0 { if gui.State.Panels.Branches.SelectedLine == 0 {
_ = gui.pullWithMode("ff-only", PullFilesOptions{}) _ = gui.pullWithMode("ff-only", PullFilesOptions{})
@ -500,14 +537,13 @@ func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error {
// way to get it to show up in the reflog) // way to get it to show up in the reflog)
promptForNewName := func() error { promptForNewName := func() error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("NewBranchNamePrompt")+" "+branch.Name+":", "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("NewBranchNamePrompt")+" "+branch.Name+":", "", func(newBranchName string) error {
newName := gui.trimmedContent(v) if err := gui.GitCommand.RenameBranch(branch.Name, newBranchName); err != nil {
if err := gui.GitCommand.RenameBranch(branch.Name, newName); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
// need to checkout so that the branch shows up in our reflog and therefore // need to checkout so that the branch shows up in our reflog and therefore
// doesn't get lost among all the other branches when we switch to something else // doesn't get lost among all the other branches when we switch to something else
if err := gui.GitCommand.Checkout(newName, commands.CheckoutOptions{Force: false}); err != nil { if err := gui.GitCommand.Checkout(newBranchName, commands.CheckoutOptions{Force: false}); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
@ -522,9 +558,14 @@ func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error {
if notTrackingRemote { if notTrackingRemote {
return promptForNewName() return promptForNewName()
} }
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("renameBranch"), gui.Tr.SLocalize("RenameBranchWarning"), func(_g *gocui.Gui, _v *gocui.View) error {
return promptForNewName() return gui.createConfirmationPanel(createConfirmationPanelOpts{
}, nil) returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("renameBranch"),
prompt: gui.Tr.SLocalize("RenameBranchWarning"),
handleConfirm: promptForNewName,
})
} }
func (gui *Gui) currentBranch() *commands.Branch { func (gui *Gui) currentBranch() *commands.Branch {

View File

@ -36,7 +36,7 @@ func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
commitFile := gui.getSelectedCommitFile() commitFile := gui.getSelectedCommitFile()
if commitFile == nil { if commitFile == nil {
gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil return nil
} }
@ -57,7 +57,7 @@ func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
} }
func (gui *Gui) handleSwitchToCommitsPanel(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleSwitchToCommitsPanel(g *gocui.Gui, v *gocui.View) error {
return gui.switchFocus(g, v, gui.getCommitsView()) return gui.switchFocus(v, gui.getCommitsView())
} }
func (gui *Gui) handleCheckoutCommitFile(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCheckoutCommitFile(g *gocui.Gui, v *gocui.View) error {
@ -77,7 +77,12 @@ func (gui *Gui) handleDiscardOldFileChange(g *gocui.Gui, v *gocui.View) error {
fileName := gui.State.CommitFiles[gui.State.Panels.CommitFiles.SelectedLine].Name fileName := gui.State.CommitFiles[gui.State.Panels.CommitFiles.SelectedLine].Name
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("DiscardFileChangesTitle"), gui.Tr.SLocalize("DiscardFileChangesPrompt"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("DiscardFileChangesTitle"),
prompt: gui.Tr.SLocalize("DiscardFileChangesPrompt"),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("RebasingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("RebasingStatus"), func() error {
if err := gui.GitCommand.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, fileName); err != nil { if err := gui.GitCommand.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, fileName); err != nil {
if err := gui.handleGenericMergeCommandResult(err); err != nil { if err := gui.handleGenericMergeCommandResult(err); err != nil {
@ -87,7 +92,8 @@ func (gui *Gui) handleDiscardOldFileChange(g *gocui.Gui, v *gocui.View) error {
return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI})
}) })
}, nil) },
})
} }
func (gui *Gui) refreshCommitFilesView() error { func (gui *Gui) refreshCommitFilesView() error {
@ -144,7 +150,7 @@ func (gui *Gui) handleToggleFileForPatch(g *gocui.Gui, v *gocui.View) error {
commitFile := gui.getSelectedCommitFile() commitFile := gui.getSelectedCommitFile()
if commitFile == nil { if commitFile == nil {
gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil return nil
} }
@ -161,10 +167,16 @@ func (gui *Gui) handleToggleFileForPatch(g *gocui.Gui, v *gocui.View) error {
} }
if gui.GitCommand.PatchManager.CommitSelected() && gui.GitCommand.PatchManager.CommitSha != commitFile.Sha { if gui.GitCommand.PatchManager.CommitSelected() && gui.GitCommand.PatchManager.CommitSha != commitFile.Sha {
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("DiscardPatch"), gui.Tr.SLocalize("DiscardPatchConfirm"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("DiscardPatch"),
prompt: gui.Tr.SLocalize("DiscardPatchConfirm"),
handleConfirm: func() error {
gui.GitCommand.PatchManager.Reset() gui.GitCommand.PatchManager.Reset()
return toggleTheFile() return toggleTheFile()
}, nil) },
})
} }
return toggleTheFile() return toggleTheFile()
@ -200,7 +212,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
commitFile := gui.getSelectedCommitFile() commitFile := gui.getSelectedCommitFile()
if commitFile == nil { if commitFile == nil {
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil return nil
} }
@ -212,18 +224,25 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
} }
gui.changeMainViewsContext("patch-building") gui.changeMainViewsContext("patch-building")
if err := gui.switchFocus(gui.g, gui.getCommitFilesView(), gui.getMainView()); err != nil { if err := gui.switchFocus(gui.getCommitFilesView(), gui.getMainView()); err != nil {
return err return err
} }
return gui.refreshPatchBuildingPanel(selectedLineIdx) return gui.refreshPatchBuildingPanel(selectedLineIdx)
} }
if gui.GitCommand.PatchManager.CommitSelected() && gui.GitCommand.PatchManager.CommitSha != commitFile.Sha { if gui.GitCommand.PatchManager.CommitSelected() && gui.GitCommand.PatchManager.CommitSha != commitFile.Sha {
return gui.createConfirmationPanel(gui.g, gui.getCommitFilesView(), false, gui.Tr.SLocalize("DiscardPatch"), gui.Tr.SLocalize("DiscardPatchConfirm"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getCommitFilesView(),
returnFocusOnClose: false,
title: gui.Tr.SLocalize("DiscardPatch"),
prompt: gui.Tr.SLocalize("DiscardPatchConfirm"),
handleConfirm: func() error {
gui.GitCommand.PatchManager.Reset() gui.GitCommand.PatchManager.Reset()
return enterTheFile(selectedLineIdx) return enterTheFile(selectedLineIdx)
}, func(g *gocui.Gui, v *gocui.View) error { },
return gui.switchFocus(gui.g, nil, gui.getCommitFilesView()) handleClose: func() error {
return gui.switchFocus(nil, gui.getCommitFilesView())
},
}) })
} }

View File

@ -47,13 +47,13 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
_ = v.SetCursor(0, 0) _ = v.SetCursor(0, 0)
_ = v.SetOrigin(0, 0) _ = v.SetOrigin(0, 0)
_, _ = g.SetViewOnBottom("commitMessage") _, _ = g.SetViewOnBottom("commitMessage")
_ = gui.switchFocus(g, v, gui.getFilesView()) _ = gui.switchFocus(v, gui.getFilesView())
return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
} }
func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error {
_, _ = g.SetViewOnBottom("commitMessage") _, _ = g.SetViewOnBottom("commitMessage")
return gui.switchFocus(g, v, gui.getFilesView()) return gui.switchFocus(v, gui.getFilesView())
} }
func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
@ -69,7 +69,7 @@ func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
"keyBindNewLine": "tab", "keyBindNewLine": "tab",
}, },
) )
gui.renderString(g, "options", message) gui.renderString("options", message)
return nil return nil
} }

View File

@ -155,12 +155,18 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Squash"), gui.Tr.SLocalize("SureSquashThisCommit"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("Squash"),
prompt: gui.Tr.SLocalize("SureSquashThisCommit"),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "squash") err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "squash")
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}) })
}, nil) },
})
} }
func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
@ -180,12 +186,18 @@ func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Fixup"), gui.Tr.SLocalize("SureFixupThisCommit"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("Fixup"),
prompt: gui.Tr.SLocalize("SureFixupThisCommit"),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("FixingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("FixingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "fixup") err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "fixup")
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}) })
}, nil) },
})
} }
func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
@ -204,8 +216,8 @@ func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
if gui.State.Panels.Commits.SelectedLine != 0 { if gui.State.Panels.Commits.SelectedLine != 0 {
return gui.createErrorPanel(gui.Tr.SLocalize("OnlyRenameTopCommit")) return gui.createErrorPanel(gui.Tr.SLocalize("OnlyRenameTopCommit"))
} }
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("renameCommit"), "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("renameCommit"), "", func(response string) error {
if err := gui.GitCommand.RenameCommit(v.Buffer()); err != nil { if err := gui.GitCommand.RenameCommit(response); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
@ -276,12 +288,18 @@ func (gui *Gui) handleCommitDelete(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("DeleteCommitTitle"), gui.Tr.SLocalize("DeleteCommitPrompt"), func(*gocui.Gui, *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("DeleteCommitTitle"),
prompt: gui.Tr.SLocalize("DeleteCommitPrompt"),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("DeletingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("DeletingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "drop") err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "drop")
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}) })
}, nil) },
})
} }
func (gui *Gui) handleCommitMoveDown(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitMoveDown(g *gocui.Gui, v *gocui.View) error {
@ -362,12 +380,18 @@ func (gui *Gui) handleCommitAmendTo(g *gocui.Gui, v *gocui.View) error {
return err return err
} }
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("AmendCommitTitle"), gui.Tr.SLocalize("AmendCommitPrompt"), func(*gocui.Gui, *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("AmendCommitTitle"),
prompt: gui.Tr.SLocalize("AmendCommitPrompt"),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("AmendingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("AmendingStatus"), func() error {
err := gui.GitCommand.AmendTo(gui.State.Commits[gui.State.Panels.Commits.SelectedLine].Sha) err := gui.GitCommand.AmendTo(gui.State.Commits[gui.State.Panels.Commits.SelectedLine].Sha)
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}) })
}, nil) },
})
} }
func (gui *Gui) handleCommitPick(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCommitPick(g *gocui.Gui, v *gocui.View) error {
@ -474,12 +498,18 @@ func (gui *Gui) HandlePasteCommits(g *gocui.Gui, v *gocui.View) error {
return err return err
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("CherryPick"), gui.Tr.SLocalize("SureCherryPick"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("CherryPick"),
prompt: gui.Tr.SLocalize("SureCherryPick"),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("CherryPickingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("CherryPickingStatus"), func() error {
err := gui.GitCommand.CherryPickCommits(gui.State.CherryPickedCommits) err := gui.GitCommand.CherryPickCommits(gui.State.CherryPickedCommits)
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}) })
}, nil) },
})
} }
func (gui *Gui) handleSwitchToCommitFilesPanel(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleSwitchToCommitFilesPanel(g *gocui.Gui, v *gocui.View) error {
@ -487,7 +517,7 @@ func (gui *Gui) handleSwitchToCommitFilesPanel(g *gocui.Gui, v *gocui.View) erro
return err return err
} }
return gui.switchFocus(g, gui.getCommitsView(), gui.getCommitFilesView()) return gui.switchFocus(gui.getCommitsView(), gui.getCommitFilesView())
} }
func (gui *Gui) hasCommit(commits []*commands.Commit, target string) (int, bool) { func (gui *Gui) hasCommit(commits []*commands.Commit, target string) (int, bool) {
@ -513,18 +543,24 @@ func (gui *Gui) handleCreateFixupCommit(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("CreateFixupCommit"), gui.Tr.TemplateLocalize( return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("CreateFixupCommit"),
prompt: gui.Tr.TemplateLocalize(
"SureCreateFixupCommit", "SureCreateFixupCommit",
Teml{ Teml{
"commit": commit.Sha, "commit": commit.Sha,
}, },
), func(g *gocui.Gui, v *gocui.View) error { ),
handleConfirm: func() error {
if err := gui.GitCommand.CreateFixupCommit(commit.Sha); err != nil { if err := gui.GitCommand.CreateFixupCommit(commit.Sha); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
}, nil) },
})
} }
func (gui *Gui) handleSquashAllAboveFixupCommits(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleSquashAllAboveFixupCommits(g *gocui.Gui, v *gocui.View) error {
@ -537,17 +573,23 @@ func (gui *Gui) handleSquashAllAboveFixupCommits(g *gocui.Gui, v *gocui.View) er
return nil return nil
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("SquashAboveCommits"), gui.Tr.TemplateLocalize( return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("SquashAboveCommits"),
prompt: gui.Tr.TemplateLocalize(
"SureSquashAboveCommits", "SureSquashAboveCommits",
Teml{ Teml{
"commit": commit.Sha, "commit": commit.Sha,
}, },
), func(g *gocui.Gui, v *gocui.View) error { ),
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error {
err := gui.GitCommand.SquashAllAboveFixupCommits(commit.Sha) err := gui.GitCommand.SquashAllAboveFixupCommits(commit.Sha)
return gui.handleGenericMergeCommandResult(err) return gui.handleGenericMergeCommandResult(err)
}) })
}, nil) },
})
} }
func (gui *Gui) handleTagCommit(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleTagCommit(g *gocui.Gui, v *gocui.View) error {
@ -563,8 +605,8 @@ func (gui *Gui) handleTagCommit(g *gocui.Gui, v *gocui.View) error {
} }
func (gui *Gui) handleCreateLightweightTag(commitSha string) error { func (gui *Gui) handleCreateLightweightTag(commitSha string) error {
return gui.createPromptPanel(gui.g, gui.getCommitsView(), gui.Tr.SLocalize("TagNameTitle"), "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(gui.getCommitsView(), gui.Tr.SLocalize("TagNameTitle"), "", func(response string) error {
if err := gui.GitCommand.CreateLightweightTag(v.Buffer(), commitSha); err != nil { if err := gui.GitCommand.CreateLightweightTag(response, commitSha); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}})
@ -577,9 +619,15 @@ func (gui *Gui) handleCheckoutCommit(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
return gui.createConfirmationPanel(g, gui.getCommitsView(), true, gui.Tr.SLocalize("checkoutCommit"), gui.Tr.SLocalize("SureCheckoutThisCommit"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getCommitsView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("checkoutCommit"),
prompt: gui.Tr.SLocalize("SureCheckoutThisCommit"),
handleConfirm: func() error {
return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{})
}, nil) },
})
} }
func (gui *Gui) renderBranchCommitsWithSelection() error { func (gui *Gui) renderBranchCommitsWithSelection() error {

View File

@ -15,11 +15,76 @@ import (
"github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/theme"
) )
func (gui *Gui) wrappedConfirmationFunction(function func(*gocui.Gui, *gocui.View) error, returnFocusOnClose bool) func(*gocui.Gui, *gocui.View) error { type createPopupPanelOpts struct {
returnToView *gocui.View
hasLoader bool
returnFocusOnClose bool
editable bool
title string
prompt string
handleConfirm func() error
handleConfirmPrompt func(string) error
handleClose func() error
}
type createConfirmationPanelOpts struct {
returnToView *gocui.View
returnFocusOnClose bool
title string
prompt string
handleConfirm func() error
handleClose func() error
}
func (gui *Gui) createLoaderPanel(currentView *gocui.View, prompt string) error {
return gui.createPopupPanel(createPopupPanelOpts{
returnToView: currentView,
prompt: prompt,
hasLoader: true,
returnFocusOnClose: true,
})
}
func (gui *Gui) createConfirmationPanel(opts createConfirmationPanelOpts) error {
return gui.createPopupPanel(createPopupPanelOpts{
returnToView: opts.returnToView,
title: opts.title,
prompt: opts.prompt,
returnFocusOnClose: opts.returnFocusOnClose,
handleConfirm: opts.handleConfirm,
handleClose: opts.handleClose,
})
}
func (gui *Gui) createPromptPanel(currentView *gocui.View, title string, initialContent string, handleConfirm func(string) error) error {
return gui.createPopupPanel(createPopupPanelOpts{
returnToView: currentView,
title: title,
prompt: initialContent,
returnFocusOnClose: true,
editable: true,
handleConfirmPrompt: handleConfirm,
})
}
func (gui *Gui) wrappedConfirmationFunction(function func() error, returnFocusOnClose bool) func(*gocui.Gui, *gocui.View) error {
return func(g *gocui.Gui, v *gocui.View) error { return func(g *gocui.Gui, v *gocui.View) error {
if function != nil { if function != nil {
if err := function(g, v); err != nil { if err := function(); err != nil {
return err
}
}
return gui.closeConfirmationPrompt(g, returnFocusOnClose)
}
}
func (gui *Gui) wrappedPromptConfirmationFunction(function func(string) error, returnFocusOnClose bool) func(*gocui.Gui, *gocui.View) error {
return func(g *gocui.Gui, v *gocui.View) error {
if function != nil {
if err := function(v.Buffer()); err != nil {
return err return err
} }
} }
@ -96,7 +161,7 @@ func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt
confirmationView.FgColor = theme.GocuiDefaultTextColor confirmationView.FgColor = theme.GocuiDefaultTextColor
} }
gui.g.Update(func(g *gocui.Gui) error { gui.g.Update(func(g *gocui.Gui) error {
return gui.switchFocus(gui.g, currentView, confirmationView) return gui.switchFocus(currentView, confirmationView)
}) })
return confirmationView, nil return confirmationView, nil
} }
@ -110,21 +175,21 @@ func (gui *Gui) onNewPopupPanel() {
} }
} }
func (gui *Gui) createPopupPanel(g *gocui.Gui, currentView *gocui.View, title, prompt string, hasLoader bool, returnFocusOnClose bool, editable bool, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error { func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error {
gui.onNewPopupPanel() gui.onNewPopupPanel()
g.Update(func(g *gocui.Gui) error { gui.g.Update(func(g *gocui.Gui) error {
// delete the existing confirmation panel if it exists // delete the existing confirmation panel if it exists
if view, _ := g.View("confirmation"); view != nil { if view, _ := g.View("confirmation"); view != nil {
if err := gui.closeConfirmationPrompt(g, true); err != nil { if err := gui.closeConfirmationPrompt(g, true); err != nil {
gui.Log.Error(err) gui.Log.Error(err)
} }
} }
confirmationView, err := gui.prepareConfirmationPanel(currentView, title, prompt, hasLoader) confirmationView, err := gui.prepareConfirmationPanel(opts.returnToView, opts.title, opts.prompt, opts.hasLoader)
if err != nil { if err != nil {
return err return err
} }
confirmationView.Editable = editable confirmationView.Editable = opts.editable
if editable { if opts.editable {
go func() { go func() {
// TODO: remove this wait (right now if you remove it the EditGotoToEndOfLine method doesn't seem to work) // TODO: remove this wait (right now if you remove it the EditGotoToEndOfLine method doesn't seem to work)
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
@ -135,26 +200,13 @@ func (gui *Gui) createPopupPanel(g *gocui.Gui, currentView *gocui.View, title, p
}() }()
} }
gui.renderString(g, "confirmation", prompt) gui.renderString("confirmation", opts.prompt)
return gui.setKeyBindings(g, handleConfirm, handleClose, returnFocusOnClose) return gui.setKeyBindings(opts)
}) })
return nil return nil
} }
func (gui *Gui) createLoaderPanel(g *gocui.Gui, currentView *gocui.View, prompt string) error { func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error {
return gui.createPopupPanel(g, currentView, "", prompt, true, true, false, nil, nil)
}
// it is very important that within this function we never include the original prompt in any error messages, because it may contain e.g. a user password
func (gui *Gui) createConfirmationPanel(g *gocui.Gui, currentView *gocui.View, returnFocusOnClose bool, title, prompt string, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error {
return gui.createPopupPanel(g, currentView, title, prompt, false, returnFocusOnClose, false, handleConfirm, handleClose)
}
func (gui *Gui) createPromptPanel(g *gocui.Gui, currentView *gocui.View, title string, initialContent string, handleConfirm func(*gocui.Gui, *gocui.View) error) error {
return gui.createPopupPanel(gui.g, currentView, title, initialContent, false, true, true, handleConfirm, nil)
}
func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error, returnFocusOnClose bool) error {
actions := gui.Tr.TemplateLocalize( actions := gui.Tr.TemplateLocalize(
"CloseConfirm", "CloseConfirm",
Teml{ Teml{
@ -163,40 +215,33 @@ func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*go
}, },
) )
gui.renderString(g, "options", actions) gui.renderString("options", actions)
if err := g.SetKeybinding("confirmation", nil, gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(handleConfirm, returnFocusOnClose)); err != nil { if opts.handleConfirmPrompt != nil {
if err := gui.g.SetKeybinding("confirmation", nil, gocui.KeyEnter, gocui.ModNone, gui.wrappedPromptConfirmationFunction(opts.handleConfirmPrompt, opts.returnFocusOnClose)); err != nil {
return err
}
} else {
if err := gui.g.SetKeybinding("confirmation", nil, gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(opts.handleConfirm, opts.returnFocusOnClose)); err != nil {
return err return err
} }
return g.SetKeybinding("confirmation", nil, gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(handleClose, returnFocusOnClose))
} }
// createSpecificErrorPanel allows you to create an error popup, specifying the return gui.g.SetKeybinding("confirmation", nil, gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(opts.handleClose, opts.returnFocusOnClose))
// view to be focused when the user closes the popup, and a boolean specifying
// whether we will log the error. If the message may include a user password,
// this function is to be used over the more generic createErrorPanel, with
// willLog set to false
func (gui *Gui) createSpecificErrorPanel(message string, nextView *gocui.View, willLog bool) error {
if willLog {
go func() {
// when reporting is switched on this log call sometimes introduces
// a delay on the error panel popping up. Here I'm adding a second wait
// so that the error is logged while the user is reading the error message
time.Sleep(time.Second)
gui.Log.Error(message)
}()
} }
func (gui *Gui) createErrorPanel(message string) error {
colorFunction := color.New(color.FgRed).SprintFunc() colorFunction := color.New(color.FgRed).SprintFunc()
coloredMessage := colorFunction(strings.TrimSpace(message)) coloredMessage := colorFunction(strings.TrimSpace(message))
if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil {
return err return err
} }
return gui.createConfirmationPanel(gui.g, nextView, true, gui.Tr.SLocalize("Error"), coloredMessage, nil, nil) return gui.createConfirmationPanel(createConfirmationPanelOpts{
} returnToView: gui.g.CurrentView(),
title: gui.Tr.SLocalize("Error"),
func (gui *Gui) createErrorPanel(message string) error { prompt: coloredMessage,
return gui.createSpecificErrorPanel(message, gui.g.CurrentView(), true) returnFocusOnClose: true,
})
} }
func (gui *Gui) surfaceError(err error) error { func (gui *Gui) surfaceError(err error) error {

View File

@ -20,7 +20,7 @@ func (gui *Gui) promptUserForCredential(passOrUname string) string {
credentialsView.Title = gui.Tr.SLocalize("CredentialsPassword") credentialsView.Title = gui.Tr.SLocalize("CredentialsPassword")
credentialsView.Mask = '*' credentialsView.Mask = '*'
} }
err := gui.switchFocus(g, gui.g.CurrentView(), credentialsView) err := gui.switchFocus(gui.g.CurrentView(), credentialsView)
if err != nil { if err != nil {
return err return err
} }
@ -43,7 +43,7 @@ func (gui *Gui) handleSubmitCredential(g *gocui.Gui, v *gocui.View) error {
if err != nil { if err != nil {
nextView = gui.getFilesView() nextView = gui.getFilesView()
} }
err = gui.switchFocus(g, nil, nextView) err = gui.switchFocus(nil, nextView)
if err != nil { if err != nil {
return err return err
} }
@ -57,7 +57,7 @@ func (gui *Gui) handleCloseCredentialsView(g *gocui.Gui, v *gocui.View) error {
} }
gui.credentials <- "" gui.credentials <- ""
return gui.switchFocus(g, nil, gui.getFilesView()) return gui.switchFocus(nil, gui.getFilesView())
} }
func (gui *Gui) handleCredentialsViewFocused(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCredentialsViewFocused(g *gocui.Gui, v *gocui.View) error {
@ -72,7 +72,7 @@ func (gui *Gui) handleCredentialsViewFocused(g *gocui.Gui, v *gocui.View) error
"keyBindConfirm": "enter", "keyBindConfirm": "enter",
}, },
) )
gui.renderString(g, "options", message) gui.renderString("options", message)
return nil return nil
} }
@ -85,7 +85,7 @@ func (gui *Gui) handleCredentialsPopup(cmdErr error) {
errMessage = gui.Tr.SLocalize("PassUnameWrong") errMessage = gui.Tr.SLocalize("PassUnameWrong")
} }
// we are not logging this error because it may contain a password // we are not logging this error because it may contain a password
_ = gui.createSpecificErrorPanel(errMessage, gui.getFilesView(), false) gui.createErrorPanel(errMessage)
} else { } else {
_ = gui.closeConfirmationPrompt(gui.g, true) _ = gui.closeConfirmationPrompt(gui.g, true)
} }

View File

@ -150,8 +150,8 @@ func (gui *Gui) handleCreateDiffingMenuPanel(g *gocui.Gui, v *gocui.View) error
{ {
displayString: gui.Tr.SLocalize("enterRefToDiff"), displayString: gui.Tr.SLocalize("enterRefToDiff"),
onPress: func() error { onPress: func() error {
return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("enteRefName"), "", func(g *gocui.Gui, promptView *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("enteRefName"), "", func(response string) error {
gui.State.Diff.Ref = strings.TrimSpace(promptView.Buffer()) gui.State.Diff.Ref = strings.TrimSpace(response)
return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
}) })
}, },

View File

@ -172,7 +172,7 @@ func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error
return gui.createErrorPanel(gui.Tr.SLocalize("FileStagingRequirements")) return gui.createErrorPanel(gui.Tr.SLocalize("FileStagingRequirements"))
} }
gui.changeMainViewsContext("staging") gui.changeMainViewsContext("staging")
if err := gui.switchFocus(gui.g, gui.getFilesView(), gui.getMainView()); err != nil { if err := gui.switchFocus(gui.getFilesView(), gui.getMainView()); err != nil {
return err return err
} }
return gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx) return gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx)
@ -249,9 +249,12 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
} }
if file.Tracked { if file.Tracked {
return gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), true, gui.Tr.SLocalize("IgnoreTracked"), gui.Tr.SLocalize("IgnoreTrackedPrompt"), return gui.createConfirmationPanel(createConfirmationPanelOpts{
// On confirmation returnToView: gui.g.CurrentView(),
func(_ *gocui.Gui, _ *gocui.View) error { returnFocusOnClose: true,
title: gui.Tr.SLocalize("IgnoreTracked"),
prompt: gui.Tr.SLocalize("IgnoreTrackedPrompt"),
handleConfirm: func() error {
if err := gui.GitCommand.Ignore(file.Name); err != nil { if err := gui.GitCommand.Ignore(file.Name); err != nil {
return err return err
} }
@ -259,7 +262,8 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
return err return err
} }
return gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}) return gui.refreshSidePanels(refreshOptions{scope: []int{FILES}})
}, nil) },
})
} }
if err := gui.GitCommand.Ignore(file.Name); err != nil { if err := gui.GitCommand.Ignore(file.Name); err != nil {
@ -275,7 +279,7 @@ func (gui *Gui) handleWIPCommitPress(g *gocui.Gui, filesView *gocui.View) error
return gui.createErrorPanel(gui.Tr.SLocalize("SkipHookPrefixNotConfigured")) return gui.createErrorPanel(gui.Tr.SLocalize("SkipHookPrefixNotConfigured"))
} }
gui.renderString(g, "commitMessage", skipHookPreifx) gui.renderString("commitMessage", skipHookPreifx)
if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil { if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil {
return err return err
} }
@ -299,7 +303,7 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
return gui.createErrorPanel(fmt.Sprintf("%s: %s", gui.Tr.SLocalize("commitPrefixPatternError"), err.Error())) return gui.createErrorPanel(fmt.Sprintf("%s: %s", gui.Tr.SLocalize("commitPrefixPatternError"), err.Error()))
} }
prefix := rgx.ReplaceAllString(gui.getCheckedOutBranch().Name, prefixReplace) prefix := rgx.ReplaceAllString(gui.getCheckedOutBranch().Name, prefixReplace)
gui.renderString(g, "commitMessage", prefix) gui.renderString("commitMessage", prefix)
if err := commitMessageView.SetCursor(len(prefix), 0); err != nil { if err := commitMessageView.SetCursor(len(prefix), 0); err != nil {
return err return err
} }
@ -310,7 +314,7 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
return err return err
} }
if err := gui.switchFocus(g, filesView, commitMessageView); err != nil { if err := gui.switchFocus(filesView, commitMessageView); err != nil {
return err return err
} }
@ -321,9 +325,12 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
} }
func (gui *Gui) promptToStageAllAndRetry(retry func() error) error { func (gui *Gui) promptToStageAllAndRetry(retry func() error) error {
return gui.createConfirmationPanel( return gui.createConfirmationPanel(createConfirmationPanelOpts{
gui.g, gui.getFilesView(), true, gui.Tr.SLocalize("NoFilesStagedTitle"), gui.Tr.SLocalize("NoFilesStagedPrompt"), returnToView: gui.getFilesView(),
func(*gocui.Gui, *gocui.View) error { returnFocusOnClose: true,
title: gui.Tr.SLocalize("NoFilesStagedTitle"),
prompt: gui.Tr.SLocalize("NoFilesStagedPrompt"),
handleConfirm: func() error {
if err := gui.GitCommand.StageAll(); err != nil { if err := gui.GitCommand.StageAll(); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
@ -332,7 +339,8 @@ func (gui *Gui) promptToStageAllAndRetry(retry func() error) error {
} }
return retry() return retry()
}, nil) },
})
} }
func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) error { func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) error {
@ -346,10 +354,12 @@ func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) erro
return gui.createErrorPanel(gui.Tr.SLocalize("NoCommitToAmend")) return gui.createErrorPanel(gui.Tr.SLocalize("NoCommitToAmend"))
} }
title := strings.Title(gui.Tr.SLocalize("AmendLastCommit")) return gui.createConfirmationPanel(createConfirmationPanelOpts{
question := gui.Tr.SLocalize("SureToAmend") returnToView: filesView,
returnFocusOnClose: true,
return gui.createConfirmationPanel(g, filesView, true, title, question, func(g *gocui.Gui, v *gocui.View) error { title: strings.Title(gui.Tr.SLocalize("AmendLastCommit")),
prompt: gui.Tr.SLocalize("SureToAmend"),
handleConfirm: func() error {
ok, err := gui.runSyncOrAsyncCommand(gui.GitCommand.AmendHead()) ok, err := gui.runSyncOrAsyncCommand(gui.GitCommand.AmendHead())
if err != nil { if err != nil {
return err return err
@ -359,7 +369,8 @@ func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) erro
} }
return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC})
}, nil) },
})
} }
// handleCommitEditorPress - handle when the user wants to commit changes via // handleCommitEditorPress - handle when the user wants to commit changes via
@ -450,8 +461,7 @@ func (gui *Gui) handlePullFiles(g *gocui.Gui, v *gocui.View) error {
} }
} }
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranch.Name, func(upstream string) error {
upstream := gui.trimmedContent(v)
if err := gui.GitCommand.SetUpstreamBranch(upstream); err != nil { if err := gui.GitCommand.SetUpstreamBranch(upstream); err != nil {
errorMessage := err.Error() errorMessage := err.Error()
if strings.Contains(errorMessage, "does not exist") { if strings.Contains(errorMessage, "does not exist") {
@ -472,7 +482,7 @@ type PullFilesOptions struct {
} }
func (gui *Gui) pullFiles(opts PullFilesOptions) error { func (gui *Gui) pullFiles(opts PullFilesOptions) error {
if err := gui.createLoaderPanel(gui.g, gui.g.CurrentView(), gui.Tr.SLocalize("PullWait")); err != nil { if err := gui.createLoaderPanel(gui.g.CurrentView(), gui.Tr.SLocalize("PullWait")); err != nil {
return err return err
} }
@ -512,16 +522,22 @@ func (gui *Gui) pullWithMode(mode string, opts PullFilesOptions) error {
} }
func (gui *Gui) pushWithForceFlag(g *gocui.Gui, v *gocui.View, force bool, upstream string, args string) error { func (gui *Gui) pushWithForceFlag(g *gocui.Gui, v *gocui.View, force bool, upstream string, args string) error {
if err := gui.createLoaderPanel(gui.g, v, gui.Tr.SLocalize("PushWait")); err != nil { if err := gui.createLoaderPanel(v, gui.Tr.SLocalize("PushWait")); err != nil {
return err return err
} }
go func() { go func() {
branchName := gui.getCheckedOutBranch().Name branchName := gui.getCheckedOutBranch().Name
err := gui.GitCommand.Push(branchName, force, upstream, args, gui.promptUserForCredential) err := gui.GitCommand.Push(branchName, force, upstream, args, gui.promptUserForCredential)
if err != nil && !force && strings.Contains(err.Error(), "Updates were rejected") { if err != nil && !force && strings.Contains(err.Error(), "Updates were rejected") {
gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("ForcePush"), gui.Tr.SLocalize("ForcePushPrompt"), func(g *gocui.Gui, v *gocui.View) error { gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("ForcePush"),
prompt: gui.Tr.SLocalize("ForcePushPrompt"),
handleConfirm: func() error {
return gui.pushWithForceFlag(gui.g, v, true, upstream, args) return gui.pushWithForceFlag(gui.g, v, true, upstream, args)
}, nil) },
})
return return
} }
@ -550,16 +566,23 @@ func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error {
if gui.GitCommand.PushToCurrent { if gui.GitCommand.PushToCurrent {
return gui.pushWithForceFlag(g, v, false, "", "--set-upstream") return gui.pushWithForceFlag(g, v, false, "", "--set-upstream")
} else { } else {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranch.Name, func(response string) error {
return gui.pushWithForceFlag(g, v, false, gui.trimmedContent(v), "") return gui.pushWithForceFlag(g, v, false, response, "")
}) })
} }
} else if currentBranch.Pullables == "0" { } else if currentBranch.Pullables == "0" {
return gui.pushWithForceFlag(g, v, false, "", "") return gui.pushWithForceFlag(g, v, false, "", "")
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("ForcePush"), gui.Tr.SLocalize("ForcePushPrompt"), func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("ForcePush"),
prompt: gui.Tr.SLocalize("ForcePushPrompt"),
handleConfirm: func() error {
return gui.pushWithForceFlag(g, v, true, "", "") return gui.pushWithForceFlag(g, v, true, "", "")
}, nil) },
})
} }
func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
@ -574,7 +597,7 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
return gui.createErrorPanel(gui.Tr.SLocalize("FileNoMergeCons")) return gui.createErrorPanel(gui.Tr.SLocalize("FileNoMergeCons"))
} }
gui.changeMainViewsContext("merging") gui.changeMainViewsContext("merging")
if err := gui.switchFocus(g, v, gui.getMainView()); err != nil { if err := gui.switchFocus(v, gui.getMainView()); err != nil {
return err return err
} }
return gui.refreshMergePanel() return gui.refreshMergePanel()
@ -597,8 +620,7 @@ func (gui *Gui) anyFilesWithMergeConflicts() bool {
} }
func (gui *Gui) handleCustomCommand(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCustomCommand(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("CustomCommand"), "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("CustomCommand"), "", func(command string) error {
command := gui.trimmedContent(v)
gui.SubProcess = gui.OSCommand.RunCustomCommand(command) gui.SubProcess = gui.OSCommand.RunCustomCommand(command)
return gui.Errors.ErrSubProcess return gui.Errors.ErrSubProcess
}) })

View File

@ -1,16 +1,22 @@
package gui package gui
import "github.com/jesseduffield/gocui"
func (gui *Gui) inFilterMode() bool { func (gui *Gui) inFilterMode() bool {
return gui.State.FilterPath != "" return gui.State.FilterPath != ""
} }
func (gui *Gui) validateNotInFilterMode() (bool, error) { func (gui *Gui) validateNotInFilterMode() (bool, error) {
if gui.inFilterMode() { if gui.inFilterMode() {
return false, gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), true, gui.Tr.SLocalize("MustExitFilterModeTitle"), gui.Tr.SLocalize("MustExitFilterModePrompt"), func(*gocui.Gui, *gocui.View) error { err := gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.g.CurrentView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("MustExitFilterModeTitle"),
prompt: gui.Tr.SLocalize("MustExitFilterModePrompt"),
handleConfirm: func() error {
return gui.exitFilterMode() return gui.exitFilterMode()
}, nil) },
})
return false, err
} }
return true, nil return true, nil
} }

View File

@ -41,8 +41,8 @@ func (gui *Gui) handleCreateFilteringMenuPanel(g *gocui.Gui, v *gocui.View) erro
menuItems = append(menuItems, &menuItem{ menuItems = append(menuItems, &menuItem{
displayString: gui.Tr.SLocalize("filterPathOption"), displayString: gui.Tr.SLocalize("filterPathOption"),
onPress: func() error { onPress: func() error {
return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("enterFileName"), "", func(g *gocui.Gui, promptView *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("enterFileName"), "", func(response string) error {
gui.State.FilterPath = strings.TrimSpace(promptView.Buffer()) gui.State.FilterPath = strings.TrimSpace(response)
return gui.Errors.ErrRestart return gui.Errors.ErrRestart
}) })
}, },

View File

@ -51,8 +51,7 @@ func (gui *Gui) handleCreateGitFlowMenu(g *gocui.Gui, v *gocui.View) error {
startHandler := func(branchType string) func() error { startHandler := func(branchType string) func() error {
return func() error { return func() error {
title := gui.Tr.TemplateLocalize("NewBranchNamePrompt", map[string]interface{}{"branchType": branchType}) title := gui.Tr.TemplateLocalize("NewBranchNamePrompt", map[string]interface{}{"branchType": branchType})
return gui.createPromptPanel(gui.g, gui.getMenuView(), title, "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(gui.getMenuView(), title, "", func(name string) error {
name := gui.trimmedContent(v)
subProcess := gui.OSCommand.PrepareSubProcess("git", "flow", branchType, "start", name) subProcess := gui.OSCommand.PrepareSubProcess("git", "flow", branchType, "start", name)
gui.SubProcess = subProcess gui.SubProcess = subProcess
return gui.Errors.ErrSubProcess return gui.Errors.ErrSubProcess

View File

@ -4,7 +4,6 @@ import (
"math" "math"
"strings" "strings"
"github.com/fatih/color"
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
@ -176,12 +175,7 @@ func (gui *Gui) fetch(canPromptForCredentials bool) (err error) {
err = gui.GitCommand.Fetch(fetchOpts) err = gui.GitCommand.Fetch(fetchOpts)
if canPromptForCredentials && err != nil && strings.Contains(err.Error(), "exit status 128") { if canPromptForCredentials && err != nil && strings.Contains(err.Error(), "exit status 128") {
colorFunction := color.New(color.FgRed).SprintFunc() gui.createErrorPanel(gui.Tr.SLocalize("PassUnameWrong"))
coloredMessage := colorFunction(strings.TrimSpace(gui.Tr.SLocalize("PassUnameWrong")))
close := func(g *gocui.Gui, v *gocui.View) error {
return nil
}
_ = gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), true, gui.Tr.SLocalize("Error"), coloredMessage, close, close)
} }
gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC}) gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC})

View File

@ -463,21 +463,35 @@ func (gui *Gui) showInitialPopups(tasks []func(chan struct{}) error) {
} }
func (gui *Gui) showShamelessSelfPromotionMessage(done chan struct{}) error { func (gui *Gui) showShamelessSelfPromotionMessage(done chan struct{}) error {
onConfirm := func(g *gocui.Gui, v *gocui.View) error { onConfirm := func() error {
done <- struct{}{} done <- struct{}{}
return gui.Config.WriteToUserConfig("startupPopupVersion", StartupPopupVersion) return gui.Config.WriteToUserConfig("startupPopupVersion", StartupPopupVersion)
} }
return gui.createConfirmationPanel(gui.g, nil, true, gui.Tr.SLocalize("ShamelessSelfPromotionTitle"), gui.Tr.SLocalize("ShamelessSelfPromotionMessage"), onConfirm, onConfirm) return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: nil,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("ShamelessSelfPromotionTitle"),
prompt: gui.Tr.SLocalize("ShamelessSelfPromotionMessage"),
handleConfirm: onConfirm,
handleClose: onConfirm,
})
} }
func (gui *Gui) promptAnonymousReporting(done chan struct{}) error { func (gui *Gui) promptAnonymousReporting(done chan struct{}) error {
return gui.createConfirmationPanel(gui.g, nil, true, gui.Tr.SLocalize("AnonymousReportingTitle"), gui.Tr.SLocalize("AnonymousReportingPrompt"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: nil,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("AnonymousReportingTitle"),
prompt: gui.Tr.SLocalize("AnonymousReportingPrompt"),
handleConfirm: func() error {
done <- struct{}{} done <- struct{}{}
return gui.Config.WriteToUserConfig("reporting", "on") return gui.Config.WriteToUserConfig("reporting", "on")
}, func(g *gocui.Gui, v *gocui.View) error { },
handleClose: func() error {
done <- struct{}{} done <- struct{}{}
return gui.Config.WriteToUserConfig("reporting", "off") return gui.Config.WriteToUserConfig("reporting", "off")
},
}) })
} }
@ -504,7 +518,12 @@ func (gui *Gui) startBackgroundFetch() {
} }
err := gui.fetch(false) err := gui.fetch(false)
if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew { if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew {
_ = gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), true, gui.Tr.SLocalize("NoAutomaticGitFetchTitle"), gui.Tr.SLocalize("NoAutomaticGitFetchBody"), nil, nil) _ = gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.g.CurrentView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("NoAutomaticGitFetchTitle"),
prompt: gui.Tr.SLocalize("NoAutomaticGitFetchBody"),
})
} else { } else {
gui.goEvery(time.Second*60, gui.stopChan, func() error { gui.goEvery(time.Second*60, gui.stopChan, func() error {
err := gui.fetch(false) err := gui.fetch(false)

View File

@ -326,7 +326,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
informationView.BgColor = gocui.ColorDefault informationView.BgColor = gocui.ColorDefault
informationView.FgColor = gocui.ColorGreen informationView.FgColor = gocui.ColorGreen
informationView.Frame = false informationView.Frame = false
gui.renderString(g, "information", INFO_SECTION_PADDING+informationStr) gui.renderString("information", INFO_SECTION_PADDING+informationStr)
} }
if gui.State.OldInformation != informationStr { if gui.State.OldInformation != informationStr {
gui.setViewContent(informationView, informationStr) gui.setViewContent(informationView, informationStr)
@ -342,7 +342,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return err return err
} }
if err := gui.switchFocus(gui.g, nil, initialView); err != nil { if err := gui.switchFocus(nil, initialView); err != nil {
return err return err
} }
} }

View File

@ -119,7 +119,7 @@ func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions cr
} }
} }
currentView := gui.g.CurrentView() currentView := gui.g.CurrentView()
return gui.switchFocus(gui.g, currentView, menuView) return gui.switchFocus(currentView, menuView)
}) })
return nil return nil
} }

View File

@ -308,7 +308,7 @@ func (gui *Gui) handleEscapeMerge(g *gocui.Gui, v *gocui.View) error {
// it's possible this method won't be called from the merging view so we need to // it's possible this method won't be called from the merging view so we need to
// ensure we only 'return' focus if we already have it // ensure we only 'return' focus if we already have it
if gui.g.CurrentView() == gui.getMainView() { if gui.g.CurrentView() == gui.getMainView() {
return gui.switchFocus(g, v, gui.getFilesView()) return gui.switchFocus(v, gui.getFilesView())
} }
return nil return nil
} }
@ -336,9 +336,15 @@ func (gui *Gui) handleCompleteMerge() error {
func (gui *Gui) promptToContinue() error { func (gui *Gui) promptToContinue() error {
gui.takeOverScrolling() gui.takeOverScrolling()
return gui.createConfirmationPanel(gui.g, gui.getFilesView(), true, "continue", gui.Tr.SLocalize("ConflictsResolved"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getFilesView(),
returnFocusOnClose: true,
title: "continue",
prompt: gui.Tr.SLocalize("ConflictsResolved"),
handleConfirm: func() error {
return gui.genericMergeCommand("continue") return gui.genericMergeCommand("continue")
}, nil) },
})
} }
func (gui *Gui) canScrollMergePanel() bool { func (gui *Gui) canScrollMergePanel() bool {

View File

@ -18,7 +18,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error {
// get diff from commit file that's currently selected // get diff from commit file that's currently selected
commitFile := gui.getSelectedCommitFile() commitFile := gui.getSelectedCommitFile()
if commitFile == nil { if commitFile == nil {
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil return nil
} }
@ -58,7 +58,7 @@ func (gui *Gui) handleToggleSelectionForPatch(g *gocui.Gui, v *gocui.View) error
// add range of lines to those set for the file // add range of lines to those set for the file
commitFile := gui.getSelectedCommitFile() commitFile := gui.getSelectedCommitFile()
if commitFile == nil { if commitFile == nil {
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil return nil
} }
@ -83,7 +83,7 @@ func (gui *Gui) handleEscapePatchBuildingPanel(g *gocui.Gui, v *gocui.View) erro
gui.State.SplitMainPanel = false gui.State.SplitMainPanel = false
} }
return gui.switchFocus(gui.g, nil, gui.getCommitFilesView()) return gui.switchFocus(nil, gui.getCommitFilesView())
} }
func (gui *Gui) refreshSecondaryPatchPanel() error { func (gui *Gui) refreshSecondaryPatchPanel() error {

View File

@ -133,9 +133,15 @@ func (gui *Gui) handlePullPatchIntoWorkingTree() error {
} }
if len(gui.trackedFiles()) > 0 { if len(gui.trackedFiles()) > 0 {
return gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), true, gui.Tr.SLocalize("MustStashTitle"), gui.Tr.SLocalize("MustStashWarning"), func(*gocui.Gui, *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.g.CurrentView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("MustStashTitle"),
prompt: gui.Tr.SLocalize("MustStashWarning"),
handleConfirm: func() error {
return pull(true) return pull(true)
}, nil) },
})
} else { } else {
return pull(false) return pull(false)
} }

View File

@ -55,9 +55,15 @@ func (gui *Gui) quit(v *gocui.View) error {
} }
if gui.Config.GetUserConfig().GetBool("confirmOnQuit") { if gui.Config.GetUserConfig().GetBool("confirmOnQuit") {
return gui.createConfirmationPanel(gui.g, v, true, "", gui.Tr.SLocalize("ConfirmQuit"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: "",
prompt: gui.Tr.SLocalize("ConfirmQuit"),
handleConfirm: func() error {
return gocui.ErrQuit return gocui.ErrQuit
}, nil) },
})
} }
return gocui.ErrQuit return gocui.ErrQuit

View File

@ -78,13 +78,18 @@ func (gui *Gui) handleGenericMergeCommandResult(result error) error {
// assume in this case that we're already done // assume in this case that we're already done
return nil return nil
} else if strings.Contains(result.Error(), "When you have resolved this problem") || strings.Contains(result.Error(), "fix conflicts") || strings.Contains(result.Error(), "Resolve all conflicts manually") { } else if strings.Contains(result.Error(), "When you have resolved this problem") || strings.Contains(result.Error(), "fix conflicts") || strings.Contains(result.Error(), "Resolve all conflicts manually") {
return gui.createConfirmationPanel(gui.g, gui.getFilesView(), true, gui.Tr.SLocalize("FoundConflictsTitle"), gui.Tr.SLocalize("FoundConflicts"), return gui.createConfirmationPanel(createConfirmationPanelOpts{
func(g *gocui.Gui, v *gocui.View) error { returnToView: gui.getFilesView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("FoundConflictsTitle"),
prompt: gui.Tr.SLocalize("FoundConflicts"),
handleConfirm: func() error {
return nil return nil
}, func(g *gocui.Gui, v *gocui.View) error { },
handleClose: func() error {
return gui.genericMergeCommand("abort") return gui.genericMergeCommand("abort")
}, },
) })
} else { } else {
return gui.createErrorPanel(result.Error()) return gui.createErrorPanel(result.Error())
} }

View File

@ -121,9 +121,15 @@ func (gui *Gui) handleCheckoutReflogCommit(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
err := gui.createConfirmationPanel(g, gui.getCommitsView(), true, gui.Tr.SLocalize("checkoutCommit"), gui.Tr.SLocalize("SureCheckoutThisCommit"), func(g *gocui.Gui, v *gocui.View) error { err := gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getCommitsView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("checkoutCommit"),
prompt: gui.Tr.SLocalize("SureCheckoutThisCommit"),
handleConfirm: func() error {
return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{})
}, nil) },
})
if err != nil { if err != nil {
return err return err
} }

View File

@ -94,7 +94,13 @@ func (gui *Gui) handleDeleteRemoteBranch(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
message := fmt.Sprintf("%s '%s'?", gui.Tr.SLocalize("DeleteRemoteBranchMessage"), remoteBranch.FullName()) message := fmt.Sprintf("%s '%s'?", gui.Tr.SLocalize("DeleteRemoteBranchMessage"), remoteBranch.FullName())
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("DeleteRemoteBranch"), message, func(*gocui.Gui, *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("DeleteRemoteBranch"),
prompt: message,
handleConfirm: func() error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("DeletingStatus"), func() error { return gui.WithWaitingStatus(gui.Tr.SLocalize("DeletingStatus"), func() error {
if err := gui.GitCommand.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name); err != nil { if err := gui.GitCommand.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name); err != nil {
return err return err
@ -102,7 +108,8 @@ func (gui *Gui) handleDeleteRemoteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
}) })
}, nil) },
})
} }
func (gui *Gui) handleRebaseOntoRemoteBranch(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleRebaseOntoRemoteBranch(g *gocui.Gui, v *gocui.View) error {
@ -122,13 +129,19 @@ func (gui *Gui) handleSetBranchUpstream(g *gocui.Gui, v *gocui.View) error {
}, },
) )
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("SetUpstreamTitle"), message, func(*gocui.Gui, *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("SetUpstreamTitle"),
prompt: message,
handleConfirm: func() error {
if err := gui.GitCommand.SetBranchUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { if err := gui.GitCommand.SetBranchUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil {
return err return err
} }
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
}, nil) },
})
} }
func (gui *Gui) handleCreateResetToRemoteBranchMenu(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCreateResetToRemoteBranchMenu(g *gocui.Gui, v *gocui.View) error {
@ -151,8 +164,8 @@ func (gui *Gui) handleNewBranchOffRemote(g *gocui.Gui, v *gocui.View) error {
"branchName": branch.FullName(), "branchName": branch.FullName(),
}, },
) )
return gui.createPromptPanel(g, v, message, branch.FullName(), func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, message, branch.FullName(), func(response string) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v), branch.FullName()); err != nil { if err := gui.GitCommand.NewBranch(response, branch.FullName()); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
gui.State.Panels.Branches.SelectedLine = 0 gui.State.Panels.Branches.SelectedLine = 0

View File

@ -116,10 +116,8 @@ func (gui *Gui) handleRemoteEnter(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleAddRemote(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleAddRemote(g *gocui.Gui, v *gocui.View) error {
branchesView := gui.getBranchesView() branchesView := gui.getBranchesView()
return gui.createPromptPanel(g, branchesView, gui.Tr.SLocalize("newRemoteName"), "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(branchesView, gui.Tr.SLocalize("newRemoteName"), "", func(remoteName string) error {
remoteName := gui.trimmedContent(v) return gui.createPromptPanel(branchesView, gui.Tr.SLocalize("newRemoteUrl"), "", func(remoteUrl string) error {
return gui.createPromptPanel(g, branchesView, gui.Tr.SLocalize("newRemoteUrl"), "", func(g *gocui.Gui, v *gocui.View) error {
remoteUrl := gui.trimmedContent(v)
if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil { if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil {
return err return err
} }
@ -133,14 +131,20 @@ func (gui *Gui) handleRemoveRemote(g *gocui.Gui, v *gocui.View) error {
if remote == nil { if remote == nil {
return nil return nil
} }
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("removeRemote"), gui.Tr.SLocalize("removeRemotePrompt")+" '"+remote.Name+"'?", func(*gocui.Gui, *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("removeRemote"),
prompt: gui.Tr.SLocalize("removeRemotePrompt") + " '" + remote.Name + "'?",
handleConfirm: func() error {
if err := gui.GitCommand.RemoveRemote(remote.Name); err != nil { if err := gui.GitCommand.RemoveRemote(remote.Name); err != nil {
return err return err
} }
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
},
}, nil) })
} }
func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error {
@ -157,9 +161,7 @@ func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error {
}, },
) )
return gui.createPromptPanel(g, branchesView, editNameMessage, "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(branchesView, editNameMessage, "", func(updatedRemoteName string) error {
updatedRemoteName := gui.trimmedContent(v)
if updatedRemoteName != remote.Name { if updatedRemoteName != remote.Name {
if err := gui.GitCommand.RenameRemote(remote.Name, updatedRemoteName); err != nil { if err := gui.GitCommand.RenameRemote(remote.Name, updatedRemoteName); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
@ -173,8 +175,7 @@ func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error {
}, },
) )
return gui.createPromptPanel(g, branchesView, editUrlMessage, "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(branchesView, editUrlMessage, "", func(updatedRemoteUrl string) error {
updatedRemoteUrl := gui.trimmedContent(v)
if err := gui.GitCommand.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { if err := gui.GitCommand.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }

View File

@ -11,8 +11,8 @@ import (
func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error {
gui.State.Searching.isSearching = true gui.State.Searching.isSearching = true
gui.State.Searching.view = v gui.State.Searching.view = v
gui.renderString(gui.g, "search", "") gui.renderString("search", "")
if err := gui.switchFocus(gui.g, v, gui.getSearchView()); err != nil { if err := gui.switchFocus(v, gui.getSearchView()); err != nil {
return err return err
} }
@ -21,7 +21,7 @@ func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleSearch(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleSearch(g *gocui.Gui, v *gocui.View) error {
gui.State.Searching.searchString = gui.getSearchView().Buffer() gui.State.Searching.searchString = gui.getSearchView().Buffer()
if err := gui.switchFocus(gui.g, nil, gui.State.Searching.view); err != nil { if err := gui.switchFocus(nil, gui.State.Searching.view); err != nil {
return err return err
} }
@ -36,7 +36,6 @@ func (gui *Gui) onSelectItemWrapper(innerFunc func(int) error) func(int, int, in
return func(y int, index int, total int) error { return func(y int, index int, total int) error {
if total == 0 { if total == 0 {
gui.renderString( gui.renderString(
gui.g,
"search", "search",
fmt.Sprintf( fmt.Sprintf(
"no matches for '%s' %s", "no matches for '%s' %s",
@ -50,7 +49,6 @@ func (gui *Gui) onSelectItemWrapper(innerFunc func(int) error) func(int, int, in
return nil return nil
} }
gui.renderString( gui.renderString(
gui.g,
"search", "search",
fmt.Sprintf( fmt.Sprintf(
"matches for '%s' (%d of %d) %s", "matches for '%s' (%d of %d) %s",
@ -86,7 +84,7 @@ func (gui *Gui) onSearchEscape() error {
} }
func (gui *Gui) handleSearchEscape(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleSearchEscape(g *gocui.Gui, v *gocui.View) error {
if err := gui.switchFocus(gui.g, nil, gui.State.Searching.view); err != nil { if err := gui.switchFocus(nil, gui.State.Searching.view); err != nil {
return err return err
} }

View File

@ -15,7 +15,7 @@ func (gui *Gui) refreshStagingPanel(forceSecondaryFocused bool, selectedLineIdx
// We need to force focus here because the confirmation panel for safely staging lines does not return focus automatically. // We need to force focus here because the confirmation panel for safely staging lines does not return focus automatically.
// This is because if we tell it to return focus it will unconditionally return it to the main panel which may not be what we want // This is because if we tell it to return focus it will unconditionally return it to the main panel which may not be what we want
// e.g. in the event that there's nothing left to stage. // e.g. in the event that there's nothing left to stage.
if err := gui.switchFocus(gui.g, nil, gui.getMainView()); err != nil { if err := gui.switchFocus(nil, gui.getMainView()); err != nil {
return err return err
} }
@ -96,7 +96,7 @@ func (gui *Gui) handleTogglePanel(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleStagingEscape(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleStagingEscape(g *gocui.Gui, v *gocui.View) error {
gui.handleEscapeLineByLinePanel() gui.handleEscapeLineByLinePanel()
return gui.switchFocus(gui.g, nil, gui.getFilesView()) return gui.switchFocus(nil, gui.getFilesView())
} }
func (gui *Gui) handleToggleStagedSelection(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleToggleStagedSelection(g *gocui.Gui, v *gocui.View) error {
@ -114,9 +114,15 @@ func (gui *Gui) handleResetSelection(g *gocui.Gui, v *gocui.View) error {
} }
if !gui.Config.GetUserConfig().GetBool("gui.skipUnstageLineWarning") { if !gui.Config.GetUserConfig().GetBool("gui.skipUnstageLineWarning") {
return gui.createConfirmationPanel(gui.g, gui.getMainView(), false, "unstage lines", "Are you sure you want to delete the selected lines (git reset)? It is irreversible.\nTo disable this dialogue set the config key of 'gui.skipUnstageLineWarning' to true", func(*gocui.Gui, *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getMainView(),
returnFocusOnClose: false,
title: gui.Tr.SLocalize("UnstageLinesTitle"),
prompt: gui.Tr.SLocalize("UnstageLinesPrompt"),
handleConfirm: func() error {
return gui.applySelection(true) return gui.applySelection(true)
}, nil) },
})
} else { } else {
return gui.applySelection(true) return gui.applySelection(true)
} }

View File

@ -76,11 +76,15 @@ func (gui *Gui) handleStashApply(g *gocui.Gui, v *gocui.View) error {
return apply() return apply()
} }
title := gui.Tr.SLocalize("StashApply") return gui.createConfirmationPanel(createConfirmationPanelOpts{
message := gui.Tr.SLocalize("SureApplyStashEntry") returnToView: v,
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { returnFocusOnClose: true,
title: gui.Tr.SLocalize("StashApply"),
prompt: gui.Tr.SLocalize("SureApplyStashEntry"),
handleConfirm: func() error {
return apply() return apply()
}, nil) },
})
} }
func (gui *Gui) handleStashPop(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleStashPop(g *gocui.Gui, v *gocui.View) error {
@ -94,19 +98,27 @@ func (gui *Gui) handleStashPop(g *gocui.Gui, v *gocui.View) error {
return pop() return pop()
} }
title := gui.Tr.SLocalize("StashPop") return gui.createConfirmationPanel(createConfirmationPanelOpts{
message := gui.Tr.SLocalize("SurePopStashEntry") returnToView: v,
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { returnFocusOnClose: true,
title: gui.Tr.SLocalize("StashPop"),
prompt: gui.Tr.SLocalize("SurePopStashEntry"),
handleConfirm: func() error {
return pop() return pop()
}, nil) },
})
} }
func (gui *Gui) handleStashDrop(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleStashDrop(g *gocui.Gui, v *gocui.View) error {
title := gui.Tr.SLocalize("StashDrop") return gui.createConfirmationPanel(createConfirmationPanelOpts{
message := gui.Tr.SLocalize("SureDropStashEntry") returnToView: v,
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { returnFocusOnClose: true,
title: gui.Tr.SLocalize("StashDrop"),
prompt: gui.Tr.SLocalize("SureDropStashEntry"),
handleConfirm: func() error {
return gui.stashDo(g, v, "drop") return gui.stashDo(g, v, "drop")
}, nil) },
})
} }
func (gui *Gui) stashDo(g *gocui.Gui, v *gocui.View, method string) error { func (gui *Gui) stashDo(g *gocui.Gui, v *gocui.View, method string) error {
@ -130,8 +142,8 @@ func (gui *Gui) handleStashSave(stashFunc func(message string) error) error {
if len(gui.trackedFiles()) == 0 && len(gui.stagedFiles()) == 0 { if len(gui.trackedFiles()) == 0 && len(gui.stagedFiles()) == 0 {
return gui.createErrorPanel(gui.Tr.SLocalize("NoTrackedStagedFilesStash")) return gui.createErrorPanel(gui.Tr.SLocalize("NoTrackedStagedFilesStash"))
} }
return gui.createPromptPanel(gui.g, gui.getFilesView(), gui.Tr.SLocalize("StashChanges"), "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(gui.getFilesView(), gui.Tr.SLocalize("StashChanges"), "", func(stashComment string) error {
if err := stashFunc(gui.trimmedContent(v)); err != nil { if err := stashFunc(stashComment); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
return gui.refreshSidePanels(refreshOptions{scope: []int{STASH, FILES}}) return gui.refreshSidePanels(refreshOptions{scope: []int{STASH, FILES}})

View File

@ -57,7 +57,7 @@ func cursorInSubstring(cx int, prefix string, substring string) bool {
func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error {
gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true) gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true)
return gui.createLoaderPanel(gui.g, v, gui.Tr.SLocalize("CheckingForUpdates")) return gui.createLoaderPanel(v, gui.Tr.SLocalize("CheckingForUpdates"))
} }
func (gui *Gui) handleStatusClick(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleStatusClick(g *gocui.Gui, v *gocui.View) error {

View File

@ -104,12 +104,18 @@ func (gui *Gui) handleDeleteTag(g *gocui.Gui, v *gocui.View) error {
}, },
) )
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("DeleteTagTitle"), prompt, func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: v,
returnFocusOnClose: true,
title: gui.Tr.SLocalize("DeleteTagTitle"),
prompt: prompt,
handleConfirm: func() error {
if err := gui.GitCommand.DeleteTag(tag.Name); err != nil { if err := gui.GitCommand.DeleteTag(tag.Name); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}}) return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}})
}, nil) },
})
} }
func (gui *Gui) handlePushTag(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handlePushTag(g *gocui.Gui, v *gocui.View) error {
@ -125,8 +131,8 @@ func (gui *Gui) handlePushTag(g *gocui.Gui, v *gocui.View) error {
}, },
) )
return gui.createPromptPanel(gui.g, v, title, "origin", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, title, "origin", func(response string) error {
if err := gui.GitCommand.PushTag(v.Buffer(), tag.Name); err != nil { if err := gui.GitCommand.PushTag(response, tag.Name); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
return nil return nil
@ -134,9 +140,8 @@ func (gui *Gui) handlePushTag(g *gocui.Gui, v *gocui.View) error {
} }
func (gui *Gui) handleCreateTag(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleCreateTag(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("CreateTagTitle"), "", func(g *gocui.Gui, v *gocui.View) error { return gui.createPromptPanel(v, gui.Tr.SLocalize("CreateTagTitle"), "", func(tagName string) error {
// leaving commit SHA blank so that we're just creating the tag for the current commit // leaving commit SHA blank so that we're just creating the tag for the current commit
tagName := v.Buffer()
if err := gui.GitCommand.CreateLightweightTag(tagName, ""); err != nil { if err := gui.GitCommand.CreateLightweightTag(tagName, ""); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }

View File

@ -59,7 +59,7 @@ func (gui *Gui) newStringTask(viewName string, str string) error {
manager := gui.getManager(view) manager := gui.getManager(view)
f := func(stop chan struct{}) error { f := func(stop chan struct{}) error {
gui.renderString(gui.g, viewName, str) gui.renderString(viewName, str)
return nil return nil
} }

View File

@ -166,7 +166,12 @@ func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHar
dirtyWorkingTree := len(gui.trackedFiles()) > 0 dirtyWorkingTree := len(gui.trackedFiles()) > 0
if dirtyWorkingTree { if dirtyWorkingTree {
// offer to autostash changes // offer to autostash changes
return gui.createConfirmationPanel(gui.g, gui.getBranchesView(), true, gui.Tr.SLocalize("AutoStashTitle"), gui.Tr.SLocalize("AutoStashPrompt"), func(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: gui.getBranchesView(),
returnFocusOnClose: true,
title: gui.Tr.SLocalize("AutoStashTitle"),
prompt: gui.Tr.SLocalize("AutoStashPrompt"),
handleConfirm: func() error {
return gui.WithWaitingStatus(options.WaitingStatus, func() error { return gui.WithWaitingStatus(options.WaitingStatus, func() error {
if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + commitSha); err != nil { if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + commitSha); err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
@ -183,7 +188,8 @@ func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHar
} }
return nil return nil
}) })
}, nil) },
})
} }
return gui.WithWaitingStatus(options.WaitingStatus, func() error { return gui.WithWaitingStatus(options.WaitingStatus, func() error {

View File

@ -3,13 +3,18 @@ package gui
import "github.com/jesseduffield/gocui" import "github.com/jesseduffield/gocui"
func (gui *Gui) showUpdatePrompt(newVersion string) error { func (gui *Gui) showUpdatePrompt(newVersion string) error {
title := "New version available!"
message := "Download latest version? (enter/esc)"
currentView := gui.g.CurrentView() currentView := gui.g.CurrentView()
return gui.createConfirmationPanel(gui.g, currentView, true, title, message, func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(createConfirmationPanelOpts{
returnToView: currentView,
returnFocusOnClose: true,
title: "New version available!",
prompt: "Download latest version? (enter/esc)",
handleConfirm: func() error {
gui.startUpdating(newVersion) gui.startUpdating(newVersion)
return nil return nil
}, nil) },
})
} }
func (gui *Gui) onUserUpdateCheckFinish(newVersion string, err error) error { func (gui *Gui) onUserUpdateCheckFinish(newVersion string, err error) error {
@ -47,7 +52,7 @@ func (gui *Gui) startUpdating(newVersion string) {
func (gui *Gui) onUpdateFinish(err error) error { func (gui *Gui) onUpdateFinish(err error) error {
gui.State.Updating = false gui.State.Updating = false
gui.statusManager.removeStatus("updating") gui.statusManager.removeStatus("updating")
gui.renderString(gui.g, "appStatus", "") gui.renderString("appStatus", "")
if err != nil { if err != nil {
return gui.createErrorPanel("Update failed: " + err.Error()) return gui.createErrorPanel("Update failed: " + err.Error())
} }
@ -55,9 +60,13 @@ func (gui *Gui) onUpdateFinish(err error) error {
} }
func (gui *Gui) createUpdateQuitConfirmation(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) createUpdateQuitConfirmation(g *gocui.Gui, v *gocui.View) error {
title := "Currently Updating" return gui.createConfirmationPanel(createConfirmationPanelOpts{
message := "An update is in progress. Are you sure you want to quit?" returnToView: v,
return gui.createConfirmationPanel(gui.g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { returnFocusOnClose: true,
title: "Currently Updating",
prompt: "An update is in progress. Are you sure you want to quit?",
handleConfirm: func() error {
return gocui.ErrQuit return gocui.ErrQuit
}, nil) },
})
} }

View File

@ -175,7 +175,7 @@ func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error {
if err := gui.resetOrigin(gui.getMainView()); err != nil { if err := gui.resetOrigin(gui.getMainView()); err != nil {
return err return err
} }
return gui.switchFocus(g, v, focusedView) return gui.switchFocus(v, focusedView)
} }
func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
@ -213,7 +213,7 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
if err := gui.resetOrigin(gui.getMainView()); err != nil { if err := gui.resetOrigin(gui.getMainView()); err != nil {
return err return err
} }
return gui.switchFocus(g, v, focusedView) return gui.switchFocus(v, focusedView)
} }
func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
@ -272,7 +272,7 @@ func (gui *Gui) returnFocus(g *gocui.Gui, v *gocui.View) error {
gui.Log.Error(err) gui.Log.Error(err)
} }
} }
return gui.switchFocus(g, v, previousView) return gui.switchFocus(v, previousView)
} }
func (gui *Gui) goToSideView(sideViewName string) func(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) goToSideView(sideViewName string) func(g *gocui.Gui, v *gocui.View) error {
@ -287,7 +287,7 @@ func (gui *Gui) goToSideView(sideViewName string) func(g *gocui.Gui, v *gocui.Vi
gui.Log.Error(err) gui.Log.Error(err)
return nil return nil
} }
return gui.switchFocus(g, nil, view) return gui.switchFocus(nil, view)
} }
} }
@ -303,7 +303,7 @@ func (gui *Gui) closePopupPanels() error {
// pass in oldView = nil if you don't want to be able to return to your old view // pass in oldView = nil if you don't want to be able to return to your old view
// TODO: move some of this logic into our onFocusLost and onFocus hooks // TODO: move some of this logic into our onFocusLost and onFocus hooks
func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error { func (gui *Gui) switchFocus(oldView, newView *gocui.View) error {
// we assume we'll never want to return focus to a popup panel i.e. // we assume we'll never want to return focus to a popup panel i.e.
// we should never stack popup panels // we should never stack popup panels
if oldView != nil && !gui.isPopupPanel(oldView.Name()) { if oldView != nil && !gui.isPopupPanel(oldView.Name()) {
@ -318,20 +318,20 @@ func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
}, },
) )
gui.Log.Info(message) gui.Log.Info(message)
if _, err := g.SetCurrentView(newView.Name()); err != nil { if _, err := gui.g.SetCurrentView(newView.Name()); err != nil {
return err return err
} }
if _, err := g.SetViewOnTop(newView.Name()); err != nil { if _, err := gui.g.SetViewOnTop(newView.Name()); err != nil {
return err return err
} }
g.Cursor = newView.Editable gui.g.Cursor = newView.Editable
if err := gui.renderPanelOptions(); err != nil { if err := gui.renderPanelOptions(); err != nil {
return err return err
} }
return gui.newLineFocused(g, newView) return gui.newLineFocused(gui.g, newView)
} }
func (gui *Gui) resetOrigin(v *gocui.View) error { func (gui *Gui) resetOrigin(v *gocui.View) error {
@ -350,9 +350,9 @@ func (gui *Gui) setViewContent(v *gocui.View, s string) {
} }
// renderString resets the origin of a view and sets its content // renderString resets the origin of a view and sets its content
func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) { func (gui *Gui) renderString(viewName, s string) {
g.Update(func(*gocui.Gui) error { gui.g.Update(func(*gocui.Gui) error {
v, err := g.View(viewName) v, err := gui.g.View(viewName)
if err != nil { if err != nil {
return nil // return gracefully if view has been deleted return nil // return gracefully if view has been deleted
} }
@ -377,7 +377,7 @@ func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
} }
func (gui *Gui) renderOptionsMap(optionsMap map[string]string) error { func (gui *Gui) renderOptionsMap(optionsMap map[string]string) error {
gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap)) gui.renderString("options", gui.optionsMapToString(optionsMap))
return nil return nil
} }

View File

@ -1165,6 +1165,12 @@ func addEnglish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{ }, &i18n.Message{
ID: "BranchNotFoundPrompt", ID: "BranchNotFoundPrompt",
Other: "Branch not found. Create a new branch named", Other: "Branch not found. Create a new branch named",
}, &i18n.Message{
ID: "UnstageLinesTitle",
Other: "Unstage lines",
}, &i18n.Message{
ID: "UnstageLinesPrompt",
Other: "Are you sure you want to delete the selected lines (git reset)? It is irreversible.\nTo disable this dialogue set the config key of 'gui.skipUnstageLineWarning' to true",
}, },
) )
} }