From d9fa02c53bb9b401f1b5ca07e8ed239862052a42 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 15 Aug 2020 16:36:39 +1000 Subject: [PATCH] clean up interface for popup panels --- pkg/gui/app_status_manager.go | 2 +- pkg/gui/branches_panel.go | 149 +++++++++++++++++---------- pkg/gui/commit_files_panel.go | 65 +++++++----- pkg/gui/commit_message_panel.go | 6 +- pkg/gui/commits_panel.go | 166 ++++++++++++++++++++----------- pkg/gui/confirmation_panel.go | 143 +++++++++++++++++--------- pkg/gui/credentials_panel.go | 10 +- pkg/gui/diffing.go | 4 +- pkg/gui/files_panel.go | 102 +++++++++++-------- pkg/gui/filtering.go | 16 ++- pkg/gui/filtering_menu_panel.go | 4 +- pkg/gui/git_flow.go | 3 +- pkg/gui/global_handlers.go | 8 +- pkg/gui/gui.go | 37 +++++-- pkg/gui/layout.go | 4 +- pkg/gui/menu_panel.go | 2 +- pkg/gui/merge_panel.go | 14 ++- pkg/gui/patch_building_panel.go | 6 +- pkg/gui/patch_options_panel.go | 12 ++- pkg/gui/quitting.go | 12 ++- pkg/gui/rebase_options_panel.go | 13 ++- pkg/gui/reflog_panel.go | 12 ++- pkg/gui/remote_branches_panel.go | 45 ++++++--- pkg/gui/remotes_panel.go | 31 +++--- pkg/gui/searching.go | 10 +- pkg/gui/staging_panel.go | 16 ++- pkg/gui/stash_panel.go | 46 +++++---- pkg/gui/status_panel.go | 2 +- pkg/gui/tags_panel.go | 25 +++-- pkg/gui/tasks_adapter.go | 2 +- pkg/gui/undoing.go | 38 ++++--- pkg/gui/updates.go | 33 +++--- pkg/gui/view_helpers.go | 26 ++--- pkg/i18n/english.go | 6 ++ 34 files changed, 674 insertions(+), 396 deletions(-) diff --git a/pkg/gui/app_status_manager.go b/pkg/gui/app_status_manager.go index 54393c443..9d8ac3725 100644 --- a/pkg/gui/app_status_manager.go +++ b/pkg/gui/app_status_manager.go @@ -66,7 +66,7 @@ func (gui *Gui) WithWaitingStatus(name string, f func() error) error { if appStatus == "" { return } - gui.renderString(gui.g, "appStatus", appStatus) + gui.renderString("appStatus", appStatus) } }() diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index ed8e7819e..22dddb65e 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -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 { - 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 } go func() { @@ -140,12 +140,19 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error { branch := gui.getSelectedBranch() message := gui.Tr.SLocalize("SureForceCheckout") title := gui.Tr.SLocalize("ForceCheckoutBranch") - return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - if err := gui.GitCommand.Checkout(branch.Name, commands.CheckoutOptions{Force: true}); err != nil { - _ = gui.surfaceError(err) - } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) - }, nil) + + 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 { + _ = gui.surfaceError(err) + } + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }) } type handleCheckoutRefOptions struct { @@ -179,24 +186,29 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions) if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { // 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 { - - if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + ref); err != nil { - return gui.surfaceError(err) - } - if err := gui.GitCommand.Checkout(ref, cmdOptions); err != nil { - return gui.surfaceError(err) - } - - onSuccess() - if err := gui.GitCommand.StashDo(0, "pop"); err != nil { - if err := gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}); err != nil { - return err + 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 { + return gui.surfaceError(err) } - return gui.surfaceError(err) - } - return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) - }, nil) + if err := gui.GitCommand.Checkout(ref, cmdOptions); err != nil { + return gui.surfaceError(err) + } + + onSuccess() + if err := gui.GitCommand.StashDo(0, "pop"); err != nil { + if err := gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}); err != nil { + return err + } + return gui.surfaceError(err) + } + return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) + }, + }) } 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 { - return gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", "", func(g *gocui.Gui, v *gocui.View) error { - return gui.handleCheckoutRef(gui.trimmedContent(v), handleCheckoutRefOptions{ + return gui.createPromptPanel(v, gui.Tr.SLocalize("BranchName")+":", "", func(response string) error { + return gui.handleCheckoutRef(response, handleCheckoutRefOptions{ 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.createNewBranchWithName(ref) - }, nil) + + 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) + }, + }) }, }) }) @@ -240,8 +259,8 @@ func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error { "branchName": branch.Name, }, ) - return gui.createPromptPanel(g, v, message, "", func(g *gocui.Gui, v *gocui.View) error { - return gui.createNewBranchWithName(gui.trimmedContent(v)) + return gui.createPromptPanel(v, message, "", func(response string) error { + return gui.createNewBranchWithName(response) }) } @@ -288,16 +307,23 @@ func (gui *Gui) deleteNamedBranch(g *gocui.Gui, v *gocui.View, selectedBranch *c "selectedBranchName": selectedBranch.Name, }, ) - return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - if err := gui.GitCommand.DeleteBranch(selectedBranch.Name, force); err != nil { - errMessage := err.Error() - if !force && strings.Contains(errMessage, "is not fully merged") { - return gui.deleteNamedBranch(g, v, selectedBranch, true) + + 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 { + errMessage := err.Error() + if !force && strings.Contains(errMessage, "is not fully merged") { + return gui.deleteNamedBranch(g, v, selectedBranch, true) + } + return gui.createErrorPanel(errMessage) } - return gui.createErrorPanel(errMessage) - } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}}) - }, nil) + return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}}) + }, + }) } func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { @@ -319,12 +345,17 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { "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{}) return gui.handleGenericMergeCommandResult(err) - }, nil) + }, + }) } func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error { @@ -357,11 +388,17 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { "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) return gui.handleGenericMergeCommandResult(err) - }, nil) + }, + }) } 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() { - _ = gui.createLoaderPanel(gui.g, v, message) + _ = gui.createLoaderPanel(v, message) if gui.State.Panels.Branches.SelectedLine == 0 { _ = 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) promptForNewName := func() error { - return gui.createPromptPanel(g, v, gui.Tr.SLocalize("NewBranchNamePrompt")+" "+branch.Name+":", "", func(g *gocui.Gui, v *gocui.View) error { - newName := gui.trimmedContent(v) - if err := gui.GitCommand.RenameBranch(branch.Name, newName); err != nil { + return gui.createPromptPanel(v, gui.Tr.SLocalize("NewBranchNamePrompt")+" "+branch.Name+":", "", func(newBranchName string) error { + if err := gui.GitCommand.RenameBranch(branch.Name, newBranchName); err != nil { return gui.surfaceError(err) } // 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 - 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) } @@ -522,9 +558,14 @@ func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error { if notTrackingRemote { 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() - }, nil) + + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("renameBranch"), + prompt: gui.Tr.SLocalize("RenameBranchWarning"), + handleConfirm: promptForNewName, + }) } func (gui *Gui) currentBranch() *commands.Branch { diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 886fe3d7b..b10f0f4bb 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -36,7 +36,7 @@ func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error { commitFile := gui.getSelectedCommitFile() if commitFile == nil { - gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) + gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) 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 { - return gui.switchFocus(g, v, gui.getCommitsView()) + return gui.switchFocus(v, gui.getCommitsView()) } func (gui *Gui) handleCheckoutCommitFile(g *gocui.Gui, v *gocui.View) error { @@ -77,17 +77,23 @@ func (gui *Gui) handleDiscardOldFileChange(g *gocui.Gui, v *gocui.View) error { 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.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.handleGenericMergeCommandResult(err); err != nil { - return err + 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 { + if err := gui.GitCommand.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, fileName); err != nil { + if err := gui.handleGenericMergeCommandResult(err); err != nil { + return err + } } - } - return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) - }) - }, nil) + return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) + }) + }, + }) } func (gui *Gui) refreshCommitFilesView() error { @@ -144,7 +150,7 @@ func (gui *Gui) handleToggleFileForPatch(g *gocui.Gui, v *gocui.View) error { commitFile := gui.getSelectedCommitFile() if commitFile == nil { - gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) + gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) 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 { - return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("DiscardPatch"), gui.Tr.SLocalize("DiscardPatchConfirm"), func(g *gocui.Gui, v *gocui.View) error { - gui.GitCommand.PatchManager.Reset() - return toggleTheFile() - }, nil) + 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() + return toggleTheFile() + }, + }) } return toggleTheFile() @@ -200,7 +212,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error { commitFile := gui.getSelectedCommitFile() if commitFile == nil { - gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) + gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil } @@ -212,18 +224,25 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error { } 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 gui.refreshPatchBuildingPanel(selectedLineIdx) } 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 { - gui.GitCommand.PatchManager.Reset() - return enterTheFile(selectedLineIdx) - }, func(g *gocui.Gui, v *gocui.View) error { - return gui.switchFocus(gui.g, nil, gui.getCommitFilesView()) + 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() + return enterTheFile(selectedLineIdx) + }, + handleClose: func() error { + return gui.switchFocus(nil, gui.getCommitFilesView()) + }, }) } diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index bcc47f6b5..af79795f1 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -47,13 +47,13 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error { _ = v.SetCursor(0, 0) _ = v.SetOrigin(0, 0) _, _ = g.SetViewOnBottom("commitMessage") - _ = gui.switchFocus(g, v, gui.getFilesView()) + _ = gui.switchFocus(v, gui.getFilesView()) return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) } func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error { _, _ = 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 { @@ -69,7 +69,7 @@ func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error { "keyBindNewLine": "tab", }, ) - gui.renderString(g, "options", message) + gui.renderString("options", message) return nil } diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index c7ea04b20..2c1beafc7 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -155,12 +155,18 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error { 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.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error { - err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "squash") - return gui.handleGenericMergeCommandResult(err) - }) - }, nil) + 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 { + err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "squash") + return gui.handleGenericMergeCommandResult(err) + }) + }, + }) } 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 gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Fixup"), gui.Tr.SLocalize("SureFixupThisCommit"), func(g *gocui.Gui, v *gocui.View) error { - return gui.WithWaitingStatus(gui.Tr.SLocalize("FixingStatus"), func() error { - err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "fixup") - return gui.handleGenericMergeCommandResult(err) - }) - }, nil) + 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 { + err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "fixup") + return gui.handleGenericMergeCommandResult(err) + }) + }, + }) } 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 { return gui.createErrorPanel(gui.Tr.SLocalize("OnlyRenameTopCommit")) } - return gui.createPromptPanel(g, v, gui.Tr.SLocalize("renameCommit"), "", func(g *gocui.Gui, v *gocui.View) error { - if err := gui.GitCommand.RenameCommit(v.Buffer()); err != nil { + return gui.createPromptPanel(v, gui.Tr.SLocalize("renameCommit"), "", func(response string) error { + if err := gui.GitCommand.RenameCommit(response); err != nil { return gui.surfaceError(err) } @@ -276,12 +288,18 @@ func (gui *Gui) handleCommitDelete(g *gocui.Gui, v *gocui.View) error { 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.WithWaitingStatus(gui.Tr.SLocalize("DeletingStatus"), func() error { - err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "drop") - return gui.handleGenericMergeCommandResult(err) - }) - }, nil) + 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 { + err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "drop") + return gui.handleGenericMergeCommandResult(err) + }) + }, + }) } 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 gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("AmendCommitTitle"), gui.Tr.SLocalize("AmendCommitPrompt"), func(*gocui.Gui, *gocui.View) error { - return gui.WithWaitingStatus(gui.Tr.SLocalize("AmendingStatus"), func() error { - err := gui.GitCommand.AmendTo(gui.State.Commits[gui.State.Panels.Commits.SelectedLine].Sha) - return gui.handleGenericMergeCommandResult(err) - }) - }, nil) + 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 { + err := gui.GitCommand.AmendTo(gui.State.Commits[gui.State.Panels.Commits.SelectedLine].Sha) + return gui.handleGenericMergeCommandResult(err) + }) + }, + }) } 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 gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("CherryPick"), gui.Tr.SLocalize("SureCherryPick"), func(g *gocui.Gui, v *gocui.View) error { - return gui.WithWaitingStatus(gui.Tr.SLocalize("CherryPickingStatus"), func() error { - err := gui.GitCommand.CherryPickCommits(gui.State.CherryPickedCommits) - return gui.handleGenericMergeCommandResult(err) - }) - }, nil) + 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 { + err := gui.GitCommand.CherryPickCommits(gui.State.CherryPickedCommits) + return gui.handleGenericMergeCommandResult(err) + }) + }, + }) } 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 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) { @@ -513,18 +543,24 @@ func (gui *Gui) handleCreateFixupCommit(g *gocui.Gui, v *gocui.View) error { return nil } - return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("CreateFixupCommit"), gui.Tr.TemplateLocalize( - "SureCreateFixupCommit", - Teml{ - "commit": commit.Sha, - }, - ), func(g *gocui.Gui, v *gocui.View) error { - if err := gui.GitCommand.CreateFixupCommit(commit.Sha); err != nil { - return gui.surfaceError(err) - } + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("CreateFixupCommit"), + prompt: gui.Tr.TemplateLocalize( + "SureCreateFixupCommit", + Teml{ + "commit": commit.Sha, + }, + ), + handleConfirm: func() error { + if err := gui.GitCommand.CreateFixupCommit(commit.Sha); err != nil { + return gui.surfaceError(err) + } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) - }, nil) + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }) } 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 gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("SquashAboveCommits"), gui.Tr.TemplateLocalize( - "SureSquashAboveCommits", - Teml{ - "commit": commit.Sha, + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("SquashAboveCommits"), + prompt: gui.Tr.TemplateLocalize( + "SureSquashAboveCommits", + Teml{ + "commit": commit.Sha, + }, + ), + handleConfirm: func() error { + return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error { + err := gui.GitCommand.SquashAllAboveFixupCommits(commit.Sha) + return gui.handleGenericMergeCommandResult(err) + }) }, - ), func(g *gocui.Gui, v *gocui.View) error { - return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error { - err := gui.GitCommand.SquashAllAboveFixupCommits(commit.Sha) - return gui.handleGenericMergeCommandResult(err) - }) - }, nil) + }) } 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 { - return gui.createPromptPanel(gui.g, gui.getCommitsView(), gui.Tr.SLocalize("TagNameTitle"), "", func(g *gocui.Gui, v *gocui.View) error { - if err := gui.GitCommand.CreateLightweightTag(v.Buffer(), commitSha); err != nil { + return gui.createPromptPanel(gui.getCommitsView(), gui.Tr.SLocalize("TagNameTitle"), "", func(response string) error { + if err := gui.GitCommand.CreateLightweightTag(response, commitSha); err != nil { return gui.surfaceError(err) } 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 gui.createConfirmationPanel(g, gui.getCommitsView(), true, gui.Tr.SLocalize("checkoutCommit"), gui.Tr.SLocalize("SureCheckoutThisCommit"), func(g *gocui.Gui, v *gocui.View) error { - return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) - }, nil) + 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{}) + }, + }) } func (gui *Gui) renderBranchCommitsWithSelection() error { diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 037be36bd..40fbca36d 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -15,11 +15,76 @@ import ( "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 { 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 } } @@ -96,7 +161,7 @@ func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt confirmationView.FgColor = theme.GocuiDefaultTextColor } gui.g.Update(func(g *gocui.Gui) error { - return gui.switchFocus(gui.g, currentView, confirmationView) + return gui.switchFocus(currentView, confirmationView) }) 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() - g.Update(func(g *gocui.Gui) error { + gui.g.Update(func(g *gocui.Gui) error { // delete the existing confirmation panel if it exists if view, _ := g.View("confirmation"); view != nil { if err := gui.closeConfirmationPrompt(g, true); err != nil { 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 { return err } - confirmationView.Editable = editable - if editable { + confirmationView.Editable = opts.editable + if opts.editable { go func() { // TODO: remove this wait (right now if you remove it the EditGotoToEndOfLine method doesn't seem to work) 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) - return gui.setKeyBindings(g, handleConfirm, handleClose, returnFocusOnClose) + gui.renderString("confirmation", opts.prompt) + return gui.setKeyBindings(opts) }) return nil } -func (gui *Gui) createLoaderPanel(g *gocui.Gui, currentView *gocui.View, prompt string) 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 { +func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error { actions := gui.Tr.TemplateLocalize( "CloseConfirm", Teml{ @@ -163,40 +215,33 @@ func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*go }, ) - gui.renderString(g, "options", actions) - if err := g.SetKeybinding("confirmation", nil, gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(handleConfirm, returnFocusOnClose)); err != nil { - return err + gui.renderString("options", actions) + 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 g.SetKeybinding("confirmation", nil, gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(handleClose, returnFocusOnClose)) + + return gui.g.SetKeybinding("confirmation", nil, gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(opts.handleClose, opts.returnFocusOnClose)) } -// createSpecificErrorPanel allows you to create an error popup, specifying the -// 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() coloredMessage := colorFunction(strings.TrimSpace(message)) if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { return err } - return gui.createConfirmationPanel(gui.g, nextView, true, gui.Tr.SLocalize("Error"), coloredMessage, nil, nil) -} - -func (gui *Gui) createErrorPanel(message string) error { - return gui.createSpecificErrorPanel(message, gui.g.CurrentView(), true) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: gui.g.CurrentView(), + title: gui.Tr.SLocalize("Error"), + prompt: coloredMessage, + returnFocusOnClose: true, + }) } func (gui *Gui) surfaceError(err error) error { diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go index 9333c2e7a..7858f26f4 100644 --- a/pkg/gui/credentials_panel.go +++ b/pkg/gui/credentials_panel.go @@ -20,7 +20,7 @@ func (gui *Gui) promptUserForCredential(passOrUname string) string { credentialsView.Title = gui.Tr.SLocalize("CredentialsPassword") credentialsView.Mask = '*' } - err := gui.switchFocus(g, gui.g.CurrentView(), credentialsView) + err := gui.switchFocus(gui.g.CurrentView(), credentialsView) if err != nil { return err } @@ -43,7 +43,7 @@ func (gui *Gui) handleSubmitCredential(g *gocui.Gui, v *gocui.View) error { if err != nil { nextView = gui.getFilesView() } - err = gui.switchFocus(g, nil, nextView) + err = gui.switchFocus(nil, nextView) if err != nil { return err } @@ -57,7 +57,7 @@ func (gui *Gui) handleCloseCredentialsView(g *gocui.Gui, v *gocui.View) error { } 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 { @@ -72,7 +72,7 @@ func (gui *Gui) handleCredentialsViewFocused(g *gocui.Gui, v *gocui.View) error "keyBindConfirm": "enter", }, ) - gui.renderString(g, "options", message) + gui.renderString("options", message) return nil } @@ -85,7 +85,7 @@ func (gui *Gui) handleCredentialsPopup(cmdErr error) { errMessage = gui.Tr.SLocalize("PassUnameWrong") } // we are not logging this error because it may contain a password - _ = gui.createSpecificErrorPanel(errMessage, gui.getFilesView(), false) + gui.createErrorPanel(errMessage) } else { _ = gui.closeConfirmationPrompt(gui.g, true) } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 633efa600..24c351b00 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -150,8 +150,8 @@ func (gui *Gui) handleCreateDiffingMenuPanel(g *gocui.Gui, v *gocui.View) error { displayString: gui.Tr.SLocalize("enterRefToDiff"), onPress: func() error { - return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("enteRefName"), "", func(g *gocui.Gui, promptView *gocui.View) error { - gui.State.Diff.Ref = strings.TrimSpace(promptView.Buffer()) + return gui.createPromptPanel(v, gui.Tr.SLocalize("enteRefName"), "", func(response string) error { + gui.State.Diff.Ref = strings.TrimSpace(response) return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) }) }, diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 994a49a0a..125a06651 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -172,7 +172,7 @@ func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error return gui.createErrorPanel(gui.Tr.SLocalize("FileStagingRequirements")) } 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 gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx) @@ -249,9 +249,12 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error { } if file.Tracked { - return gui.createConfirmationPanel(gui.g, gui.g.CurrentView(), true, gui.Tr.SLocalize("IgnoreTracked"), gui.Tr.SLocalize("IgnoreTrackedPrompt"), - // On confirmation - func(_ *gocui.Gui, _ *gocui.View) error { + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: gui.g.CurrentView(), + returnFocusOnClose: true, + title: gui.Tr.SLocalize("IgnoreTracked"), + prompt: gui.Tr.SLocalize("IgnoreTrackedPrompt"), + handleConfirm: func() error { if err := gui.GitCommand.Ignore(file.Name); err != nil { return err } @@ -259,7 +262,8 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error { return err } return gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}) - }, 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")) } - gui.renderString(g, "commitMessage", skipHookPreifx) + gui.renderString("commitMessage", skipHookPreifx) if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil { 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())) } 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 { return err } @@ -310,7 +314,7 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error { return err } - if err := gui.switchFocus(g, filesView, commitMessageView); err != nil { + if err := gui.switchFocus(filesView, commitMessageView); err != nil { 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 { - return gui.createConfirmationPanel( - gui.g, gui.getFilesView(), true, gui.Tr.SLocalize("NoFilesStagedTitle"), gui.Tr.SLocalize("NoFilesStagedPrompt"), - func(*gocui.Gui, *gocui.View) error { + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: gui.getFilesView(), + returnFocusOnClose: true, + title: gui.Tr.SLocalize("NoFilesStagedTitle"), + prompt: gui.Tr.SLocalize("NoFilesStagedPrompt"), + handleConfirm: func() error { if err := gui.GitCommand.StageAll(); err != nil { return gui.surfaceError(err) } @@ -332,7 +339,8 @@ func (gui *Gui) promptToStageAllAndRetry(retry func() error) error { } return retry() - }, nil) + }, + }) } func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) error { @@ -346,20 +354,23 @@ func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) erro return gui.createErrorPanel(gui.Tr.SLocalize("NoCommitToAmend")) } - title := strings.Title(gui.Tr.SLocalize("AmendLastCommit")) - question := gui.Tr.SLocalize("SureToAmend") + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: filesView, + returnFocusOnClose: true, + title: strings.Title(gui.Tr.SLocalize("AmendLastCommit")), + prompt: gui.Tr.SLocalize("SureToAmend"), + handleConfirm: func() error { + ok, err := gui.runSyncOrAsyncCommand(gui.GitCommand.AmendHead()) + if err != nil { + return err + } + if !ok { + return nil + } - return gui.createConfirmationPanel(g, filesView, true, title, question, func(g *gocui.Gui, v *gocui.View) error { - ok, err := gui.runSyncOrAsyncCommand(gui.GitCommand.AmendHead()) - if err != nil { - return err - } - if !ok { - return nil - } - - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) - }, nil) + return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + }, + }) } // 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 { - upstream := gui.trimmedContent(v) + return gui.createPromptPanel(v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranch.Name, func(upstream string) error { if err := gui.GitCommand.SetUpstreamBranch(upstream); err != nil { errorMessage := err.Error() if strings.Contains(errorMessage, "does not exist") { @@ -472,7 +482,7 @@ type PullFilesOptions struct { } 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 } @@ -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 { - 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 } go func() { branchName := gui.getCheckedOutBranch().Name err := gui.GitCommand.Push(branchName, force, upstream, args, gui.promptUserForCredential) 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 { - return gui.pushWithForceFlag(gui.g, v, true, upstream, args) - }, nil) + 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 } @@ -550,16 +566,23 @@ func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error { if gui.GitCommand.PushToCurrent { return gui.pushWithForceFlag(g, v, false, "", "--set-upstream") } else { - return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error { - return gui.pushWithForceFlag(g, v, false, gui.trimmedContent(v), "") + return gui.createPromptPanel(v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranch.Name, func(response string) error { + return gui.pushWithForceFlag(g, v, false, response, "") }) } } else if currentBranch.Pullables == "0" { 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.pushWithForceFlag(g, v, true, "", "") - }, nil) + + 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, "", "") + }, + }) } 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")) } 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 gui.refreshMergePanel() @@ -597,8 +620,7 @@ func (gui *Gui) anyFilesWithMergeConflicts() bool { } 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 { - command := gui.trimmedContent(v) + return gui.createPromptPanel(v, gui.Tr.SLocalize("CustomCommand"), "", func(command string) error { gui.SubProcess = gui.OSCommand.RunCustomCommand(command) return gui.Errors.ErrSubProcess }) diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index 66232e3fb..3acb3c34a 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -1,16 +1,22 @@ package gui -import "github.com/jesseduffield/gocui" - func (gui *Gui) inFilterMode() bool { return gui.State.FilterPath != "" } func (gui *Gui) validateNotInFilterMode() (bool, error) { 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 { - return gui.exitFilterMode() - }, nil) + 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 false, err } return true, nil } diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index 856b71572..dcd2be5fd 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -41,8 +41,8 @@ func (gui *Gui) handleCreateFilteringMenuPanel(g *gocui.Gui, v *gocui.View) erro menuItems = append(menuItems, &menuItem{ displayString: gui.Tr.SLocalize("filterPathOption"), onPress: func() error { - return gui.createPromptPanel(gui.g, v, gui.Tr.SLocalize("enterFileName"), "", func(g *gocui.Gui, promptView *gocui.View) error { - gui.State.FilterPath = strings.TrimSpace(promptView.Buffer()) + return gui.createPromptPanel(v, gui.Tr.SLocalize("enterFileName"), "", func(response string) error { + gui.State.FilterPath = strings.TrimSpace(response) return gui.Errors.ErrRestart }) }, diff --git a/pkg/gui/git_flow.go b/pkg/gui/git_flow.go index 9076ae7f0..cddc0ae9d 100644 --- a/pkg/gui/git_flow.go +++ b/pkg/gui/git_flow.go @@ -51,8 +51,7 @@ func (gui *Gui) handleCreateGitFlowMenu(g *gocui.Gui, v *gocui.View) error { startHandler := func(branchType string) func() error { return func() error { 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 { - name := gui.trimmedContent(v) + return gui.createPromptPanel(gui.getMenuView(), title, "", func(name string) error { subProcess := gui.OSCommand.PrepareSubProcess("git", "flow", branchType, "start", name) gui.SubProcess = subProcess return gui.Errors.ErrSubProcess diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 46e558989..8282cea2d 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -4,7 +4,6 @@ import ( "math" "strings" - "github.com/fatih/color" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/utils" @@ -176,12 +175,7 @@ func (gui *Gui) fetch(canPromptForCredentials bool) (err error) { err = gui.GitCommand.Fetch(fetchOpts) if canPromptForCredentials && err != nil && strings.Contains(err.Error(), "exit status 128") { - colorFunction := color.New(color.FgRed).SprintFunc() - 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.createErrorPanel(gui.Tr.SLocalize("PassUnameWrong")) } gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC}) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 71cda50f7..ec582e131 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -463,21 +463,35 @@ func (gui *Gui) showInitialPopups(tasks []func(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{}{} 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 { - return gui.createConfirmationPanel(gui.g, nil, true, gui.Tr.SLocalize("AnonymousReportingTitle"), gui.Tr.SLocalize("AnonymousReportingPrompt"), func(g *gocui.Gui, v *gocui.View) error { - done <- struct{}{} - return gui.Config.WriteToUserConfig("reporting", "on") - }, func(g *gocui.Gui, v *gocui.View) error { - done <- struct{}{} - return gui.Config.WriteToUserConfig("reporting", "off") + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: nil, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("AnonymousReportingTitle"), + prompt: gui.Tr.SLocalize("AnonymousReportingPrompt"), + handleConfirm: func() error { + done <- struct{}{} + return gui.Config.WriteToUserConfig("reporting", "on") + }, + handleClose: func() error { + done <- struct{}{} + return gui.Config.WriteToUserConfig("reporting", "off") + }, }) } @@ -504,7 +518,12 @@ func (gui *Gui) startBackgroundFetch() { } err := gui.fetch(false) 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 { gui.goEvery(time.Second*60, gui.stopChan, func() error { err := gui.fetch(false) diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 9f49c0d25..8eecdda48 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -326,7 +326,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { informationView.BgColor = gocui.ColorDefault informationView.FgColor = gocui.ColorGreen informationView.Frame = false - gui.renderString(g, "information", INFO_SECTION_PADDING+informationStr) + gui.renderString("information", INFO_SECTION_PADDING+informationStr) } if gui.State.OldInformation != informationStr { gui.setViewContent(informationView, informationStr) @@ -342,7 +342,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { return err } - if err := gui.switchFocus(gui.g, nil, initialView); err != nil { + if err := gui.switchFocus(nil, initialView); err != nil { return err } } diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 9b2eefac5..b8fc80b81 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -119,7 +119,7 @@ func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions cr } } currentView := gui.g.CurrentView() - return gui.switchFocus(gui.g, currentView, menuView) + return gui.switchFocus(currentView, menuView) }) return nil } diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index a70d7fbbb..5918b9476 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -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 // ensure we only 'return' focus if we already have it if gui.g.CurrentView() == gui.getMainView() { - return gui.switchFocus(g, v, gui.getFilesView()) + return gui.switchFocus(v, gui.getFilesView()) } return nil } @@ -336,9 +336,15 @@ func (gui *Gui) handleCompleteMerge() error { func (gui *Gui) promptToContinue() error { 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.genericMergeCommand("continue") - }, nil) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: gui.getFilesView(), + returnFocusOnClose: true, + title: "continue", + prompt: gui.Tr.SLocalize("ConflictsResolved"), + handleConfirm: func() error { + return gui.genericMergeCommand("continue") + }, + }) } func (gui *Gui) canScrollMergePanel() bool { diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index def631d47..ad05f33c9 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -18,7 +18,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { // get diff from commit file that's currently selected commitFile := gui.getSelectedCommitFile() if commitFile == nil { - gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) + gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) 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 commitFile := gui.getSelectedCommitFile() if commitFile == nil { - gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) + gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) return nil } @@ -83,7 +83,7 @@ func (gui *Gui) handleEscapePatchBuildingPanel(g *gocui.Gui, v *gocui.View) erro gui.State.SplitMainPanel = false } - return gui.switchFocus(gui.g, nil, gui.getCommitFilesView()) + return gui.switchFocus(nil, gui.getCommitFilesView()) } func (gui *Gui) refreshSecondaryPatchPanel() error { diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index 4ec3cd228..5407e7c31 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -133,9 +133,15 @@ func (gui *Gui) handlePullPatchIntoWorkingTree() error { } 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 pull(true) - }, nil) + 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) + }, + }) } else { return pull(false) } diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index b6cd57e23..915babcca 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -55,9 +55,15 @@ func (gui *Gui) quit(v *gocui.View) error { } 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 gocui.ErrQuit - }, nil) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: "", + prompt: gui.Tr.SLocalize("ConfirmQuit"), + handleConfirm: func() error { + return gocui.ErrQuit + }, + }) } return gocui.ErrQuit diff --git a/pkg/gui/rebase_options_panel.go b/pkg/gui/rebase_options_panel.go index d34733591..ae0db7d0f 100644 --- a/pkg/gui/rebase_options_panel.go +++ b/pkg/gui/rebase_options_panel.go @@ -78,13 +78,18 @@ func (gui *Gui) handleGenericMergeCommandResult(result error) error { // assume in this case that we're already done 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") { - return gui.createConfirmationPanel(gui.g, gui.getFilesView(), true, gui.Tr.SLocalize("FoundConflictsTitle"), gui.Tr.SLocalize("FoundConflicts"), - func(g *gocui.Gui, v *gocui.View) error { + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: gui.getFilesView(), + returnFocusOnClose: true, + title: gui.Tr.SLocalize("FoundConflictsTitle"), + prompt: gui.Tr.SLocalize("FoundConflicts"), + handleConfirm: func() error { return nil - }, func(g *gocui.Gui, v *gocui.View) error { + }, + handleClose: func() error { return gui.genericMergeCommand("abort") }, - ) + }) } else { return gui.createErrorPanel(result.Error()) } diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 0e69cbbd8..b985f0faa 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -121,9 +121,15 @@ func (gui *Gui) handleCheckoutReflogCommit(g *gocui.Gui, v *gocui.View) error { 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 { - return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) - }, nil) + 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{}) + }, + }) if err != nil { return err } diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 4d92e6f7e..be0092359 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -94,15 +94,22 @@ func (gui *Gui) handleDeleteRemoteBranch(g *gocui.Gui, v *gocui.View) error { return nil } 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.WithWaitingStatus(gui.Tr.SLocalize("DeletingStatus"), func() error { - if err := gui.GitCommand.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name); err != nil { - return err - } - return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) - }) - }, nil) + 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 { + if err := gui.GitCommand.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name); err != nil { + return err + } + + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) + }) + }, + }) } 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 { - if err := gui.GitCommand.SetBranchUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { - return err - } + 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 { + return err + } - return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) - }, nil) + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) + }, + }) } 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(), }, ) - return gui.createPromptPanel(g, v, message, branch.FullName(), func(g *gocui.Gui, v *gocui.View) error { - if err := gui.GitCommand.NewBranch(gui.trimmedContent(v), branch.FullName()); err != nil { + return gui.createPromptPanel(v, message, branch.FullName(), func(response string) error { + if err := gui.GitCommand.NewBranch(response, branch.FullName()); err != nil { return gui.surfaceError(err) } gui.State.Panels.Branches.SelectedLine = 0 diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index 58479b93b..3957adc10 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -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 { branchesView := gui.getBranchesView() - return gui.createPromptPanel(g, branchesView, gui.Tr.SLocalize("newRemoteName"), "", func(g *gocui.Gui, v *gocui.View) error { - remoteName := gui.trimmedContent(v) - return gui.createPromptPanel(g, branchesView, gui.Tr.SLocalize("newRemoteUrl"), "", func(g *gocui.Gui, v *gocui.View) error { - remoteUrl := gui.trimmedContent(v) + return gui.createPromptPanel(branchesView, gui.Tr.SLocalize("newRemoteName"), "", func(remoteName string) error { + return gui.createPromptPanel(branchesView, gui.Tr.SLocalize("newRemoteUrl"), "", func(remoteUrl string) error { if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil { return err } @@ -133,14 +131,20 @@ func (gui *Gui) handleRemoveRemote(g *gocui.Gui, v *gocui.View) error { if remote == 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 { - if err := gui.GitCommand.RemoveRemote(remote.Name); err != nil { - return err - } - return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) + 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 { + return err + } - }, nil) + return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) + }, + }) } 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 { - updatedRemoteName := gui.trimmedContent(v) - + return gui.createPromptPanel(branchesView, editNameMessage, "", func(updatedRemoteName string) error { if updatedRemoteName != remote.Name { if err := gui.GitCommand.RenameRemote(remote.Name, updatedRemoteName); err != nil { 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 { - updatedRemoteUrl := gui.trimmedContent(v) + return gui.createPromptPanel(branchesView, editUrlMessage, "", func(updatedRemoteUrl string) error { if err := gui.GitCommand.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { return gui.surfaceError(err) } diff --git a/pkg/gui/searching.go b/pkg/gui/searching.go index 228ae35be..7ced4292f 100644 --- a/pkg/gui/searching.go +++ b/pkg/gui/searching.go @@ -11,8 +11,8 @@ import ( func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error { gui.State.Searching.isSearching = true gui.State.Searching.view = v - gui.renderString(gui.g, "search", "") - if err := gui.switchFocus(gui.g, v, gui.getSearchView()); err != nil { + gui.renderString("search", "") + if err := gui.switchFocus(v, gui.getSearchView()); err != nil { 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 { 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 } @@ -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 { if total == 0 { gui.renderString( - gui.g, "search", fmt.Sprintf( "no matches for '%s' %s", @@ -50,7 +49,6 @@ func (gui *Gui) onSelectItemWrapper(innerFunc func(int) error) func(int, int, in return nil } gui.renderString( - gui.g, "search", fmt.Sprintf( "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 { - 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 } diff --git a/pkg/gui/staging_panel.go b/pkg/gui/staging_panel.go index 8bb586a9d..92e3868d4 100644 --- a/pkg/gui/staging_panel.go +++ b/pkg/gui/staging_panel.go @@ -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. // 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. - if err := gui.switchFocus(gui.g, nil, gui.getMainView()); err != nil { + if err := gui.switchFocus(nil, gui.getMainView()); err != nil { 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 { 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 { @@ -114,9 +114,15 @@ func (gui *Gui) handleResetSelection(g *gocui.Gui, v *gocui.View) error { } 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.applySelection(true) - }, nil) + 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) + }, + }) } else { return gui.applySelection(true) } diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index a6f2d0b48..6979591ab 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -76,11 +76,15 @@ func (gui *Gui) handleStashApply(g *gocui.Gui, v *gocui.View) error { return apply() } - title := gui.Tr.SLocalize("StashApply") - message := gui.Tr.SLocalize("SureApplyStashEntry") - return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - return apply() - }, nil) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("StashApply"), + prompt: gui.Tr.SLocalize("SureApplyStashEntry"), + handleConfirm: func() error { + return apply() + }, + }) } 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() } - title := gui.Tr.SLocalize("StashPop") - message := gui.Tr.SLocalize("SurePopStashEntry") - return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - return pop() - }, nil) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("StashPop"), + prompt: gui.Tr.SLocalize("SurePopStashEntry"), + handleConfirm: func() error { + return pop() + }, + }) } func (gui *Gui) handleStashDrop(g *gocui.Gui, v *gocui.View) error { - title := gui.Tr.SLocalize("StashDrop") - message := gui.Tr.SLocalize("SureDropStashEntry") - return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - return gui.stashDo(g, v, "drop") - }, nil) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: gui.Tr.SLocalize("StashDrop"), + prompt: gui.Tr.SLocalize("SureDropStashEntry"), + handleConfirm: func() error { + return gui.stashDo(g, v, "drop") + }, + }) } 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 { 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 { - if err := stashFunc(gui.trimmedContent(v)); err != nil { + return gui.createPromptPanel(gui.getFilesView(), gui.Tr.SLocalize("StashChanges"), "", func(stashComment string) error { + if err := stashFunc(stashComment); err != nil { return gui.surfaceError(err) } return gui.refreshSidePanels(refreshOptions{scope: []int{STASH, FILES}}) diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 26f3b6d3a..b14dc141c 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -57,7 +57,7 @@ func cursorInSubstring(cx int, prefix string, substring string) bool { func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error { 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 { diff --git a/pkg/gui/tags_panel.go b/pkg/gui/tags_panel.go index 8de632a8a..7dc8f3e65 100644 --- a/pkg/gui/tags_panel.go +++ b/pkg/gui/tags_panel.go @@ -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 { - if err := gui.GitCommand.DeleteTag(tag.Name); err != nil { - return gui.surfaceError(err) - } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}}) - }, nil) + 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 { + return gui.surfaceError(err) + } + return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}}) + }, + }) } 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 { - if err := gui.GitCommand.PushTag(v.Buffer(), tag.Name); err != nil { + return gui.createPromptPanel(v, title, "origin", func(response string) error { + if err := gui.GitCommand.PushTag(response, tag.Name); err != nil { return gui.surfaceError(err) } 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 { - 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 - tagName := v.Buffer() if err := gui.GitCommand.CreateLightweightTag(tagName, ""); err != nil { return gui.surfaceError(err) } diff --git a/pkg/gui/tasks_adapter.go b/pkg/gui/tasks_adapter.go index aa9f26f14..0a05bb0c9 100644 --- a/pkg/gui/tasks_adapter.go +++ b/pkg/gui/tasks_adapter.go @@ -59,7 +59,7 @@ func (gui *Gui) newStringTask(viewName string, str string) error { manager := gui.getManager(view) f := func(stop chan struct{}) error { - gui.renderString(gui.g, viewName, str) + gui.renderString(viewName, str) return nil } diff --git a/pkg/gui/undoing.go b/pkg/gui/undoing.go index 06057af37..7bc128b89 100644 --- a/pkg/gui/undoing.go +++ b/pkg/gui/undoing.go @@ -166,24 +166,30 @@ func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHar dirtyWorkingTree := len(gui.trackedFiles()) > 0 if dirtyWorkingTree { // 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.WithWaitingStatus(options.WaitingStatus, func() error { - if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + commitSha); err != nil { - return gui.surfaceError(err) - } - if err := reset(); err != nil { - return err - } - - if err := gui.GitCommand.StashDo(0, "pop"); err != nil { - if err := gui.refreshSidePanels(refreshOptions{}); err != nil { + 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 { + if err := gui.GitCommand.StashSave(gui.Tr.SLocalize("StashPrefix") + commitSha); err != nil { + return gui.surfaceError(err) + } + if err := reset(); err != nil { return err } - return gui.surfaceError(err) - } - return nil - }) - }, nil) + + if err := gui.GitCommand.StashDo(0, "pop"); err != nil { + if err := gui.refreshSidePanels(refreshOptions{}); err != nil { + return err + } + return gui.surfaceError(err) + } + return nil + }) + }, + }) } return gui.WithWaitingStatus(options.WaitingStatus, func() error { diff --git a/pkg/gui/updates.go b/pkg/gui/updates.go index b44c5d5e4..97ef123fd 100644 --- a/pkg/gui/updates.go +++ b/pkg/gui/updates.go @@ -3,13 +3,18 @@ package gui import "github.com/jesseduffield/gocui" func (gui *Gui) showUpdatePrompt(newVersion string) error { - title := "New version available!" - message := "Download latest version? (enter/esc)" currentView := gui.g.CurrentView() - return gui.createConfirmationPanel(gui.g, currentView, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - gui.startUpdating(newVersion) - return nil - }, nil) + + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: currentView, + returnFocusOnClose: true, + title: "New version available!", + prompt: "Download latest version? (enter/esc)", + handleConfirm: func() error { + gui.startUpdating(newVersion) + return nil + }, + }) } 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 { gui.State.Updating = false gui.statusManager.removeStatus("updating") - gui.renderString(gui.g, "appStatus", "") + gui.renderString("appStatus", "") if err != nil { 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 { - title := "Currently Updating" - message := "An update is in progress. Are you sure you want to quit?" - return gui.createConfirmationPanel(gui.g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error { - return gocui.ErrQuit - }, nil) + return gui.createConfirmationPanel(createConfirmationPanelOpts{ + returnToView: v, + returnFocusOnClose: true, + title: "Currently Updating", + prompt: "An update is in progress. Are you sure you want to quit?", + handleConfirm: func() error { + return gocui.ErrQuit + }, + }) } diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 56386c872..d060be269 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -175,7 +175,7 @@ func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error { if err := gui.resetOrigin(gui.getMainView()); err != nil { return err } - return gui.switchFocus(g, v, focusedView) + return gui.switchFocus(v, focusedView) } 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 { return err } - return gui.switchFocus(g, v, focusedView) + return gui.switchFocus(v, focusedView) } 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) } } - 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 { @@ -287,7 +287,7 @@ func (gui *Gui) goToSideView(sideViewName string) func(g *gocui.Gui, v *gocui.Vi gui.Log.Error(err) 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 // 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 should never stack popup panels 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) - if _, err := g.SetCurrentView(newView.Name()); err != nil { + if _, err := gui.g.SetCurrentView(newView.Name()); err != nil { return err } - if _, err := g.SetViewOnTop(newView.Name()); err != nil { + if _, err := gui.g.SetViewOnTop(newView.Name()); err != nil { return err } - g.Cursor = newView.Editable + gui.g.Cursor = newView.Editable if err := gui.renderPanelOptions(); err != nil { return err } - return gui.newLineFocused(g, newView) + return gui.newLineFocused(gui.g, newView) } 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 -func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) { - g.Update(func(*gocui.Gui) error { - v, err := g.View(viewName) +func (gui *Gui) renderString(viewName, s string) { + gui.g.Update(func(*gocui.Gui) error { + v, err := gui.g.View(viewName) if err != nil { 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 { - gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap)) + gui.renderString("options", gui.optionsMapToString(optionsMap)) return nil } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index feb1947d0..5f974dc64 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -1165,6 +1165,12 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "BranchNotFoundPrompt", 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", }, ) }