From b3435bd59cc96a81f4ac46b750e3551546e49b70 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 15 Nov 2025 13:05:39 +0100 Subject: [PATCH] Add AllowEmptyInput flag to PromptOpts 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). --- pkg/gui/controllers/files_controller.go | 1 + .../helpers/confirmation_helper.go | 20 ++++++++++++++++--- .../controllers/helpers/credentials_helper.go | 1 + .../controllers/helpers/worktree_helper.go | 2 ++ pkg/gui/controllers/stash_controller.go | 1 + pkg/gui/popup/popup_handler.go | 1 + .../custom_commands/handler_creator.go | 1 + pkg/gui/types/common.go | 2 ++ pkg/i18n/english.go | 2 ++ 9 files changed, 28 insertions(+), 3 deletions(-) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 0289936de..d9477db4a 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -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}}) return nil }, + AllowEmptyInput: true, }) return nil diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go index d96159aea..2650de203 100644 --- a/pkg/gui/controllers/helpers/confirmation_helper.go +++ b/pkg/gui/controllers/helpers/confirmation_helper.go @@ -44,7 +44,12 @@ func (self *ConfirmationHelper) wrappedConfirmationFunction(cancel goContext.Can } } -func (self *ConfirmationHelper) wrappedPromptConfirmationFunction(cancel goContext.CancelFunc, function func(string) error, getResponse func() string) func() error { +func (self *ConfirmationHelper) wrappedPromptConfirmationFunction( + cancel goContext.CancelFunc, + function func(string) error, + getResponse func() string, + allowEmptyInput bool, +) func() error { return func() error { if self.c.GocuiGui().IsPasting { // The user is pasting multi-line text into a prompt; we don't want to handle the @@ -54,8 +59,15 @@ func (self *ConfirmationHelper) wrappedPromptConfirmationFunction(cancel goConte return nil } + response := getResponse() + + if response == "" && !allowEmptyInput { + self.c.ErrorToast(self.c.Tr.PromptInputCannotBeEmptyToast) + return nil + } + return self.closeAndCallConfirmationFunction(cancel, func() error { - return function(getResponse()) + return function(response) }) } } @@ -235,12 +247,14 @@ func (self *ConfirmationHelper) setConfirmationKeyBindings(cancel goContext.Canc func (self *ConfirmationHelper) setPromptKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) { 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) onSuggestionConfirm := self.wrappedPromptConfirmationFunction( cancel, opts.HandleConfirmPrompt, self.getSelectedSuggestionValue, + opts.AllowEmptyInput, ) onClose := self.wrappedConfirmationFunction(cancel, opts.HandleClose) diff --git a/pkg/gui/controllers/helpers/credentials_helper.go b/pkg/gui/controllers/helpers/credentials_helper.go index 0783e65f2..2d3654887 100644 --- a/pkg/gui/controllers/helpers/credentials_helper.go +++ b/pkg/gui/controllers/helpers/credentials_helper.go @@ -41,6 +41,7 @@ func (self *CredentialsHelper) PromptUserForCredential(passOrUname oscommands.Cr return nil }, + AllowEmptyInput: true, }) return nil diff --git a/pkg/gui/controllers/helpers/worktree_helper.go b/pkg/gui/controllers/helpers/worktree_helper.go index 419dcbe64..39ffadbdc 100644 --- a/pkg/gui/controllers/helpers/worktree_helper.go +++ b/pkg/gui/controllers/helpers/worktree_helper.go @@ -130,6 +130,7 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo return f() }, + AllowEmptyInput: true, }) return nil @@ -147,6 +148,7 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo return f() }, + AllowEmptyInput: false, }) return nil diff --git a/pkg/gui/controllers/stash_controller.go b/pkg/gui/controllers/stash_controller.go index 889bc0872..87f84d7ea 100644 --- a/pkg/gui/controllers/stash_controller.go +++ b/pkg/gui/controllers/stash_controller.go @@ -209,6 +209,7 @@ func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntr self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) return nil }, + AllowEmptyInput: true, }) return nil diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go index d8ce654b4..2cfbca946 100644 --- a/pkg/gui/popup/popup_handler.go +++ b/pkg/gui/popup/popup_handler.go @@ -139,6 +139,7 @@ func (self *PopupHandler) Prompt(opts types.PromptOpts) { HandleDeleteSuggestion: opts.HandleDeleteSuggestion, FindSuggestionsFunc: opts.FindSuggestionsFunc, AllowEditSuggestion: opts.AllowEditSuggestion, + AllowEmptyInput: opts.AllowEmptyInput, Mask: opts.Mask, }) } diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go index 73e68c3b3..1bfaaaa0f 100644 --- a/pkg/gui/services/custom_commands/handler_creator.go +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -125,6 +125,7 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap HandleConfirm: func(str string) error { return wrappedF(str) }, + AllowEmptyInput: true, }) return nil diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 905a9b65d..f754e0da5 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -172,6 +172,7 @@ type CreatePopupPanelOpts struct { FindSuggestionsFunc func(string) []*Suggestion Mask bool AllowEditSuggestion bool + AllowEmptyInput bool } type ConfirmOpts struct { @@ -190,6 +191,7 @@ type PromptOpts struct { FindSuggestionsFunc func(string) []*Suggestion HandleConfirm func(string) error AllowEditSuggestion bool + AllowEmptyInput bool // CAPTURE THIS HandleClose func() error HandleDeleteSuggestion func(int) error diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index cb070b892..794f58570 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -618,6 +618,7 @@ type TranslationSet struct { MustStashTitle string ConfirmationTitle string PromptTitle string + PromptInputCannotBeEmptyToast string PrevPage string NextPage string GotoTop string @@ -1713,6 +1714,7 @@ func EnglishTranslationSet() *TranslationSet { MustStashTitle: "Must stash", ConfirmationTitle: "Confirmation panel", PromptTitle: "Input prompt", + PromptInputCannotBeEmptyToast: "Empty input is not allowed", PrevPage: "Previous page", NextPage: "Next page", GotoTop: "Scroll to top",