From 068a5b514916c92a1afc32f9460de8c877180934 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Tue, 11 Oct 2022 17:41:13 -0400 Subject: [PATCH] feat(bait): add error hook and hooks function (closes #205) an `error` hook is now thrown when an event in lua throws an error (errors from go side should not happen) it includes the event name, handler, and error message a hooks function has also been added. it returns a table of handlers for a specific event. --- docs/hooks/index.txt | 5 +++++ golibs/bait/bait.go | 41 +++++++++++++++++++++++++++++++++++++++-- lua.go | 2 +- nature/init.lua | 5 +++++ 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/docs/hooks/index.txt b/docs/hooks/index.txt index f771543..6616b05 100644 --- a/docs/hooks/index.txt +++ b/docs/hooks/index.txt @@ -6,3 +6,8 @@ Here is the format for a doc for a hook: `` just means the arguments of the hook. If a hook doc has the format of `arg...`, it means the hook can take/recieve any number of `arg`. + ++ error -> eventName, handler, err > Emitted when there is an error in +an event handler. The `eventName` is the name of the event the handler +is for, the `handler` is the callback function, and `err` is the error +message. diff --git a/golibs/bait/bait.go b/golibs/bait/bait.go index 89e0c4a..f071f92 100644 --- a/golibs/bait/bait.go +++ b/golibs/bait/bait.go @@ -1,6 +1,8 @@ package bait import ( + "errors" + "hilbish/util" rt "github.com/arnodel/golua/runtime" @@ -72,8 +74,12 @@ func (b *Bait) Emit(event string, args ...interface{}) { } _, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...) if err != nil { - // panicking here won't actually cause hilbish to panic and instead will - // print the error and remove the hook. reference the recoverer function in lua.go + if event != "error" { + b.Emit("error", event, handle.luaCaller, err.Error()) + return + } + // if there is an error in an error event handler, panic instead + // (calls the go recoverer function) panic(err) } } else { @@ -187,6 +193,7 @@ func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { "catchOnce": util.LuaExport{b.bcatchOnce, 2, false}, "throw": util.LuaExport{b.bthrow, 1, true}, "release": util.LuaExport{b.brelease, 2, false}, + "hooks": util.LuaExport{b.bhooks, 1, false}, } mod := rt.NewTable() util.SetExports(rtm, mod, exports) @@ -289,3 +296,33 @@ func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } + +// hooks(name) -> {cb, cb...} +// Returns a table with hooks on the event with `name`. +func (b *Bait) bhooks(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + evName, err := c.StringArg(0) + if err != nil { + return nil, err + } + noHooks := errors.New("no hooks for event " + evName) + + handlers := b.handlers[evName] + if handlers == nil { + return nil, noHooks + } + + luaHandlers := rt.NewTable() + for _, handler := range handlers { + if handler.typ != luaListener { continue } + luaHandlers.Set(rt.IntValue(luaHandlers.Len() + 1), rt.FunctionValue(handler.luaCaller)) + } + + if luaHandlers.Len() == 0 { + return nil, noHooks + } + + return c.PushingNext1(t.Runtime, rt.TableValue(luaHandlers)), nil +} diff --git a/lua.go b/lua.go index 419970c..79eb1f7 100644 --- a/lua.go +++ b/lua.go @@ -49,7 +49,7 @@ func luaInit() { hooks = bait.New(l) hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) { - fmt.Println("Error in", event, "event:", err) + fmt.Println("Error in `error` hook handler:", err) hooks.Off(event, handler) }) diff --git a/nature/init.lua b/nature/init.lua index 5359dc0..aa85a2e 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -1,5 +1,6 @@ -- Prelude initializes everything else for our shell local _ = require 'succulent' -- Function additions +local bait = require 'bait' local fs = require 'fs' package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' @@ -64,3 +65,7 @@ do package.path = package.path .. ';' .. startSearchPath end + +bait.catch('error', function(event, handler, err) + bait.release(event, handler) +end)