mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-21 12:16:54 +02:00
fix: fix goroutine leaks
This commit is contained in:
parent
1bb138c79c
commit
00b922604a
@ -1,6 +1,7 @@
|
|||||||
package gui
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -16,8 +17,10 @@ import (
|
|||||||
// 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 (gui *Gui) wrappedConfirmationFunction(function func() error) func() error {
|
func (gui *Gui) wrappedConfirmationFunction(cancel context.CancelFunc, function func() error) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
|
cancel()
|
||||||
|
|
||||||
if err := gui.c.PopContext(); err != nil {
|
if err := gui.c.PopContext(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -32,8 +35,10 @@ func (gui *Gui) wrappedConfirmationFunction(function func() error) func() error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) wrappedPromptConfirmationFunction(function func(string) error, getResponse func() string) func() error {
|
func (gui *Gui) wrappedPromptConfirmationFunction(cancel context.CancelFunc, function func(string) error, getResponse func() string) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
|
cancel()
|
||||||
|
|
||||||
if err := gui.c.PopContext(); err != nil {
|
if err := gui.c.PopContext(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -111,11 +116,12 @@ func (gui *Gui) getConfirmationPanelWidth() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) prepareConfirmationPanel(
|
func (gui *Gui) prepareConfirmationPanel(
|
||||||
|
ctx context.Context,
|
||||||
opts types.ConfirmOpts,
|
opts types.ConfirmOpts,
|
||||||
) error {
|
) error {
|
||||||
gui.Views.Confirmation.HasLoader = opts.HasLoader
|
gui.Views.Confirmation.HasLoader = opts.HasLoader
|
||||||
if opts.HasLoader {
|
if opts.HasLoader {
|
||||||
gui.g.StartTicking()
|
gui.g.StartTicking(ctx)
|
||||||
}
|
}
|
||||||
gui.Views.Confirmation.Title = opts.Title
|
gui.Views.Confirmation.Title = opts.Title
|
||||||
// for now we do not support wrapping in our editor
|
// for now we do not support wrapping in our editor
|
||||||
@ -145,16 +151,19 @@ func runeForMask(mask bool) rune {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
|
func (gui *Gui) createPopupPanel(ctx context.Context, opts types.CreatePopupPanelOpts) error {
|
||||||
gui.Mutexes.PopupMutex.Lock()
|
gui.Mutexes.PopupMutex.Lock()
|
||||||
defer gui.Mutexes.PopupMutex.Unlock()
|
defer gui.Mutexes.PopupMutex.Unlock()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
// we don't allow interruptions of non-loader popups in case we get stuck somehow
|
// we don't allow interruptions of non-loader popups in case we get stuck somehow
|
||||||
// e.g. a credentials popup never gets its required user input so a process hangs
|
// e.g. a credentials popup never gets its required user input so a process hangs
|
||||||
// forever.
|
// forever.
|
||||||
// The proper solution is to have a queue of popup options
|
// The proper solution is to have a queue of popup options
|
||||||
if gui.State.CurrentPopupOpts != nil && !gui.State.CurrentPopupOpts.HasLoader {
|
if gui.State.CurrentPopupOpts != nil && !gui.State.CurrentPopupOpts.HasLoader {
|
||||||
gui.Log.Error("ignoring create popup panel because a popup panel is already open")
|
gui.Log.Error("ignoring create popup panel because a popup panel is already open")
|
||||||
|
cancel()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +171,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
|
|||||||
gui.clearConfirmationViewKeyBindings()
|
gui.clearConfirmationViewKeyBindings()
|
||||||
|
|
||||||
err := gui.prepareConfirmationPanel(
|
err := gui.prepareConfirmationPanel(
|
||||||
|
ctx,
|
||||||
types.ConfirmOpts{
|
types.ConfirmOpts{
|
||||||
Title: opts.Title,
|
Title: opts.Title,
|
||||||
Prompt: opts.Prompt,
|
Prompt: opts.Prompt,
|
||||||
@ -171,6 +181,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
|
|||||||
Mask: opts.Mask,
|
Mask: opts.Mask,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cancel()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
confirmationView := gui.Views.Confirmation
|
confirmationView := gui.Views.Confirmation
|
||||||
@ -185,11 +196,13 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
|
|||||||
confirmationView.RenderTextArea()
|
confirmationView.RenderTextArea()
|
||||||
} else {
|
} else {
|
||||||
if err := gui.renderString(confirmationView, style.AttrBold.Sprint(opts.Prompt)); err != nil {
|
if err := gui.renderString(confirmationView, style.AttrBold.Sprint(opts.Prompt)); err != nil {
|
||||||
|
cancel()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.setKeyBindings(opts); err != nil {
|
if err := gui.setKeyBindings(cancel, opts); err != nil {
|
||||||
|
cancel()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +211,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
|
|||||||
return gui.c.PushContext(gui.State.Contexts.Confirmation)
|
return gui.c.PushContext(gui.State.Contexts.Confirmation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error {
|
func (gui *Gui) setKeyBindings(cancel context.CancelFunc, opts types.CreatePopupPanelOpts) error {
|
||||||
actions := utils.ResolvePlaceholderString(
|
actions := utils.ResolvePlaceholderString(
|
||||||
gui.c.Tr.CloseConfirm,
|
gui.c.Tr.CloseConfirm,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
@ -210,13 +223,14 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error {
|
|||||||
_ = gui.renderString(gui.Views.Options, actions)
|
_ = gui.renderString(gui.Views.Options, actions)
|
||||||
var onConfirm func() error
|
var onConfirm func() error
|
||||||
if opts.HandleConfirmPrompt != nil {
|
if opts.HandleConfirmPrompt != nil {
|
||||||
onConfirm = gui.wrappedPromptConfirmationFunction(opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() })
|
onConfirm = gui.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() })
|
||||||
} else {
|
} else {
|
||||||
onConfirm = gui.wrappedConfirmationFunction(opts.HandleConfirm)
|
onConfirm = gui.wrappedConfirmationFunction(cancel, opts.HandleConfirm)
|
||||||
}
|
}
|
||||||
|
|
||||||
keybindingConfig := gui.c.UserConfig.Keybinding
|
keybindingConfig := gui.c.UserConfig.Keybinding
|
||||||
onSuggestionConfirm := gui.wrappedPromptConfirmationFunction(
|
onSuggestionConfirm := gui.wrappedPromptConfirmationFunction(
|
||||||
|
cancel,
|
||||||
opts.HandleConfirmPrompt,
|
opts.HandleConfirmPrompt,
|
||||||
gui.getSelectedSuggestionValue,
|
gui.getSelectedSuggestionValue,
|
||||||
)
|
)
|
||||||
@ -235,7 +249,7 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error {
|
|||||||
{
|
{
|
||||||
ViewName: "confirmation",
|
ViewName: "confirmation",
|
||||||
Key: keybindings.GetKey(keybindingConfig.Universal.Return),
|
Key: keybindings.GetKey(keybindingConfig.Universal.Return),
|
||||||
Handler: gui.wrappedConfirmationFunction(opts.HandleClose),
|
Handler: gui.wrappedConfirmationFunction(cancel, opts.HandleClose),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "confirmation",
|
ViewName: "confirmation",
|
||||||
@ -260,7 +274,7 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error {
|
|||||||
{
|
{
|
||||||
ViewName: "suggestions",
|
ViewName: "suggestions",
|
||||||
Key: keybindings.GetKey(keybindingConfig.Universal.Return),
|
Key: keybindings.GetKey(keybindingConfig.Universal.Return),
|
||||||
Handler: gui.wrappedConfirmationFunction(opts.HandleClose),
|
Handler: gui.wrappedConfirmationFunction(cancel, opts.HandleClose),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "suggestions",
|
ViewName: "suggestions",
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package popup
|
package popup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
gctx "github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
@ -16,7 +17,7 @@ type PopupHandler struct {
|
|||||||
*common.Common
|
*common.Common
|
||||||
index int
|
index int
|
||||||
deadlock.Mutex
|
deadlock.Mutex
|
||||||
createPopupPanelFn func(types.CreatePopupPanelOpts) error
|
createPopupPanelFn func(context.Context, types.CreatePopupPanelOpts) error
|
||||||
onErrorFn func() error
|
onErrorFn func() error
|
||||||
popContextFn func() error
|
popContextFn func() error
|
||||||
currentContextFn func() types.Context
|
currentContextFn func() types.Context
|
||||||
@ -30,7 +31,7 @@ var _ types.IPopupHandler = &PopupHandler{}
|
|||||||
|
|
||||||
func NewPopupHandler(
|
func NewPopupHandler(
|
||||||
common *common.Common,
|
common *common.Common,
|
||||||
createPopupPanelFn func(types.CreatePopupPanelOpts) error,
|
createPopupPanelFn func(context.Context, types.CreatePopupPanelOpts) error,
|
||||||
onErrorFn func() error,
|
onErrorFn func() error,
|
||||||
popContextFn func() error,
|
popContextFn func() error,
|
||||||
currentContextFn func() types.Context,
|
currentContextFn func() types.Context,
|
||||||
@ -96,7 +97,7 @@ func (self *PopupHandler) Confirm(opts types.ConfirmOpts) error {
|
|||||||
self.index++
|
self.index++
|
||||||
self.Unlock()
|
self.Unlock()
|
||||||
|
|
||||||
return self.createPopupPanelFn(types.CreatePopupPanelOpts{
|
return self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
||||||
Title: opts.Title,
|
Title: opts.Title,
|
||||||
Prompt: opts.Prompt,
|
Prompt: opts.Prompt,
|
||||||
HandleConfirm: opts.HandleConfirm,
|
HandleConfirm: opts.HandleConfirm,
|
||||||
@ -109,7 +110,7 @@ func (self *PopupHandler) Prompt(opts types.PromptOpts) error {
|
|||||||
self.index++
|
self.index++
|
||||||
self.Unlock()
|
self.Unlock()
|
||||||
|
|
||||||
return self.createPopupPanelFn(types.CreatePopupPanelOpts{
|
return self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
||||||
Title: opts.Title,
|
Title: opts.Title,
|
||||||
Prompt: opts.InitialContent,
|
Prompt: opts.InitialContent,
|
||||||
Editable: true,
|
Editable: true,
|
||||||
@ -127,12 +128,15 @@ func (self *PopupHandler) WithLoaderPanel(message string, f func() error) error
|
|||||||
index = self.index
|
index = self.index
|
||||||
self.Unlock()
|
self.Unlock()
|
||||||
|
|
||||||
err := self.createPopupPanelFn(types.CreatePopupPanelOpts{
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
err := self.createPopupPanelFn(ctx, types.CreatePopupPanelOpts{
|
||||||
Prompt: message,
|
Prompt: message,
|
||||||
HasLoader: true,
|
HasLoader: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Error(err)
|
self.Log.Error(err)
|
||||||
|
cancel()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,8 +145,10 @@ func (self *PopupHandler) WithLoaderPanel(message string, f func() error) error
|
|||||||
self.Log.Error(err)
|
self.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
self.Lock()
|
self.Lock()
|
||||||
if index == self.index && self.currentContextFn().GetKey() == context.CONFIRMATION_CONTEXT_KEY {
|
if index == self.index && self.currentContextFn().GetKey() == gctx.CONFIRMATION_CONTEXT_KEY {
|
||||||
_ = self.popContextFn()
|
_ = self.popContextFn()
|
||||||
}
|
}
|
||||||
self.Unlock()
|
self.Unlock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user