diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f1fe1b1..d0b59b4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,10 +10,11 @@ on: jobs: build: - name: ${{ matrix.goos }}-${{ matrix.goarch }} + name: ${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.midnight == 'true' && ' (Midnight Edition)' || ''}} runs-on: ubuntu-latest strategy: matrix: + midnight: [false, true] goos: [linux, windows, darwin] goarch: ["386", amd64, arm64] exclude: @@ -33,11 +34,11 @@ jobs: - name: Download Task run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d' - name: Build - run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} ./bin/task + run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} ./bin/task ${{ matrix.midnight == 'true' && 'midnight' || ''}} - uses: actions/upload-artifact@v4 if: matrix.goos == 'windows' with: - name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} + name: hilbish${{ matrix.midnight == 'true' && '-midnight-edition' || ''}}-${{ matrix.goos }}-${{ matrix.goarch }} path: | hilbish.exe LICENSE @@ -51,7 +52,7 @@ jobs: - uses: actions/upload-artifact@v4 if: matrix.goos != 'windows' with: - name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} + name: hilbish${{ matrix.midnight == 'true' && '-midnight-edition' || ''}}-${{ matrix.goos }}-${{ matrix.goarch }} path: | hilbish LICENSE diff --git a/README.md b/README.md index 4566c30..c34ea12 100644 --- a/README.md +++ b/README.md @@ -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! - -
+
🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨
@@ -12,6 +9,27 @@ 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. + +Build instructions and 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 @@ -53,13 +71,13 @@ go get -d ./... To build, run: ``` -task +go-task ``` Or, if you want a stable branch, run these commands: ``` git checkout $(git describe --tags `git rev-list --tags --max-count=1`) -task build +go-task build ``` After you did all that, run `sudo task install` to install Hilbish globally. diff --git a/Taskfile.yaml b/Taskfile.yaml index 264e7d5..04f7667 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -10,6 +10,8 @@ vars: LIBDIR: '{{default .libdir__ .LIBDIR}}' goflags__: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"' GOFLAGS: '{{default .goflags__ .GOFLAGS}}' + lua__: 'lua' + LUA: '{{default .lua__ .LUA}}' tasks: default: @@ -24,6 +26,12 @@ tasks: vars: GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"' + midnight: + cmds: + - go build -tags midnight,{{.LUA}} {{.GOFLAGS}} + vars: + GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"' + build: cmds: - go build {{.GOFLAGS}} diff --git a/aliases.go b/aliases.go index 8c90fe5..a6c46fe 100644 --- a/aliases.go +++ b/aliases.go @@ -97,10 +97,12 @@ 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}, "list": util.LuaExport{a.luaList, 0, false}, "del": util.LuaExport{a.luaDelete, 1, false}, "resolve": util.LuaExport{a.luaResolve, 1, false}, + */ } mod := rt.NewTable() diff --git a/api.go b/api.go index 43e361a..5abcb71 100644 --- a/api.go +++ b/api.go @@ -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{ - "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 +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", moonlight.StringValue(mode)) hooks.Emit("hilbish.vimMode", mode) } func unsetVimMode() { - util.SetField(l, hshMod, "vimMode", rt.NilValue) + hshMod.SetField("vimMode", moonlight.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 } +*/ 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/editor.go b/editor.go index 9c49440..67248ff 100644 --- a/editor.go +++ b/editor.go @@ -12,11 +12,13 @@ import ( // directly interact with the line editor in use. func editorLoader(rtm *rt.Runtime) *rt.Table { exports := map[string]util.LuaExport{ + /* "insert": {editorInsert, 1, false}, "setVimRegister": {editorSetRegister, 1, false}, "getVimRegister": {editorGetRegister, 2, false}, "getLine": {editorGetLine, 0, false}, "readChar": {editorReadChar, 0, false}, + */ } mod := rt.NewTable() diff --git a/exec.go b/exec.go index 446a14d..0828e01 100644 --- a/exec.go +++ b/exec.go @@ -15,7 +15,8 @@ import ( "syscall" "time" - "hilbish/util" + "hilbish/moonlight" + //"hilbish/util" rt "github.com/arnodel/golua/runtime" "mvdan.cc/sh/v3/shell" @@ -27,7 +28,7 @@ import ( var errNotExec = errors.New("not executable") var errNotFound = errors.New("not found") -var runnerMode rt.Value = rt.StringValue("hybrid") +var runnerMode moonlight.Value = moonlight.StringValue("hybrid") type streams struct { stdout io.Writer @@ -100,7 +101,7 @@ func runInput(input string, priv bool) { var cont bool // save incase it changes while prompting (For some reason) currentRunner := runnerMode - if currentRunner.Type() == rt.StringType { + if currentRunner.Type() == moonlight.StringType { switch currentRunner.AsString() { case "hybrid": _, _, err = handleLua(input) @@ -170,70 +171,41 @@ 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) +func runLuaRunner(runr moonlight.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) { + runnerRet, err := l.Call1(runr, moonlight.StringValue(userInput)) if err != nil { return "", 124, false, nil, err } - var runner *rt.Table + var runner *moonlight.Table var ok bool - runnerRet := term.Get(0) - if runner, ok = runnerRet.TryTable(); !ok { + if runner, ok = moonlight.TryTable(runnerRet); !ok { fmt.Fprintln(os.Stderr, "runner did not return a table") exitCode = 125 input = userInput return } - if code, ok := runner.Get(rt.StringValue("exitCode")).TryInt(); ok { + if code, ok := runner.Get(moonlight.StringValue("exitCode")).TryInt(); ok { exitCode = uint8(code) } - if inp, ok := runner.Get(rt.StringValue("input")).TryString(); ok { + if inp, ok := runner.Get(moonlight.StringValue("input")).TryString(); ok { input = inp } - if errStr, ok := runner.Get(rt.StringValue("err")).TryString(); ok { + if errStr, ok := runner.Get(moonlight.StringValue("err")).TryString(); ok { runnerErr = fmt.Errorf("%s", errStr) } - if c, ok := runner.Get(rt.StringValue("continue")).TryBool(); ok { + if c, ok := runner.Get(moonlight.StringValue("continue")).TryBool(); ok { continued = c } return } -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())) - if err != nil && noexecute { - fmt.Println(err) - /* if lerr, ok := err.(*lua.ApiError); ok { - if perr, ok := lerr.Cause.(*parse.Error); ok { - print(perr.Pos.Line == parse.EOF) - } - } - */ - return cmdString, 125, err - } - // 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)) - } - } - if err == nil { - return cmdString, 0, nil - } - - return cmdString, 125, err -} - func handleSh(cmdString string) (input string, exitCode uint8, cont bool, runErr error) { - shRunner := hshMod.Get(rt.StringValue("runner")).AsTable().Get(rt.StringValue("sh")) + shRunner := hshMod.Get(moonlight.StringValue("runner")).AsTable().Get(moonlight.StringValue("sh")) var err error input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString) if err != nil { @@ -352,7 +324,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 +340,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,9 +579,9 @@ 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", moonlight.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 - hooks.Emit("command.exit", rt.IntValue(int64(code)), cmdstr, private) + hooks.Emit("command.exit", moonlight.IntValue(int64(code)), cmdstr, private) } diff --git a/go.mod b/go.mod index 985f2e2..19cbc60 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 toolchain go1.22.2 require ( + github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765 github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1 github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504 github.com/blackfireio/osinfo v1.0.5 diff --git a/go.sum b/go.sum index 136f827..53f9b33 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749 h1:jIFnWBTsYw8s7RX7 github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240720131751-805c301321fd h1:THNle0FR2g7DMO1y3Bx1Zr7rYeiLXt3st3UkxEsMzL4= github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240720131751-805c301321fd/go.mod h1:YZalN5H7WNQw3DGij6IvHsEhn5YMW7M2FCwG6gnfKy4= +github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765 h1:N6gB4UCRBZz8twlJbMFiCKj0zX5Et2nFU/LRafT4x80= +github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765/go.mod h1:hMjfaJVSqVnxenMlsxrq3Ni+vrm9Hs64tU4M7dhUoO4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw= diff --git a/golibs/bait/bait.go b/golibs/bait/bait.go index 1f85c76..b0e7bb2 100644 --- a/golibs/bait/bait.go +++ b/golibs/bait/bait.go @@ -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 } @@ -87,17 +82,18 @@ func (b *Bait) Emit(event string, args ...interface{}) { }() if handle.typ == luaListener { - funcVal := rt.FunctionValue(handle.luaCaller) - var luaArgs []rt.Value + //funcVal := moonlight.FunctionValue(handle.luaCaller) + 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) - default: luarg = rt.AsValue(arg) + case moonlight.Value: luarg = arg.(moonlight.Value) + default: luarg = moonlight.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()) @@ -107,6 +103,7 @@ func (b *Bait) Emit(event string, args ...interface{}) { // (calls the go recoverer function) panic(err) } + */ } else { handle.caller(args...) } @@ -129,8 +126,8 @@ 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 { - listener :=&Listener{ +func (b *Bait) OnLua(event string, handler *moonlight.Closure) *Listener { + listener := &Listener{ typ: luaListener, luaCaller: handler, } @@ -151,7 +148,7 @@ func (b *Bait) Off(event string, listener *Listener) { } // OffLua removes a Lua function handler for an event. -func (b *Bait) OffLua(event string, handler *rt.Closure) { +func (b *Bait) OffLua(event string, handler *moonlight.Closure) { handles := b.handlers[event] for i, handle := range handles { @@ -174,7 +171,7 @@ func (b *Bait) Once(event string, handler func(...interface{})) *Listener { } // OnceLua adds a Lua function listener for an event that only runs once. -func (b *Bait) OnceLua(event string, handler *rt.Closure) *Listener { +func (b *Bait) OnceLua(event string, handler *moonlight.Closure) *Listener { listener := &Listener{ typ: luaListener, once: true, @@ -212,18 +209,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 +257,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 +268,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 +315,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 +334,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 +345,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 +361,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 +378,4 @@ func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } +*/ diff --git a/golibs/commander/commander.go b/golibs/commander/commander.go index 840aaa1..486db42 100644 --- a/golibs/commander/commander.go +++ b/golibs/commander/commander.go @@ -33,42 +33,35 @@ 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 + Commands map[string]*moonlight.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", + Commands: make(map[string]*moonlight.Closure), } 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 +81,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 +95,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 +113,16 @@ 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", moonlight.FunctionValue(cmd)) + print(cmd) + cmdTbl.SetField("exec", moonlight.StringValue("placeholder")) - 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 } diff --git a/golibs/fs/fs.go b/golibs/fs/fs.go index 13f972d..6b3b643 100644 --- a/golibs/fs/fs.go +++ b/golibs/fs/fs.go @@ -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", moonlight.StringValue(string(os.PathSeparator))) + mod.SetField("pathListSep", moonlight.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,26 +264,26 @@ 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 { return nil, err } for i, entry := range dirEntries { - names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name())) + names.Set(moonlight.IntValue(int64(i + 1)), moonlight.StringValue(entry.Name())) } - return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil + return mlr.PushNext1(c, moonlight.TableValue(names)), nil } // stat(path) -> {} diff --git a/golibs/terminal/terminal.go b/golibs/terminal/terminal.go index 954a4dd..270d668 100644 --- a/golibs/terminal/terminal.go +++ b/golibs/terminal/terminal.go @@ -5,52 +5,46 @@ 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 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}, +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}, } - mod := rt.NewTable() - util.SetExports(rtm, mod, exports) + mod := moonlight.NewTable() + rtm.SetExports(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.Set(rt.StringValue("width"), rt.IntValue(int64(w))) - dimensions.Set(rt.StringValue("height"), rt.IntValue(int64(h))) + dimensions := moonlight.NewTable() + dimensions.SetField("width", moonlight.IntValue(int64(w))) + dimensions.SetField("height", moonlight.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 +56,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 +67,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 diff --git a/history.go b/history.go index 51ccf27..83d7c5b 100644 --- a/history.go +++ b/history.go @@ -7,17 +7,17 @@ import ( "path/filepath" "strings" - rt "github.com/arnodel/golua/runtime" + "hilbish/moonlight" ) 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)) + histWrite := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("add")) + ln, err := l.Call1(histWrite, moonlight.StringValue(line)) var num int64 - if ln.Type() == rt.IntType { + if ln.Type() == moonlight.IntType { num = ln.AsInt() } @@ -25,11 +25,11 @@ 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))) + histGet := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("get")) + lcmd, err := l.Call1(histGet, moonlight.IntValue(int64(idx))) var cmd string - if lcmd.Type() == rt.StringType { + if lcmd.Type() == moonlight.StringType { cmd = lcmd.AsString() } @@ -37,11 +37,11 @@ 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) + histSize := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("size")) + ln, _ := l.Call1(histSize) var num int64 - if ln.Type() == rt.IntType { + if ln.Type() == moonlight.IntType { num = ln.AsInt() } diff --git a/job.go b/job.go index f5bd6f2..408619b 100644 --- a/job.go +++ b/job.go @@ -10,6 +10,7 @@ import ( "sync" "syscall" + "hilbish/moonlight" "hilbish/util" rt "github.com/arnodel/golua/runtime" @@ -260,7 +261,7 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job { stdout: &bytes.Buffer{}, stderr: &bytes.Buffer{}, } - jb.ud = jobUserData(jb) + //jb.ud = jobUserData(jb) j.jobs[j.latestID] = jb hooks.Emit("job.add", rt.UserDataValue(jb.ud)) @@ -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 } @@ -382,10 +389,12 @@ func valueToJob(val rt.Value) (*job, bool) { return j, ok } +/* func jobUserData(j *job) *rt.UserData { - jobMeta := l.Registry(jobMetaKey) + jobMeta := l.UnderlyingRuntime().Registry(jobMetaKey) return rt.NewUserData(j, jobMeta.AsTable()) } +*/ // #interface jobs // get(id) -> @Job diff --git a/lua.go b/lua.go index 88fedf8..9e05af1 100644 --- a/lua.go +++ b/lua.go @@ -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) } } diff --git a/lua_exec.go b/lua_exec.go new file mode 100644 index 0000000..8fca346 --- /dev/null +++ b/lua_exec.go @@ -0,0 +1,37 @@ +//go:build !midnight +package main + +import ( + "fmt" + + "hilbish/moonlight" + rt "github.com/arnodel/golua/runtime" +) + +func handleLua(input string) (string, uint8, error) { + cmdString := aliases.Resolve(input) + // First try to load input, essentially compiling to bytecode + 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 { + if perr, ok := lerr.Cause.(*parse.Error); ok { + print(perr.Pos.Line == parse.EOF) + } + } + */ + return cmdString, 125, err + } + // And if there's no syntax errors and -n isnt provided, run + if !noexecute { + if chunk != nil { + _, err = l.Call1(rt.FunctionValue(chunk)) + } + } + if err == nil { + return cmdString, 0, nil + } + + return cmdString, 125, err +} diff --git a/lua_exec_midnight.go b/lua_exec_midnight.go new file mode 100644 index 0000000..85e57b7 --- /dev/null +++ b/lua_exec_midnight.go @@ -0,0 +1,10 @@ +//go:build midnight +package main + +import ( + "errors" +) + +func handleLua(input string) (string, uint8, error) { + return "", 7, errors.New("lua input in midnight placeholder") +} diff --git a/main.go b/main.go index 41d1d35..723712e 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" @@ -25,7 +26,7 @@ import ( ) var ( - l *rt.Runtime + l *moonlight.Runtime lr *lineReader luaCompletions = map[string]*rt.Closure{} @@ -169,13 +170,13 @@ func main() { } if getopt.NArgs() > 0 { - luaArgs := rt.NewTable() + luaArgs := moonlight.NewTable() for i, arg := range getopt.Args() { - luaArgs.Set(rt.IntValue(int64(i)), rt.StringValue(arg)) + luaArgs.Set(moonlight.IntValue(int64(i)), moonlight.StringValue(arg)) } - l.GlobalEnv().Set(rt.StringValue("args"), rt.TableValue(luaArgs)) - err := util.DoFile(l, getopt.Arg(0)) + l.GlobalTable().SetField("args", moonlight.TableValue(luaArgs)) + err := l.DoFile(getopt.Arg(0)) if err != nil { fmt.Fprintln(os.Stderr, err) exit(1) diff --git a/module.go b/module.go index bf4e32a..e0a6efd 100644 --- a/module.go +++ b/module.go @@ -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 } diff --git a/moonlight/closure_clua.go b/moonlight/closure_clua.go new file mode 100644 index 0000000..549c20a --- /dev/null +++ b/moonlight/closure_clua.go @@ -0,0 +1,28 @@ +//go:build midnight +package moonlight + +import ( + "fmt" +) + +type Callable interface{ + Continuation(*Runtime, Cont) Cont +} + +type Closure struct{ + refIdx int // so since we cant store the actual lua closure, + // we need a index to the ref in the lua registry... or something like that. +} + +func (mlr *Runtime) ClosureArg(c *GoCont, num int) (*Closure, error) { + fmt.Println("type at ", num, "is", mlr.state.LTypename(num)) + + return &Closure{ + refIdx: -1, + }, nil +} + +/* +func (c *Closure) Continuation(mlr *Runtime, c Cont) Cont { +} +*/ diff --git a/moonlight/cont_clua.go b/moonlight/cont_clua.go new file mode 100644 index 0000000..088b8c0 --- /dev/null +++ b/moonlight/cont_clua.go @@ -0,0 +1,12 @@ +//go:build midnight +package moonlight + +type GoCont struct{ + vals []Value + f GoFunctionFunc +} +type Cont interface{} + +func (gc *GoCont) Next() Cont { + return gc +} diff --git a/moonlight/cont_golua.go b/moonlight/cont_golua.go new file mode 100644 index 0000000..34cd858 --- /dev/null +++ b/moonlight/cont_golua.go @@ -0,0 +1,18 @@ +//go:build !midnight +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() +} diff --git a/moonlight/export.go b/moonlight/export.go new file mode 100644 index 0000000..2567af5 --- /dev/null +++ b/moonlight/export.go @@ -0,0 +1,7 @@ +package moonlight + +type Export struct{ + Function GoToLuaFunc + ArgNum int + Variadic bool +} diff --git a/moonlight/export_clua.go b/moonlight/export_clua.go new file mode 100644 index 0000000..8857392 --- /dev/null +++ b/moonlight/export_clua.go @@ -0,0 +1,8 @@ +//go:build midnight +package moonlight + +func (mlr *Runtime) SetExports(tbl *Table, exports map[string]Export) { + for name, export := range exports { + tbl.SetField(name, FunctionValue(mlr.GoFunction(export.Function))) + } +} diff --git a/moonlight/export_golua.go b/moonlight/export_golua.go new file mode 100644 index 0000000..50efdea --- /dev/null +++ b/moonlight/export_golua.go @@ -0,0 +1,8 @@ +//go:build !midnight +package moonlight + +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_clua.go b/moonlight/function_clua.go new file mode 100644 index 0000000..ee3d482 --- /dev/null +++ b/moonlight/function_clua.go @@ -0,0 +1,61 @@ +//go:build midnight +package moonlight + +import ( + "fmt" + + "github.com/aarzilli/golua/lua" +) + +type GoFunctionFunc struct{ + cf lua.LuaGoFunction +} + +func (gf GoFunctionFunc) Continuation(mlr *Runtime, c Cont) Cont { + return &GoCont{ + f: gf, + vals: []Value{}, + } +} + +func (mlr *Runtime) CheckNArgs(c *GoCont, num int) error { + args := mlr.state.GetTop() + if args < num { + return fmt.Errorf("%d arguments needed", num) + } + + return nil +} + +func (mlr *Runtime) Check1Arg(c *GoCont) error { + return mlr.CheckNArgs(c, 1) +} + +func (mlr *Runtime) StringArg(c *GoCont, num int) (string, error) { + return mlr.state.CheckString(num + 1), nil +} + +func (mlr *Runtime) Arg(c *GoCont, num int) Value { + return c.vals[num] +} + +func (mlr *Runtime) GoFunction(fun GoToLuaFunc) GoFunctionFunc { + return GoFunctionFunc{ + cf: func(L *lua.State) int { + cont, err := fun(mlr, &GoCont{}) + if err != nil { + L.RaiseError(err.Error()) + return 0 + } + + for _, val := range cont.(*GoCont).vals { + switch Type(val) { + case StringType: + L.PushString(val.AsString()) + } + } + + return len(cont.(*GoCont).vals) + }, + } +} diff --git a/moonlight/function_golua.go b/moonlight/function_golua.go new file mode 100644 index 0000000..9f9b05f --- /dev/null +++ b/moonlight/function_golua.go @@ -0,0 +1,38 @@ +//go:build !midnight +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) GoFunctionFunc { + return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + gocont := GoCont{ + cont: c, + thread: t, + } + return fun(mlr, &gocont) + } +} diff --git a/moonlight/loader_clua.go b/moonlight/loader_clua.go new file mode 100644 index 0000000..6f3a601 --- /dev/null +++ b/moonlight/loader_clua.go @@ -0,0 +1,21 @@ +//go:build midnight +package moonlight + +import ( + "github.com/aarzilli/golua/lua" +) + +type Loader func(*Runtime) Value + +func (mlr *Runtime) LoadLibrary(ldr Loader, name string) { + cluaLoader := func (L *lua.State) int { + mlr.pushToState(ldr(mlr)) + + return 1 + } + + mlr.state.GetGlobal("package") + mlr.state.GetField(-1, "preload") + mlr.state.PushGoFunction(cluaLoader) + mlr.state.SetField(-2, name) +} diff --git a/moonlight/loader_golua.go b/moonlight/loader_golua.go new file mode 100644 index 0000000..9560021 --- /dev/null +++ b/moonlight/loader_golua.go @@ -0,0 +1,23 @@ +//go:build !midnight +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_clua.go b/moonlight/runtime_clua.go new file mode 100644 index 0000000..89b4643 --- /dev/null +++ b/moonlight/runtime_clua.go @@ -0,0 +1,49 @@ +//go:build midnight +package moonlight + +import ( + "github.com/aarzilli/golua/lua" +) + +type Runtime struct{ + state *lua.State +} + +func NewRuntime() *Runtime { + L := lua.NewState() + L.OpenLibs() + + return &Runtime{ + state: L, + } +} + +func (mlr *Runtime) PushNext1(c *GoCont, v Value) Cont { + c.vals = []Value{v} + + return c +} + +func (mlr *Runtime) Call1(f Value, args ...Value) (Value, error) { + for _, arg := range args { + mlr.pushToState(arg) + } + + if f.refIdx > 0 { + mlr.state.RawGeti(lua.LUA_REGISTRYINDEX, f.refIdx) + mlr.state.Call(len(args), 1) + } + + if mlr.state.GetTop() == 0 { + return NilValue, nil + } + + return NilValue, nil +} + +func (mlr *Runtime) pushToState(v Value) { + switch v.Type() { + case NilType: mlr.state.PushNil() + case StringType: mlr.state.PushString(v.AsString()) + } +} diff --git a/moonlight/runtime_golua.go b/moonlight/runtime_golua.go new file mode 100644 index 0000000..57c90d0 --- /dev/null +++ b/moonlight/runtime_golua.go @@ -0,0 +1,49 @@ +//go:build !midnight +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) +} + +func (mlr *Runtime) Call1(val Value, args ...Value) (Value, error) { + return rt.Call1(mlr.rt.MainThread(), val, args...) +} diff --git a/moonlight/table_clua.go b/moonlight/table_clua.go new file mode 100644 index 0000000..4533553 --- /dev/null +++ b/moonlight/table_clua.go @@ -0,0 +1,43 @@ +//go:build midnight +package moonlight + +//import "github.com/aarzilli/golua/lua" + +type Table struct{ + refIdx int +} + +func NewTable() *Table { + return &Table{ + refIdx: -1, + } +} + +func (t *Table) Get(val Value) Value { + return NilValue +} + +func (t *Table) SetField(key string, value Value) { +} + +func (t *Table) Set(key Value, value Value) { +} + +func ForEach(tbl *Table, cb func(key Value, val Value)) { +} + +func (mlr *Runtime) GlobalTable() *Table { + return &Table{ + refIdx: -1, + } +} + +func ToTable(v Value) *Table { + return &Table{ + refIdx: -1, + } +} + +func TryTable(v Value) (*Table, bool) { + return nil, false +} diff --git a/moonlight/table_golua.go b/moonlight/table_golua.go new file mode 100644 index 0000000..b78d88a --- /dev/null +++ b/moonlight/table_golua.go @@ -0,0 +1,59 @@ +//go:build !midnight +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, + } +} + +func TryTable(v Value) (*Table, bool) { + t, ok := v.TryTable() + + return convertToMoonlightTable(t), ok +} diff --git a/moonlight/util_clua.go b/moonlight/util_clua.go new file mode 100644 index 0000000..aa60f0e --- /dev/null +++ b/moonlight/util_clua.go @@ -0,0 +1,12 @@ +//go:build midnight +package moonlight + +func (mlr *Runtime) DoString(code string) (Value, error) { + err := mlr.state.DoString(code) + + return NilValue, err +} + +func (mlr *Runtime) DoFile(filename string) error { + return mlr.state.DoFile(filename) +} diff --git a/moonlight/util_golua.go b/moonlight/util_golua.go new file mode 100644 index 0000000..64e61cd --- /dev/null +++ b/moonlight/util_golua.go @@ -0,0 +1,72 @@ +//go:build !midnight +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) (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_clua.go b/moonlight/value_clua.go new file mode 100644 index 0000000..1662851 --- /dev/null +++ b/moonlight/value_clua.go @@ -0,0 +1,121 @@ +//go:build midnight +package moonlight + +type Value struct{ + iface interface{} + relIdx int + refIdx int +} + +var NilValue = Value{nil, -1, -1} + +type ValueType uint8 +const ( + NilType ValueType = iota + BoolType + IntType + StringType + TableType + FunctionType + UnknownType +) + +func Type(v Value) ValueType { + return v.Type() +} + +func BoolValue(b bool) Value { + return Value{iface: b} +} + +func IntValue(i int64) Value { + return Value{iface: i} +} + +func StringValue(str string) Value { + return Value{iface: str} +} + +func TableValue(t *Table) Value { + return Value{iface: t} +} + +func FunctionValue(f Callable) Value { + return NilValue +} + +func AsValue(i interface{}) Value { + if i == nil { + return NilValue + } + + switch v := i.(type) { + case bool: return BoolValue(v) + case int64: return IntValue(v) + case string: return StringValue(v) + case *Table: return TableValue(v) + case Value: return v + default: + return Value{iface: i} + } +} + +func (v Value) Type() ValueType { + if v.iface == nil { + return NilType + } + + switch v.iface.(type) { + case bool: return BoolType + case int: return IntType + case string: return StringType + case *Table: return TableType + case *Closure: return FunctionType + default: return UnknownType + } +} + +func (v Value) AsInt() int64 { + return v.iface.(int64) +} + +func (v Value) AsString() string { + if v.Type() != StringType { + panic("value type was not string") + } + + return v.iface.(string) +} + +func (v Value) AsTable() *Table { + panic("Value.AsTable unimplemented in midnight") +} + +func ToString(v Value) string { + return v.AsString() +} + +func (v Value) TypeName() string { + switch v.iface.(type) { + case bool: return "bool" + case int: return "number" + case string: return "string" + case *Table: return "table" + default: return "" + } +} + +func (v Value) TryBool() (n bool, ok bool) { + n, ok = v.iface.(bool) + return +} + +func (v Value) TryInt() (n int, ok bool) { + n, ok = v.iface.(int) + return +} + +func (v Value) TryString() (n string, ok bool) { + n, ok = v.iface.(string) + return +} diff --git a/moonlight/value_golua.go b/moonlight/value_golua.go new file mode 100644 index 0000000..5989f96 --- /dev/null +++ b/moonlight/value_golua.go @@ -0,0 +1,49 @@ +//go:build !midnight +package moonlight + +import ( + rt "github.com/arnodel/golua/runtime" +) + +var NilValue = rt.NilValue + +type Value = rt.Value +type ValueType = rt.ValueType +const ( + IntType = rt.IntType + StringType = rt.StringType + FunctionType = rt.FunctionType + TableType = rt.TableType +) + +func Type(v Value) ValueType { + return ValueType(v.Type()) +} + +func StringValue(str string) Value { + return rt.StringValue(str) +} + +func IntValue(i int64) Value { + return rt.IntValue(i) +} + +func BoolValue(b bool) Value { + return rt.BoolValue(b) +} + +func TableValue(t *Table) Value { + return rt.TableValue(t.lt) +} + +func ToString(v Value) string { + return v.AsString() +} + +func ToTable(v Value) *Table { + return convertToMoonlightTable(v.AsTable()) +} + +func AsValue(v interface{}) Value { + return rt.AsValue(v) +} diff --git a/os.go b/os.go index 46e3d3c..b2f8530 100644 --- a/os.go +++ b/os.go @@ -1,9 +1,9 @@ package main import ( - "hilbish/util" + "hilbish/moonlight" + //"hilbish/util" - rt "github.com/arnodel/golua/runtime" "github.com/blackfireio/osinfo" ) @@ -14,13 +14,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", moonlight.StringValue(info.Family)) + mod.SetField("name", moonlight.StringValue(info.Name)) + mod.SetField("version", moonlight.StringValue(info.Version)) return mod } diff --git a/rl.go b/rl.go index 231d04b..50151b1 100644 --- a/rl.go +++ b/rl.go @@ -5,6 +5,7 @@ import ( "io" "strings" + "hilbish/moonlight" "hilbish/util" rt "github.com/arnodel/golua/runtime" @@ -27,7 +28,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) @@ -70,9 +71,8 @@ func newLineReader(prompt string, noHist bool) *lineReader { hooks.Emit("hilbish.vimAction", actionStr, args) } 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))) + hinter := hshMod.Get(moonlight.StringValue("hinter")) + retVal, err := l.Call1(hinter, moonlight.StringValue(string(line)), moonlight.IntValue(int64(pos))) if err != nil { fmt.Println(err) return []rune{} @@ -86,9 +86,8 @@ func newLineReader(prompt string, noHist bool) *lineReader { return []rune(hintText) } rl.SyntaxHighlighter = func(line []rune) string { - highlighter := hshMod.Get(rt.StringValue("highlighter")) - retVal, err := rt.Call1(l.MainThread(), highlighter, - rt.StringValue(string(line))) + highlighter := hshMod.Get(moonlight.StringValue("highlighter")) + retVal, err := l.Call1(highlighter, moonlight.StringValue(string(line))) if err != nil { fmt.Println(err) return string(line) @@ -101,93 +100,7 @@ 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) - compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler")) - err := rt.Call(l.MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)), - rt.IntValue(int64(pos))}, term) - - var compGroups []*readline.CompletionGroup - if err != nil { - return "", compGroups - } - - luaCompGroups := term.Get(0) - luaPrefix := term.Get(1) - - if luaCompGroups.Type() != rt.TableType { - return "", compGroups - } - - groups := luaCompGroups.AsTable() - // prefix is optional - pfx, _ := luaPrefix.TryString() - - util.ForEach(groups, func(key rt.Value, val rt.Value) { - if key.Type() != rt.IntType || val.Type() != rt.TableType { - return - } - - valTbl := val.AsTable() - luaCompType := valTbl.Get(rt.StringValue("type")) - luaCompItems := valTbl.Get(rt.StringValue("items")) - - if luaCompType.Type() != rt.StringType || luaCompItems.Type() != rt.TableType { - return - } - - items := []string{} - itemDescriptions := make(map[string]string) - - util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) { - if keytyp := lkey.Type(); keytyp == rt.StringType { - // ['--flag'] = {'description', '--flag-alias'} - itemName, ok := lkey.TryString() - vlTbl, okk := lval.TryTable() - if !ok && !okk { - // TODO: error - return - } - - items = append(items, itemName) - itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString() - if !ok { - // TODO: error - return - } - itemDescriptions[itemName] = itemDescription - } else if keytyp == rt.IntType { - vlStr, ok := lval.TryString() - if !ok { - // TODO: error - return - } - items = append(items, vlStr) - } else { - // TODO: error - return - } - }) - - var dispType readline.TabDisplayType - switch luaCompType.AsString() { - case "grid": dispType = readline.TabDisplayGrid - case "list": dispType = readline.TabDisplayList - // need special cases, will implement later - //case "map": dispType = readline.TabDisplayMap - } - - compGroups = append(compGroups, &readline.CompletionGroup{ - DisplayType: dispType, - Descriptions: itemDescriptions, - Suggestions: items, - TrimSlash: false, - NoSpace: true, - }) - }) - - return pfx, compGroups - } + setupTabCompleter(rl) return lr } @@ -246,11 +159,13 @@ func (lr *lineReader) Resize() { // method of saving history. func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table { lrLua := map[string]util.LuaExport{ + /* "add": {lr.luaAddHistory, 1, false}, "all": {lr.luaAllHistory, 0, false}, "clear": {lr.luaClearHistory, 0, false}, "get": {lr.luaGetHistory, 1, false}, "size": {lr.luaSize, 0, false}, + */ } mod := rt.NewTable() diff --git a/rl_midnight.go b/rl_midnight.go new file mode 100644 index 0000000..25fdfda --- /dev/null +++ b/rl_midnight.go @@ -0,0 +1,10 @@ +//go:build midnight +package main + +import ( + "github.com/maxlandon/readline" +) + +func setupTabCompleter(rl *readline.Instance) { + // TODO +} diff --git a/rl_notmidnight.go b/rl_notmidnight.go new file mode 100644 index 0000000..219439f --- /dev/null +++ b/rl_notmidnight.go @@ -0,0 +1,99 @@ +//go:build !midnight +package main + +import ( + "hilbish/util" + + rt "github.com/arnodel/golua/runtime" + "github.com/maxlandon/readline" +) + +func setupTabCompleter(rl *readline.Instance) { + rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) { + term := rt.NewTerminationWith(l.UnderlyingRuntime().MainThread().CurrentCont(), 2, false) + compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler")) + err := rt.Call(l.UnderlyingRuntime().MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)), + rt.IntValue(int64(pos))}, term) + + var compGroups []*readline.CompletionGroup + if err != nil { + return "", compGroups + } + + luaCompGroups := term.Get(0) + luaPrefix := term.Get(1) + + if luaCompGroups.Type() != rt.TableType { + return "", compGroups + } + + groups := luaCompGroups.AsTable() + // prefix is optional + pfx, _ := luaPrefix.TryString() + + util.ForEach(groups, func(key rt.Value, val rt.Value) { + if key.Type() != rt.IntType || val.Type() != rt.TableType { + return + } + + valTbl := val.AsTable() + luaCompType := valTbl.Get(rt.StringValue("type")) + luaCompItems := valTbl.Get(rt.StringValue("items")) + + if luaCompType.Type() != rt.StringType || luaCompItems.Type() != rt.TableType { + return + } + + items := []string{} + itemDescriptions := make(map[string]string) + + util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) { + if keytyp := lkey.Type(); keytyp == rt.StringType { + // ['--flag'] = {'description', '--flag-alias'} + itemName, ok := lkey.TryString() + vlTbl, okk := lval.TryTable() + if !ok && !okk { + // TODO: error + return + } + + items = append(items, itemName) + itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString() + if !ok { + // TODO: error + return + } + itemDescriptions[itemName] = itemDescription + } else if keytyp == rt.IntType { + vlStr, ok := lval.TryString() + if !ok { + // TODO: error + return + } + items = append(items, vlStr) + } else { + // TODO: error + return + } + }) + + var dispType readline.TabDisplayType + switch luaCompType.AsString() { + case "grid": dispType = readline.TabDisplayGrid + case "list": dispType = readline.TabDisplayList + // need special cases, will implement later + //case "map": dispType = readline.TabDisplayMap + } + + compGroups = append(compGroups, &readline.CompletionGroup{ + DisplayType: dispType, + Descriptions: itemDescriptions, + Suggestions: items, + TrimSlash: false, + NoSpace: true, + }) + }) + + return pfx, compGroups + } +} diff --git a/runnermode.go b/runnermode.go index 55adfdc..269831d 100644 --- a/runnermode.go +++ b/runnermode.go @@ -1,9 +1,7 @@ package main import ( - "hilbish/util" - - rt "github.com/arnodel/golua/runtime" + "hilbish/moonlight" ) // #interface runner @@ -49,15 +47,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 +74,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 = moonlight.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(int64(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 +102,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 = moonlight.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(int64(exitCode))) + runnerRet.SetField("err", luaErr) - return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil + + return mlr.PushNext1(c, moonlight.TableValue(runnerRet)), nil } diff --git a/sink.go b/sink.go index 3aa5507..ec52634 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)) +*/ } @@ -216,7 +220,7 @@ func newSinkInput(r io.Reader) *sink { s := &sink{ reader: bufio.NewReader(r), } - s.ud = sinkUserData(s) + //s.ud = sinkUserData(s) if f, ok := r.(*os.File); ok { s.file = f @@ -230,7 +234,7 @@ func newSinkOutput(w io.Writer) *sink { writer: bufio.NewWriter(w), autoFlush: true, } - s.ud = sinkUserData(s) + //s.ud = sinkUserData(s) return s } @@ -254,7 +258,9 @@ func valueToSink(val rt.Value) (*sink, bool) { return s, ok } +/* 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..68f85ed 100644 --- a/timer.go +++ b/timer.go @@ -2,10 +2,12 @@ package main import ( "errors" - "fmt" - "os" +// "fmt" +// "os" "time" +// "hilbish/moonlight" + rt "github.com/arnodel/golua/runtime" ) @@ -47,7 +49,8 @@ func (t *timer) start() error { for { select { case <-t.ticker.C: - _, err := rt.Call1(l.MainThread(), rt.FunctionValue(t.fun)) + /* + _, err := l.Call1(moonlight.FunctionValue(t.fun)) if err != nil { fmt.Fprintln(os.Stderr, "Error in function:\n", err) t.stop() @@ -56,6 +59,7 @@ func (t *timer) start() error { if t.typ == timerTimeout { t.stop() } + */ case <-t.channel: t.ticker.Stop() return diff --git a/timerhandler.go b/timerhandler.go index 0a8e34f..0a981d3 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" ) @@ -47,7 +48,7 @@ func (th *timersModule) create(typ timerType, dur time.Duration, fun *rt.Closure th: th, id: th.latestID, } - t.ud = timerUserData(t) + //t.ud = timerUserData(t) th.timers[th.latestID] = t @@ -133,14 +134,17 @@ 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) { ti, _ := timerArg(c, 0) @@ -164,18 +168,21 @@ 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", moonlight.IntValue(0)) + luaTh.SetField("TIMEOUT", moonlight.IntValue(1)) return luaTh } @@ -199,7 +206,9 @@ func valueToTimer(val rt.Value) (*timer, bool) { return j, ok } +/* 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..d4cbd39 100644 --- a/userdir.go +++ b/userdir.go @@ -1,9 +1,7 @@ package main import ( - "hilbish/util" - - rt "github.com/arnodel/golua/runtime" + "hilbish/moonlight" ) // #interface userDir @@ -13,11 +11,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", moonlight.StringValue(confDir)) + mod.SetField("data", moonlight.StringValue(userDataDir)) return mod } diff --git a/util/export.go b/util/export.go index ee0b4a6..a4bd277 100644 --- a/util/export.go +++ b/util/export.go @@ -1,19 +1,23 @@ 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 } // SetExports puts the Lua function exports in the table. func SetExports(rtm *rt.Runtime, tbl *rt.Table, exports map[string]LuaExport) { + /* for name, export := range exports { rtm.SetEnvGoFunc(tbl, name, export.Function, export.ArgNum, export.Variadic) } + */ } diff --git a/util/util.go b/util/util.go index 0fcd4b0..46a6a2d 100644 --- a/util/util.go +++ b/util/util.go @@ -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("", []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 }