sammyette 2024-07-27 15:05:55 -04:00 committed by GitHub
commit 2de1d26b39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 1314 additions and 573 deletions

View File

@ -10,10 +10,11 @@ on:
jobs: jobs:
build: build:
name: ${{ matrix.goos }}-${{ matrix.goarch }} name: ${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.midnight == 'true' && ' (Midnight Edition)' || ''}}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
midnight: [false, true]
goos: [linux, windows, darwin] goos: [linux, windows, darwin]
goarch: ["386", amd64, arm64] goarch: ["386", amd64, arm64]
exclude: exclude:
@ -33,11 +34,11 @@ jobs:
- name: Download Task - name: Download Task
run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d' run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d'
- name: Build - 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 - uses: actions/upload-artifact@v4
if: matrix.goos == 'windows' if: matrix.goos == 'windows'
with: with:
name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} name: hilbish${{ matrix.midnight == 'true' && '-midnight-edition' || ''}}-${{ matrix.goos }}-${{ matrix.goarch }}
path: | path: |
hilbish.exe hilbish.exe
LICENSE LICENSE
@ -51,7 +52,7 @@ jobs:
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: matrix.goos != 'windows' if: matrix.goos != 'windows'
with: with:
name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} name: hilbish${{ matrix.midnight == 'true' && '-midnight-edition' || ''}}-${{ matrix.goos }}-${{ matrix.goarch }}
path: | path: |
hilbish hilbish
LICENSE LICENSE

View File

@ -1,7 +1,4 @@
> [!TIP] <img src="./assets/hilbish-logo-and-text-midnight-edition.png" width=512><br>
> Check out [Hilbish: Midnight Edition](https://github.com/Rosettea/Hilbish/tree/midnight-edition) if you want to use C Lua, LuaJIT or anything related!
<img src="./assets/hilbish-logo-and-text.png" width=512><br>
<blockquote> <blockquote>
🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨ 🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨
</blockquote> </blockquote>
@ -12,6 +9,27 @@
<a href="https://discord.gg/3PDdcQz"><img alt="Discord" src="https://img.shields.io/discord/732357621503229962?color=blue&style=flat-square"></a> <a href="https://discord.gg/3PDdcQz"><img alt="Discord" src="https://img.shields.io/discord/732357621503229962?color=blue&style=flat-square"></a>
<br> <br>
# Midnight Edition
> [!CAUTION]
> This is a **HEAVILY** WORK IN PROGRESS branch which makes a lot of internal changes.
Functionality **will** be missing if you use this branch,
and you may see crashes too. Tread lightly.
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. Hilbish is an extensible shell designed to be highly customizable.
It is configured in Lua and provides a good range of features. 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 It aims to be easy to use for anyone but powerful enough for
@ -53,13 +71,13 @@ go get -d ./...
To build, run: To build, run:
``` ```
task go-task
``` ```
Or, if you want a stable branch, run these commands: Or, if you want a stable branch, run these commands:
``` ```
git checkout $(git describe --tags `git rev-list --tags --max-count=1`) 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. After you did all that, run `sudo task install` to install Hilbish globally.

View File

@ -10,6 +10,8 @@ vars:
LIBDIR: '{{default .libdir__ .LIBDIR}}' LIBDIR: '{{default .libdir__ .LIBDIR}}'
goflags__: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"' goflags__: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"'
GOFLAGS: '{{default .goflags__ .GOFLAGS}}' GOFLAGS: '{{default .goflags__ .GOFLAGS}}'
lua__: 'lua'
LUA: '{{default .lua__ .LUA}}'
tasks: tasks:
default: default:
@ -24,6 +26,12 @@ tasks:
vars: 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)"' 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: build:
cmds: cmds:
- go build {{.GOFLAGS}} - go build {{.GOFLAGS}}

View File

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

184
api.go
View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

View File

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

View File

@ -12,11 +12,13 @@ import (
// directly interact with the line editor in use. // directly interact with the line editor in use.
func editorLoader(rtm *rt.Runtime) *rt.Table { func editorLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{ exports := map[string]util.LuaExport{
/*
"insert": {editorInsert, 1, false}, "insert": {editorInsert, 1, false},
"setVimRegister": {editorSetRegister, 1, false}, "setVimRegister": {editorSetRegister, 1, false},
"getVimRegister": {editorGetRegister, 2, false}, "getVimRegister": {editorGetRegister, 2, false},
"getLine": {editorGetLine, 0, false}, "getLine": {editorGetLine, 0, false},
"readChar": {editorReadChar, 0, false}, "readChar": {editorReadChar, 0, false},
*/
} }
mod := rt.NewTable() mod := rt.NewTable()

65
exec.go
View File

@ -15,7 +15,8 @@ import (
"syscall" "syscall"
"time" "time"
"hilbish/util" "hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
"mvdan.cc/sh/v3/shell" "mvdan.cc/sh/v3/shell"
@ -27,7 +28,7 @@ import (
var errNotExec = errors.New("not executable") var errNotExec = errors.New("not executable")
var errNotFound = errors.New("not found") var errNotFound = errors.New("not found")
var runnerMode rt.Value = rt.StringValue("hybrid") var runnerMode moonlight.Value = moonlight.StringValue("hybrid")
type streams struct { type streams struct {
stdout io.Writer stdout io.Writer
@ -100,7 +101,7 @@ func runInput(input string, priv bool) {
var cont bool var cont bool
// save incase it changes while prompting (For some reason) // save incase it changes while prompting (For some reason)
currentRunner := runnerMode currentRunner := runnerMode
if currentRunner.Type() == rt.StringType { if currentRunner.Type() == moonlight.StringType {
switch currentRunner.AsString() { switch currentRunner.AsString() {
case "hybrid": case "hybrid":
_, _, err = handleLua(input) _, _, 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) { func runLuaRunner(runr moonlight.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) {
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 3, false) runnerRet, err := l.Call1(runr, moonlight.StringValue(userInput))
err = rt.Call(l.MainThread(), runr, []rt.Value{rt.StringValue(userInput)}, term)
if err != nil { if err != nil {
return "", 124, false, nil, err return "", 124, false, nil, err
} }
var runner *rt.Table var runner *moonlight.Table
var ok bool var ok bool
runnerRet := term.Get(0) if runner, ok = moonlight.TryTable(runnerRet); !ok {
if runner, ok = runnerRet.TryTable(); !ok {
fmt.Fprintln(os.Stderr, "runner did not return a table") fmt.Fprintln(os.Stderr, "runner did not return a table")
exitCode = 125 exitCode = 125
input = userInput input = userInput
return return
} }
if code, ok := runner.Get(rt.StringValue("exitCode")).TryInt(); ok { if code, ok := runner.Get(moonlight.StringValue("exitCode")).TryInt(); ok {
exitCode = uint8(code) 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 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) 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 continued = c
} }
return 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) { 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 var err error
input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString) input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString)
if err != nil { 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("out"), rt.UserDataValue(stdout.ud))
sinks.Set(rt.StringValue("err"), rt.UserDataValue(stderr.ud)) sinks.Set(rt.StringValue("err"), rt.UserDataValue(stderr.ud))
t := rt.NewThread(l) //t := rt.NewThread(l)
sig := make(chan os.Signal) sig := make(chan os.Signal)
exit := make(chan bool) exit := make(chan bool)
@ -368,14 +340,15 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
signal.Notify(sig, os.Interrupt) signal.Notify(sig, os.Interrupt)
select { select {
case <-sig: case <-sig:
t.KillContext() //t.KillContext()
return return
} }
}() }()
go func() { 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 exit <- true
}() }()
@ -606,9 +579,9 @@ func splitInput(input string) ([]string, string) {
} }
func cmdFinish(code uint8, cmdstr string, private bool) { 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 // using AsValue (to convert to lua type) on an interface which is an int
// results in it being unknown in lua .... ???? // results in it being unknown in lua .... ????
// so we allow the hook handler to take lua runtime Values // 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)
} }

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.21
toolchain go1.22.2 toolchain go1.22.2
require ( require (
github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765
github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1 github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1
github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504 github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504
github.com/blackfireio/osinfo v1.0.5 github.com/blackfireio/osinfo v1.0.5

2
go.sum
View File

@ -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/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 h1:THNle0FR2g7DMO1y3Bx1Zr7rYeiLXt3st3UkxEsMzL4=
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240720131751-805c301321fd/go.mod h1:YZalN5H7WNQw3DGij6IvHsEhn5YMW7M2FCwG6gnfKy4= 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 h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= 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= github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw=

View File

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

View File

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

View File

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

View File

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

View File

@ -7,17 +7,17 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
rt "github.com/arnodel/golua/runtime" "hilbish/moonlight"
) )
type luaHistory struct {} type luaHistory struct {}
func (h *luaHistory) Write(line string) (int, error) { func (h *luaHistory) Write(line string) (int, error) {
histWrite := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("add")) histWrite := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("add"))
ln, err := rt.Call1(l.MainThread(), histWrite, rt.StringValue(line)) ln, err := l.Call1(histWrite, moonlight.StringValue(line))
var num int64 var num int64
if ln.Type() == rt.IntType { if ln.Type() == moonlight.IntType {
num = ln.AsInt() num = ln.AsInt()
} }
@ -25,11 +25,11 @@ func (h *luaHistory) Write(line string) (int, error) {
} }
func (h *luaHistory) GetLine(idx int) (string, error) { func (h *luaHistory) GetLine(idx int) (string, error) {
histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get")) histGet := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("get"))
lcmd, err := rt.Call1(l.MainThread(), histGet, rt.IntValue(int64(idx))) lcmd, err := l.Call1(histGet, moonlight.IntValue(int64(idx)))
var cmd string var cmd string
if lcmd.Type() == rt.StringType { if lcmd.Type() == moonlight.StringType {
cmd = lcmd.AsString() cmd = lcmd.AsString()
} }
@ -37,11 +37,11 @@ func (h *luaHistory) GetLine(idx int) (string, error) {
} }
func (h *luaHistory) Len() int { func (h *luaHistory) Len() int {
histSize := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("size")) histSize := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("size"))
ln, _ := rt.Call1(l.MainThread(), histSize) ln, _ := l.Call1(histSize)
var num int64 var num int64
if ln.Type() == rt.IntType { if ln.Type() == moonlight.IntType {
num = ln.AsInt() num = ln.AsInt()
} }

21
job.go
View File

@ -10,6 +10,7 @@ import (
"sync" "sync"
"syscall" "syscall"
"hilbish/moonlight"
"hilbish/util" "hilbish/util"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
@ -260,7 +261,7 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job {
stdout: &bytes.Buffer{}, stdout: &bytes.Buffer{},
stderr: &bytes.Buffer{}, stderr: &bytes.Buffer{},
} }
jb.ud = jobUserData(jb) //jb.ud = jobUserData(jb)
j.jobs[j.latestID] = jb j.jobs[j.latestID] = jb
hooks.Emit("job.add", rt.UserDataValue(jb.ud)) 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 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. */ 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() jobMethods := rt.NewTable()
jFuncs := map[string]util.LuaExport{ jFuncs := map[string]util.LuaExport{
"stop": {luaStopJob, 1, false}, "stop": {luaStopJob, 1, false},
@ -319,7 +321,9 @@ func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
"background": {luaBackgroundJob, 1, false}, "background": {luaBackgroundJob, 1, false},
} }
util.SetExports(l, jobMethods, jFuncs) util.SetExports(l, jobMethods, jFuncs)
*/
/*
jobMeta := rt.NewTable() jobMeta := rt.NewTable()
jobIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jobIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
j, _ := jobArg(c, 0) 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))) jobMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(jobIndex, "__index", 2, false)))
l.SetRegistry(jobMetaKey, rt.TableValue(jobMeta)) l.SetRegistry(jobMetaKey, rt.TableValue(jobMeta))
*/
jobFuncs := map[string]util.LuaExport{ jobFuncs := map[string]moonlight.Export{
/*
"all": {j.luaAllJobs, 0, false}, "all": {j.luaAllJobs, 0, false},
"last": {j.luaLastJob, 0, false}, "last": {j.luaLastJob, 0, false},
"get": {j.luaGetJob, 1, false}, "get": {j.luaGetJob, 1, false},
"add": {j.luaAddJob, 3, false}, "add": {j.luaAddJob, 3, false},
"disown": {j.luaDisownJob, 1, false}, "disown": {j.luaDisownJob, 1, false},
*/
} }
luaJob := rt.NewTable() luaJob := moonlight.NewTable()
util.SetExports(rtm, luaJob, jobFuncs) l.SetExports(luaJob, jobFuncs)
return luaJob return luaJob
} }
@ -382,10 +389,12 @@ func valueToJob(val rt.Value) (*job, bool) {
return j, ok return j, ok
} }
/*
func jobUserData(j *job) *rt.UserData { func jobUserData(j *job) *rt.UserData {
jobMeta := l.Registry(jobMetaKey) jobMeta := l.UnderlyingRuntime().Registry(jobMetaKey)
return rt.NewUserData(j, jobMeta.AsTable()) return rt.NewUserData(j, jobMeta.AsTable())
} }
*/
// #interface jobs // #interface jobs
// get(id) -> @Job // get(id) -> @Job

42
lua.go
View File

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

37
lua_exec.go 100644
View File

@ -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
}

View File

@ -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")
}

11
main.go
View File

@ -16,6 +16,7 @@ import (
"hilbish/util" "hilbish/util"
"hilbish/golibs/bait" "hilbish/golibs/bait"
"hilbish/golibs/commander" "hilbish/golibs/commander"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
"github.com/pborman/getopt" "github.com/pborman/getopt"
@ -25,7 +26,7 @@ import (
) )
var ( var (
l *rt.Runtime l *moonlight.Runtime
lr *lineReader lr *lineReader
luaCompletions = map[string]*rt.Closure{} luaCompletions = map[string]*rt.Closure{}
@ -169,13 +170,13 @@ func main() {
} }
if getopt.NArgs() > 0 { if getopt.NArgs() > 0 {
luaArgs := rt.NewTable() luaArgs := moonlight.NewTable()
for i, arg := range getopt.Args() { 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)) l.GlobalTable().SetField("args", moonlight.TableValue(luaArgs))
err := util.DoFile(l, getopt.Arg(0)) err := l.DoFile(getopt.Arg(0))
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
exit(1) exit(1)

View File

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

View File

@ -0,0 +1,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 {
}
*/

View File

@ -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
}

View File

@ -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()
}

View File

@ -0,0 +1,7 @@
package moonlight
type Export struct{
Function GoToLuaFunc
ArgNum int
Variadic bool
}

View File

@ -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)))
}
}

View File

@ -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)
}
}

View File

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

View File

@ -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)
},
}
}

View File

@ -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)
}
}

View File

@ -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, "loaded")
mlr.state.PushGoFunction(cluaLoader)
mlr.state.SetField(-2, name)
}

View File

@ -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)
}

View File

@ -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())
}
}

View File

@ -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...)
}

View File

@ -0,0 +1,47 @@
//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
}
func (t *Table) setRefIdx(mlr *Runtime, i idx) {
t.refIdx = mlr.state.Ref(i)
}

View File

@ -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
}

View File

@ -0,0 +1,13 @@
//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)
return nil
}

View File

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

View File

@ -0,0 +1,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 "<unknown type>"
}
}
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
}

View File

@ -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)
}

14
os.go
View File

@ -1,9 +1,9 @@
package main package main
import ( import (
"hilbish/util" "hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/blackfireio/osinfo" "github.com/blackfireio/osinfo"
) )
@ -14,13 +14,13 @@ import (
// #field family Family name of the current OS // #field family Family name of the current OS
// #field name Pretty name of the current OS // #field name Pretty name of the current OS
// #field version Version 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() info, _ := osinfo.GetOSInfo()
mod := rt.NewTable() mod := moonlight.NewTable()
util.SetField(rtm, mod, "family", rt.StringValue(info.Family)) mod.SetField("family", moonlight.StringValue(info.Family))
util.SetField(rtm, mod, "name", rt.StringValue(info.Name)) mod.SetField("name", moonlight.StringValue(info.Name))
util.SetField(rtm, mod, "version", rt.StringValue(info.Version)) mod.SetField("version", moonlight.StringValue(info.Version))
return mod return mod
} }

103
rl.go
View File

@ -5,6 +5,7 @@ import (
"io" "io"
"strings" "strings"
"hilbish/moonlight"
"hilbish/util" "hilbish/util"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
@ -27,7 +28,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
regexSearcher := rl.Searcher regexSearcher := rl.Searcher
rl.Searcher = func(needle string, haystack []string) []string { 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() fuzz, ok := fz.TryBool()
if !fuzz || !ok { if !fuzz || !ok {
return regexSearcher(needle, haystack) return regexSearcher(needle, haystack)
@ -70,9 +71,8 @@ func newLineReader(prompt string, noHist bool) *lineReader {
hooks.Emit("hilbish.vimAction", actionStr, args) hooks.Emit("hilbish.vimAction", actionStr, args)
} }
rl.HintText = func(line []rune, pos int) []rune { rl.HintText = func(line []rune, pos int) []rune {
hinter := hshMod.Get(rt.StringValue("hinter")) hinter := hshMod.Get(moonlight.StringValue("hinter"))
retVal, err := rt.Call1(l.MainThread(), hinter, retVal, err := l.Call1(hinter, moonlight.StringValue(string(line)), moonlight.IntValue(int64(pos)))
rt.StringValue(string(line)), rt.IntValue(int64(pos)))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return []rune{} return []rune{}
@ -86,9 +86,8 @@ func newLineReader(prompt string, noHist bool) *lineReader {
return []rune(hintText) return []rune(hintText)
} }
rl.SyntaxHighlighter = func(line []rune) string { rl.SyntaxHighlighter = func(line []rune) string {
highlighter := hshMod.Get(rt.StringValue("highlighter")) highlighter := hshMod.Get(moonlight.StringValue("highlighter"))
retVal, err := rt.Call1(l.MainThread(), highlighter, retVal, err := l.Call1(highlighter, moonlight.StringValue(string(line)))
rt.StringValue(string(line)))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return string(line) return string(line)
@ -101,93 +100,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
return highlighted return highlighted
} }
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) { setupTabCompleter(rl)
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
}
return lr return lr
} }
@ -246,11 +159,13 @@ func (lr *lineReader) Resize() {
// method of saving history. // method of saving history.
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table { func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
lrLua := map[string]util.LuaExport{ lrLua := map[string]util.LuaExport{
/*
"add": {lr.luaAddHistory, 1, false}, "add": {lr.luaAddHistory, 1, false},
"all": {lr.luaAllHistory, 0, false}, "all": {lr.luaAllHistory, 0, false},
"clear": {lr.luaClearHistory, 0, false}, "clear": {lr.luaClearHistory, 0, false},
"get": {lr.luaGetHistory, 1, false}, "get": {lr.luaGetHistory, 1, false},
"size": {lr.luaSize, 0, false}, "size": {lr.luaSize, 0, false},
*/
} }
mod := rt.NewTable() mod := rt.NewTable()

10
rl_midnight.go 100644
View File

@ -0,0 +1,10 @@
//go:build midnight
package main
import (
"github.com/maxlandon/readline"
)
func setupTabCompleter(rl *readline.Instance) {
// TODO
}

99
rl_notmidnight.go 100644
View File

@ -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
}
}

View File

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

26
sink.go
View File

@ -7,7 +7,8 @@ import (
"os" "os"
"strings" "strings"
"hilbish/util" //"hilbish/util"
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
@ -25,20 +26,22 @@ type sink struct{
autoFlush bool autoFlush bool
} }
func setupSinkType(rtm *rt.Runtime) { func setupSinkType() {
sinkMeta := rt.NewTable() //sinkMeta := moonlight.NewTable()
sinkMethods := rt.NewTable() sinkMethods := moonlight.NewTable()
sinkFuncs := map[string]util.LuaExport{ sinkFuncs := map[string]moonlight.Export{
/*
"flush": {luaSinkFlush, 1, false}, "flush": {luaSinkFlush, 1, false},
"read": {luaSinkRead, 1, false}, "read": {luaSinkRead, 1, false},
"readAll": {luaSinkReadAll, 1, false}, "readAll": {luaSinkReadAll, 1, false},
"autoFlush": {luaSinkAutoFlush, 2, false}, "autoFlush": {luaSinkAutoFlush, 2, false},
"write": {luaSinkWrite, 2, false}, "write": {luaSinkWrite, 2, false},
"writeln": {luaSinkWriteln, 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) { sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
s, _ := sinkArg(c, 0) 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))) sinkMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(sinkIndex, "__index", 2, false)))
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta)) l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta))
*/
} }
@ -216,7 +220,7 @@ func newSinkInput(r io.Reader) *sink {
s := &sink{ s := &sink{
reader: bufio.NewReader(r), reader: bufio.NewReader(r),
} }
s.ud = sinkUserData(s) //s.ud = sinkUserData(s)
if f, ok := r.(*os.File); ok { if f, ok := r.(*os.File); ok {
s.file = f s.file = f
@ -230,7 +234,7 @@ func newSinkOutput(w io.Writer) *sink {
writer: bufio.NewWriter(w), writer: bufio.NewWriter(w),
autoFlush: true, autoFlush: true,
} }
s.ud = sinkUserData(s) //s.ud = sinkUserData(s)
return s return s
} }
@ -254,7 +258,9 @@ func valueToSink(val rt.Value) (*sink, bool) {
return s, ok return s, ok
} }
/*
func sinkUserData(s *sink) *rt.UserData { func sinkUserData(s *sink) *rt.UserData {
sinkMeta := l.Registry(sinkMetaKey) sinkMeta := l.UnderlyingRuntime().Registry(sinkMetaKey)
return rt.NewUserData(s, sinkMeta.AsTable()) return rt.NewUserData(s, sinkMeta.AsTable())
} }
*/

View File

@ -2,10 +2,12 @@ package main
import ( import (
"errors" "errors"
"fmt" // "fmt"
"os" // "os"
"time" "time"
// "hilbish/moonlight"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
@ -47,7 +49,8 @@ func (t *timer) start() error {
for { for {
select { select {
case <-t.ticker.C: case <-t.ticker.C:
_, err := rt.Call1(l.MainThread(), rt.FunctionValue(t.fun)) /*
_, err := l.Call1(moonlight.FunctionValue(t.fun))
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "Error in function:\n", err) fmt.Fprintln(os.Stderr, "Error in function:\n", err)
t.stop() t.stop()
@ -56,6 +59,7 @@ func (t *timer) start() error {
if t.typ == timerTimeout { if t.typ == timerTimeout {
t.stop() t.stop()
} }
*/
case <-t.channel: case <-t.channel:
t.ticker.Stop() t.ticker.Stop()
return return

View File

@ -5,7 +5,8 @@ import (
"sync" "sync"
"time" "time"
"hilbish/util" "hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
@ -47,7 +48,7 @@ func (th *timersModule) create(typ timerType, dur time.Duration, fun *rt.Closure
th: th, th: th,
id: th.latestID, id: th.latestID,
} }
t.ud = timerUserData(t) //t.ud = timerUserData(t)
th.timers[th.latestID] = t th.timers[th.latestID] = t
@ -133,14 +134,17 @@ t:start()
print(t.running) // true print(t.running) // true
``` ```
*/ */
func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table { func (th *timersModule) loader() *moonlight.Table {
timerMethods := rt.NewTable() timerMethods := moonlight.NewTable()
timerFuncs := map[string]util.LuaExport{ timerFuncs := map[string]moonlight.Export{
/*
"start": {timerStart, 1, false}, "start": {timerStart, 1, false},
"stop": {timerStop, 1, false}, "stop": {timerStop, 1, false},
*/
} }
util.SetExports(rtm, timerMethods, timerFuncs) l.SetExports(timerMethods, timerFuncs)
/*
timerMeta := rt.NewTable() timerMeta := rt.NewTable()
timerIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { timerIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
ti, _ := timerArg(c, 0) 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))) 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}, "create": {th.luaCreate, 3, false},
"get": {th.luaGet, 1, false}, "get": {th.luaGet, 1, false},
*/
} }
luaTh := rt.NewTable() luaTh := moonlight.NewTable()
util.SetExports(rtm, luaTh, thExports) l.SetExports(luaTh, thExports)
util.SetField(rtm, luaTh, "INTERVAL", rt.IntValue(0)) luaTh.SetField("INTERVAL", moonlight.IntValue(0))
util.SetField(rtm, luaTh, "TIMEOUT", rt.IntValue(1)) luaTh.SetField("TIMEOUT", moonlight.IntValue(1))
return luaTh return luaTh
} }
@ -199,7 +206,9 @@ func valueToTimer(val rt.Value) (*timer, bool) {
return j, ok return j, ok
} }
/*
func timerUserData(j *timer) *rt.UserData { func timerUserData(j *timer) *rt.UserData {
timerMeta := l.Registry(timerMetaKey) timerMeta := l.UnderlyingRuntime().Registry(timerMetaKey)
return rt.NewUserData(j, timerMeta.AsTable()) return rt.NewUserData(j, timerMeta.AsTable())
} }
*/

View File

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

View File

@ -1,19 +1,23 @@
package util package util
import ( import (
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
// LuaExport represents a Go function which can be exported to Lua. // LuaExport represents a Go function which can be exported to Lua.
type LuaExport struct { type LuaExport struct {
Function rt.GoFunctionFunc Function moonlight.GoFunctionFunc
ArgNum int ArgNum int
Variadic bool Variadic bool
} }
// SetExports puts the Lua function exports in the table. // SetExports puts the Lua function exports in the table.
func SetExports(rtm *rt.Runtime, tbl *rt.Table, exports map[string]LuaExport) { func SetExports(rtm *rt.Runtime, tbl *rt.Table, exports map[string]LuaExport) {
/*
for name, export := range exports { for name, export := range exports {
rtm.SetEnvGoFunc(tbl, name, export.Function, export.ArgNum, export.Variadic) rtm.SetEnvGoFunc(tbl, name, export.Function, export.ArgNum, export.Variadic)
} }
*/
} }

View File

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