diff --git a/README.md b/README.md index 9d6446c..1fdb086 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -
+
🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨
@@ -9,6 +9,26 @@ Discord
+# 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 diff --git a/aliases.go b/aliases.go index 8c90fe5..4b0eb8d 100644 --- a/aliases.go +++ b/aliases.go @@ -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}, diff --git a/api.go b/api.go index 43e361a..c3081a2 100644 --- a/api.go +++ b/api.go @@ -15,56 +15,52 @@ 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{ - "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 *moonlight.Table -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 +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}, + */ + } + hshMod = moonlight.NewTable() + mlr.SetExports(hshMod, exports) host, _ := os.Hostname() username := curuser.Username @@ -73,68 +69,68 @@ 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(rtm) + //mod.Set(rt.StringValue("userDir"), rt.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)) + //aliases = newAliases() + //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(rtm) + //mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule)) // hilbish.jobs table - jobs = newJobHandler() - jobModule := jobs.loader(rtm) - mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule)) + //jobs = newJobHandler() + //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)) + //timers = newTimersModule() + //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)) + //pluginModule := moduleLoader(rtm) + //mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule)) - return rt.TableValue(mod), nil + return moonlight.TableValue(hshMod) } func getenv(key, fallback string) string { @@ -146,12 +142,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 { @@ -429,15 +425,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 } @@ -461,7 +459,6 @@ hilbish.appendPath { '~/.local/bin' } #example -*/ func hlappendPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { return nil, err @@ -529,7 +526,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 +612,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 +648,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 +657,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 @@ -769,6 +770,7 @@ func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } +*/ // hinter(line, pos) // The command line hint handler. It gets called on every key insert to @@ -786,6 +788,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 +818,4 @@ func hlhighlighter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.PushingNext1(t.Runtime, rt.StringValue(line)), nil } +*/ diff --git a/assets/hilbish-logo-and-text-midnight-edition.png b/assets/hilbish-logo-and-text-midnight-edition.png new file mode 100644 index 0000000..19332c4 Binary files /dev/null and b/assets/hilbish-logo-and-text-midnight-edition.png differ diff --git a/complete.go b/complete.go index 1c40b20..45a932f 100644 --- a/complete.go +++ b/complete.go @@ -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 } +*/ diff --git a/exec.go b/exec.go index cf1b299..9836a6c 100644 --- a/exec.go +++ b/exec.go @@ -14,7 +14,8 @@ import ( "syscall" "time" - "hilbish/util" + "hilbish/moonlight" + //"hilbish/util" rt "github.com/arnodel/golua/runtime" "mvdan.cc/sh/v3/shell" @@ -170,15 +171,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 @@ -207,7 +206,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 { @@ -221,7 +221,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 { @@ -353,7 +353,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)) - luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(cmd), rt.TableValue(luacmdArgs), rt.TableValue(sinks)) + luaexitcode, err := l.Call1(rt.FunctionValue(cmd), rt.TableValue(luacmdArgs), rt.TableValue(sinks)) if err != nil { fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error()) return interp.NewExitStatus(1) @@ -580,7 +580,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 diff --git a/history.go b/history.go index 51ccf27..aab4466 100644 --- a/history.go +++ b/history.go @@ -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 { diff --git a/job.go b/job.go index f5bd6f2..cf2615f 100644 --- a/job.go +++ b/job.go @@ -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()) } diff --git a/lua.go b/lua.go index 94b7910..161fa38 100644 --- a/lua.go +++ b/lua.go @@ -4,32 +4,27 @@ import ( "fmt" "os" - "hilbish/util" - "hilbish/golibs/bait" - "hilbish/golibs/commander" - "hilbish/golibs/fs" - "hilbish/golibs/terminal" + //"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 + /* lib.LoadLibs(l, fs.Loader) lib.LoadLibs(l, terminal.Loader) @@ -54,16 +49,17 @@ 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, "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) @@ -76,9 +72,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) } } diff --git a/main.go b/main.go index fd511a9..7a0c7b3 100644 --- a/main.go +++ b/main.go @@ -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" @@ -24,7 +25,7 @@ import ( ) var ( - l *rt.Runtime + l *moonlight.Runtime lr *lineReader luaCompletions = map[string]*rt.Closure{} @@ -171,8 +172,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) diff --git a/moonlight/export_golua.go b/moonlight/export_golua.go new file mode 100644 index 0000000..426d6a8 --- /dev/null +++ b/moonlight/export_golua.go @@ -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) + } +} diff --git a/moonlight/function.go b/moonlight/function.go new file mode 100644 index 0000000..3ebdff5 --- /dev/null +++ b/moonlight/function.go @@ -0,0 +1,3 @@ +package moonlight + +type GoToLuaFunc func(mlr *Runtime, c *GoCont) (Cont, error) diff --git a/moonlight/function_golua.go b/moonlight/function_golua.go new file mode 100644 index 0000000..ad019ff --- /dev/null +++ b/moonlight/function_golua.go @@ -0,0 +1,29 @@ +package moonlight + +import ( + rt "github.com/arnodel/golua/runtime" +) + +type GoFunctionFunc = rt.GoFunctionFunc + +type GoCont = rt.GoCont +type Cont = rt.Cont + +func (mlr *Runtime) CheckNArgs(c *GoCont, num int) error { + return c.CheckNArgs(num) +} + +func (mlr *Runtime) StringArg(c *GoCont, num int) (string, error) { + return c.StringArg(num) +} + +func (mlr *Runtime) GoFunction(fun GoToLuaFunc) rt.GoFunctionFunc { + return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + gocont := GoCont(*c) + return fun(mlr, &gocont) + } +} + +func (mlr *Runtime) Call1(val Value, args ...Value) (Value, error) { + return rt.Call1(mlr.rt.MainThread(), val, args...) +} diff --git a/moonlight/loader_golua.go b/moonlight/loader_golua.go new file mode 100644 index 0000000..e2d505f --- /dev/null +++ b/moonlight/loader_golua.go @@ -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) +} diff --git a/moonlight/runtime_golua.go b/moonlight/runtime_golua.go new file mode 100644 index 0000000..6072ea4 --- /dev/null +++ b/moonlight/runtime_golua.go @@ -0,0 +1,35 @@ +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 +} diff --git a/moonlight/table_golua.go b/moonlight/table_golua.go new file mode 100644 index 0000000..3c64eb9 --- /dev/null +++ b/moonlight/table_golua.go @@ -0,0 +1,29 @@ +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 (mlr *Runtime) GlobalTable() *Table { + return &Table{ + lt: mlr.rt.GlobalEnv(), + } +} diff --git a/moonlight/util_golua.go b/moonlight/util_golua.go new file mode 100644 index 0000000..bc0a440 --- /dev/null +++ b/moonlight/util_golua.go @@ -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("", []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 +} diff --git a/moonlight/value_golua.go b/moonlight/value_golua.go new file mode 100644 index 0000000..2300da4 --- /dev/null +++ b/moonlight/value_golua.go @@ -0,0 +1,23 @@ +package moonlight + +import ( + rt "github.com/arnodel/golua/runtime" +) + +type Value = rt.Value + +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) +} diff --git a/os.go b/os.go index 46e3d3c..4738d9b 100644 --- a/os.go +++ b/os.go @@ -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 } diff --git a/rl.go b/rl.go index 231d04b..28db1f6 100644 --- a/rl.go +++ b/rl.go @@ -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 diff --git a/runnermode.go b/runnermode.go index 55adfdc..e66e5fa 100644 --- a/runnermode.go +++ b/runnermode.go @@ -51,9 +51,11 @@ end) */ func runnerModeLoader(rtm *rt.Runtime) *rt.Table { exports := map[string]util.LuaExport{ + /* "sh": {shRunner, 1, false}, "lua": {luaRunner, 1, false}, "setMode": {hlrunnerMode, 1, false}, + */ } mod := rt.NewTable() diff --git a/sink.go b/sink.go index 3aa5507..5934533 100644 --- a/sink.go +++ b/sink.go @@ -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()) } diff --git a/timer.go b/timer.go index 5d536f5..5c1fa0d 100644 --- a/timer.go +++ b/timer.go @@ -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() diff --git a/timerhandler.go b/timerhandler.go index 0a8e34f..c4cfc61 100644 --- a/timerhandler.go +++ b/timerhandler.go @@ -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()) } diff --git a/userdir.go b/userdir.go index a6c4852..3ccd9ee 100644 --- a/userdir.go +++ b/userdir.go @@ -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 } diff --git a/util/export.go b/util/export.go index ee0b4a6..9cb40de 100644 --- a/util/export.go +++ b/util/export.go @@ -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 } diff --git a/util/util.go b/util/util.go index 0fcd4b0..c50fae3 100644 --- a/util/util.go +++ b/util/util.go @@ -1,10 +1,7 @@ package util import ( - "bufio" - "io" "strings" - "os" "os/user" rt "github.com/arnodel/golua/runtime" @@ -12,81 +9,10 @@ import ( // 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("", []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) {