feat: implement bait

lua5.4
TorchedSammy 2022-03-28 17:48:12 -04:00
parent 2086a1ec78
commit 26add67287
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
4 changed files with 98 additions and 21 deletions

View File

@ -1,6 +1,6 @@
-- Default Hilbish config -- Default Hilbish config
local lunacolors = require 'lunacolors' local lunacolors = require 'lunacolors'
--local bait = require 'bait' local bait = require 'bait'
local ansikit = require 'ansikit' local ansikit = require 'ansikit'
local function doPrompt(fail) local function doPrompt(fail)
@ -13,7 +13,6 @@ print(lunacolors.format(hilbish.greeting))
doPrompt() doPrompt()
--[[
bait.catch('command.exit', function(code) bait.catch('command.exit', function(code)
doPrompt(code ~= 0) doPrompt(code ~= 0)
end) end)
@ -25,4 +24,3 @@ bait.catch('hilbish.vimMode', function(mode)
ansikit.cursorStyle(ansikit.lineCursor) ansikit.cursorStyle(ansikit.lineCursor)
end end
end) end)
]]--

View File

@ -447,5 +447,6 @@ func cmdFinish(code uint8, cmdstr string, private bool) {
handleHistory(cmdstr) handleHistory(cmdstr)
} }
// util.SetField(l, hshMod, "exitCode", lua.LNumber(code), "Exit code of last exected command") // 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)
} }

View File

@ -5,12 +5,13 @@ import (
"hilbish/util" "hilbish/util"
"github.com/chuckpreslar/emission" "github.com/chuckpreslar/emission"
"github.com/yuin/gopher-lua" rt "github.com/arnodel/golua/runtime"
"layeh.com/gopher-luar" "github.com/arnodel/golua/lib/packagelib"
) )
type Bait struct{ type Bait struct{
Em *emission.Emitter Em *emission.Emitter
Loader packagelib.Loader
} }
func New() Bait { func New() Bait {
@ -19,14 +20,27 @@ func New() Bait {
emitter.Off(hookname, hookfunc) emitter.Off(hookname, hookfunc)
fmt.Println(err) fmt.Println(err)
}) })
return Bait{ b := Bait{
Em: emitter, Em: emitter,
} }
b.Loader = packagelib.Loader{
Load: b.LoaderFunc,
Name: "bait",
}
return b
} }
func (b *Bait) Loader(L *lua.LState) int { func (b *Bait) LoaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{}) 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, util.Document(L, mod,
`Bait is the event emitter for Hilbish. Why name it bait? `Bait is the event emitter for Hilbish. Why name it bait?
Because it throws hooks that you can catch (emits events 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, in on hooks to know when certain things have happened,
like when you've changed directory, a command has like when you've changed directory, a command has
failed, etc. To find all available hooks, see doc hooks.`) failed, etc. To find all available hooks, see doc hooks.`)
*/
L.SetField(mod, "throw", luar.New(L, b.bthrow)) return rt.TableValue(mod), nil
L.SetField(mod, "catch", luar.New(L, b.bcatch)) }
L.SetField(mod, "catchOnce", luar.New(L, b.bcatchOnce))
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) // throw(name, ...args)
// Throws a hook with `name` with the provided `args` // Throws a hook with `name` with the provided `args`
// --- @param name string // --- @param name string
// --- @vararg any // --- @vararg any
func (b *Bait) bthrow(name string, args ...interface{}) { func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
b.Em.Emit(name, args...) 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) // catch(name, cb)
// Catches a hook with `name`. Runs the `cb` when it is thrown // Catches a hook with `name`. Runs the `cb` when it is thrown
// --- @param name string // --- @param name string
// --- @param cb function // --- @param cb function
func (b *Bait) bcatch(name string, catcher func(...interface{})) { func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
b.Em.On(name, catcher) 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) // catchOnce(name, cb)
// Same as catch, but only runs the `cb` once and then removes the hook // Same as catch, but only runs the `cb` once and then removes the hook
// --- @param name string // --- @param name string
// --- @param cb function // --- @param cb function
func (b *Bait) bcatchOnce(name string, catcher func(...interface{})) { func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
b.Em.Once(name, catcher) 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
} }

3
lua.go
View File

@ -43,7 +43,8 @@ func luaInit() {
*/ */
hooks = bait.New() hooks = bait.New()
// l.PreloadModule("bait", hooks.Loader) lib.LoadLibs(l, hooks.Loader)
// Add Ctrl-C handler // Add Ctrl-C handler
hooks.Em.On("signal.sigint", func() { hooks.Em.On("signal.sigint", func() {
if !interactive { if !interactive {