Compare commits

...

4 Commits

Author SHA1 Message Date
TorchedSammy 26add67287
feat: implement bait 2022-03-28 17:48:12 -04:00
TorchedSammy 2086a1ec78
fix: handle panic in lua input if it is incorrect 2022-03-28 17:43:31 -04:00
TorchedSammy d34aa09e8e
fix: handle errors in user config 2022-03-28 17:40:36 -04:00
TorchedSammy 9fc2247c20
fix: call cont next in prompt function
this continues execution of lua, very obvious
fixes an issue with code stopping at the prompt function
2022-03-28 16:30:04 -04:00
6 changed files with 124 additions and 30 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)
]]--

2
api.go
View File

@ -271,7 +271,7 @@ func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
} }
lr.SetPrompt(fmtPrompt(prompt)) lr.SetPrompt(fmtPrompt(prompt))
return nil, nil return c.Next(), nil
} }
// multiprompt(str) // multiprompt(str)

View File

@ -114,7 +114,9 @@ func handleLua(cmdString string) (uint8, error) {
} }
// And if there's no syntax errors and -n isnt provided, run // And if there's no syntax errors and -n isnt provided, run
if !noexecute { if !noexecute {
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk)) if chunk != nil {
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
}
} }
if err == nil { if err == nil {
return 0, nil return 0, nil
@ -445,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
} }

13
lua.go
View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"hilbish/util"
"hilbish/golibs/bait" "hilbish/golibs/bait"
/* /*
"hilbish/golibs/commander" "hilbish/golibs/commander"
@ -42,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 {
@ -71,14 +73,9 @@ func runConfig(confpath string) {
if !interactive { if !interactive {
return return
} }
data, err := os.ReadFile(confpath) err := util.DoFile(l, confpath)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err, "\nAn error has occured while loading your config! Falling back to minimal default config.") fmt.Fprintln(os.Stderr, err, "\nAn error has occured while loading your config! Falling back to minimal default config.")
chunk, _ := l.CompileAndLoadLuaChunk("", []byte(minimalconf), rt.TableValue(l.GlobalEnv())) util.DoString(l, minimalconf)
_, err := rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
fmt.Println(err)
} }
chunk, _ := l.CompileAndLoadLuaChunk("", data, rt.TableValue(l.GlobalEnv()))
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
fmt.Println("config", err)
} }

View File

@ -1,6 +1,8 @@
package util package util
import ( import (
"os"
"github.com/yuin/gopher-lua" "github.com/yuin/gopher-lua"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
@ -36,3 +38,20 @@ func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, d
module.Set(rt.StringValue(field), value) module.Set(rt.StringValue(field), value)
} }
func DoString(rtm *rt.Runtime, code string) error {
chunk, err := rtm.CompileAndLoadLuaChunk("", []byte(code), rt.TableValue(rtm.GlobalEnv()))
if chunk != nil {
_, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(chunk))
}
return err
}
func DoFile(rtm *rt.Runtime, filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
return err
}
return DoString(rtm, string(data))
}