diff --git a/.hilbishrc.lua b/.hilbishrc.lua index 9a2daa2..4a06b26 100644 --- a/.hilbishrc.lua +++ b/.hilbishrc.lua @@ -1,6 +1,6 @@ -- Default Hilbish config local lunacolors = require 'lunacolors' ---local bait = require 'bait' +local bait = require 'bait' local ansikit = require 'ansikit' local function doPrompt(fail) @@ -13,7 +13,6 @@ print(lunacolors.format(hilbish.greeting)) doPrompt() ---[[ bait.catch('command.exit', function(code) doPrompt(code ~= 0) end) @@ -25,4 +24,3 @@ bait.catch('hilbish.vimMode', function(mode) ansikit.cursorStyle(ansikit.lineCursor) end end) -]]-- diff --git a/exec.go b/exec.go index fc34625..e6ca549 100644 --- a/exec.go +++ b/exec.go @@ -447,5 +447,6 @@ func cmdFinish(code uint8, cmdstr string, private bool) { handleHistory(cmdstr) } // util.SetField(l, hshMod, "exitCode", lua.LNumber(code), "Exit code of last exected command") - hooks.Em.Emit("command.exit", code, cmdstr) + // using AsValue on an interface which is an int results in it being unknown .... ???? + hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr) } diff --git a/golibs/bait/bait.go b/golibs/bait/bait.go index 491d9ab..a465f7b 100644 --- a/golibs/bait/bait.go +++ b/golibs/bait/bait.go @@ -5,12 +5,13 @@ import ( "hilbish/util" "github.com/chuckpreslar/emission" - "github.com/yuin/gopher-lua" - "layeh.com/gopher-luar" + rt "github.com/arnodel/golua/runtime" + "github.com/arnodel/golua/lib/packagelib" ) type Bait struct{ Em *emission.Emitter + Loader packagelib.Loader } func New() Bait { @@ -19,14 +20,27 @@ func New() Bait { emitter.Off(hookname, hookfunc) fmt.Println(err) }) - return Bait{ + b := Bait{ Em: emitter, } + b.Loader = packagelib.Loader{ + Load: b.LoaderFunc, + Name: "bait", + } + + return b } -func (b *Bait) Loader(L *lua.LState) int { - mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{}) +func (b *Bait) LoaderFunc(rtm *rt.Runtime) (rt.Value, func()) { + exports := map[string]util.LuaExport{ + "catch": util.LuaExport{b.bcatch, 2, false}, + "catchOnce": util.LuaExport{b.bcatchOnce, 2, false}, + "throw": util.LuaExport{b.bthrow, 1, true}, + } + mod := rt.NewTable() + util.SetExports(rtm, mod, exports) +/* util.Document(L, mod, `Bait is the event emitter for Hilbish. Why name it bait? Because it throws hooks that you can catch (emits events @@ -35,36 +49,99 @@ is fun. This is what you will use if you want to listen in on hooks to know when certain things have happened, like when you've changed directory, a command has failed, etc. To find all available hooks, see doc hooks.`) +*/ - L.SetField(mod, "throw", luar.New(L, b.bthrow)) - L.SetField(mod, "catch", luar.New(L, b.bcatch)) - L.SetField(mod, "catchOnce", luar.New(L, b.bcatchOnce)) + return rt.TableValue(mod), nil +} - L.Push(mod) +func handleArgs(t *rt.Thread, c *rt.GoCont) (string, *rt.Closure, error) { + if err := c.CheckNArgs(2); err != nil { + return "", nil, err + } + name, err := c.StringArg(0) + if err != nil { + return "", nil, err + } + catcher, err := c.ClosureArg(1) + if err != nil { + return "", nil, err + } - return 1 + return name, catcher, err +} + +func handleHook(t *rt.Thread, c *rt.GoCont, name string, catcher *rt.Closure, args ...interface{}) { + funcVal := rt.FunctionValue(catcher) + var luaArgs []rt.Value + for _, arg := range args { + var luarg rt.Value + switch arg.(type) { + case rt.Value: luarg = arg.(rt.Value) + default: luarg = rt.AsValue(arg) + } + luaArgs = append(luaArgs, luarg) + } + _, err := rt.Call1(t, funcVal, luaArgs...) + if err != nil { + e := rt.NewError(rt.StringValue(err.Error())) + e = e.AddContext(c.Next(), 1) + // panicking here won't actually cause hilbish to panic and instead will + // print the error and remove the hook (look at emission recover from above) + panic(e) + } } // throw(name, ...args) // Throws a hook with `name` with the provided `args` // --- @param name string // --- @vararg any -func (b *Bait) bthrow(name string, args ...interface{}) { - b.Em.Emit(name, args...) +func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + name, err := c.StringArg(0) + if err != nil { + return nil, err + } + ifaceSlice := make([]interface{}, len(c.Etc())) + for i, v := range c.Etc() { + ifaceSlice[i] = v + } + b.Em.Emit(name, ifaceSlice...) + + return c.Next(), nil } // catch(name, cb) // Catches a hook with `name`. Runs the `cb` when it is thrown // --- @param name string // --- @param cb function -func (b *Bait) bcatch(name string, catcher func(...interface{})) { - b.Em.On(name, catcher) +func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + name, catcher, err := handleArgs(t, c) + if err != nil { + return nil, err + } + + b.Em.On(name, func(args ...interface{}) { + handleHook(t, c, name, catcher, args...) + }) + + return c.Next(), nil } // catchOnce(name, cb) // Same as catch, but only runs the `cb` once and then removes the hook // --- @param name string // --- @param cb function -func (b *Bait) bcatchOnce(name string, catcher func(...interface{})) { - b.Em.Once(name, catcher) +func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + name, catcher, err := handleArgs(t, c) + if err != nil { + return nil, err + } + + b.Em.Once(name, func(args ...interface{}) { + handleHook(t, c, name, catcher, args...) + }) + + return c.Next(), nil } diff --git a/lua.go b/lua.go index 9c3bc20..1740ef7 100644 --- a/lua.go +++ b/lua.go @@ -43,7 +43,8 @@ func luaInit() { */ hooks = bait.New() -// l.PreloadModule("bait", hooks.Loader) + lib.LoadLibs(l, hooks.Loader) + // Add Ctrl-C handler hooks.Em.On("signal.sigint", func() { if !interactive {