mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-06 23:46:13 +02:00
If a DisabledReason has its AllowFurtherDispatching flag set, it is returned as a ErrKeybindingNotHandled error, instead of shown as a toast right away. This allows gocui to continue to dispatch the keybinding, and we can unwrap the error at the other end (in our global ErrorHandler) and display it then. This allows having keybindings for the same key at the local and global levels, and they will continue to be dispatched even if the first one returns a DisabledReason. It is opt-in, so we only use it for cases where we know that a local and a global handler share the same (default) keybinding.
137 lines
4.3 KiB
Go
137 lines
4.3 KiB
Go
package popup
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
|
|
"github.com/jesseduffield/gocui"
|
|
"github.com/jesseduffield/lazygit/pkg/common"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
)
|
|
|
|
type PopupHandler struct {
|
|
*common.Common
|
|
createPopupPanelFn func(context.Context, types.CreatePopupPanelOpts)
|
|
onErrorFn func() error
|
|
popContextFn func()
|
|
currentContextFn func() types.Context
|
|
createMenuFn func(types.CreateMenuOptions) error
|
|
withWaitingStatusFn func(message string, f func(gocui.Task) error)
|
|
withWaitingStatusSyncFn func(message string, f func() error) error
|
|
toastFn func(message string, kind types.ToastKind)
|
|
getPromptInputFn func() string
|
|
inDemo func() bool
|
|
}
|
|
|
|
var _ types.IPopupHandler = &PopupHandler{}
|
|
|
|
func NewPopupHandler(
|
|
common *common.Common,
|
|
createPopupPanelFn func(context.Context, types.CreatePopupPanelOpts),
|
|
onErrorFn func() error,
|
|
popContextFn func(),
|
|
currentContextFn func() types.Context,
|
|
createMenuFn func(types.CreateMenuOptions) error,
|
|
withWaitingStatusFn func(message string, f func(gocui.Task) error),
|
|
withWaitingStatusSyncFn func(message string, f func() error) error,
|
|
toastFn func(message string, kind types.ToastKind),
|
|
getPromptInputFn func() string,
|
|
inDemo func() bool,
|
|
) *PopupHandler {
|
|
return &PopupHandler{
|
|
Common: common,
|
|
createPopupPanelFn: createPopupPanelFn,
|
|
onErrorFn: onErrorFn,
|
|
popContextFn: popContextFn,
|
|
currentContextFn: currentContextFn,
|
|
createMenuFn: createMenuFn,
|
|
withWaitingStatusFn: withWaitingStatusFn,
|
|
withWaitingStatusSyncFn: withWaitingStatusSyncFn,
|
|
toastFn: toastFn,
|
|
getPromptInputFn: getPromptInputFn,
|
|
inDemo: inDemo,
|
|
}
|
|
}
|
|
|
|
func (self *PopupHandler) Menu(opts types.CreateMenuOptions) error {
|
|
return self.createMenuFn(opts)
|
|
}
|
|
|
|
func (self *PopupHandler) Toast(message string) {
|
|
self.toastFn(message, types.ToastKindStatus)
|
|
}
|
|
|
|
func (self *PopupHandler) ErrorToast(message string) {
|
|
self.toastFn(message, types.ToastKindError)
|
|
}
|
|
|
|
func (self *PopupHandler) SetToastFunc(f func(string, types.ToastKind)) {
|
|
self.toastFn = f
|
|
}
|
|
|
|
func (self *PopupHandler) WithWaitingStatus(message string, f func(gocui.Task) error) error {
|
|
self.withWaitingStatusFn(message, f)
|
|
return nil
|
|
}
|
|
|
|
func (self *PopupHandler) WithWaitingStatusSync(message string, f func() error) error {
|
|
return self.withWaitingStatusSyncFn(message, f)
|
|
}
|
|
|
|
func (self *PopupHandler) ErrorHandler(err error) error {
|
|
var notHandledError *types.ErrKeybindingNotHandled
|
|
if errors.As(err, ¬HandledError) {
|
|
if !notHandledError.DisabledReason.ShowErrorInPanel {
|
|
if msg := notHandledError.DisabledReason.Text; len(msg) > 0 {
|
|
self.ErrorToast(self.Tr.DisabledMenuItemPrefix + msg)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Need to set bold here explicitly; otherwise it gets cancelled by the red colouring.
|
|
coloredMessage := style.FgRed.SetBold().Sprint(strings.TrimSpace(err.Error()))
|
|
if err := self.onErrorFn(); err != nil {
|
|
return err
|
|
}
|
|
|
|
self.Alert(self.Tr.Error, coloredMessage)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *PopupHandler) Alert(title string, message string) {
|
|
self.Confirm(types.ConfirmOpts{Title: title, Prompt: message})
|
|
}
|
|
|
|
func (self *PopupHandler) Confirm(opts types.ConfirmOpts) {
|
|
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
|
Title: opts.Title,
|
|
Prompt: opts.Prompt,
|
|
HandleConfirm: opts.HandleConfirm,
|
|
HandleClose: opts.HandleClose,
|
|
})
|
|
}
|
|
|
|
func (self *PopupHandler) Prompt(opts types.PromptOpts) {
|
|
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
|
Title: opts.Title,
|
|
Prompt: opts.InitialContent,
|
|
Editable: true,
|
|
HandleConfirmPrompt: opts.HandleConfirm,
|
|
HandleClose: opts.HandleClose,
|
|
HandleDeleteSuggestion: opts.HandleDeleteSuggestion,
|
|
FindSuggestionsFunc: opts.FindSuggestionsFunc,
|
|
AllowEditSuggestion: opts.AllowEditSuggestion,
|
|
Mask: opts.Mask,
|
|
})
|
|
}
|
|
|
|
// returns the content that has currently been typed into the prompt. Useful for
|
|
// asynchronously updating the suggestions list under the prompt.
|
|
func (self *PopupHandler) GetPromptInput() string {
|
|
return self.getPromptInputFn()
|
|
}
|