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

View File

@ -1,7 +1,4 @@
> [!TIP] <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,26 @@
<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.
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

View File

@ -97,7 +97,7 @@ 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},

181
api.go
View File

@ -15,56 +15,58 @@ 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 {
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},
*/
} }
hshMod = moonlight.NewTable()
var hshMod *rt.Table mlr.SetExports(hshMod, exports)
var hilbishLoader = packagelib.Loader{
Load: hilbishLoad,
Name: "hilbish",
}
func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
hshMod = mod
host, _ := os.Hostname() host, _ := os.Hostname()
username := curuser.Username username := curuser.Username
@ -73,68 +75,69 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
username = strings.Split(username, "\\")[1] // for some reason Username includes the hostname on windows 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 +149,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", rt.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", rt.NilValue)
} }
func handleStream(v rt.Value, strms *streams, errStream bool) error { func handleStream(v rt.Value, strms *streams, errStream bool) error {
@ -292,10 +295,10 @@ func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// cwd() -> string // 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 +351,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 +371,7 @@ func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return nil, errors.New("bad argument to run (expected string, got " + ltyp.TypeName() + ")") return nil, errors.New("bad argument to run (expected string, got " + ltyp.TypeName() + ")")
} }
} }
*/
switch typ { switch typ {
case "left": case "left":
@ -429,15 +434,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 +469,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 +501,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 +537,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 +623,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 +659,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 +668,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 +753,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 +764,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 +799,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 +829,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
} }
*/

21
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"
@ -171,15 +172,13 @@ func reprompt(input string) (string, error) {
} }
func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) { func runLuaRunner(runr rt.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 *rt.Table
var ok bool var ok bool
runnerRet := term.Get(0)
if runner, ok = runnerRet.TryTable(); !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
@ -208,7 +207,8 @@ func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8
func handleLua(input string) (string, uint8, error) { func handleLua(input string) (string, uint8, error) {
cmdString := aliases.Resolve(input) cmdString := aliases.Resolve(input)
// First try to load input, essentially compiling to bytecode // First try to load input, essentially compiling to bytecode
chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv())) rtm := l.UnderlyingRuntime()
chunk, err := rtm.CompileAndLoadLuaChunk("", []byte(cmdString), moonlight.TableValue(l.GlobalTable()))
if err != nil && noexecute { if err != nil && noexecute {
fmt.Println(err) fmt.Println(err)
/* if lerr, ok := err.(*lua.ApiError); ok { /* if lerr, ok := err.(*lua.ApiError); ok {
@ -222,7 +222,7 @@ func handleLua(input string) (string, uint8, error) {
// And if there's no syntax errors and -n isnt provided, run // And if there's no syntax errors and -n isnt provided, run
if !noexecute { if !noexecute {
if chunk != nil { if chunk != nil {
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk)) _, err = l.Call1(rt.FunctionValue(chunk))
} }
} }
if err == nil { if err == nil {
@ -352,7 +352,7 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
sinks.Set(rt.StringValue("out"), rt.UserDataValue(stdout.ud)) sinks.Set(rt.StringValue("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 +368,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,7 +607,7 @@ 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", rt.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

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
} }
@ -88,16 +83,16 @@ func (b *Bait) Emit(event string, args ...interface{}) {
if handle.typ == luaListener { if handle.typ == luaListener {
funcVal := rt.FunctionValue(handle.luaCaller) funcVal := rt.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 = rt.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())
@ -129,7 +124,7 @@ 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,
@ -212,18 +207,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 +255,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 +266,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 +313,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 +332,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 +343,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 +359,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 +376,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,37 @@ 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" 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]*rt.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]*rt.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 +83,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 +97,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 +115,14 @@ func (c *Commander) cderegister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
// Returns all registered commanders. Returns a list of tables with the following keys: // 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", rt.FunctionValue(cmd))
registryLua.Set(rt.StringValue(cmdName), rt.TableValue(cmdTbl)) registryLua.SetField(cmdName, moonlight.TableValue(cmdTbl))
} }
return ct.PushingNext1(t.Runtime, rt.TableValue(registryLua)), nil return mlr.PushNext1(ct, moonlight.TableValue(registryLua)), nil
} }

View File

@ -14,50 +14,51 @@ import (
"os" "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) Loader(rtm *moonlight.Runtime) moonlight.Value {
} exports := map[string]moonlight.Export{
/*
func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
"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", rt.StringValue(string(os.PathSeparator)))
mod.SetField("pathListSep", rt.StringValue(string(os.PathListSeparator)))
return moonlight.TableValue(mod)
} }
// abs(path) -> string // abs(path) -> string
@ -124,16 +125,17 @@ func (f *fs) fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// `~/Documents/doc.txt` then this function will return `~/Documents`. // `~/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)
@ -262,16 +264,16 @@ func (f *fs) fpipe(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// Returns a list of all files and directories in the provided path. // 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 {
@ -281,7 +283,7 @@ func (f *fs) freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name())) names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
} }
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil return mlr.PushNext1(c, moonlight.TableValue(names)), nil
} }
// stat(path) -> {} // stat(path) -> {}

View File

@ -5,52 +5,47 @@ package terminal
import ( import (
"os" "os"
"hilbish/util" "hilbish/moonlight"
rt "github.com/arnodel/golua/runtime" 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, func Loader(rtm *moonlight.Runtime) moonlight.Value {
Name: "terminal", exports := map[string]moonlight.Export{
"setRaw": {termsetRaw, 0, false},
"restoreState": {termrestoreState, 0, false},
"size": {termsize, 0, false},
"saveState": {termsaveState, 0, false},
} }
func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { mod := moonlight.NewTable()
exports := map[string]util.LuaExport{ rtm.SetExports(mod, exports)
"setRaw": util.LuaExport{termsetRaw, 0, false},
"restoreState": util.LuaExport{termrestoreState, 0, false},
"size": util.LuaExport{termsize, 0, false},
"saveState": util.LuaExport{termsaveState, 0, false},
}
mod := rt.NewTable() return moonlight.TableValue(mod)
util.SetExports(rtm, mod, exports)
return rt.TableValue(mod), nil
} }
// 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.Set(rt.StringValue("width"), rt.IntValue(int64(w)))
dimensions.Set(rt.StringValue("height"), rt.IntValue(int64(h))) dimensions.Set(rt.StringValue("height"), rt.IntValue(int64(h)))
return c.PushingNext1(t.Runtime, rt.TableValue(dimensions)), nil return mlr.PushNext1(c, moonlight.TableValue(dimensions)), nil
} }
// saveState() // 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 +57,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 +68,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

@ -14,7 +14,7 @@ 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(rt.StringValue("history")).AsTable().Get(rt.StringValue("add"))
ln, err := rt.Call1(l.MainThread(), histWrite, rt.StringValue(line)) ln, err := l.Call1(histWrite, rt.StringValue(line))
var num int64 var num int64
if ln.Type() == rt.IntType { if ln.Type() == rt.IntType {
@ -26,7 +26,7 @@ func (h *luaHistory) Write(line string) (int, error) {
func (h *luaHistory) GetLine(idx int) (string, error) { func (h *luaHistory) GetLine(idx int) (string, error) {
histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get")) histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get"))
lcmd, err := rt.Call1(l.MainThread(), histGet, rt.IntValue(int64(idx))) lcmd, err := l.Call1(histGet, rt.IntValue(int64(idx)))
var cmd string var cmd string
if lcmd.Type() == rt.StringType { if lcmd.Type() == rt.StringType {
@ -38,7 +38,7 @@ 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(rt.StringValue("history")).AsTable().Get(rt.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() == rt.IntType {

17
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"
@ -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
} }
@ -383,7 +390,7 @@ func valueToJob(val rt.Value) (*job, bool) {
} }
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())
} }

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

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{}
@ -174,8 +175,8 @@ func main() {
luaArgs.Set(rt.IntValue(int64(i)), rt.StringValue(arg)) luaArgs.Set(rt.IntValue(int64(i)), rt.StringValue(arg))
} }
l.GlobalEnv().Set(rt.StringValue("args"), rt.TableValue(luaArgs)) l.GlobalTable().SetField("args", rt.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,16 @@
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
)
type GoCont struct{
cont *rt.GoCont
thread *rt.Thread
}
type Cont = rt.Cont
type Closure = rt.Closure
func (gc *GoCont) Next() Cont {
return gc.cont.Next()
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

13
os.go
View File

@ -1,7 +1,8 @@
package main package main
import ( import (
"hilbish/util" "hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
"github.com/blackfireio/osinfo" "github.com/blackfireio/osinfo"
@ -14,13 +15,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", rt.StringValue(info.Family))
util.SetField(rtm, mod, "name", rt.StringValue(info.Name)) mod.SetField("name", rt.StringValue(info.Name))
util.SetField(rtm, mod, "version", rt.StringValue(info.Version)) mod.SetField("version", rt.StringValue(info.Version))
return mod return mod
} }

12
rl.go
View File

@ -27,7 +27,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)
@ -71,8 +71,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
} }
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(rt.StringValue("hinter"))
retVal, err := rt.Call1(l.MainThread(), hinter, retVal, err := l.Call1(hinter, rt.StringValue(string(line)), rt.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{}
@ -87,8 +86,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
} }
rl.SyntaxHighlighter = func(line []rune) string { rl.SyntaxHighlighter = func(line []rune) string {
highlighter := hshMod.Get(rt.StringValue("highlighter")) highlighter := hshMod.Get(rt.StringValue("highlighter"))
retVal, err := rt.Call1(l.MainThread(), highlighter, retVal, err := l.Call1(highlighter, rt.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)
@ -102,9 +100,9 @@ func newLineReader(prompt string, noHist bool) *lineReader {
return highlighted return highlighted
} }
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) { rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false) term := rt.NewTerminationWith(l.UnderlyingRuntime().MainThread().CurrentCont(), 2, false)
compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler")) compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler"))
err := rt.Call(l.MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)), err := rt.Call(l.UnderlyingRuntime().MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)),
rt.IntValue(int64(pos))}, term) rt.IntValue(int64(pos))}, term)
var compGroups []*readline.CompletionGroup var compGroups []*readline.CompletionGroup

View File

@ -1,7 +1,7 @@
package main package main
import ( import (
"hilbish/util" "hilbish/moonlight"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
@ -49,15 +49,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 +76,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 = rt.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(int(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 +104,25 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// Evaluates `cmd` as Lua input. This is the same as using `dofile` // 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 = rt.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(int(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
} }

20
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))
*/
} }
@ -255,6 +259,6 @@ func valueToSink(val rt.Value) (*sink, bool) {
} }
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

@ -47,7 +47,7 @@ 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(rt.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()

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"
) )
@ -133,13 +134,15 @@ 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) {
@ -164,18 +167,20 @@ func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
} }
timerMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(timerIndex, "__index", 2, false))) 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", rt.IntValue(0))
util.SetField(rtm, luaTh, "TIMEOUT", rt.IntValue(1)) luaTh.SetField("TIMEOUT", rt.IntValue(1))
return luaTh return luaTh
} }
@ -200,6 +205,6 @@ func valueToTimer(val rt.Value) (*timer, bool) {
} }
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,7 +1,8 @@
package main package main
import ( import (
"hilbish/util" "hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
) )
@ -13,11 +14,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", rt.StringValue(confDir))
util.SetField(rtm, mod, "data", rt.StringValue(userDataDir)) mod.SetField("data", rt.StringValue(userDataDir))
return mod return mod
} }

View File

@ -1,12 +1,14 @@
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
} }

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