1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-14 11:23:09 +02:00
lazygit/pkg/gui/popup/popup_handler.go
2022-03-17 19:13:40 +11:00

252 lines
6.1 KiB
Go

package popup
import (
"strings"
"sync"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type IPopupHandler interface {
ErrorMsg(message string) error
Error(err error) error
Ask(opts AskOpts) error
Prompt(opts PromptOpts) error
WithLoaderPanel(message string, f func() error) error
WithWaitingStatus(message string, f func() error) error
Menu(opts CreateMenuOptions) error
Toast(message string)
GetPromptInput() string
}
type CreateMenuOptions struct {
Title string
Items []*MenuItem
HideCancel bool
}
type CreatePopupPanelOpts struct {
HasLoader bool
Editable bool
Title string
Prompt string
HandleConfirm func() error
HandleConfirmPrompt func(string) error
HandleClose func() error
// when HandlersManageFocus is true, do not return from the confirmation context automatically. It's expected that the handlers will manage focus, whether that means switching to another context, or manually returning the context.
HandlersManageFocus bool
FindSuggestionsFunc func(string) []*types.Suggestion
}
type AskOpts struct {
Title string
Prompt string
HandleConfirm func() error
HandleClose func() error
HandlersManageFocus bool
}
type PromptOpts struct {
Title string
InitialContent string
FindSuggestionsFunc func(string) []*types.Suggestion
HandleConfirm func(string) error
}
type MenuItem struct {
DisplayString string
DisplayStrings []string
OnPress func() error
// only applies when displayString is used
OpensMenu bool
}
type RealPopupHandler struct {
*common.Common
index int
sync.Mutex
createPopupPanelFn func(CreatePopupPanelOpts) error
onErrorFn func() error
closePopupFn func() error
createMenuFn func(CreateMenuOptions) error
withWaitingStatusFn func(message string, f func() error) error
toastFn func(message string)
getPromptInputFn func() string
}
var _ IPopupHandler = &RealPopupHandler{}
func NewPopupHandler(
common *common.Common,
createPopupPanelFn func(CreatePopupPanelOpts) error,
onErrorFn func() error,
closePopupFn func() error,
createMenuFn func(CreateMenuOptions) error,
withWaitingStatusFn func(message string, f func() error) error,
toastFn func(message string),
getPromptInputFn func() string,
) *RealPopupHandler {
return &RealPopupHandler{
Common: common,
index: 0,
createPopupPanelFn: createPopupPanelFn,
onErrorFn: onErrorFn,
closePopupFn: closePopupFn,
createMenuFn: createMenuFn,
withWaitingStatusFn: withWaitingStatusFn,
toastFn: toastFn,
getPromptInputFn: getPromptInputFn,
}
}
func (self *RealPopupHandler) Menu(opts CreateMenuOptions) error {
return self.createMenuFn(opts)
}
func (self *RealPopupHandler) Toast(message string) {
self.toastFn(message)
}
func (self *RealPopupHandler) WithWaitingStatus(message string, f func() error) error {
return self.withWaitingStatusFn(message, f)
}
func (self *RealPopupHandler) Error(err error) error {
if err == gocui.ErrQuit {
return err
}
return self.ErrorMsg(err.Error())
}
func (self *RealPopupHandler) ErrorMsg(message string) error {
self.Lock()
self.index++
self.Unlock()
coloredMessage := style.FgRed.Sprint(strings.TrimSpace(message))
if err := self.onErrorFn(); err != nil {
return err
}
return self.Ask(AskOpts{
Title: self.Tr.Error,
Prompt: coloredMessage,
})
}
func (self *RealPopupHandler) Ask(opts AskOpts) error {
self.Lock()
self.index++
self.Unlock()
return self.createPopupPanelFn(CreatePopupPanelOpts{
Title: opts.Title,
Prompt: opts.Prompt,
HandleConfirm: opts.HandleConfirm,
HandleClose: opts.HandleClose,
HandlersManageFocus: opts.HandlersManageFocus,
})
}
func (self *RealPopupHandler) Prompt(opts PromptOpts) error {
self.Lock()
self.index++
self.Unlock()
return self.createPopupPanelFn(CreatePopupPanelOpts{
Title: opts.Title,
Prompt: opts.InitialContent,
Editable: true,
HandleConfirmPrompt: opts.HandleConfirm,
FindSuggestionsFunc: opts.FindSuggestionsFunc,
})
}
func (self *RealPopupHandler) WithLoaderPanel(message string, f func() error) error {
index := 0
self.Lock()
self.index++
index = self.index
self.Unlock()
err := self.createPopupPanelFn(CreatePopupPanelOpts{
Prompt: message,
HasLoader: true,
})
if err != nil {
self.Log.Error(err)
return nil
}
go utils.Safe(func() {
if err := f(); err != nil {
self.Log.Error(err)
}
self.Lock()
if index == self.index {
_ = self.closePopupFn()
}
self.Unlock()
})
return nil
}
// returns the content that has currently been typed into the prompt. Useful for
// asyncronously updating the suggestions list under the prompt.
func (self *RealPopupHandler) GetPromptInput() string {
return self.getPromptInputFn()
}
type TestPopupHandler struct {
OnErrorMsg func(message string) error
OnAsk func(opts AskOpts) error
OnPrompt func(opts PromptOpts) error
}
var _ IPopupHandler = &TestPopupHandler{}
func (self *TestPopupHandler) Error(err error) error {
return self.ErrorMsg(err.Error())
}
func (self *TestPopupHandler) ErrorMsg(message string) error {
return self.OnErrorMsg(message)
}
func (self *TestPopupHandler) Ask(opts AskOpts) error {
return self.OnAsk(opts)
}
func (self *TestPopupHandler) Prompt(opts PromptOpts) error {
return self.OnPrompt(opts)
}
func (self *TestPopupHandler) WithLoaderPanel(message string, f func() error) error {
return f()
}
func (self *TestPopupHandler) WithWaitingStatus(message string, f func() error) error {
return f()
}
func (self *TestPopupHandler) Menu(opts CreateMenuOptions) error {
panic("not yet implemented")
}
func (self *TestPopupHandler) Toast(message string) {
panic("not yet implemented")
}
func (self *TestPopupHandler) GetPromptInput() string {
panic("not yet implemented")
}