mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-11-23 16:22:24 +03:00
Don't allow empty input in most prompts (#5043)
Most of our prompts don't (shouldn't) allow empty input, but most callers didn't check, and would run into cryptic errors when the user pressed enter at an empty prompt (e.g. when creating a new branch). Now we simply don't allow hitting enter in this case, and show an error toast instead. This behavior is opt-out, because there are a few cases where empty input is supported (e.g. creating a stash).
This commit is contained in:
@@ -2,7 +2,6 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
@@ -38,7 +37,7 @@ func (self *DiffingMenuAction) Call() error {
|
|||||||
Title: self.c.Tr.EnterRefName,
|
Title: self.c.Tr.EnterRefName,
|
||||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRefsSuggestionsFunc(),
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRefsSuggestionsFunc(),
|
||||||
HandleConfirm: func(response string) error {
|
HandleConfirm: func(response string) error {
|
||||||
self.c.Modes().Diffing.Ref = strings.TrimSpace(response)
|
self.c.Modes().Diffing.Ref = response
|
||||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1211,6 +1211,7 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro
|
|||||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
|
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
AllowEmptyInput: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
@@ -66,7 +65,7 @@ func (self *FilteringMenuAction) Call() error {
|
|||||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetFilePathSuggestionsFunc(),
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetFilePathSuggestionsFunc(),
|
||||||
Title: self.c.Tr.EnterFileName,
|
Title: self.c.Tr.EnterFileName,
|
||||||
HandleConfirm: func(response string) error {
|
HandleConfirm: func(response string) error {
|
||||||
return self.setFilteringPath(strings.TrimSpace(response))
|
return self.setFilteringPath(response)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ func (self *FilteringMenuAction) Call() error {
|
|||||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc(),
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc(),
|
||||||
Title: self.c.Tr.EnterAuthor,
|
Title: self.c.Tr.EnterAuthor,
|
||||||
HandleConfirm: func(response string) error {
|
HandleConfirm: func(response string) error {
|
||||||
return self.setFilteringAuthor(strings.TrimSpace(response))
|
return self.setFilteringAuthor(response)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,33 @@ func NewConfirmationHelper(c *HelperCommon) *ConfirmationHelper {
|
|||||||
// This file is for the rendering of confirmation panels along with setting and handling associated
|
// This file is for the rendering of confirmation panels along with setting and handling associated
|
||||||
// keybindings.
|
// keybindings.
|
||||||
|
|
||||||
|
func (self *ConfirmationHelper) closeAndCallConfirmationFunction(cancel goContext.CancelFunc, function func() error) error {
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
self.c.Context().Pop()
|
||||||
|
|
||||||
|
if function != nil {
|
||||||
|
if err := function(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (self *ConfirmationHelper) wrappedConfirmationFunction(cancel goContext.CancelFunc, function func() error) func() error {
|
func (self *ConfirmationHelper) wrappedConfirmationFunction(cancel goContext.CancelFunc, function func() error) func() error {
|
||||||
|
return func() error {
|
||||||
|
return self.closeAndCallConfirmationFunction(cancel, function)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ConfirmationHelper) wrappedPromptConfirmationFunction(
|
||||||
|
cancel goContext.CancelFunc,
|
||||||
|
function func(string) error,
|
||||||
|
getResponse func() string,
|
||||||
|
allowEmptyInput bool,
|
||||||
|
preserveWhitespace bool,
|
||||||
|
) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
if self.c.GocuiGui().IsPasting {
|
if self.c.GocuiGui().IsPasting {
|
||||||
// The user is pasting multi-line text into a prompt; we don't want to handle the
|
// The user is pasting multi-line text into a prompt; we don't want to handle the
|
||||||
@@ -34,24 +60,20 @@ func (self *ConfirmationHelper) wrappedConfirmationFunction(cancel goContext.Can
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel()
|
response := getResponse()
|
||||||
|
if !preserveWhitespace {
|
||||||
self.c.Context().Pop()
|
response = strings.TrimSpace(response)
|
||||||
|
|
||||||
if function != nil {
|
|
||||||
if err := function(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if response == "" && !allowEmptyInput {
|
||||||
}
|
self.c.ErrorToast(self.c.Tr.PromptInputCannotBeEmptyToast)
|
||||||
}
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (self *ConfirmationHelper) wrappedPromptConfirmationFunction(cancel goContext.CancelFunc, function func(string) error, getResponse func() string) func() error {
|
return self.closeAndCallConfirmationFunction(cancel, func() error {
|
||||||
return self.wrappedConfirmationFunction(cancel, func() error {
|
return function(response)
|
||||||
return function(getResponse())
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ConfirmationHelper) DeactivateConfirmation() {
|
func (self *ConfirmationHelper) DeactivateConfirmation() {
|
||||||
@@ -229,12 +251,15 @@ func (self *ConfirmationHelper) setConfirmationKeyBindings(cancel goContext.Canc
|
|||||||
|
|
||||||
func (self *ConfirmationHelper) setPromptKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) {
|
func (self *ConfirmationHelper) setPromptKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) {
|
||||||
onConfirm := self.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt,
|
onConfirm := self.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt,
|
||||||
func() string { return self.c.Views().Prompt.TextArea.GetContent() })
|
func() string { return self.c.Views().Prompt.TextArea.GetContent() },
|
||||||
|
opts.AllowEmptyInput, opts.PreserveWhitespace)
|
||||||
|
|
||||||
onSuggestionConfirm := self.wrappedPromptConfirmationFunction(
|
onSuggestionConfirm := self.wrappedPromptConfirmationFunction(
|
||||||
cancel,
|
cancel,
|
||||||
opts.HandleConfirmPrompt,
|
opts.HandleConfirmPrompt,
|
||||||
self.getSelectedSuggestionValue,
|
self.getSelectedSuggestionValue,
|
||||||
|
opts.AllowEmptyInput,
|
||||||
|
opts.PreserveWhitespace,
|
||||||
)
|
)
|
||||||
|
|
||||||
onClose := self.wrappedConfirmationFunction(cancel, opts.HandleClose)
|
onClose := self.wrappedConfirmationFunction(cancel, opts.HandleClose)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ func (self *CredentialsHelper) PromptUserForCredential(passOrUname oscommands.Cr
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
AllowEmptyInput: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -130,23 +130,21 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo
|
|||||||
|
|
||||||
return f()
|
return f()
|
||||||
},
|
},
|
||||||
|
AllowEmptyInput: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// prompt for the new branch name where a blank means we just check out the branch
|
// prompt for the new branch name
|
||||||
self.c.Prompt(types.PromptOpts{
|
self.c.Prompt(types.PromptOpts{
|
||||||
Title: self.c.Tr.NewBranchName,
|
Title: self.c.Tr.NewBranchName,
|
||||||
HandleConfirm: func(branchName string) error {
|
HandleConfirm: func(branchName string) error {
|
||||||
if branchName == "" {
|
|
||||||
return errors.New(self.c.Tr.BranchNameCannotBeBlank)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.Branch = branchName
|
opts.Branch = branchName
|
||||||
|
|
||||||
return f()
|
return f()
|
||||||
},
|
},
|
||||||
|
AllowEmptyInput: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ func (self *ShellCommandAction) Call() error {
|
|||||||
Title: self.c.Tr.ShellCommand,
|
Title: self.c.Tr.ShellCommand,
|
||||||
FindSuggestionsFunc: self.GetShellCommandsHistorySuggestionsFunc(),
|
FindSuggestionsFunc: self.GetShellCommandsHistorySuggestionsFunc(),
|
||||||
AllowEditSuggestion: true,
|
AllowEditSuggestion: true,
|
||||||
|
PreserveWhitespace: true,
|
||||||
HandleConfirm: func(command string) error {
|
HandleConfirm: func(command string) error {
|
||||||
if self.shouldSaveCommand(command) {
|
if self.shouldSaveCommand(command) {
|
||||||
self.c.GetAppState().ShellCommandsHistory = utils.Limit(
|
self.c.GetAppState().ShellCommandsHistory = utils.Limit(
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntr
|
|||||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
AllowEmptyInput: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ func (self *PopupHandler) Prompt(opts types.PromptOpts) {
|
|||||||
HandleDeleteSuggestion: opts.HandleDeleteSuggestion,
|
HandleDeleteSuggestion: opts.HandleDeleteSuggestion,
|
||||||
FindSuggestionsFunc: opts.FindSuggestionsFunc,
|
FindSuggestionsFunc: opts.FindSuggestionsFunc,
|
||||||
AllowEditSuggestion: opts.AllowEditSuggestion,
|
AllowEditSuggestion: opts.AllowEditSuggestion,
|
||||||
|
AllowEmptyInput: opts.AllowEmptyInput,
|
||||||
|
PreserveWhitespace: opts.PreserveWhitespace,
|
||||||
Mask: opts.Mask,
|
Mask: opts.Mask,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap
|
|||||||
HandleConfirm: func(str string) error {
|
HandleConfirm: func(str string) error {
|
||||||
return wrappedF(str)
|
return wrappedF(str)
|
||||||
},
|
},
|
||||||
|
AllowEmptyInput: true,
|
||||||
|
PreserveWhitespace: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -172,6 +172,8 @@ type CreatePopupPanelOpts struct {
|
|||||||
FindSuggestionsFunc func(string) []*Suggestion
|
FindSuggestionsFunc func(string) []*Suggestion
|
||||||
Mask bool
|
Mask bool
|
||||||
AllowEditSuggestion bool
|
AllowEditSuggestion bool
|
||||||
|
AllowEmptyInput bool
|
||||||
|
PreserveWhitespace bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfirmOpts struct {
|
type ConfirmOpts struct {
|
||||||
@@ -190,6 +192,8 @@ type PromptOpts struct {
|
|||||||
FindSuggestionsFunc func(string) []*Suggestion
|
FindSuggestionsFunc func(string) []*Suggestion
|
||||||
HandleConfirm func(string) error
|
HandleConfirm func(string) error
|
||||||
AllowEditSuggestion bool
|
AllowEditSuggestion bool
|
||||||
|
AllowEmptyInput bool
|
||||||
|
PreserveWhitespace bool
|
||||||
// CAPTURE THIS
|
// CAPTURE THIS
|
||||||
HandleClose func() error
|
HandleClose func() error
|
||||||
HandleDeleteSuggestion func(int) error
|
HandleDeleteSuggestion func(int) error
|
||||||
|
|||||||
@@ -618,6 +618,7 @@ type TranslationSet struct {
|
|||||||
MustStashTitle string
|
MustStashTitle string
|
||||||
ConfirmationTitle string
|
ConfirmationTitle string
|
||||||
PromptTitle string
|
PromptTitle string
|
||||||
|
PromptInputCannotBeEmptyToast string
|
||||||
PrevPage string
|
PrevPage string
|
||||||
NextPage string
|
NextPage string
|
||||||
GotoTop string
|
GotoTop string
|
||||||
@@ -861,7 +862,6 @@ type TranslationSet struct {
|
|||||||
NewWorktreePath string
|
NewWorktreePath string
|
||||||
NewWorktreeBase string
|
NewWorktreeBase string
|
||||||
RemoveWorktreeTooltip string
|
RemoveWorktreeTooltip string
|
||||||
BranchNameCannotBeBlank string
|
|
||||||
NewBranchName string
|
NewBranchName string
|
||||||
NewBranchNameLeaveBlank string
|
NewBranchNameLeaveBlank string
|
||||||
ViewWorktreeOptions string
|
ViewWorktreeOptions string
|
||||||
@@ -1713,6 +1713,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
MustStashTitle: "Must stash",
|
MustStashTitle: "Must stash",
|
||||||
ConfirmationTitle: "Confirmation panel",
|
ConfirmationTitle: "Confirmation panel",
|
||||||
PromptTitle: "Input prompt",
|
PromptTitle: "Input prompt",
|
||||||
|
PromptInputCannotBeEmptyToast: "Empty input is not allowed",
|
||||||
PrevPage: "Previous page",
|
PrevPage: "Previous page",
|
||||||
NextPage: "Next page",
|
NextPage: "Next page",
|
||||||
GotoTop: "Scroll to top",
|
GotoTop: "Scroll to top",
|
||||||
@@ -1954,7 +1955,6 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
NewWorktreePath: "New worktree path",
|
NewWorktreePath: "New worktree path",
|
||||||
NewWorktreeBase: "New worktree base ref",
|
NewWorktreeBase: "New worktree base ref",
|
||||||
RemoveWorktreeTooltip: "Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory.",
|
RemoveWorktreeTooltip: "Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory.",
|
||||||
BranchNameCannotBeBlank: "Branch name cannot be blank",
|
|
||||||
NewBranchName: "New branch name",
|
NewBranchName: "New branch name",
|
||||||
NewBranchNameLeaveBlank: "New branch name (leave blank to checkout {{.default}})",
|
NewBranchNameLeaveBlank: "New branch name (leave blank to checkout {{.default}})",
|
||||||
ViewWorktreeOptions: "View worktree options",
|
ViewWorktreeOptions: "View worktree options",
|
||||||
|
|||||||
Reference in New Issue
Block a user