Add OnQuit hook for controllers

This allows the controller of the currently focused context to do some last
minute cleanup before quitting.
This commit is contained in:
Stefan Haller 2026-04-21 10:55:10 +02:00
parent 3de2a2d96c
commit afbfbb27a4
6 changed files with 31 additions and 1 deletions

View file

@ -21,6 +21,7 @@ type BaseContext struct {
onRenderToMainFn func()
onFocusFns []onFocusFn
onFocusLostFns []onFocusLostFn
onQuitFns []func()
focusable bool
transient bool
@ -141,6 +142,7 @@ func (self *BaseContext) ClearAllAttachedControllerFunctions() {
self.mouseKeybindingsFns = nil
self.onFocusFns = nil
self.onFocusLostFns = nil
self.onQuitFns = nil
self.onDoubleClickFn = nil
self.onClickFn = nil
self.onClickFocusedMainViewFn = nil
@ -207,6 +209,12 @@ func (self *BaseContext) AddOnFocusLostFn(fn onFocusLostFn) {
}
}
func (self *BaseContext) AddOnQuitFn(fn func()) {
if fn != nil {
self.onQuitFns = append(self.onQuitFns, fn)
}
}
func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
bindings := []*gocui.ViewMouseBinding{}
for i := range self.mouseKeybindingsFns {

View file

@ -54,6 +54,12 @@ func (self *SimpleContext) HandleFocusLost(opts types.OnFocusLostOpts) {
}
}
func (self *SimpleContext) HandleQuit() {
for _, fn := range self.onQuitFns {
fn()
}
}
func (self *SimpleContext) FocusLine(scrollIntoView bool) {
}

View file

@ -12,5 +12,6 @@ func AttachControllers(context types.Context, controllers ...types.IController)
context.AddOnRenderToMainFn(controller.GetOnRenderToMain())
context.AddOnFocusFn(controller.GetOnFocus())
context.AddOnFocusLostFn(controller.GetOnFocusLost())
context.AddOnQuitFn(controller.GetOnQuit())
}
}

View file

@ -38,3 +38,7 @@ func (self *baseController) GetOnFocus() func(types.OnFocusOpts) {
func (self *baseController) GetOnFocusLost() func(types.OnFocusLostOpts) {
return nil
}
func (self *baseController) GetOnQuit() func() {
return nil
}

View file

@ -935,7 +935,12 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
// setting here so we can use it in layout.go
gui.integrationTest = startArgs.IntegrationTest
return gui.g.MainLoop()
err = gui.g.MainLoop()
if errors.Is(err, gocui.ErrQuit) {
// Give the focused context a chance to clean up before we tear down the app.
gui.c.Context().Current().HandleQuit()
}
return err
}
func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error {

View file

@ -105,6 +105,7 @@ type IBaseContext interface {
AddOnRenderToMainFn(func())
AddOnFocusFn(func(OnFocusOpts))
AddOnFocusLostFn(func(OnFocusLostOpts))
AddOnQuitFn(func())
}
type Context interface {
@ -112,6 +113,7 @@ type Context interface {
HandleFocus(opts OnFocusOpts)
HandleFocusLost(opts OnFocusLostOpts)
HandleQuit()
FocusLine(scrollIntoView bool)
HandleRender()
HandleRenderToMain()
@ -273,6 +275,10 @@ type IController interface {
GetOnRenderToMain() func()
GetOnFocus() func(OnFocusOpts)
GetOnFocusLost() func(OnFocusLostOpts)
// Implement this to get called when the app quits, and the controller's context has the focus.
// Useful for saving state on quit.
GetOnQuit() func()
}
type IList interface {