sammyette 2024-07-20 19:18:09 +00:00 committed by GitHub
commit 676f70b9ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 699 additions and 413 deletions

View File

@ -1,7 +1,4 @@
> [!TIP]
> Check out [Hilbish: Midnight Edition](https://github.com/Rosettea/Hilbish/tree/midnight-edition) if you want to use C Lua, LuaJIT or anything related!
<img src="./assets/hilbish-logo-and-text.png" width=512><br>
<img src="./assets/hilbish-logo-and-text-midnight-edition.png" width=512><br>
<blockquote>
🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨
</blockquote>
@ -12,6 +9,26 @@
<a href="https://discord.gg/3PDdcQz"><img alt="Discord" src="https://img.shields.io/discord/732357621503229962?color=blue&style=flat-square"></a>
<br>
# Midnight Edition
> [!CAUTION]
> This is a **HEAVILY** WORK IN PROGRESS branch which makes a lot of internal changes.
Functionality **will** be missing if you use this branch,
and you may see crashes too. Tread lightly.
Progress on Midnight Edition is tracked in this PR: [#314](https://github.com/Rosettea/Hilbish/pull/314)
Hilbish: Midinight Edition is a version of Hilbish meant to be compatible with
the original C implementation of Lua by using a Go library binding. The end goal
is to offer Midnight Edition as a separate, "not as supported" build for users
that *really* want to access a certain library made for C Lua or want the
most performance with their Lua code.
**The standard edition, which is all native Go,
will always be more supported than Midnight Edition.**
# Back the original README
Hilbish is an extensible shell designed to be highly customizable.
It is configured in Lua and provides a good range of features.
It aims to be easy to use for anyone but powerful enough for

View File

@ -97,7 +97,7 @@ func (a *aliasModule) Resolve(cmdstr string) string {
func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
// create a lua module with our functions
hshaliasesLua := map[string]util.LuaExport{
"add": util.LuaExport{hlalias, 2, false},
//"add": util.LuaExport{hlalias, 2, false},
"list": util.LuaExport{a.luaList, 0, false},
"del": util.LuaExport{a.luaDelete, 1, false},
"resolve": util.LuaExport{a.luaResolve, 1, false},

181
api.go
View File

@ -15,56 +15,58 @@ package main
import (
"bytes"
"errors"
"fmt"
//"fmt"
"io"
"os"
"os/exec"
//"os/exec"
"runtime"
"strings"
"syscall"
"time"
//"syscall"
//"time"
"hilbish/util"
//"hilbish/util"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
//"github.com/arnodel/golua/lib/packagelib"
"github.com/arnodel/golua/lib/iolib"
"github.com/maxlandon/readline"
"mvdan.cc/sh/v3/interp"
)
var exports = map[string]util.LuaExport{
var hshMod *moonlight.Table
func hilbishLoader(mlr *moonlight.Runtime) moonlight.Value {
var exports = map[string]moonlight.Export{
"alias": {hlalias, 2, false},
"appendPath": {hlappendPath, 1, false},
/*
"complete": {hlcomplete, 2, false},
*/
"cwd": {hlcwd, 0, false},
/*
"exec": {hlexec, 1, false},
*/
"runnerMode": {hlrunnerMode, 1, false},
/*
"goro": {hlgoro, 1, true},
"highlighter": {hlhighlighter, 1, false},
"hinter": {hlhinter, 1, false},
"multiprompt": {hlmultiprompt, 1, false},
"prependPath": {hlprependPath, 1, false},
*/
"prompt": {hlprompt, 1, true},
/*
"inputMode": {hlinputMode, 1, false},
"interval": {hlinterval, 2, false},
"read": {hlread, 1, false},
"run": {hlrun, 1, true},
"timeout": {hltimeout, 2, false},
"which": {hlwhich, 1, false},
*/
}
var hshMod *rt.Table
var hilbishLoader = packagelib.Loader{
Load: hilbishLoad,
Name: "hilbish",
}
func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
hshMod = mod
hshMod = moonlight.NewTable()
mlr.SetExports(hshMod, exports)
host, _ := os.Hostname()
username := curuser.Username
@ -73,68 +75,69 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
username = strings.Split(username, "\\")[1] // for some reason Username includes the hostname on windows
}
util.SetField(rtm, mod, "ver", rt.StringValue(getVersion()))
util.SetField(rtm, mod, "goVersion", rt.StringValue(runtime.Version()))
util.SetField(rtm, mod, "user", rt.StringValue(username))
util.SetField(rtm, mod, "host", rt.StringValue(host))
util.SetField(rtm, mod, "home", rt.StringValue(curuser.HomeDir))
util.SetField(rtm, mod, "dataDir", rt.StringValue(dataDir))
util.SetField(rtm, mod, "interactive", rt.BoolValue(interactive))
util.SetField(rtm, mod, "login", rt.BoolValue(login))
util.SetField(rtm, mod, "vimMode", rt.NilValue)
util.SetField(rtm, mod, "exitCode", rt.IntValue(0))
hshMod.SetField("ver", moonlight.StringValue(getVersion()))
hshMod.SetField("goVersion", moonlight.StringValue(runtime.Version()))
hshMod.SetField("user", moonlight.StringValue(username))
hshMod.SetField("host", moonlight.StringValue(host))
hshMod.SetField("home", moonlight.StringValue(curuser.HomeDir))
hshMod.SetField("dataDir", moonlight.StringValue(dataDir))
hshMod.SetField("interactive", moonlight.BoolValue(interactive))
hshMod.SetField("login", moonlight.BoolValue(login))
hshMod.SetField("exitCode", moonlight.IntValue(0))
//util.SetField(rtm, mod, "vimMode", rt.NilValue)
// hilbish.userDir table
hshuser := userDirLoader(rtm)
mod.Set(rt.StringValue("userDir"), rt.TableValue(hshuser))
hshuser := userDirLoader()
hshMod.SetField("userDir", moonlight.TableValue(hshuser))
// hilbish.os table
hshos := hshosLoader(rtm)
mod.Set(rt.StringValue("os"), rt.TableValue(hshos))
//hshos := hshosLoader(rtm)
//mod.Set(rt.StringValue("os"), rt.TableValue(hshos))
// hilbish.aliases table
aliases = newAliases()
aliasesModule := aliases.Loader(rtm)
mod.Set(rt.StringValue("aliases"), rt.TableValue(aliasesModule))
//aliasesModule := aliases.Loader(rtm)
//mod.Set(rt.StringValue("aliases"), rt.TableValue(aliasesModule))
// hilbish.history table
historyModule := lr.Loader(rtm)
mod.Set(rt.StringValue("history"), rt.TableValue(historyModule))
//historyModule := lr.Loader(rtm)
//mod.Set(rt.StringValue("history"), rt.TableValue(historyModule))
// hilbish.completion table
hshcomp := completionLoader(rtm)
//hshcomp := completionLoader(rtm)
// TODO: REMOVE "completion" AND ONLY USE "completions" WITH AN S
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
mod.Set(rt.StringValue("completions"), rt.TableValue(hshcomp))
//mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
//mod.Set(rt.StringValue("completions"), rt.TableValue(hshcomp))
// hilbish.runner table
runnerModule := runnerModeLoader(rtm)
mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule))
runnerModule := runnerModeLoader(mlr)
hshMod.SetField("runner", moonlight.TableValue(runnerModule))
// hilbish.jobs table
jobs = newJobHandler()
jobModule := jobs.loader(rtm)
mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
//jobModule := jobs.loader(rtm)
//mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
// hilbish.timers table
timers = newTimersModule()
timersModule := timers.loader(rtm)
mod.Set(rt.StringValue("timers"), rt.TableValue(timersModule))
//timersModule := timers.loader(rtm)
//mod.Set(rt.StringValue("timers"), rt.TableValue(timersModule))
editorModule := editorLoader(rtm)
mod.Set(rt.StringValue("editor"), rt.TableValue(editorModule))
//editorModule := editorLoader(rtm)
//mod.Set(rt.StringValue("editor"), rt.TableValue(editorModule))
versionModule := rt.NewTable()
util.SetField(rtm, versionModule, "branch", rt.StringValue(gitBranch))
util.SetField(rtm, versionModule, "full", rt.StringValue(getVersion()))
util.SetField(rtm, versionModule, "commit", rt.StringValue(gitCommit))
util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName))
mod.Set(rt.StringValue("version"), rt.TableValue(versionModule))
//versionModule := rt.NewTable()
//util.SetField(rtm, versionModule, "branch", rt.StringValue(gitBranch))
//util.SetField(rtm, versionModule, "full", rt.StringValue(getVersion()))
//util.SetField(rtm, versionModule, "commit", rt.StringValue(gitCommit))
//util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName))
//mod.Set(rt.StringValue("version"), rt.TableValue(versionModule))
pluginModule := moduleLoader(rtm)
mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule))
// very meta
moduleModule := moduleLoader(mlr)
hshMod.SetField("module", moonlight.TableValue(moduleModule))
return rt.TableValue(mod), nil
return moonlight.TableValue(hshMod)
}
func getenv(key, fallback string) string {
@ -146,12 +149,12 @@ func getenv(key, fallback string) string {
}
func setVimMode(mode string) {
util.SetField(l, hshMod, "vimMode", rt.StringValue(mode))
hshMod.SetField("vimMode", rt.StringValue(mode))
hooks.Emit("hilbish.vimMode", mode)
}
func unsetVimMode() {
util.SetField(l, hshMod, "vimMode", rt.NilValue)
hshMod.SetField("vimMode", rt.NilValue)
}
func handleStream(v rt.Value, strms *streams, errStream bool) error {
@ -292,10 +295,10 @@ func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// cwd() -> string
// Returns the current directory of the shell.
// #returns string
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
func hlcwd(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
cwd, _ := os.Getwd()
return c.PushingNext1(t.Runtime, rt.StringValue(cwd)), nil
return mlr.PushNext1(c, moonlight.StringValue(cwd)), nil
}
@ -348,17 +351,18 @@ hilbish.prompt '%u@%h :%d $'
-- prompt: user@hostname: ~/directory $
#example
*/
func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
err := c.Check1Arg()
func hlprompt(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
err := mlr.Check1Arg(c)
if err != nil {
return nil, err
}
p, err := c.StringArg(0)
p, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
typ := "left"
// optional 2nd arg
/*
if len(c.Etc()) != 0 {
ltyp := c.Etc()[0]
var ok bool
@ -367,6 +371,7 @@ func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return nil, errors.New("bad argument to run (expected string, got " + ltyp.TypeName() + ")")
}
}
*/
switch typ {
case "left":
@ -429,15 +434,17 @@ hilbish.alias('dircount', 'ls %1 | wc -l')
-- "dircount ~" would count how many files are in ~ (home directory).
#example
*/
func hlalias(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(2); err != nil {
//func hlalias(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
func hlalias(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.CheckNArgs(c, 2); err != nil {
return nil, err
}
cmd, err := c.StringArg(0)
cmd, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
orig, err := c.StringArg(1)
orig, err := mlr.StringArg(c, 1)
if err != nil {
return nil, err
}
@ -462,20 +469,20 @@ hilbish.appendPath {
}
#example
*/
func hlappendPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
func hlappendPath(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
arg := c.Arg(0)
arg := mlr.Arg(c, 0)
// check if dir is a table or a string
if arg.Type() == rt.TableType {
util.ForEach(arg.AsTable(), func(k rt.Value, v rt.Value) {
if v.Type() == rt.StringType {
appendPath(v.AsString())
if moonlight.Type(arg) == moonlight.TableType {
moonlight.ForEach(moonlight.ToTable(arg), func(_ moonlight.Value, v moonlight.Value) {
if moonlight.Type(v) == moonlight.StringType {
appendPath(moonlight.ToString(v))
}
})
} else if arg.Type() == rt.StringType {
} else if moonlight.Type(arg) == moonlight.StringType {
appendPath(arg.AsString())
} else {
return nil, errors.New("bad argument to appendPath (expected string or table, got " + arg.TypeName() + ")")
@ -494,6 +501,7 @@ func appendPath(dir string) {
}
}
/*
// exec(cmd)
// Replaces the currently running Hilbish instance with the supplied command.
// This can be used to do an in-place restart.
@ -529,7 +537,9 @@ func hlexec(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
*/
/*
// goro(fn)
// Puts `fn` in a Goroutine.
// This can be used to run any function in another thread at the same time as other Lua code.
@ -613,6 +623,7 @@ func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil
}
*/
// complete(scope, cb)
// Registers a completion handler for the specified scope.
@ -648,7 +659,6 @@ hilbish.complete('command.sudo', function(query, ctx, fields)
return {compGroup}, pfx
end)
#example
*/
func hlcomplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
scope, cb, err := util.HandleStrCallback(t, c)
if err != nil {
@ -658,7 +668,9 @@ func hlcomplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
*/
/*
// prependPath(dir)
// Prepends `dir` to $PATH.
// #param dir string
@ -741,6 +753,7 @@ func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
*/
// runnerMode(mode)
// Sets the execution/runner mode for interactive Hilbish.
@ -751,19 +764,19 @@ func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// will call it to execute user input instead.
// Read [about runner mode](../features/runner-mode) for more information.
// #param mode string|function
func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
func hlrunnerMode(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
mode := c.Arg(0)
mode := mlr.Arg(c, 0)
switch mode.Type() {
case rt.StringType:
switch moonlight.Type(mode) {
case moonlight.StringType:
switch mode.AsString() {
case "hybrid", "hybridRev", "lua", "sh": runnerMode = mode
default: return nil, errors.New("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received " + mode.AsString())
}
case rt.FunctionType: runnerMode = mode
case moonlight.FunctionType: runnerMode = mode
default: return nil, errors.New("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received " + mode.TypeName())
}
@ -786,6 +799,7 @@ function hilbish.hinter(line, pos)
end
#example
*/
/*
func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
@ -815,3 +829,4 @@ func hlhighlighter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.StringValue(line)), nil
}
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

View File

@ -1,14 +1,14 @@
package main
import (
"errors"
//"errors"
"path/filepath"
"strings"
"os"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
//rt "github.com/arnodel/golua/runtime"
)
var charEscapeMap = []string{
@ -191,6 +191,7 @@ func escapeFilename(fname string) string {
// #interface completion
// tab completions
// The completions interface deals with tab completions.
/*
func completionLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
"bins": {hcmpBins, 3, false},
@ -204,6 +205,7 @@ func completionLoader(rtm *rt.Runtime) *rt.Table {
return mod
}
*/
// #interface completion
// bins(query, ctx, fields) -> entries (table), prefix (string)
@ -231,6 +233,7 @@ hilbish.complete('command.sudo', function(query, ctx, fields)
end)
#example
*/
/*
func hcmpBins(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
query, ctx, fds, err := getCompleteParams(t, c)
if err != nil {
@ -246,6 +249,7 @@ func hcmpBins(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
}
*/
// #interface completion
// call(name, query, ctx, fields) -> completionGroups (table), prefix (string)
@ -256,6 +260,7 @@ func hcmpBins(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// #param query string
// #param ctx string
// #param fields table
/*
func hcmpCall(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(4); err != nil {
return nil, err
@ -283,11 +288,15 @@ func hcmpCall(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return nil, errors.New("completer " + completer + " does not exist")
}
// we must keep the holy 80 cols
cont := c.Next()
err = rt.Call(l.MainThread(), rt.FunctionValue(completecb),
[]rt.Value{rt.StringValue(query), rt.StringValue(ctx), rt.TableValue(fields)},
cont)
err = l.Call(moonlight.FunctionValue(completecb), []moonlight.Value{
moonlight.StringValue(query),
moonlight.StringValue(ctx),
moonlight.TableValue(fields)
}, cont)
err = rt.Call(l.MainThread(), rt.FunctionValue(completecb), []rt.Value{
rt.StringValue(query), rt.StringValue(ctx), rt.TableValue(fields)
}, cont)
if err != nil {
return nil, err
@ -295,6 +304,7 @@ func hcmpCall(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return cont, nil
}
*/
// #interface completion
// files(query, ctx, fields) -> entries (table), prefix (string)
@ -303,6 +313,7 @@ func hcmpCall(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// #param query string
// #param ctx string
// #param fields table
/*
func hcmpFiles(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
query, ctx, fds, err := getCompleteParams(t, c)
if err != nil {
@ -318,6 +329,7 @@ func hcmpFiles(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
}
*/
// #interface completion
// handler(line, pos)
@ -340,11 +352,11 @@ function hilbish.completion.handler(line, pos)
end
#example
*/
/*
func hcmpHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) {
if err := c.CheckNArgs(3); err != nil {
return "", "", []string{}, err
@ -371,3 +383,4 @@ func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, er
return query, ctx, fds, err
}
*/

21
exec.go
View File

@ -15,7 +15,8 @@ import (
"syscall"
"time"
"hilbish/util"
"hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"mvdan.cc/sh/v3/shell"
@ -171,15 +172,13 @@ func reprompt(input string) (string, error) {
}
func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) {
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 3, false)
err = rt.Call(l.MainThread(), runr, []rt.Value{rt.StringValue(userInput)}, term)
runnerRet, err := l.Call1(runr, moonlight.StringValue(userInput))
if err != nil {
return "", 124, false, nil, err
}
var runner *rt.Table
var ok bool
runnerRet := term.Get(0)
if runner, ok = runnerRet.TryTable(); !ok {
fmt.Fprintln(os.Stderr, "runner did not return a table")
exitCode = 125
@ -208,7 +207,8 @@ func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8
func handleLua(input string) (string, uint8, error) {
cmdString := aliases.Resolve(input)
// First try to load input, essentially compiling to bytecode
chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv()))
rtm := l.UnderlyingRuntime()
chunk, err := rtm.CompileAndLoadLuaChunk("", []byte(cmdString), moonlight.TableValue(l.GlobalTable()))
if err != nil && noexecute {
fmt.Println(err)
/* if lerr, ok := err.(*lua.ApiError); ok {
@ -222,7 +222,7 @@ func handleLua(input string) (string, uint8, error) {
// And if there's no syntax errors and -n isnt provided, run
if !noexecute {
if chunk != nil {
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
_, err = l.Call1(rt.FunctionValue(chunk))
}
}
if err == nil {
@ -352,7 +352,7 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
sinks.Set(rt.StringValue("out"), rt.UserDataValue(stdout.ud))
sinks.Set(rt.StringValue("err"), rt.UserDataValue(stderr.ud))
t := rt.NewThread(l)
//t := rt.NewThread(l)
sig := make(chan os.Signal)
exit := make(chan bool)
@ -368,14 +368,15 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
signal.Notify(sig, os.Interrupt)
select {
case <-sig:
t.KillContext()
//t.KillContext()
return
}
}()
go func() {
luaexitcode, err = rt.Call1(t, rt.FunctionValue(cmd), rt.TableValue(luacmdArgs), rt.TableValue(sinks))
// TODO: call in thread function?
//luaexitcode, err = l.CallInThread1(t, rt.FunctionValue(cmd), rt.TableValue(luacmdArgs), rt.TableValue(sinks))
exit <- true
}()
@ -606,7 +607,7 @@ func splitInput(input string) ([]string, string) {
}
func cmdFinish(code uint8, cmdstr string, private bool) {
util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)))
hshMod.SetField("exitCode", rt.IntValue(int64(code)))
// using AsValue (to convert to lua type) on an interface which is an int
// results in it being unknown in lua .... ????
// so we allow the hook handler to take lua runtime Values

View File

@ -26,12 +26,12 @@ this function will set the user prompt.
package bait
import (
"errors"
//"errors"
"hilbish/moonlight"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
)
type listenerType int
@ -48,26 +48,21 @@ type Listener struct{
typ listenerType
once bool
caller func(...interface{})
luaCaller *rt.Closure
luaCaller *moonlight.Closure
}
type Bait struct{
Loader packagelib.Loader
recoverer Recoverer
handlers map[string][]*Listener
rtm *rt.Runtime
rtm *moonlight.Runtime
}
// New creates a new Bait instance.
func New(rtm *rt.Runtime) *Bait {
func New(rtm *moonlight.Runtime) *Bait {
b := &Bait{
handlers: make(map[string][]*Listener),
rtm: rtm,
}
b.Loader = packagelib.Loader{
Load: b.loaderFunc,
Name: "bait",
}
return b
}
@ -88,16 +83,16 @@ func (b *Bait) Emit(event string, args ...interface{}) {
if handle.typ == luaListener {
funcVal := rt.FunctionValue(handle.luaCaller)
var luaArgs []rt.Value
var luaArgs []moonlight.Value
for _, arg := range args {
var luarg rt.Value
var luarg moonlight.Value
switch arg.(type) {
case rt.Value: luarg = arg.(rt.Value)
case moonlight.Value: luarg = arg.(moonlight.Value)
default: luarg = rt.AsValue(arg)
}
luaArgs = append(luaArgs, luarg)
}
_, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...)
_, err := b.rtm.Call1(funcVal, luaArgs...)
if err != nil {
if event != "error" {
b.Emit("error", event, handle.luaCaller, err.Error())
@ -129,7 +124,7 @@ func (b *Bait) On(event string, handler func(...interface{})) *Listener {
}
// OnLua adds a Lua function handler for an event.
func (b *Bait) OnLua(event string, handler *rt.Closure) *Listener {
func (b *Bait) OnLua(event string, handler *moonlight.Closure) *Listener {
listener := &Listener{
typ: luaListener,
luaCaller: handler,
@ -212,18 +207,20 @@ func (b *Bait) callRecoverer(event string, handler *Listener, err interface{}) {
b.recoverer(event, handler, err)
}
func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
"catch": util.LuaExport{b.bcatch, 2, false},
func (b *Bait) Loader(rtm *moonlight.Runtime) moonlight.Value {
exports := map[string]moonlight.Export{
"catch": {b.bcatch, 2, false},
/*
"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)
mod := moonlight.NewTable()
rtm.SetExports(mod, exports)
return rt.TableValue(mod), nil
return moonlight.TableValue(mod)
}
func handleHook(t *rt.Thread, c *rt.GoCont, name string, catcher *rt.Closure, args ...interface{}) {
@ -258,8 +255,8 @@ bait.catch('hilbish.exit', function()
end)
#example
*/
func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := util.HandleStrCallback(t, c)
func (b *Bait) bcatch(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
name, catcher, err := util.HandleStrCallback(mlr, c)
if err != nil {
return nil, err
}
@ -269,6 +266,7 @@ func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
/*
// catchOnce(name, cb)
// Catches an event, but only once. This will remove the hook immediately after it runs for the first time.
// #param name string The name of the event
@ -315,6 +313,7 @@ func (b *Bait) bhooks(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.TableValue(luaHandlers)), nil
}
*/
// release(name, catcher)
// Removes the `catcher` for the event with `name`.
@ -333,6 +332,7 @@ bait.release('event', hookCallback)
-- and now hookCallback will no longer be ran for the event.
#example
*/
/*
func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
@ -343,6 +343,7 @@ func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
*/
// throw(name, ...args)
// #param name string The name of the hook.
@ -358,6 +359,7 @@ bait.catch('gretting', function(greetTo)
end)
#example
*/
/*
func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@ -374,3 +376,4 @@ func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
*/

View File

@ -33,42 +33,37 @@ This sink is for writing errors, as the name would suggest.
package commander
import (
"hilbish/moonlight"
"hilbish/util"
"hilbish/golibs/bait"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
)
type Commander struct{
Events *bait.Bait
Loader packagelib.Loader
Commands map[string]*rt.Closure
}
func New(rtm *rt.Runtime) *Commander {
func New(rtm *moonlight.Runtime) *Commander {
c := &Commander{
Events: bait.New(rtm),
Commands: make(map[string]*rt.Closure),
}
c.Loader = packagelib.Loader{
Load: c.loaderFunc,
Name: "commander",
}
return c
}
func (c *Commander) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
"register": util.LuaExport{c.cregister, 2, false},
"deregister": util.LuaExport{c.cderegister, 1, false},
"registry": util.LuaExport{c.cregistry, 0, false},
func (c *Commander) Loader(rtm *moonlight.Runtime) moonlight.Value {
exports := map[string]moonlight.Export{
"register": {c.cregister, 2, false},
"deregister": {c.cderegister, 1, false},
"registry": {c.cregistry, 0, false},
}
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
mod := moonlight.NewTable()
rtm.SetExports(mod, exports)
return rt.TableValue(mod), nil
return moonlight.TableValue(mod)
}
// register(name, cb)
@ -88,8 +83,8 @@ commander.register('hello', function(args, sinks)
end)
#example
*/
func (c *Commander) cregister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
cmdName, cmd, err := util.HandleStrCallback(t, ct)
func (c *Commander) cregister(mlr *moonlight.Runtime, ct *moonlight.GoCont) (moonlight.Cont, error) {
cmdName, cmd, err := util.HandleStrCallback(mlr, ct)
if err != nil {
return nil, err
}
@ -102,11 +97,11 @@ func (c *Commander) cregister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
// deregister(name)
// Removes the named command. Note that this will only remove Commander-registered commands.
// #param name string Name of the command to remove.
func (c *Commander) cderegister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
if err := ct.Check1Arg(); err != nil {
func (c *Commander) cderegister(mlr *moonlight.Runtime, ct *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(ct); err != nil {
return nil, err
}
cmdName, err := ct.StringArg(0)
cmdName, err := mlr.StringArg(ct, 0)
if err != nil {
return nil, err
}
@ -120,14 +115,14 @@ func (c *Commander) cderegister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
// Returns all registered commanders. Returns a list of tables with the following keys:
// - `exec`: The function used to run the commander. Commanders require args and sinks to be passed.
// #returns table
func (c *Commander) cregistry(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
registryLua := rt.NewTable()
func (c *Commander) cregistry(mlr *moonlight.Runtime, ct *moonlight.GoCont) (moonlight.Cont, error) {
registryLua := moonlight.NewTable()
for cmdName, cmd := range c.Commands {
cmdTbl := rt.NewTable()
cmdTbl.Set(rt.StringValue("exec"), rt.FunctionValue(cmd))
cmdTbl := moonlight.NewTable()
cmdTbl.SetField("exec", rt.FunctionValue(cmd))
registryLua.Set(rt.StringValue(cmdName), rt.TableValue(cmdTbl))
registryLua.SetField(cmdName, moonlight.TableValue(cmdTbl))
}
return ct.PushingNext1(t.Runtime, rt.TableValue(registryLua)), nil
return mlr.PushNext1(ct, moonlight.TableValue(registryLua)), nil
}

View File

@ -14,50 +14,51 @@ import (
"os"
"strings"
"hilbish/moonlight"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
"github.com/arnodel/golua/lib/iolib"
"mvdan.cc/sh/v3/interp"
)
type fs struct{
runner *interp.Runner
Loader packagelib.Loader
}
func New(runner *interp.Runner) *fs {
f := &fs{
return &fs{
runner: runner,
}
f.Loader = packagelib.Loader{
Load: f.loaderFunc,
Name: "fs",
}
return f
}
func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
func (f *fs) Loader(rtm *moonlight.Runtime) moonlight.Value {
exports := map[string]moonlight.Export{
/*
"cd": util.LuaExport{f.fcd, 1, false},
"mkdir": util.LuaExport{f.fmkdir, 2, false},
"stat": util.LuaExport{f.fstat, 1, false},
"readdir": util.LuaExport{f.freaddir, 1, false},
*/
"readdir": {f.freaddir, 1, false},
/*
"abs": util.LuaExport{f.fabs, 1, false},
"basename": util.LuaExport{f.fbasename, 1, false},
"dir": util.LuaExport{f.fdir, 1, false},
*/
"dir": {f.fdir, 1, false},
/*
"glob": util.LuaExport{f.fglob, 1, false},
"join": util.LuaExport{f.fjoin, 0, true},
"pipe": util.LuaExport{f.fpipe, 0, false},
*/
}
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
mod.Set(rt.StringValue("pathSep"), rt.StringValue(string(os.PathSeparator)))
mod.Set(rt.StringValue("pathListSep"), rt.StringValue(string(os.PathListSeparator)))
return rt.TableValue(mod), nil
mod := moonlight.NewTable()
rtm.SetExports(mod, exports)
mod.SetField("pathSep", rt.StringValue(string(os.PathSeparator)))
mod.SetField("pathListSep", rt.StringValue(string(os.PathListSeparator)))
return moonlight.TableValue(mod)
}
// abs(path) -> string
@ -124,16 +125,17 @@ func (f *fs) fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// `~/Documents/doc.txt` then this function will return `~/Documents`.
// #param path string Path to get the directory for.
// #returns string
func (f *fs) fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
func (f *fs) fdir(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
path, err := c.StringArg(0)
path, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil
next := mlr.PushNext1(c, moonlight.StringValue(filepath.Dir(path)))
return next, nil
}
// glob(pattern) -> matches (table)
@ -262,16 +264,16 @@ func (f *fs) fpipe(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// Returns a list of all files and directories in the provided path.
// #param dir string
// #returns table
func (f *fs) freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
func (f *fs) freaddir(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
dir, err := c.StringArg(0)
dir, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
dir = util.ExpandHome(dir)
names := rt.NewTable()
names := moonlight.NewTable()
dirEntries, err := os.ReadDir(dir)
if err != nil {
@ -281,7 +283,7 @@ func (f *fs) freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
}
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
return mlr.PushNext1(c, moonlight.TableValue(names)), nil
}
// stat(path) -> {}

View File

@ -5,52 +5,47 @@ package terminal
import (
"os"
"hilbish/util"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
"golang.org/x/term"
)
var termState *term.State
var Loader = packagelib.Loader{
Load: loaderFunc,
Name: "terminal",
func Loader(rtm *moonlight.Runtime) moonlight.Value {
exports := map[string]moonlight.Export{
"setRaw": {termsetRaw, 0, false},
"restoreState": {termrestoreState, 0, false},
"size": {termsize, 0, false},
"saveState": {termsaveState, 0, false},
}
func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
"setRaw": util.LuaExport{termsetRaw, 0, false},
"restoreState": util.LuaExport{termrestoreState, 0, false},
"size": util.LuaExport{termsize, 0, false},
"saveState": util.LuaExport{termsaveState, 0, false},
}
mod := moonlight.NewTable()
rtm.SetExports(mod, exports)
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
return rt.TableValue(mod), nil
return moonlight.TableValue(mod)
}
// size()
// Gets the dimensions of the terminal. Returns a table with `width` and `height`
// NOTE: The size refers to the amount of columns and rows of text that can fit in the terminal.
func termsize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
func termsize(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
w, h, err := term.GetSize(int(os.Stdin.Fd()))
if err != nil {
return nil, err
}
dimensions := rt.NewTable()
dimensions := moonlight.NewTable()
dimensions.Set(rt.StringValue("width"), rt.IntValue(int64(w)))
dimensions.Set(rt.StringValue("height"), rt.IntValue(int64(h)))
return c.PushingNext1(t.Runtime, rt.TableValue(dimensions)), nil
return mlr.PushNext1(c, moonlight.TableValue(dimensions)), nil
}
// saveState()
// Saves the current state of the terminal.
func termsaveState(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
func termsaveState(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
state, err := term.GetState(int(os.Stdin.Fd()))
if err != nil {
return nil, err
@ -62,7 +57,7 @@ func termsaveState(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// restoreState()
// Restores the last saved state of the terminal
func termrestoreState(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
func termrestoreState(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
err := term.Restore(int(os.Stdin.Fd()), termState)
if err != nil {
return nil, err
@ -73,7 +68,7 @@ func termrestoreState(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// setRaw()
// Puts the terminal into raw mode.
func termsetRaw(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
func termsetRaw(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
_, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
return nil, err

View File

@ -14,7 +14,7 @@ type luaHistory struct {}
func (h *luaHistory) Write(line string) (int, error) {
histWrite := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("add"))
ln, err := rt.Call1(l.MainThread(), histWrite, rt.StringValue(line))
ln, err := l.Call1(histWrite, rt.StringValue(line))
var num int64
if ln.Type() == rt.IntType {
@ -26,7 +26,7 @@ func (h *luaHistory) Write(line string) (int, error) {
func (h *luaHistory) GetLine(idx int) (string, error) {
histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get"))
lcmd, err := rt.Call1(l.MainThread(), histGet, rt.IntValue(int64(idx)))
lcmd, err := l.Call1(histGet, rt.IntValue(int64(idx)))
var cmd string
if lcmd.Type() == rt.StringType {
@ -38,7 +38,7 @@ func (h *luaHistory) GetLine(idx int) (string, error) {
func (h *luaHistory) Len() int {
histSize := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("size"))
ln, _ := rt.Call1(l.MainThread(), histSize)
ln, _ := l.Call1(histSize)
var num int64
if ln.Type() == rt.IntType {

17
job.go
View File

@ -10,6 +10,7 @@ import (
"sync"
"syscall"
"hilbish/moonlight"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
@ -310,7 +311,8 @@ Manage interactive jobs in Hilbish via Lua.
Jobs are the name of background tasks/commands. A job can be started via
interactive usage or with the functions defined below for use in external runners. */
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
func (j *jobHandler) loader() *moonlight.Table {
/*
jobMethods := rt.NewTable()
jFuncs := map[string]util.LuaExport{
"stop": {luaStopJob, 1, false},
@ -319,7 +321,9 @@ func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
"background": {luaBackgroundJob, 1, false},
}
util.SetExports(l, jobMethods, jFuncs)
*/
/*
jobMeta := rt.NewTable()
jobIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
j, _ := jobArg(c, 0)
@ -348,17 +352,20 @@ func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
jobMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(jobIndex, "__index", 2, false)))
l.SetRegistry(jobMetaKey, rt.TableValue(jobMeta))
*/
jobFuncs := map[string]util.LuaExport{
jobFuncs := map[string]moonlight.Export{
/*
"all": {j.luaAllJobs, 0, false},
"last": {j.luaLastJob, 0, false},
"get": {j.luaGetJob, 1, false},
"add": {j.luaAddJob, 3, false},
"disown": {j.luaDisownJob, 1, false},
*/
}
luaJob := rt.NewTable()
util.SetExports(rtm, luaJob, jobFuncs)
luaJob := moonlight.NewTable()
l.SetExports(luaJob, jobFuncs)
return luaJob
}
@ -383,7 +390,7 @@ func valueToJob(val rt.Value) (*job, bool) {
}
func jobUserData(j *job) *rt.UserData {
jobMeta := l.Registry(jobMetaKey)
jobMeta := l.UnderlyingRuntime().Registry(jobMetaKey)
return rt.NewUserData(j, jobMeta.AsTable())
}

42
lua.go
View File

@ -4,47 +4,41 @@ import (
"fmt"
"os"
"hilbish/util"
//"hilbish/util"
"hilbish/golibs/bait"
"hilbish/golibs/commander"
"hilbish/golibs/fs"
"hilbish/golibs/terminal"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib"
"github.com/arnodel/golua/lib/debuglib"
"hilbish/moonlight"
)
var minimalconf = `hilbish.prompt '& '`
func luaInit() {
l = rt.New(os.Stdout)
l.PushContext(rt.RuntimeContextDef{
MessageHandler: debuglib.Traceback,
})
lib.LoadAll(l)
setupSinkType(l)
l = moonlight.NewRuntime()
setupSinkType()
lib.LoadLibs(l, hilbishLoader)
l.LoadLibrary(hilbishLoader, "hilbish")
// yes this is stupid, i know
util.DoString(l, "hilbish = require 'hilbish'")
l.DoString("hilbish = require 'hilbish'")
// Add fs and terminal module module to Lua
f := fs.New(runner)
lib.LoadLibs(l, f.Loader)
lib.LoadLibs(l, terminal.Loader)
l.LoadLibrary(f.Loader, "fs")
l.LoadLibrary(terminal.Loader, "terminal")
cmds = commander.New(l)
lib.LoadLibs(l, cmds.Loader)
l.LoadLibrary(cmds.Loader, "commander")
hooks = bait.New(l)
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
fmt.Println("Error in `error` hook handler:", err)
hooks.Off(event, handler)
})
lib.LoadLibs(l, hooks.Loader)
l.LoadLibrary(hooks.Loader, "bait")
/*
// Add Ctrl-C handler
hooks.On("signal.sigint", func(...interface{}) {
if !interactive {
@ -55,16 +49,18 @@ func luaInit() {
lr.rl.RawInputCallback = func(r []rune) {
hooks.Emit("hilbish.rawInput", string(r))
}
*/
// Add more paths that Lua can require from
_, err := util.DoString(l, "package.path = package.path .. " + requirePaths)
_, err := l.DoString("package.path = package.path .. " + requirePaths)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.")
}
err1 := util.DoFile(l, "nature/init.lua")
err1 := l.DoFile("nature/init.lua")
if err1 != nil {
err2 := util.DoFile(l, preloadPath)
err2 := l.DoFile(preloadPath)
if err2 != nil {
fmt.Fprintln(os.Stderr, "Missing nature module, some functionality and builtins will be missing.")
fmt.Fprintln(os.Stderr, "local error:", err1)
@ -77,9 +73,9 @@ func runConfig(confpath string) {
if !interactive {
return
}
err := util.DoFile(l, confpath)
err := l.DoFile(confpath)
if err != nil {
fmt.Fprintln(os.Stderr, err, "\nAn error has occured while loading your config! Falling back to minimal default config.")
util.DoString(l, minimalconf)
l.DoString(minimalconf)
}
}

View File

@ -16,6 +16,7 @@ import (
"hilbish/util"
"hilbish/golibs/bait"
"hilbish/golibs/commander"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
"github.com/pborman/getopt"
@ -25,7 +26,7 @@ import (
)
var (
l *rt.Runtime
l *moonlight.Runtime
lr *lineReader
luaCompletions = map[string]*rt.Closure{}
@ -174,8 +175,8 @@ func main() {
luaArgs.Set(rt.IntValue(int64(i)), rt.StringValue(arg))
}
l.GlobalEnv().Set(rt.StringValue("args"), rt.TableValue(luaArgs))
err := util.DoFile(l, getopt.Arg(0))
l.GlobalTable().SetField("args", rt.TableValue(luaArgs))
err := l.DoFile(getopt.Arg(0))
if err != nil {
fmt.Fprintln(os.Stderr, err)
exit(1)

View File

@ -3,9 +3,7 @@ package main
import (
"plugin"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"hilbish/moonlight"
)
// #interface module
@ -46,13 +44,13 @@ func Loader(rtm *rt.Runtime) rt.Value {
This can be compiled with `go build -buildmode=plugin plugin.go`.
If you attempt to require and print the result (`print(require 'plugin')`), it will show "hello world!"
*/
func moduleLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
func moduleLoader(mlr *moonlight.Runtime) *moonlight.Table {
exports := map[string]moonlight.Export{
"load": {moduleLoad, 2, false},
}
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
mod := moonlight.NewTable()
mlr.SetExports(mod, exports)
return mod
}
@ -62,12 +60,12 @@ func moduleLoader(rtm *rt.Runtime) *rt.Table {
// Loads a module at the designated `path`.
// It will throw if any error occurs.
// #param path string
func moduleLoad(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(1); err != nil {
func moduleLoad(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
path, err := c.StringArg(0)
path, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
@ -82,12 +80,12 @@ func moduleLoad(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return nil, err
}
loader, ok := value.(func(*rt.Runtime) rt.Value)
loader, ok := value.(func(*moonlight.Runtime) moonlight.Value)
if !ok {
return nil, nil
}
val := loader(t.Runtime)
val := loader(mlr)
return c.PushingNext1(t.Runtime, val), nil
return mlr.PushNext1(c, val), nil
}

View File

@ -0,0 +1,16 @@
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
)
type GoCont struct{
cont *rt.GoCont
thread *rt.Thread
}
type Cont = rt.Cont
type Closure = rt.Closure
func (gc *GoCont) Next() Cont {
return gc.cont.Next()
}

View File

@ -0,0 +1,13 @@
package moonlight
type Export struct{
Function GoToLuaFunc
ArgNum int
Variadic bool
}
func (mlr *Runtime) SetExports(tbl *Table, exports map[string]Export) {
for name, export := range exports {
mlr.rt.SetEnvGoFunc(tbl.lt, name, mlr.GoFunction(export.Function), export.ArgNum, export.Variadic)
}
}

View File

@ -0,0 +1,3 @@
package moonlight
type GoToLuaFunc func(mlr *Runtime, c *GoCont) (Cont, error)

View File

@ -0,0 +1,41 @@
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
)
type GoFunctionFunc = rt.GoFunctionFunc
func (mlr *Runtime) CheckNArgs(c *GoCont, num int) error {
return c.cont.CheckNArgs(num)
}
func (mlr *Runtime) Check1Arg(c *GoCont) error {
return c.cont.CheckNArgs(1)
}
func (mlr *Runtime) StringArg(c *GoCont, num int) (string, error) {
return c.cont.StringArg(num)
}
func (mlr *Runtime) ClosureArg(c *GoCont, num int) (*Closure, error) {
return c.cont.ClosureArg(num)
}
func (mlr *Runtime) Arg(c *GoCont, num int) Value {
return c.cont.Arg(num)
}
func (mlr *Runtime) GoFunction(fun GoToLuaFunc) rt.GoFunctionFunc {
return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
gocont := GoCont{
cont: c,
thread: t,
}
return fun(mlr, &gocont)
}
}
func (mlr *Runtime) Call1(val Value, args ...Value) (Value, error) {
return rt.Call1(mlr.rt.MainThread(), val, args...)
}

View File

@ -0,0 +1,22 @@
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib"
"github.com/arnodel/golua/lib/packagelib"
)
type Loader func(*Runtime) Value
func (mlr *Runtime) LoadLibrary(ldr Loader, name string) {
goluaLoader := packagelib.Loader{
Load: func(rt *rt.Runtime) (rt.Value, func()) {
val := ldr(specificRuntimeToGeneric(rt))
return val, nil
},
Name: name,
}
lib.LoadLibs(mlr.rt, goluaLoader)
}

View File

@ -0,0 +1,44 @@
package moonlight
import (
"os"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib"
"github.com/arnodel/golua/lib/debuglib"
)
type Runtime struct{
rt *rt.Runtime
}
func NewRuntime() *Runtime {
r := rt.New(os.Stdout)
r.PushContext(rt.RuntimeContextDef{
MessageHandler: debuglib.Traceback,
})
lib.LoadAll(r)
return specificRuntimeToGeneric(r)
}
func specificRuntimeToGeneric(rtm *rt.Runtime) *Runtime {
rr := Runtime{
rt: rtm,
}
return &rr
}
func (mlr *Runtime) UnderlyingRuntime() *rt.Runtime {
return mlr.rt
}
// Push will push a Lua value onto the stack.
func (mlr *Runtime) Push(c *GoCont, v Value) {
c.cont.Push(c.thread.Runtime, v)
}
func (mlr *Runtime) PushNext1(c *GoCont, v Value) Cont {
return c.cont.PushingNext1(c.thread.Runtime, v)
}

View File

@ -0,0 +1,52 @@
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
)
type Table struct{
lt *rt.Table
}
func NewTable() *Table {
return &Table{
lt: rt.NewTable(),
}
}
func (t *Table) Get(val Value) Value {
return t.lt.Get(val)
}
func (t *Table) SetField(key string, value Value) {
t.lt.Set(rt.StringValue(key), value)
}
func (t *Table) Set(key Value, value Value) {
t.lt.Set(key, value)
}
func ForEach(tbl *Table, cb func(key Value, val Value)) {
nextVal := rt.NilValue
for {
key, val, _ := tbl.lt.Next(nextVal)
if key == rt.NilValue {
break
}
nextVal = key
cb(Value(key), Value(val))
}
}
func (mlr *Runtime) GlobalTable() *Table {
return &Table{
lt: mlr.rt.GlobalEnv(),
}
}
func convertToMoonlightTable(t *rt.Table) *Table {
return &Table{
lt: t,
}
}

View File

@ -0,0 +1,71 @@
package moonlight
import (
"bufio"
"io"
"os"
rt "github.com/arnodel/golua/runtime"
)
// DoString runs the code string in the Lua runtime.
func (mlr *Runtime) DoString(code string) (rt.Value, error) {
chunk, err := mlr.rt.CompileAndLoadLuaChunk("<string>", []byte(code), rt.TableValue(mlr.rt.GlobalEnv()))
var ret rt.Value
if chunk != nil {
ret, err = rt.Call1(mlr.rt.MainThread(), rt.FunctionValue(chunk))
}
return ret, err
}
// DoFile runs the contents of the file in the Lua runtime.
func (mlr *Runtime) DoFile(path string) error {
f, err := os.Open(path)
defer f.Close()
if err != nil {
return err
}
reader := bufio.NewReader(f)
c, err := reader.ReadByte()
if err != nil && err != io.EOF {
return err
}
// unread so a char won't be missing
err = reader.UnreadByte()
if err != nil {
return err
}
var buf []byte
if c == byte('#') {
// shebang - skip that line
_, err := reader.ReadBytes('\n')
if err != nil && err != io.EOF {
return err
}
buf = []byte{'\n'}
}
for {
line, err := reader.ReadBytes('\n')
if err != nil {
if err == io.EOF {
break
}
return err
}
buf = append(buf, line...)
}
clos, err := mlr.rt.LoadFromSourceOrCode(path, buf, "bt", rt.TableValue(mlr.rt.GlobalEnv()), false)
if clos != nil {
_, err = rt.Call1(mlr.rt.MainThread(), rt.FunctionValue(clos))
}
return err
}

View File

@ -0,0 +1,41 @@
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
)
type Value = rt.Value
type ValueType = rt.ValueType
const (
StringType = rt.StringType
FunctionType = rt.FunctionType
TableType = rt.TableType
)
func StringValue(str string) Value {
return rt.StringValue(str)
}
func IntValue(i int) Value {
return rt.IntValue(int64(i))
}
func BoolValue(b bool) Value {
return rt.BoolValue(b)
}
func TableValue(t *Table) Value {
return rt.TableValue(t.lt)
}
func Type(v Value) ValueType {
return ValueType(v.Type())
}
func ToString(v Value) string {
return v.AsString()
}
func ToTable(v Value) *Table {
return convertToMoonlightTable(v.AsTable())
}

13
os.go
View File

@ -1,7 +1,8 @@
package main
import (
"hilbish/util"
"hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/blackfireio/osinfo"
@ -14,13 +15,13 @@ import (
// #field family Family name of the current OS
// #field name Pretty name of the current OS
// #field version Version of the current OS
func hshosLoader(rtm *rt.Runtime) *rt.Table {
func hshosLoader() *moonlight.Table {
info, _ := osinfo.GetOSInfo()
mod := rt.NewTable()
mod := moonlight.NewTable()
util.SetField(rtm, mod, "family", rt.StringValue(info.Family))
util.SetField(rtm, mod, "name", rt.StringValue(info.Name))
util.SetField(rtm, mod, "version", rt.StringValue(info.Version))
mod.SetField("family", rt.StringValue(info.Family))
mod.SetField("name", rt.StringValue(info.Name))
mod.SetField("version", rt.StringValue(info.Version))
return mod
}

12
rl.go
View File

@ -27,7 +27,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
regexSearcher := rl.Searcher
rl.Searcher = func(needle string, haystack []string) []string {
fz, _ := util.DoString(l, "return hilbish.opts.fuzzy")
fz, _ := l.DoString("return hilbish.opts.fuzzy")
fuzz, ok := fz.TryBool()
if !fuzz || !ok {
return regexSearcher(needle, haystack)
@ -71,8 +71,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
}
rl.HintText = func(line []rune, pos int) []rune {
hinter := hshMod.Get(rt.StringValue("hinter"))
retVal, err := rt.Call1(l.MainThread(), hinter,
rt.StringValue(string(line)), rt.IntValue(int64(pos)))
retVal, err := l.Call1(hinter, rt.StringValue(string(line)), rt.IntValue(int64(pos)))
if err != nil {
fmt.Println(err)
return []rune{}
@ -87,8 +86,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
}
rl.SyntaxHighlighter = func(line []rune) string {
highlighter := hshMod.Get(rt.StringValue("highlighter"))
retVal, err := rt.Call1(l.MainThread(), highlighter,
rt.StringValue(string(line)))
retVal, err := l.Call1(highlighter, rt.StringValue(string(line)))
if err != nil {
fmt.Println(err)
return string(line)
@ -102,9 +100,9 @@ func newLineReader(prompt string, noHist bool) *lineReader {
return highlighted
}
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false)
term := rt.NewTerminationWith(l.UnderlyingRuntime().MainThread().CurrentCont(), 2, false)
compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler"))
err := rt.Call(l.MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)),
err := rt.Call(l.UnderlyingRuntime().MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)),
rt.IntValue(int64(pos))}, term)
var compGroups []*readline.CompletionGroup

View File

@ -1,7 +1,7 @@
package main
import (
"hilbish/util"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
)
@ -49,15 +49,15 @@ hilbish.runnerMode(function(input)
end)
```
*/
func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
func runnerModeLoader(rtm *moonlight.Runtime) *moonlight.Table {
exports := map[string]moonlight.Export{
"sh": {shRunner, 1, false},
"lua": {luaRunner, 1, false},
"setMode": {hlrunnerMode, 1, false},
}
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
mod := moonlight.NewTable()
rtm.SetExports(mod, exports)
return mod
}
@ -76,27 +76,27 @@ func _runnerMode() {}
// Runs a command in Hilbish's shell script interpreter.
// This is the equivalent of using `source`.
// #param cmd string
func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
func shRunner(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
cmd, err := c.StringArg(0)
cmd, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
_, exitCode, cont, err := execSh(aliases.Resolve(cmd))
var luaErr rt.Value = rt.NilValue
var luaErr moonlight.Value = rt.NilValue
if err != nil {
luaErr = rt.StringValue(err.Error())
luaErr = moonlight.StringValue(err.Error())
}
runnerRet := rt.NewTable()
runnerRet.Set(rt.StringValue("input"), rt.StringValue(cmd))
runnerRet.Set(rt.StringValue("exitCode"), rt.IntValue(int64(exitCode)))
runnerRet.Set(rt.StringValue("continue"), rt.BoolValue(cont))
runnerRet.Set(rt.StringValue("err"), luaErr)
runnerRet := moonlight.NewTable()
runnerRet.SetField("input", moonlight.StringValue(cmd))
runnerRet.SetField("exitCode", moonlight.IntValue(int(exitCode)))
runnerRet.SetField("continue", moonlight.BoolValue(cont))
runnerRet.SetField("err", luaErr)
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil
return mlr.PushNext1(c, moonlight.TableValue(runnerRet)), nil
}
// #interface runner
@ -104,24 +104,25 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// Evaluates `cmd` as Lua input. This is the same as using `dofile`
// or `load`, but is appropriated for the runner interface.
// #param cmd string
func luaRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
func luaRunner(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, error) {
if err := mlr.Check1Arg(c); err != nil {
return nil, err
}
cmd, err := c.StringArg(0)
cmd, err := mlr.StringArg(c, 0)
if err != nil {
return nil, err
}
input, exitCode, err := handleLua(cmd)
var luaErr rt.Value = rt.NilValue
var luaErr moonlight.Value = rt.NilValue
if err != nil {
luaErr = rt.StringValue(err.Error())
luaErr = moonlight.StringValue(err.Error())
}
runnerRet := rt.NewTable()
runnerRet.Set(rt.StringValue("input"), rt.StringValue(input))
runnerRet.Set(rt.StringValue("exitCode"), rt.IntValue(int64(exitCode)))
runnerRet.Set(rt.StringValue("err"), luaErr)
runnerRet := moonlight.NewTable()
runnerRet.SetField("input", moonlight.StringValue(input))
runnerRet.SetField("exitCode", moonlight.IntValue(int(exitCode)))
runnerRet.SetField("err", luaErr)
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil
return mlr.PushNext1(c, moonlight.TableValue(runnerRet)), nil
}

20
sink.go
View File

@ -7,7 +7,8 @@ import (
"os"
"strings"
"hilbish/util"
//"hilbish/util"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
)
@ -25,20 +26,22 @@ type sink struct{
autoFlush bool
}
func setupSinkType(rtm *rt.Runtime) {
sinkMeta := rt.NewTable()
func setupSinkType() {
//sinkMeta := moonlight.NewTable()
sinkMethods := rt.NewTable()
sinkFuncs := map[string]util.LuaExport{
sinkMethods := moonlight.NewTable()
sinkFuncs := map[string]moonlight.Export{
/*
"flush": {luaSinkFlush, 1, false},
"read": {luaSinkRead, 1, false},
"readAll": {luaSinkReadAll, 1, false},
"autoFlush": {luaSinkAutoFlush, 2, false},
"write": {luaSinkWrite, 2, false},
"writeln": {luaSinkWriteln, 2, false},
*/
}
util.SetExports(l, sinkMethods, sinkFuncs)
l.SetExports(sinkMethods, sinkFuncs)
/*
sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
s, _ := sinkArg(c, 0)
@ -65,6 +68,7 @@ func setupSinkType(rtm *rt.Runtime) {
sinkMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(sinkIndex, "__index", 2, false)))
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta))
*/
}
@ -255,6 +259,6 @@ func valueToSink(val rt.Value) (*sink, bool) {
}
func sinkUserData(s *sink) *rt.UserData {
sinkMeta := l.Registry(sinkMetaKey)
sinkMeta := l.UnderlyingRuntime().Registry(sinkMetaKey)
return rt.NewUserData(s, sinkMeta.AsTable())
}

View File

@ -47,7 +47,7 @@ func (t *timer) start() error {
for {
select {
case <-t.ticker.C:
_, err := rt.Call1(l.MainThread(), rt.FunctionValue(t.fun))
_, err := l.Call1(rt.FunctionValue(t.fun))
if err != nil {
fmt.Fprintln(os.Stderr, "Error in function:\n", err)
t.stop()

View File

@ -5,7 +5,8 @@ import (
"sync"
"time"
"hilbish/util"
"hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
)
@ -133,13 +134,15 @@ t:start()
print(t.running) // true
```
*/
func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
timerMethods := rt.NewTable()
timerFuncs := map[string]util.LuaExport{
func (th *timersModule) loader() *moonlight.Table {
timerMethods := moonlight.NewTable()
timerFuncs := map[string]moonlight.Export{
/*
"start": {timerStart, 1, false},
"stop": {timerStop, 1, false},
*/
}
util.SetExports(rtm, timerMethods, timerFuncs)
l.SetExports(timerMethods, timerFuncs)
timerMeta := rt.NewTable()
timerIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
@ -164,18 +167,20 @@ func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
}
timerMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(timerIndex, "__index", 2, false)))
l.SetRegistry(timerMetaKey, rt.TableValue(timerMeta))
l.UnderlyingRuntime().SetRegistry(timerMetaKey, rt.TableValue(timerMeta))
thExports := map[string]util.LuaExport{
thExports := map[string]moonlight.Export{
/*
"create": {th.luaCreate, 3, false},
"get": {th.luaGet, 1, false},
*/
}
luaTh := rt.NewTable()
util.SetExports(rtm, luaTh, thExports)
luaTh := moonlight.NewTable()
l.SetExports(luaTh, thExports)
util.SetField(rtm, luaTh, "INTERVAL", rt.IntValue(0))
util.SetField(rtm, luaTh, "TIMEOUT", rt.IntValue(1))
luaTh.SetField("INTERVAL", rt.IntValue(0))
luaTh.SetField("TIMEOUT", rt.IntValue(1))
return luaTh
}
@ -200,6 +205,6 @@ func valueToTimer(val rt.Value) (*timer, bool) {
}
func timerUserData(j *timer) *rt.UserData {
timerMeta := l.Registry(timerMetaKey)
timerMeta := l.UnderlyingRuntime().Registry(timerMetaKey)
return rt.NewUserData(j, timerMeta.AsTable())
}

View File

@ -1,7 +1,8 @@
package main
import (
"hilbish/util"
"hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
)
@ -13,11 +14,11 @@ import (
// for configs and data.
// #field config The user's config directory
// #field data The user's directory for program data
func userDirLoader(rtm *rt.Runtime) *rt.Table {
mod := rt.NewTable()
func userDirLoader() *moonlight.Table {
mod := moonlight.NewTable()
util.SetField(rtm, mod, "config", rt.StringValue(confDir))
util.SetField(rtm, mod, "data", rt.StringValue(userDataDir))
mod.SetField("config", rt.StringValue(confDir))
mod.SetField("data", rt.StringValue(userDataDir))
return mod
}

View File

@ -1,12 +1,14 @@
package util
import (
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
)
// LuaExport represents a Go function which can be exported to Lua.
type LuaExport struct {
Function rt.GoFunctionFunc
Function moonlight.GoFunctionFunc
ArgNum int
Variadic bool
}

View File

@ -1,103 +1,31 @@
package util
import (
"bufio"
"io"
"strings"
"os"
"os/user"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
)
// SetField sets a field in a table, adding docs for it.
// It is accessible via the __docProp metatable. It is a table of the names of the fields.
func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value) {
// TODO: ^ rtm isnt needed, i should remove it
func SetField(module *rt.Table, field string, value rt.Value) {
module.Set(rt.StringValue(field), value)
}
// SetFieldProtected sets a field in a protected table. A protected table
// is one which has a metatable proxy to ensure no overrides happen to it.
// It sets the field in the table and sets the __docProp metatable on the
// user facing table.
func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Value) {
realModule.Set(rt.StringValue(field), value)
}
// DoString runs the code string in the Lua runtime.
func DoString(rtm *rt.Runtime, code string) (rt.Value, error) {
chunk, err := rtm.CompileAndLoadLuaChunk("<string>", []byte(code), rt.TableValue(rtm.GlobalEnv()))
var ret rt.Value
if chunk != nil {
ret, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(chunk))
}
return ret, err
}
// DoFile runs the contents of the file in the Lua runtime.
func DoFile(rtm *rt.Runtime, path string) error {
f, err := os.Open(path)
defer f.Close()
if err != nil {
return err
}
reader := bufio.NewReader(f)
c, err := reader.ReadByte()
if err != nil && err != io.EOF {
return err
}
// unread so a char won't be missing
err = reader.UnreadByte()
if err != nil {
return err
}
var buf []byte
if c == byte('#') {
// shebang - skip that line
_, err := reader.ReadBytes('\n')
if err != nil && err != io.EOF {
return err
}
buf = []byte{'\n'}
}
for {
line, err := reader.ReadBytes('\n')
if err != nil {
if err == io.EOF {
break
}
return err
}
buf = append(buf, line...)
}
clos, err := rtm.LoadFromSourceOrCode(path, buf, "bt", rt.TableValue(rtm.GlobalEnv()), false)
if clos != nil {
_, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(clos))
}
return err
}
// HandleStrCallback handles function parameters for Go functions which take
// a string and a closure.
func HandleStrCallback(t *rt.Thread, c *rt.GoCont) (string, *rt.Closure, error) {
if err := c.CheckNArgs(2); err != nil {
func HandleStrCallback(mlr *moonlight.Runtime, c *moonlight.GoCont) (string, *moonlight.Closure, error) {
if err := mlr.CheckNArgs(c, 2); err != nil {
return "", nil, err
}
name, err := c.StringArg(0)
name, err := mlr.StringArg(c, 0)
if err != nil {
return "", nil, err
}
cb, err := c.ClosureArg(1)
cb, err := mlr.ClosureArg(c, 1)
if err != nil {
return "", nil, err
}