mirror of https://github.com/Hilbis/Hilbish
Compare commits
2 Commits
64bf7024d2
...
69d38d7048
Author | SHA1 | Date |
---|---|---|
TorchedSammy | 69d38d7048 | |
sammyette | 0fc5f457ad |
47
aliases.go
47
aliases.go
|
@ -4,7 +4,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/yuin/gopher-lua"
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var aliases *aliasHandler
|
var aliases *aliasHandler
|
||||||
|
@ -64,41 +66,38 @@ func (a *aliasHandler) Resolve(cmdstr string) string {
|
||||||
|
|
||||||
// lua section
|
// lua section
|
||||||
|
|
||||||
func (a *aliasHandler) Loader(L *lua.LState) *lua.LTable {
|
func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
|
||||||
// create a lua module with our functions
|
// create a lua module with our functions
|
||||||
hshaliasesLua := map[string]lua.LGFunction{
|
hshaliasesLua := map[string]util.LuaExport{
|
||||||
"add": a.luaAdd,
|
"add": util.LuaExport{hlalias, 2, false},
|
||||||
"list": a.luaList,
|
"list": util.LuaExport{a.luaList, 0, false},
|
||||||
"del": a.luaDelete,
|
"del": util.LuaExport{a.luaDelete, 1, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
mod := L.SetFuncs(L.NewTable(), hshaliasesLua)
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, hshaliasesLua)
|
||||||
|
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) luaAdd(L *lua.LState) int {
|
func (a *aliasHandler) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
alias := L.CheckString(1)
|
aliasesList := rt.NewTable()
|
||||||
cmd := L.CheckString(2)
|
|
||||||
a.Add(alias, cmd)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *aliasHandler) luaList(L *lua.LState) int {
|
|
||||||
aliasesList := L.NewTable()
|
|
||||||
for k, v := range a.All() {
|
for k, v := range a.All() {
|
||||||
aliasesList.RawSetString(k, lua.LString(v))
|
aliasesList.Set(rt.StringValue(k), rt.StringValue(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(aliasesList)
|
return c.PushingNext1(t.Runtime, rt.TableValue(aliasesList)), nil
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) luaDelete(L *lua.LState) int {
|
func (a *aliasHandler) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
alias := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
alias, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
a.Delete(alias)
|
a.Delete(alias)
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
651
api.go
651
api.go
|
@ -4,6 +4,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -14,38 +16,44 @@ import (
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
"github.com/yuin/gopher-lua"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib/packagelib"
|
||||||
"github.com/maxlandon/readline"
|
"github.com/maxlandon/readline"
|
||||||
"github.com/blackfireio/osinfo"
|
"github.com/blackfireio/osinfo"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var exports = map[string]lua.LGFunction {
|
var exports = map[string]util.LuaExport{
|
||||||
"alias": hlalias,
|
"alias": {hlalias, 2, false},
|
||||||
"appendPath": hlappendPath,
|
"appendPath": {hlappendPath, 1, false},
|
||||||
"complete": hlcomplete,
|
"complete": {hlcomplete, 2, false},
|
||||||
"cwd": hlcwd,
|
"cwd": {hlcwd, 0, false},
|
||||||
"exec": hlexec,
|
"exec": {hlexec, 1, false},
|
||||||
"runnerMode": hlrunnerMode,
|
"runnerMode": {hlrunnerMode, 1, false},
|
||||||
"goro": hlgoro,
|
"goro": {hlgoro, 1, true},
|
||||||
"highlighter": hlhighlighter,
|
"highlighter": {hlhighlighter, 1, false},
|
||||||
"hinter": hlhinter,
|
"hinter": {hlhinter, 1, false},
|
||||||
"multiprompt": hlmlprompt,
|
"multiprompt": {hlmultiprompt, 1, false},
|
||||||
"prependPath": hlprependPath,
|
"prependPath": {hlprependPath, 1, false},
|
||||||
"prompt": hlprompt,
|
"prompt": {hlprompt, 1, false},
|
||||||
"inputMode": hlinputMode,
|
"inputMode": {hlinputMode, 1, false},
|
||||||
"interval": hlinterval,
|
"interval": {hlinterval, 2, false},
|
||||||
"read": hlread,
|
"read": {hlread, 1, false},
|
||||||
"run": hlrun,
|
"run": {hlrun, 1, true},
|
||||||
"timeout": hltimeout,
|
"timeout": {hltimeout, 2, false},
|
||||||
"which": hlwhich,
|
"which": {hlwhich, 1, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
var greeting string
|
var greeting string
|
||||||
var hshMod *lua.LTable
|
var hshMod *rt.Table
|
||||||
|
var hilbishLoader = packagelib.Loader{
|
||||||
|
Load: hilbishLoad,
|
||||||
|
Name: "hilbish",
|
||||||
|
}
|
||||||
|
|
||||||
func hilbishLoader(L *lua.LState) int {
|
func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
mod := L.SetFuncs(L.NewTable(), exports)
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, exports)
|
||||||
hshMod = mod
|
hshMod = mod
|
||||||
|
|
||||||
host, _ := os.Hostname()
|
host, _ := os.Hostname()
|
||||||
|
@ -59,151 +67,72 @@ func hilbishLoader(L *lua.LState) int {
|
||||||
The nice lil shell for {blue}Lua{reset} fanatics!
|
The nice lil shell for {blue}Lua{reset} fanatics!
|
||||||
Check out the {blue}{bold}guide{reset} command to get started.
|
Check out the {blue}{bold}guide{reset} command to get started.
|
||||||
`
|
`
|
||||||
|
util.SetField(rtm, mod, "ver", rt.StringValue(version), "Hilbish version")
|
||||||
util.SetField(L, mod, "ver", lua.LString(version), "Hilbish version")
|
util.SetField(rtm, mod, "user", rt.StringValue(username), "Username of user")
|
||||||
util.SetField(L, mod, "user", lua.LString(username), "Username of user")
|
util.SetField(rtm, mod, "host", rt.StringValue(host), "Host name of the machine")
|
||||||
util.SetField(L, mod, "host", lua.LString(host), "Host name of the machine")
|
util.SetField(rtm, mod, "home", rt.StringValue(curuser.HomeDir), "Home directory of the user")
|
||||||
util.SetField(L, mod, "home", lua.LString(curuser.HomeDir), "Home directory of the user")
|
util.SetField(rtm, mod, "dataDir", rt.StringValue(dataDir), "Directory for Hilbish's data files")
|
||||||
util.SetField(L, mod, "dataDir", lua.LString(dataDir), "Directory for Hilbish's data files")
|
util.SetField(rtm, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive shell")
|
||||||
util.SetField(L, mod, "interactive", lua.LBool(interactive), "If this is an interactive shell")
|
util.SetField(rtm, mod, "login", rt.BoolValue(login), "Whether this is a login shell")
|
||||||
util.SetField(L, mod, "login", lua.LBool(interactive), "Whether this is a login shell")
|
util.SetField(rtm, mod, "greeting", rt.StringValue(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.")
|
||||||
util.SetField(L, mod, "greeting", lua.LString(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.")
|
util.SetField(rtm, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||||
util.SetField(l, mod, "vimMode", lua.LNil, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
util.SetField(rtm, hshMod, "exitCode", rt.IntValue(0), "Exit code of last exected command")
|
||||||
util.SetField(l, hshMod, "exitCode", lua.LNumber(0), "Exit code of last exected command")
|
util.Document(mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
|
||||||
util.Document(L, mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
|
|
||||||
|
|
||||||
// hilbish.userDir table
|
// hilbish.userDir table
|
||||||
hshuser := L.NewTable()
|
hshuser := rt.NewTable()
|
||||||
|
|
||||||
util.SetField(L, hshuser, "config", lua.LString(confDir), "User's config directory")
|
util.SetField(rtm, hshuser, "config", rt.StringValue(confDir), "User's config directory")
|
||||||
util.SetField(L, hshuser, "data", lua.LString(userDataDir), "XDG data directory")
|
util.SetField(rtm, hshuser, "data", rt.StringValue(userDataDir), "XDG data directory")
|
||||||
util.Document(L, hshuser, "User directories to store configs and/or modules.")
|
util.Document(hshuser, "User directories to store configs and/or modules.")
|
||||||
L.SetField(mod, "userDir", hshuser)
|
mod.Set(rt.StringValue("userDir"), rt.TableValue(hshuser))
|
||||||
|
|
||||||
// hilbish.os table
|
// hilbish.os table
|
||||||
hshos := L.NewTable()
|
hshos := rt.NewTable()
|
||||||
info, _ := osinfo.GetOSInfo()
|
info, _ := osinfo.GetOSInfo()
|
||||||
|
|
||||||
util.SetField(L, hshos, "family", lua.LString(info.Family), "Family name of the current OS")
|
util.SetField(rtm, hshos, "family", rt.StringValue(info.Family), "Family name of the current OS")
|
||||||
util.SetField(L, hshos, "name", lua.LString(info.Name), "Pretty name of the current OS")
|
util.SetField(rtm, hshos, "name", rt.StringValue(info.Name), "Pretty name of the current OS")
|
||||||
util.SetField(L, hshos, "version", lua.LString(info.Version), "Version of the current OS")
|
util.SetField(rtm, hshos, "version", rt.StringValue(info.Version), "Version of the current OS")
|
||||||
util.Document(L, hshos, "OS info interface")
|
util.Document(hshos, "OS info interface")
|
||||||
L.SetField(mod, "os", hshos)
|
mod.Set(rt.StringValue("os"), rt.TableValue(hshos))
|
||||||
|
|
||||||
// hilbish.aliases table
|
// hilbish.aliases table
|
||||||
aliases = newAliases()
|
aliases = newAliases()
|
||||||
aliasesModule := aliases.Loader(L)
|
aliasesModule := aliases.Loader(rtm)
|
||||||
util.Document(L, aliasesModule, "Alias inferface for Hilbish.")
|
util.Document(aliasesModule, "Alias inferface for Hilbish.")
|
||||||
L.SetField(mod, "aliases", aliasesModule)
|
mod.Set(rt.StringValue("aliases"), rt.TableValue(aliasesModule))
|
||||||
|
|
||||||
// hilbish.history table
|
// hilbish.history table
|
||||||
historyModule := lr.Loader(L)
|
historyModule := lr.Loader(rtm)
|
||||||
util.Document(L, historyModule, "History interface for Hilbish.")
|
mod.Set(rt.StringValue("history"), rt.TableValue(historyModule))
|
||||||
L.SetField(mod, "history", historyModule)
|
util.Document(historyModule, "History interface for Hilbish.")
|
||||||
|
|
||||||
// hilbish.completions table
|
// hilbish.completion table
|
||||||
hshcomp := L.NewTable()
|
hshcomp := rt.NewTable()
|
||||||
|
util.SetField(rtm, hshcomp, "files",
|
||||||
|
rt.FunctionValue(rt.NewGoFunction(luaFileComplete, "files", 3, false)),
|
||||||
|
"Completer for files")
|
||||||
|
|
||||||
util.SetField(L, hshcomp, "files", L.NewFunction(luaFileComplete), "Completer for files")
|
util.SetField(rtm, hshcomp, "bins",
|
||||||
util.SetField(L, hshcomp, "bins", L.NewFunction(luaBinaryComplete), "Completer for executables/binaries")
|
rt.FunctionValue(rt.NewGoFunction(luaBinaryComplete, "bins", 3, false)),
|
||||||
util.Document(L, hshcomp, "Completions interface for Hilbish.")
|
"Completer for executables/binaries")
|
||||||
L.SetField(mod, "completion", hshcomp)
|
|
||||||
|
util.Document(hshcomp, "Completions interface for Hilbish.")
|
||||||
|
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
|
||||||
|
|
||||||
// hilbish.runner table
|
// hilbish.runner table
|
||||||
runnerModule := runnerModeLoader(L)
|
runnerModule := runnerModeLoader(rtm)
|
||||||
util.Document(L, runnerModule, "Runner/exec interface for Hilbish.")
|
util.Document(runnerModule, "Runner/exec interface for Hilbish.")
|
||||||
L.SetField(mod, "runner", runnerModule)
|
mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule))
|
||||||
|
|
||||||
// hilbish.jobs table
|
// hilbish.jobs table
|
||||||
jobs = newJobHandler()
|
jobs = newJobHandler()
|
||||||
jobModule := jobs.loader(L)
|
jobModule := jobs.loader(rtm)
|
||||||
util.Document(L, jobModule, "(Background) job interface.")
|
util.Document(jobModule, "(Background) job interface.")
|
||||||
L.SetField(mod, "jobs", jobModule)
|
mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
|
||||||
|
|
||||||
L.Push(mod)
|
return rt.TableValue(mod), nil
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func luaFileComplete(L *lua.LState) int {
|
|
||||||
query := L.CheckString(1)
|
|
||||||
ctx := L.CheckString(2)
|
|
||||||
fields := L.CheckTable(3)
|
|
||||||
|
|
||||||
var fds []string
|
|
||||||
fields.ForEach(func(k lua.LValue, v lua.LValue) {
|
|
||||||
fds = append(fds, v.String())
|
|
||||||
})
|
|
||||||
|
|
||||||
completions := fileComplete(query, ctx, fds)
|
|
||||||
luaComps := L.NewTable()
|
|
||||||
|
|
||||||
for _, comp := range completions {
|
|
||||||
luaComps.Append(lua.LString(comp))
|
|
||||||
}
|
|
||||||
|
|
||||||
L.Push(luaComps)
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func luaBinaryComplete(L *lua.LState) int {
|
|
||||||
query := L.CheckString(1)
|
|
||||||
ctx := L.CheckString(2)
|
|
||||||
fields := L.CheckTable(3)
|
|
||||||
|
|
||||||
var fds []string
|
|
||||||
fields.ForEach(func(k lua.LValue, v lua.LValue) {
|
|
||||||
fds = append(fds, v.String())
|
|
||||||
})
|
|
||||||
|
|
||||||
completions, _ := binaryComplete(query, ctx, fds)
|
|
||||||
luaComps := L.NewTable()
|
|
||||||
|
|
||||||
for _, comp := range completions {
|
|
||||||
luaComps.Append(lua.LString(comp))
|
|
||||||
}
|
|
||||||
|
|
||||||
L.Push(luaComps)
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func setVimMode(mode string) {
|
|
||||||
util.SetField(l, hshMod, "vimMode", lua.LString(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
|
||||||
hooks.Em.Emit("hilbish.vimMode", mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func unsetVimMode() {
|
|
||||||
util.SetField(l, hshMod, "vimMode", lua.LNil, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// run(cmd)
|
|
||||||
// Runs `cmd` in Hilbish's sh interpreter.
|
|
||||||
// --- @param cmd string
|
|
||||||
func hlrun(L *lua.LState) int {
|
|
||||||
var exitcode uint8
|
|
||||||
cmd := L.CheckString(1)
|
|
||||||
err := execCommand(cmd)
|
|
||||||
|
|
||||||
if code, ok := interp.IsExitStatus(err); ok {
|
|
||||||
exitcode = code
|
|
||||||
} else if err != nil {
|
|
||||||
exitcode = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
L.Push(lua.LNumber(exitcode))
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// cwd()
|
|
||||||
// Returns the current directory of the shell
|
|
||||||
func hlcwd(L *lua.LState) int {
|
|
||||||
cwd, _ := os.Getwd()
|
|
||||||
|
|
||||||
L.Push(lua.LString(cwd))
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getenv(key, fallback string) string {
|
func getenv(key, fallback string) string {
|
||||||
|
@ -214,24 +143,160 @@ func getenv(key, fallback string) string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
query, ctx, fds, err := getCompleteParams(t, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
completions := fileComplete(query, ctx, fds)
|
||||||
|
luaComps := rt.NewTable()
|
||||||
|
|
||||||
|
for i, comp := range completions {
|
||||||
|
luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
query, ctx, fds, err := getCompleteParams(t, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
completions, _ := binaryComplete(query, ctx, fds)
|
||||||
|
luaComps := rt.NewTable()
|
||||||
|
|
||||||
|
for i, comp := range completions {
|
||||||
|
luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) {
|
||||||
|
if err := c.CheckNArgs(3); err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
query, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
ctx, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
fields, err := c.TableArg(2)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fds []string
|
||||||
|
nextVal := rt.NilValue
|
||||||
|
for {
|
||||||
|
next, val, ok := fields.Next(nextVal)
|
||||||
|
if next == rt.NilValue {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nextVal = next
|
||||||
|
|
||||||
|
valStr, ok := val.TryString()
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fds = append(fds, valStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return query, ctx, fds, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func setVimMode(mode string) {
|
||||||
|
util.SetField(l, hshMod, "vimMode", rt.StringValue(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||||
|
hooks.Em.Emit("hilbish.vimMode", mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsetVimMode() {
|
||||||
|
util.SetField(l, hshMod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// run(cmd, returnOut) -> exitCode, stdout, stderr
|
||||||
|
// Runs `cmd` in Hilbish's sh interpreter.
|
||||||
|
// If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
||||||
|
// 3rd values instead of being outputted to the terminal.
|
||||||
|
// --- @param cmd string
|
||||||
|
func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var terminalOut bool
|
||||||
|
if len(c.Etc()) != 0 {
|
||||||
|
tout := c.Etc()[0]
|
||||||
|
termOut, ok := tout.TryBool()
|
||||||
|
terminalOut = termOut
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("bad argument to run (expected boolean, got " + tout.TypeName() + ")")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
terminalOut = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var exitcode uint8
|
||||||
|
stdout, stderr, err := execCommand(cmd, terminalOut)
|
||||||
|
|
||||||
|
if code, ok := interp.IsExitStatus(err); ok {
|
||||||
|
exitcode = code
|
||||||
|
} else if err != nil {
|
||||||
|
exitcode = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
stdoutStr := ""
|
||||||
|
stderrStr := ""
|
||||||
|
if !terminalOut {
|
||||||
|
stdoutStr = stdout.(*bytes.Buffer).String()
|
||||||
|
stderrStr = stderr.(*bytes.Buffer).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitcode)), rt.StringValue(stdoutStr), rt.StringValue(stderrStr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cwd()
|
||||||
|
// Returns the current directory of the shell
|
||||||
|
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.StringValue(cwd)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// read(prompt) -> input?
|
// read(prompt) -> input?
|
||||||
// Read input from the user, using Hilbish's line editor/input reader.
|
// Read input from the user, using Hilbish's line editor/input reader.
|
||||||
// This is a separate instance from the one Hilbish actually uses.
|
// This is a separate instance from the one Hilbish actually uses.
|
||||||
// Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
// Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
||||||
// --- @param prompt string
|
// --- @param prompt string
|
||||||
func hlread(L *lua.LState) int {
|
func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
luaprompt := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
luaprompt, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
lualr := newLineReader("", true)
|
lualr := newLineReader("", true)
|
||||||
lualr.SetPrompt(luaprompt)
|
lualr.SetPrompt(luaprompt)
|
||||||
|
|
||||||
input, err := lualr.Read()
|
input, err := lualr.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.Push(lua.LNil)
|
return c.Next(), nil
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(lua.LString(input))
|
return c.PushingNext1(t.Runtime, rt.StringValue(input)), nil
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -244,52 +309,91 @@ These will be formatted and replaced with the appropriate values.
|
||||||
`%h` - Hostname of device
|
`%h` - Hostname of device
|
||||||
--- @param str string
|
--- @param str string
|
||||||
*/
|
*/
|
||||||
func hlprompt(L *lua.LState) int {
|
func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
prompt = L.CheckString(1)
|
var prompt string
|
||||||
|
err := c.Check1Arg()
|
||||||
|
if err == nil {
|
||||||
|
prompt, err = c.StringArg(0)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
lr.SetPrompt(fmtPrompt(prompt))
|
lr.SetPrompt(fmtPrompt(prompt))
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiprompt(str)
|
// multiprompt(str)
|
||||||
// Changes the continued line prompt to `str`
|
// Changes the continued line prompt to `str`
|
||||||
// --- @param str string
|
// --- @param str string
|
||||||
func hlmlprompt(L *lua.LState) int {
|
func hlmultiprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
multilinePrompt = L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
prompt, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
multilinePrompt = prompt
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// alias(cmd, orig)
|
// alias(cmd, orig)
|
||||||
// Sets an alias of `cmd` to `orig`
|
// Sets an alias of `cmd` to `orig`
|
||||||
// --- @param cmd string
|
// --- @param cmd string
|
||||||
// --- @param orig string
|
// --- @param orig string
|
||||||
func hlalias(L *lua.LState) int {
|
func hlalias(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
alias := L.CheckString(1)
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
source := L.CheckString(2)
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
orig, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
aliases.Add(alias, source)
|
aliases.Add(cmd, orig)
|
||||||
|
|
||||||
return 1
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendPath(dir)
|
// appendPath(dir)
|
||||||
// Appends `dir` to $PATH
|
// Appends `dir` to $PATH
|
||||||
// --- @param dir string|table
|
// --- @param dir string|table
|
||||||
func hlappendPath(L *lua.LState) int {
|
func hlappendPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arg := c.Arg(0)
|
||||||
|
|
||||||
// check if dir is a table or a string
|
// check if dir is a table or a string
|
||||||
arg := L.Get(1)
|
if arg.Type() == rt.TableType {
|
||||||
if arg.Type() == lua.LTTable {
|
nextVal := rt.NilValue
|
||||||
arg.(*lua.LTable).ForEach(func(k lua.LValue, v lua.LValue) {
|
for {
|
||||||
appendPath(v.String())
|
next, val, ok := arg.AsTable().Next(nextVal)
|
||||||
})
|
if next == rt.NilValue {
|
||||||
} else if arg.Type() == lua.LTString {
|
break
|
||||||
appendPath(arg.String())
|
}
|
||||||
|
nextVal = next
|
||||||
|
|
||||||
|
valStr, ok := val.TryString()
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
appendPath(valStr)
|
||||||
|
}
|
||||||
|
} else if arg.Type() == rt.StringType {
|
||||||
|
appendPath(arg.AsString())
|
||||||
} else {
|
} else {
|
||||||
L.RaiseError("bad argument to appendPath (expected string or table, got %v)", L.Get(1).Type().String())
|
return nil, errors.New("bad argument to appendPath (expected string or table, got " + arg.TypeName() + ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendPath(dir string) {
|
func appendPath(dir string) {
|
||||||
|
@ -305,8 +409,14 @@ func appendPath(dir string) {
|
||||||
// exec(cmd)
|
// exec(cmd)
|
||||||
// Replaces running hilbish with `cmd`
|
// Replaces running hilbish with `cmd`
|
||||||
// --- @param cmd string
|
// --- @param cmd string
|
||||||
func hlexec(L *lua.LState) int {
|
func hlexec(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cmd := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
cmdArgs, _ := splitInput(cmd)
|
cmdArgs, _ := splitInput(cmd)
|
||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
cmdPath, err := exec.LookPath(cmdArgs[0])
|
cmdPath, err := exec.LookPath(cmdArgs[0])
|
||||||
|
@ -328,78 +438,89 @@ func hlexec(L *lua.LState) int {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// goro(fn)
|
// goro(fn)
|
||||||
// Puts `fn` in a goroutine
|
// Puts `fn` in a goroutine
|
||||||
// --- @param fn function
|
// --- @param fn function
|
||||||
func hlgoro(L *lua.LState) int {
|
func hlgoro(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
fn := L.CheckFunction(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
argnum := L.GetTop()
|
return nil, err
|
||||||
args := make([]lua.LValue, argnum)
|
}
|
||||||
for i := 1; i <= argnum; i++ {
|
fn, err := c.ClosureArg(0)
|
||||||
args[i - 1] = L.Get(i)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// call fn
|
// call fn
|
||||||
go func() {
|
go func() {
|
||||||
if err := L.CallByParam(lua.P{
|
_, err := rt.Call1(l.MainThread(), rt.FunctionValue(fn), c.Etc()...)
|
||||||
Fn: fn,
|
if err != nil {
|
||||||
NRet: 0,
|
|
||||||
Protect: true,
|
|
||||||
}, args...); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error in goro function:\n\n", err)
|
fmt.Fprintln(os.Stderr, "Error in goro function:\n\n", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeout(cb, time)
|
// timeout(cb, time)
|
||||||
// Runs the `cb` function after `time` in milliseconds
|
// Runs the `cb` function after `time` in milliseconds
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
// --- @param time number
|
// --- @param time number
|
||||||
func hltimeout(L *lua.LState) int {
|
func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cb := L.CheckFunction(1)
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
ms := L.CheckInt(2)
|
return nil, err
|
||||||
|
}
|
||||||
|
cb, err := c.ClosureArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ms, err := c.IntArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
timeout := time.Duration(ms) * time.Millisecond
|
timeout := time.Duration(ms) * time.Millisecond
|
||||||
time.Sleep(timeout)
|
time.Sleep(timeout)
|
||||||
|
|
||||||
if err := L.CallByParam(lua.P{
|
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(cb))
|
||||||
Fn: cb,
|
if err != nil {
|
||||||
NRet: 0,
|
return nil, err
|
||||||
Protect: true,
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error in goro function:\n\n", err)
|
|
||||||
}
|
}
|
||||||
return 0
|
|
||||||
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// interval(cb, time)
|
// interval(cb, time)
|
||||||
// Runs the `cb` function every `time` milliseconds
|
// Runs the `cb` function every `time` milliseconds
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
// --- @param time number
|
// --- @param time number
|
||||||
func hlinterval(L *lua.LState) int {
|
func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
intervalfunc := L.CheckFunction(1)
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
ms := L.CheckInt(2)
|
return nil, err
|
||||||
|
}
|
||||||
|
cb, err := c.ClosureArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ms, err := c.IntArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
interval := time.Duration(ms) * time.Millisecond
|
interval := time.Duration(ms) * time.Millisecond
|
||||||
|
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
stop := make(chan lua.LValue)
|
stop := make(chan rt.Value)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
if err := L.CallByParam(lua.P{
|
_, err := rt.Call1(l.MainThread(), rt.FunctionValue(cb))
|
||||||
Fn: intervalfunc,
|
if err != nil {
|
||||||
NRet: 0,
|
|
||||||
Protect: true,
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error in interval function:\n\n", err)
|
fmt.Fprintln(os.Stderr, "Error in interval function:\n\n", err)
|
||||||
stop <- lua.LTrue // stop the interval
|
stop <- rt.BoolValue(true) // stop the interval
|
||||||
}
|
}
|
||||||
case <-stop:
|
case <-stop:
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
|
@ -408,8 +529,8 @@ func hlinterval(L *lua.LState) int {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
L.Push(lua.LChannel(stop))
|
// TODO: return channel
|
||||||
return 1
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// complete(scope, cb)
|
// complete(scope, cb)
|
||||||
|
@ -422,20 +543,27 @@ func hlinterval(L *lua.LState) int {
|
||||||
// `grid` (the normal file completion display) or `list` (with a description)
|
// `grid` (the normal file completion display) or `list` (with a description)
|
||||||
// --- @param scope string
|
// --- @param scope string
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
func hlcomplete(L *lua.LState) int {
|
func hlcomplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
scope := L.CheckString(1)
|
scope, cb, err := util.HandleStrCallback(t, c)
|
||||||
cb := L.CheckFunction(2)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
luaCompletions[scope] = cb
|
luaCompletions[scope] = cb
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// prependPath(dir)
|
// prependPath(dir)
|
||||||
// Prepends `dir` to $PATH
|
// Prepends `dir` to $PATH
|
||||||
// --- @param dir string
|
// --- @param dir string
|
||||||
func hlprependPath(L *lua.LState) int {
|
func hlprependPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
dir := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dir, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
|
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
|
||||||
pathenv := os.Getenv("PATH")
|
pathenv := os.Getenv("PATH")
|
||||||
|
|
||||||
|
@ -444,29 +572,40 @@ func hlprependPath(L *lua.LState) int {
|
||||||
os.Setenv("PATH", dir + string(os.PathListSeparator) + pathenv)
|
os.Setenv("PATH", dir + string(os.PathListSeparator) + pathenv)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// which(binName)
|
// which(binName)
|
||||||
// Searches for an executable called `binName` in the directories of $PATH
|
// Searches for an executable called `binName` in the directories of $PATH
|
||||||
// --- @param binName string
|
// --- @param binName string
|
||||||
func hlwhich(L *lua.LState) int {
|
func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
binName := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
binName, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
path, err := exec.LookPath(binName)
|
path, err := exec.LookPath(binName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Push(lua.LNil)
|
return c.Next(), nil
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Push(lua.LString(path))
|
return c.PushingNext1(t.Runtime, rt.StringValue(path)), nil
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// inputMode(mode)
|
// inputMode(mode)
|
||||||
// Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
|
// Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
|
||||||
// --- @param mode string
|
// --- @param mode string
|
||||||
func hlinputMode(L *lua.LState) int {
|
func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
mode := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mode, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case "emacs":
|
case "emacs":
|
||||||
unsetVimMode()
|
unsetVimMode()
|
||||||
|
@ -474,9 +613,11 @@ func hlinputMode(L *lua.LState) int {
|
||||||
case "vim":
|
case "vim":
|
||||||
setVimMode("insert")
|
setVimMode("insert")
|
||||||
lr.rl.InputMode = readline.Vim
|
lr.rl.InputMode = readline.Vim
|
||||||
default: L.RaiseError("inputMode: expected vim or emacs, received " + mode)
|
default:
|
||||||
|
return nil, errors.New("inputMode: expected vim or emacs, received " + mode)
|
||||||
}
|
}
|
||||||
return 0
|
|
||||||
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// runnerMode(mode)
|
// runnerMode(mode)
|
||||||
|
@ -486,24 +627,24 @@ func hlinputMode(L *lua.LState) int {
|
||||||
// sh, and lua. It also accepts a function, to which if it is passed one
|
// sh, and lua. It also accepts a function, to which if it is passed one
|
||||||
// will call it to execute user input instead.
|
// will call it to execute user input instead.
|
||||||
// --- @param mode string|function
|
// --- @param mode string|function
|
||||||
func hlrunnerMode(L *lua.LState) int {
|
func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
mode := L.CheckAny(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mode := c.Arg(0)
|
||||||
|
|
||||||
switch mode.Type() {
|
switch mode.Type() {
|
||||||
case lua.LTString:
|
case rt.StringType:
|
||||||
switch mode.String() {
|
switch mode.AsString() {
|
||||||
// no fallthrough doesnt work so eh
|
// no fallthrough doesnt work so eh
|
||||||
case "hybrid": fallthrough
|
case "hybrid", "hybridRev", "lua", "sh": runnerMode = mode
|
||||||
case "hybridRev": fallthrough
|
default: return nil, errors.New("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received " + mode.AsString())
|
||||||
case "lua": fallthrough
|
|
||||||
case "sh":
|
|
||||||
runnerMode = mode
|
|
||||||
default: L.RaiseError("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received %v", mode)
|
|
||||||
}
|
}
|
||||||
case lua.LTFunction: runnerMode = mode
|
case rt.FunctionType: runnerMode = mode
|
||||||
default: L.RaiseError("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received %v", mode)
|
default: return nil, errors.New("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received " + mode.TypeName())
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hinter(cb)
|
// hinter(cb)
|
||||||
|
@ -512,11 +653,17 @@ func hlrunnerMode(L *lua.LState) int {
|
||||||
// the current line and the position. It is expected to return a string
|
// the current line and the position. It is expected to return a string
|
||||||
// which will be used for the hint.
|
// which will be used for the hint.
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
func hlhinter(L *lua.LState) int {
|
func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
hinterCb := L.CheckFunction(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hinterCb, err := c.ClosureArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
hinter = hinterCb
|
hinter = hinterCb
|
||||||
|
|
||||||
return 0
|
return c.Next(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// highlighter(cb)
|
// highlighter(cb)
|
||||||
|
@ -525,9 +672,15 @@ func hlhinter(L *lua.LState) int {
|
||||||
// is passed the current line as typed and is expected to return a line that will
|
// is passed the current line as typed and is expected to return a line that will
|
||||||
// be used to display in the line.
|
// be used to display in the line.
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
func hlhighlighter(L *lua.LState) int {
|
func hlhighlighter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
highlighterCb := L.CheckFunction(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
highlighterCb, err := c.ClosureArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
highlighter = highlighterCb
|
highlighter = highlighterCb
|
||||||
|
|
||||||
return 0
|
return c.Next(), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,9 @@ read(prompt) -> input? > Read input from the user, using Hilbish's line editor/i
|
||||||
This is a separate instance from the one Hilbish actually uses.
|
This is a separate instance from the one Hilbish actually uses.
|
||||||
Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
||||||
|
|
||||||
run(cmd) > Runs `cmd` in Hilbish's sh interpreter.
|
run(cmd, returnOut) -> exitCode, stdout, stderr > Runs `cmd` in Hilbish's sh interpreter.
|
||||||
|
If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
||||||
|
3rd values instead of being outputted to the terminal.
|
||||||
|
|
||||||
runnerMode(mode) > Sets the execution/runner mode for interactive Hilbish. This determines whether
|
runnerMode(mode) > Sets the execution/runner mode for interactive Hilbish. This determines whether
|
||||||
Hilbish wll try to run input as Lua and/or sh or only do one of either.
|
Hilbish wll try to run input as Lua and/or sh or only do one of either.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
setRaw() > Puts the terminal in raw mode
|
|
||||||
|
|
||||||
restoreState() > Restores the last saved state of the terminal
|
restoreState() > Restores the last saved state of the terminal
|
||||||
|
|
||||||
saveState() > Saves the current state of the terminal
|
saveState() > Saves the current state of the terminal
|
||||||
|
|
||||||
|
setRaw() > Puts the terminal in raw mode
|
||||||
|
|
||||||
size() > Gets the dimensions of the terminal. Returns a table with `width` and `height`
|
size() > Gets the dimensions of the terminal. Returns a table with `width` and `height`
|
||||||
Note: this is not the size in relation to the dimensions of the display
|
Note: this is not the size in relation to the dimensions of the display
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ function hilbish.interval(cb, time) end
|
||||||
|
|
||||||
--- Changes the continued line prompt to `str`
|
--- Changes the continued line prompt to `str`
|
||||||
--- @param str string
|
--- @param str string
|
||||||
function hilbish.mlprompt(str) end
|
function hilbish.multiprompt(str) end
|
||||||
|
|
||||||
--- Prepends `dir` to $PATH
|
--- Prepends `dir` to $PATH
|
||||||
--- @param dir string
|
--- @param dir string
|
||||||
|
@ -80,6 +80,8 @@ function hilbish.prompt(str) end
|
||||||
function hilbish.read(prompt) end
|
function hilbish.read(prompt) end
|
||||||
|
|
||||||
--- Runs `cmd` in Hilbish's sh interpreter.
|
--- Runs `cmd` in Hilbish's sh interpreter.
|
||||||
|
--- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
||||||
|
--- 3rd values instead of being outputted to the terminal.
|
||||||
--- @param cmd string
|
--- @param cmd string
|
||||||
function hilbish.run(cmd) end
|
function hilbish.run(cmd) end
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
local terminal = {}
|
local terminal = {}
|
||||||
|
|
||||||
--- Puts the terminal in raw mode
|
|
||||||
function terminal.raw() end
|
|
||||||
|
|
||||||
--- Restores the last saved state of the terminal
|
--- Restores the last saved state of the terminal
|
||||||
function terminal.restoreState() end
|
function terminal.restoreState() end
|
||||||
|
|
||||||
--- Saves the current state of the terminal
|
--- Saves the current state of the terminal
|
||||||
function terminal.saveState() end
|
function terminal.saveState() end
|
||||||
|
|
||||||
|
--- Puts the terminal in raw mode
|
||||||
|
function terminal.setRaw() end
|
||||||
|
|
||||||
--- 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: this is not the size in relation to the dimensions of the display
|
--- Note: this is not the size in relation to the dimensions of the display
|
||||||
function terminal.size() end
|
function terminal.size() end
|
||||||
|
|
84
exec.go
84
exec.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -15,7 +16,7 @@ import (
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
"github.com/yuin/gopher-lua"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
"mvdan.cc/sh/v3/shell"
|
"mvdan.cc/sh/v3/shell"
|
||||||
//"github.com/yuin/gopher-lua/parse"
|
//"github.com/yuin/gopher-lua/parse"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
@ -24,15 +25,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var errNotExec = errors.New("not executable")
|
var errNotExec = errors.New("not executable")
|
||||||
var runnerMode lua.LValue = lua.LString("hybrid")
|
var runnerMode rt.Value = rt.StringValue("hybrid")
|
||||||
|
|
||||||
func runInput(input string, priv bool) {
|
func runInput(input string, priv bool) {
|
||||||
running = true
|
running = true
|
||||||
cmdString := aliases.Resolve(input)
|
cmdString := aliases.Resolve(input)
|
||||||
hooks.Em.Emit("command.preexec", input, cmdString)
|
hooks.Em.Emit("command.preexec", input, cmdString)
|
||||||
|
|
||||||
if runnerMode.Type() == lua.LTString {
|
if runnerMode.Type() == rt.StringType {
|
||||||
switch runnerMode.String() {
|
switch runnerMode.AsString() {
|
||||||
case "hybrid":
|
case "hybrid":
|
||||||
_, err := handleLua(cmdString)
|
_, err := handleLua(cmdString)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -70,27 +71,23 @@ func runInput(input string, priv bool) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// can only be a string or function so
|
// can only be a string or function so
|
||||||
err := l.CallByParam(lua.P{
|
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false)
|
||||||
Fn: runnerMode,
|
err := rt.Call(l.MainThread(), runnerMode, []rt.Value{rt.StringValue(cmdString)}, term)
|
||||||
NRet: 2,
|
|
||||||
Protect: true,
|
|
||||||
}, lua.LString(cmdString))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
cmdFinish(124, cmdString, priv)
|
cmdFinish(124, cmdString, priv)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
luaexitcode := l.Get(-2) // first return value (makes sense right i love stacks)
|
luaexitcode := term.Get(0) // first return value (makes sense right i love stacks)
|
||||||
runErr := l.Get(-1)
|
runErr := term.Get(1)
|
||||||
l.Pop(2)
|
|
||||||
|
|
||||||
var exitCode uint8
|
var exitCode uint8
|
||||||
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
|
if code, ok := luaexitcode.TryInt(); ok {
|
||||||
exitCode = uint8(code)
|
exitCode = uint8(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
if runErr != lua.LNil {
|
if runErr != rt.NilValue {
|
||||||
fmt.Fprintln(os.Stderr, runErr)
|
fmt.Fprintln(os.Stderr, runErr)
|
||||||
}
|
}
|
||||||
cmdFinish(exitCode, cmdString, priv)
|
cmdFinish(exitCode, cmdString, priv)
|
||||||
|
@ -99,7 +96,7 @@ func runInput(input string, priv bool) {
|
||||||
|
|
||||||
func handleLua(cmdString string) (uint8, error) {
|
func handleLua(cmdString string) (uint8, error) {
|
||||||
// First try to load input, essentially compiling to bytecode
|
// First try to load input, essentially compiling to bytecode
|
||||||
fn, err := l.LoadString(cmdString)
|
chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv()))
|
||||||
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 {
|
||||||
|
@ -112,8 +109,9 @@ func handleLua(cmdString 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 {
|
||||||
l.Push(fn)
|
if chunk != nil {
|
||||||
err = l.PCall(0, lua.MultRet, nil)
|
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
@ -123,7 +121,7 @@ func handleLua(cmdString string) (uint8, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSh(cmdString string) (uint8, error) {
|
func handleSh(cmdString string) (uint8, error) {
|
||||||
err := execCommand(cmdString)
|
_, _, err := execCommand(cmdString, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If input is incomplete, start multiline prompting
|
// If input is incomplete, start multiline prompting
|
||||||
if syntax.IsIncomplete(err) {
|
if syntax.IsIncomplete(err) {
|
||||||
|
@ -132,7 +130,7 @@ func handleSh(cmdString string) (uint8, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err = execCommand(cmdString)
|
_, _, err = execCommand(cmdString, true)
|
||||||
if syntax.IsIncomplete(err) || strings.HasSuffix(cmdString, "\\") {
|
if syntax.IsIncomplete(err) || strings.HasSuffix(cmdString, "\\") {
|
||||||
continue
|
continue
|
||||||
} else if code, ok := interp.IsExitStatus(err); ok {
|
} else if code, ok := interp.IsExitStatus(err); ok {
|
||||||
|
@ -156,10 +154,16 @@ func handleSh(cmdString string) (uint8, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run command in sh interpreter
|
// Run command in sh interpreter
|
||||||
func execCommand(cmd string) error {
|
func execCommand(cmd string, terminalOut bool) (io.Writer, io.Writer, error) {
|
||||||
file, err := syntax.NewParser().Parse(strings.NewReader(cmd), "")
|
file, err := syntax.NewParser().Parse(strings.NewReader(cmd), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
var stdout io.Writer = os.Stdout
|
||||||
|
var stderr io.Writer = os.Stderr
|
||||||
|
if !terminalOut {
|
||||||
|
stdout = new(bytes.Buffer)
|
||||||
|
stderr = new(bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
var bg bool
|
var bg bool
|
||||||
|
@ -180,31 +184,26 @@ func execCommand(cmd string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If command is defined in Lua then run it
|
// If command is defined in Lua then run it
|
||||||
luacmdArgs := l.NewTable()
|
luacmdArgs := rt.NewTable()
|
||||||
for _, str := range args[1:] {
|
for i, str := range args[1:] {
|
||||||
luacmdArgs.Append(lua.LString(str))
|
luacmdArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
if commands[args[0]] != nil {
|
if commands[args[0]] != nil {
|
||||||
err := l.CallByParam(lua.P{
|
luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(commands[args[0]]), rt.TableValue(luacmdArgs))
|
||||||
Fn: commands[args[0]],
|
|
||||||
NRet: 1,
|
|
||||||
Protect: true,
|
|
||||||
}, luacmdArgs)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr,
|
fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error())
|
||||||
"Error in command:\n\n" + err.Error())
|
|
||||||
return interp.NewExitStatus(1)
|
return interp.NewExitStatus(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
luaexitcode := l.Get(-1)
|
|
||||||
var exitcode uint8
|
var exitcode uint8
|
||||||
|
|
||||||
l.Pop(1)
|
if code, ok := luaexitcode.TryInt(); ok {
|
||||||
|
|
||||||
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
|
|
||||||
exitcode = uint8(code)
|
exitcode = uint8(code)
|
||||||
|
} else if luaexitcode != rt.NilValue {
|
||||||
|
// deregister commander
|
||||||
|
delete(commands, args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, "Commander did not return number for exit code. %s, you're fired.\n", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return interp.NewExitStatus(exitcode)
|
return interp.NewExitStatus(exitcode)
|
||||||
|
@ -331,7 +330,7 @@ func execCommand(cmd string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
runner, _ := interp.New(
|
runner, _ := interp.New(
|
||||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
|
interp.StdIO(os.Stdin, stdout, stderr),
|
||||||
interp.ExecHandler(exechandle),
|
interp.ExecHandler(exechandle),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -351,11 +350,11 @@ func execCommand(cmd string) error {
|
||||||
|
|
||||||
err = runner.Run(context.TODO(), stmt)
|
err = runner.Run(context.TODO(), stmt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return stdout, stderr, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return stdout, stderr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookpath(file string) error { // custom lookpath function so we know if a command is found *and* is executable
|
func lookpath(file string) error { // custom lookpath function so we know if a command is found *and* is executable
|
||||||
|
@ -441,6 +440,9 @@ func cmdFinish(code uint8, cmdstr string, private bool) {
|
||||||
if interactive && !private {
|
if interactive && !private {
|
||||||
handleHistory(cmdstr)
|
handleHistory(cmdstr)
|
||||||
}
|
}
|
||||||
util.SetField(l, hshMod, "exitCode", lua.LNumber(code), "Exit code of last exected command")
|
util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)), "Exit code of last exected command")
|
||||||
hooks.Em.Emit("command.exit", code, cmdstr)
|
// using AsValue (to convert to lua type) on an interface which is an int
|
||||||
|
// results in it being unknown in lua .... ????
|
||||||
|
// so we allow the hook handler to take lua runtime Values
|
||||||
|
hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr)
|
||||||
}
|
}
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -3,18 +3,18 @@ module hilbish
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86
|
||||||
github.com/blackfireio/osinfo v1.0.3
|
github.com/blackfireio/osinfo v1.0.3
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
||||||
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
|
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
|
||||||
github.com/pborman/getopt v1.1.0
|
github.com/pborman/getopt v1.1.0
|
||||||
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||||
layeh.com/gopher-luar v1.0.10
|
|
||||||
mvdan.cc/sh/v3 v3.4.3
|
mvdan.cc/sh/v3 v3.4.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||||
|
github.com/arnodel/strftime v0.1.6 // indirect
|
||||||
github.com/evilsocket/islazy v1.10.6 // indirect
|
github.com/evilsocket/islazy v1.10.6 // indirect
|
||||||
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect
|
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
@ -27,3 +27,5 @@ replace mvdan.cc/sh/v3 => github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.2022030614040
|
||||||
replace github.com/maxlandon/readline => ./readline
|
replace github.com/maxlandon/readline => ./readline
|
||||||
|
|
||||||
replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10
|
replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10
|
||||||
|
|
||||||
|
replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20220329151031-261b8fbd3f78
|
||||||
|
|
26
go.sum
26
go.sum
|
@ -1,19 +1,24 @@
|
||||||
|
github.com/Rosettea/golua v0.0.0-20220329151031-261b8fbd3f78 h1:9YuMWEHn85Av2ZF60OWkcha5Wt56+i6R7hRcHKB5how=
|
||||||
|
github.com/Rosettea/golua v0.0.0-20220329151031-261b8fbd3f78/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE=
|
||||||
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e h1:P2XupP8SaylWaudD1DqbWtZ3mIa8OsE9635LmR+Q+lg=
|
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e h1:P2XupP8SaylWaudD1DqbWtZ3mIa8OsE9635LmR+Q+lg=
|
||||||
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs=
|
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs=
|
||||||
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/edit v0.0.0-20220202110212-dfc8d7a13890/go.mod h1:AcpttpuZBaL9xl8/CX+Em4fBTUbwIkJ66RiAsJlNrBk=
|
||||||
|
github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw=
|
||||||
|
github.com/arnodel/strftime v0.1.6/go.mod h1:5NbK5XqYK8QpRZpqKNt4OlxLtIB8cotkLk4KTKzJfWs=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c=
|
github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c=
|
||||||
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
|
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
|
github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
|
||||||
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/evilsocket/islazy v1.10.6 h1:MFq000a1ByoumoJWlytqg0qon0KlBeUfPsDjY0hK0bo=
|
github.com/evilsocket/islazy v1.10.6 h1:MFq000a1ByoumoJWlytqg0qon0KlBeUfPsDjY0hK0bo=
|
||||||
github.com/evilsocket/islazy v1.10.6/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
|
github.com/evilsocket/islazy v1.10.6/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
|
||||||
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
|
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
||||||
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
@ -23,32 +28,35 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/layeh/gopher-luar v1.0.10 h1:8NIv4MX1Arz96kK4buGK1D87DyDxKZyq6KKvJ2diHp0=
|
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/layeh/gopher-luar v1.0.10/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw=
|
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw=
|
||||||
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0=
|
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0=
|
||||||
github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
|
github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
|
||||||
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I=
|
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I=
|
||||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw=
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
|
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
|
||||||
|
|
|
@ -4,13 +4,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib/packagelib"
|
||||||
"github.com/chuckpreslar/emission"
|
"github.com/chuckpreslar/emission"
|
||||||
"github.com/yuin/gopher-lua"
|
|
||||||
"layeh.com/gopher-luar"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bait struct{
|
type Bait struct{
|
||||||
Em *emission.Emitter
|
Em *emission.Emitter
|
||||||
|
Loader packagelib.Loader
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() Bait {
|
func New() Bait {
|
||||||
|
@ -19,15 +20,27 @@ func New() Bait {
|
||||||
emitter.Off(hookname, hookfunc)
|
emitter.Off(hookname, hookfunc)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
})
|
})
|
||||||
return Bait{
|
b := Bait{
|
||||||
Em: emitter,
|
Em: emitter,
|
||||||
}
|
}
|
||||||
|
b.Loader = packagelib.Loader{
|
||||||
|
Load: b.loaderFunc,
|
||||||
|
Name: "bait",
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bait) Loader(L *lua.LState) int {
|
func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{})
|
exports := map[string]util.LuaExport{
|
||||||
|
"catch": util.LuaExport{b.bcatch, 2, false},
|
||||||
|
"catchOnce": util.LuaExport{b.bcatchOnce, 2, false},
|
||||||
|
"throw": util.LuaExport{b.bthrow, 1, true},
|
||||||
|
}
|
||||||
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, exports)
|
||||||
|
|
||||||
util.Document(L, mod,
|
util.Document(mod,
|
||||||
`Bait is the event emitter for Hilbish. Why name it bait?
|
`Bait is the event emitter for Hilbish. Why name it bait?
|
||||||
Because it throws hooks that you can catch (emits events
|
Because it throws hooks that you can catch (emits events
|
||||||
that you can listen to) and because why not, fun naming
|
that you can listen to) and because why not, fun naming
|
||||||
|
@ -36,35 +49,81 @@ in on hooks to know when certain things have happened,
|
||||||
like when you've changed directory, a command has
|
like when you've changed directory, a command has
|
||||||
failed, etc. To find all available hooks, see doc hooks.`)
|
failed, etc. To find all available hooks, see doc hooks.`)
|
||||||
|
|
||||||
L.SetField(mod, "throw", luar.New(L, b.bthrow))
|
return rt.TableValue(mod), nil
|
||||||
L.SetField(mod, "catch", luar.New(L, b.bcatch))
|
}
|
||||||
L.SetField(mod, "catchOnce", luar.New(L, b.bcatchOnce))
|
|
||||||
|
|
||||||
L.Push(mod)
|
func handleHook(t *rt.Thread, c *rt.GoCont, name string, catcher *rt.Closure, args ...interface{}) {
|
||||||
|
funcVal := rt.FunctionValue(catcher)
|
||||||
return 1
|
var luaArgs []rt.Value
|
||||||
|
for _, arg := range args {
|
||||||
|
var luarg rt.Value
|
||||||
|
switch arg.(type) {
|
||||||
|
case rt.Value: luarg = arg.(rt.Value)
|
||||||
|
default: luarg = rt.AsValue(arg)
|
||||||
|
}
|
||||||
|
luaArgs = append(luaArgs, luarg)
|
||||||
|
}
|
||||||
|
_, err := rt.Call1(t, funcVal, luaArgs...)
|
||||||
|
if err != nil {
|
||||||
|
e := rt.NewError(rt.StringValue(err.Error()))
|
||||||
|
e = e.AddContext(c.Next(), 1)
|
||||||
|
// panicking here won't actually cause hilbish to panic and instead will
|
||||||
|
// print the error and remove the hook (look at emission recover from above)
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw(name, ...args)
|
// throw(name, ...args)
|
||||||
// Throws a hook with `name` with the provided `args`
|
// Throws a hook with `name` with the provided `args`
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
// --- @vararg any
|
// --- @vararg any
|
||||||
func (b *Bait) bthrow(name string, args ...interface{}) {
|
func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
b.Em.Emit(name, args...)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ifaceSlice := make([]interface{}, len(c.Etc()))
|
||||||
|
for i, v := range c.Etc() {
|
||||||
|
ifaceSlice[i] = v
|
||||||
|
}
|
||||||
|
b.Em.Emit(name, ifaceSlice...)
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// catch(name, cb)
|
// catch(name, cb)
|
||||||
// Catches a hook with `name`. Runs the `cb` when it is thrown
|
// Catches a hook with `name`. Runs the `cb` when it is thrown
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
func (b *Bait) bcatch(name string, catcher func(...interface{})) {
|
func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
b.Em.On(name, catcher)
|
name, catcher, err := util.HandleStrCallback(t, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Em.On(name, func(args ...interface{}) {
|
||||||
|
handleHook(t, c, name, catcher, args...)
|
||||||
|
})
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// catchOnce(name, cb)
|
// catchOnce(name, cb)
|
||||||
// Same as catch, but only runs the `cb` once and then removes the hook
|
// Same as catch, but only runs the `cb` once and then removes the hook
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
func (b *Bait) bcatchOnce(name string, catcher func(...interface{})) {
|
func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
b.Em.Once(name, catcher)
|
name, catcher, err := util.HandleStrCallback(t, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Em.Once(name, func(args ...interface{}) {
|
||||||
|
handleHook(t, c, name, catcher, args...)
|
||||||
|
})
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,52 +3,68 @@ package commander
|
||||||
import (
|
import (
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib/packagelib"
|
||||||
"github.com/chuckpreslar/emission"
|
"github.com/chuckpreslar/emission"
|
||||||
"github.com/yuin/gopher-lua"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Commander struct{
|
type Commander struct{
|
||||||
Events *emission.Emitter
|
Events *emission.Emitter
|
||||||
|
Loader packagelib.Loader
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() Commander {
|
func New() Commander {
|
||||||
return Commander{
|
c := Commander{
|
||||||
Events: emission.NewEmitter(),
|
Events: emission.NewEmitter(),
|
||||||
}
|
}
|
||||||
|
c.Loader = packagelib.Loader{
|
||||||
|
Load: c.loaderFunc,
|
||||||
|
Name: "commander",
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commander) Loader(L *lua.LState) int {
|
func (c *Commander) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
exports := map[string]lua.LGFunction{
|
exports := map[string]util.LuaExport{
|
||||||
"register": c.cregister,
|
"register": util.LuaExport{c.cregister, 2, false},
|
||||||
"deregister": c.cderegister,
|
"deregister": util.LuaExport{c.cderegister, 1, false},
|
||||||
}
|
}
|
||||||
mod := L.SetFuncs(L.NewTable(), exports)
|
mod := rt.NewTable()
|
||||||
util.Document(L, mod, "Commander is Hilbish's custom command library, a way to write commands in Lua.")
|
util.SetExports(rtm, mod, exports)
|
||||||
L.Push(mod)
|
util.Document(mod, "Commander is Hilbish's custom command library, a way to write commands in Lua.")
|
||||||
|
|
||||||
return 1
|
return rt.TableValue(mod), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// register(name, cb)
|
// register(name, cb)
|
||||||
// Register a command with `name` that runs `cb` when ran
|
// Register a command with `name` that runs `cb` when ran
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
func (c *Commander) cregister(L *lua.LState) int {
|
func (c *Commander) cregister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
|
||||||
cmdName := L.CheckString(1)
|
cmdName, cmd, err := util.HandleStrCallback(t, ct)
|
||||||
cmd := L.CheckFunction(2)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
c.Events.Emit("commandRegister", cmdName, cmd)
|
c.Events.Emit("commandRegister", cmdName, cmd)
|
||||||
|
|
||||||
return 0
|
return ct.Next(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// deregister(name)
|
// deregister(name)
|
||||||
// Deregisters any command registered with `name`
|
// Deregisters any command registered with `name`
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
func (c *Commander) cderegister(L *lua.LState) int {
|
func (c *Commander) cderegister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
|
||||||
cmdName := L.CheckString(1)
|
if err := ct.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmdName, err := ct.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
c.Events.Emit("commandDeregister", cmdName)
|
c.Events.Emit("commandDeregister", cmdName)
|
||||||
|
|
||||||
return 0
|
return ct.Next(), err
|
||||||
}
|
}
|
||||||
|
|
124
golibs/fs/fs.go
124
golibs/fs/fs.go
|
@ -1,5 +1,3 @@
|
||||||
// The fs module provides easy and simple access to filesystem functions and other
|
|
||||||
// things, and acts an addition to the Lua standard library's I/O and fs functions.
|
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -8,51 +6,70 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
"github.com/yuin/gopher-lua"
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib/packagelib"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Loader(L *lua.LState) int {
|
var Loader = packagelib.Loader{
|
||||||
mod := L.SetFuncs(L.NewTable(), exports)
|
Load: loaderFunc,
|
||||||
|
Name: "fs",
|
||||||
|
}
|
||||||
|
|
||||||
util.Document(L, mod, `The fs module provides easy and simple access to
|
func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
|
exports := map[string]util.LuaExport{
|
||||||
|
"cd": util.LuaExport{fcd, 1, false},
|
||||||
|
"mkdir": util.LuaExport{fmkdir, 2, false},
|
||||||
|
"stat": util.LuaExport{fstat, 1, false},
|
||||||
|
"readdir": util.LuaExport{freaddir, 1, false},
|
||||||
|
}
|
||||||
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, exports)
|
||||||
|
|
||||||
|
util.Document(mod, `The fs module provides easy and simple access to
|
||||||
filesystem functions and other things, and acts an
|
filesystem functions and other things, and acts an
|
||||||
addition to the Lua standard library's I/O and fs functions.`)
|
addition to the Lua standard library's I/O and fs functions.`)
|
||||||
|
|
||||||
L.Push(mod)
|
return rt.TableValue(mod), nil
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
var exports = map[string]lua.LGFunction{
|
|
||||||
"cd": fcd,
|
|
||||||
"mkdir": fmkdir,
|
|
||||||
"stat": fstat,
|
|
||||||
"readdir": freaddir,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cd(dir)
|
// cd(dir)
|
||||||
// Changes directory to `dir`
|
// Changes directory to `dir`
|
||||||
// --- @param dir string
|
// --- @param dir string
|
||||||
func fcd(L *lua.LState) int {
|
func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
path := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
err := os.Chdir(strings.TrimSpace(path))
|
}
|
||||||
|
path, err := c.StringArg(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := err.(*os.PathError).Err.Error()
|
return nil, err
|
||||||
L.RaiseError(e + ": " + path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
err = os.Chdir(strings.TrimSpace(path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Next(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// mkdir(name, recursive)
|
// mkdir(name, recursive)
|
||||||
// Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
// Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
||||||
// --- @param name string
|
// --- @param name string
|
||||||
// --- @param recursive boolean
|
// --- @param recursive boolean
|
||||||
func fmkdir(L *lua.LState) int {
|
func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
dirname := L.CheckString(1)
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
recursive := L.ToBool(2)
|
return nil, err
|
||||||
|
}
|
||||||
|
dirname, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
recursive, err := c.BoolArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
path := strings.TrimSpace(dirname)
|
path := strings.TrimSpace(dirname)
|
||||||
var err error
|
|
||||||
|
|
||||||
if recursive {
|
if recursive {
|
||||||
err = os.MkdirAll(path, 0744)
|
err = os.MkdirAll(path, 0744)
|
||||||
|
@ -60,51 +77,58 @@ func fmkdir(L *lua.LState) int {
|
||||||
err = os.Mkdir(path, 0744)
|
err = os.Mkdir(path, 0744)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.RaiseError(err.Error() + ": " + path)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// stat(path)
|
// stat(path)
|
||||||
// Returns info about `path`
|
// Returns info about `path`
|
||||||
// --- @param path string
|
// --- @param path string
|
||||||
func fstat(L *lua.LState) int {
|
func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
path := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
path, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
pathinfo, err := os.Stat(path)
|
pathinfo, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.RaiseError(err.Error() + ": " + path)
|
return nil, err
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
statTbl := L.NewTable()
|
statTbl := rt.NewTable()
|
||||||
L.SetField(statTbl, "name", lua.LString(pathinfo.Name()))
|
statTbl.Set(rt.StringValue("name"), rt.StringValue(pathinfo.Name()))
|
||||||
L.SetField(statTbl, "size", lua.LNumber(pathinfo.Size()))
|
statTbl.Set(rt.StringValue("size"), rt.IntValue(pathinfo.Size()))
|
||||||
L.SetField(statTbl, "mode", lua.LString("0" + strconv.FormatInt(int64(pathinfo.Mode().Perm()), 8)))
|
statTbl.Set(rt.StringValue("mode"), rt.StringValue("0" + strconv.FormatInt(int64(pathinfo.Mode().Perm()), 8)))
|
||||||
L.SetField(statTbl, "isDir", lua.LBool(pathinfo.IsDir()))
|
statTbl.Set(rt.StringValue("isDir"), rt.BoolValue(pathinfo.IsDir()))
|
||||||
L.Push(statTbl)
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// readdir(dir)
|
// readdir(dir)
|
||||||
// Returns a table of files in `dir`
|
// Returns a table of files in `dir`
|
||||||
// --- @param dir string
|
// --- @param dir string
|
||||||
// --- @return table
|
// --- @return table
|
||||||
func freaddir(L *lua.LState) int {
|
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
dir := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
names := L.NewTable()
|
return nil, err
|
||||||
|
}
|
||||||
|
dir, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
names := rt.NewTable()
|
||||||
|
|
||||||
dirEntries, err := os.ReadDir(dir)
|
dirEntries, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.RaiseError(err.Error() + ": " + dir)
|
return nil, err
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
for _, entry := range dirEntries {
|
for i, entry := range dirEntries {
|
||||||
names.Append(lua.LString(entry.Name()))
|
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(names)
|
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,76 +5,78 @@ import (
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib/packagelib"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
"github.com/yuin/gopher-lua"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var termState *term.State
|
var termState *term.State
|
||||||
|
var Loader = packagelib.Loader{
|
||||||
func Loader(L *lua.LState) int {
|
Load: loaderFunc,
|
||||||
mod := L.SetFuncs(L.NewTable(), exports)
|
Name: "terminal",
|
||||||
util.Document(L, mod, "The terminal library is a simple and lower level library for certain terminal interactions.")
|
|
||||||
|
|
||||||
L.Push(mod)
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var exports = map[string]lua.LGFunction{
|
func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
"setRaw": termraw,
|
exports := map[string]util.LuaExport{
|
||||||
"restoreState": termrestoreState,
|
"setRaw": util.LuaExport{termsetRaw, 0, false},
|
||||||
"size": termsize,
|
"restoreState": util.LuaExport{termrestoreState, 0, false},
|
||||||
"saveState": termsaveState,
|
"size": util.LuaExport{termsize, 0, false},
|
||||||
|
"saveState": util.LuaExport{termsaveState, 0, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, exports)
|
||||||
|
util.Document(mod, "The terminal library is a simple and lower level library for certain terminal interactions.")
|
||||||
|
|
||||||
|
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: this is not the size in relation to the dimensions of the display
|
// Note: this is not the size in relation to the dimensions of the display
|
||||||
func termsize(L *lua.LState) int {
|
func termsize(t *rt.Thread, c *rt.GoCont) (rt.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 {
|
||||||
L.RaiseError(err.Error())
|
return nil, err
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
dimensions := L.NewTable()
|
|
||||||
L.SetField(dimensions, "width", lua.LNumber(w))
|
|
||||||
L.SetField(dimensions, "height", lua.LNumber(h))
|
|
||||||
|
|
||||||
L.Push(dimensions)
|
dimensions := rt.NewTable()
|
||||||
return 1
|
dimensions.Set(rt.StringValue("width"), rt.IntValue(int64(w)))
|
||||||
|
dimensions.Set(rt.StringValue("height"), rt.IntValue(int64(h)))
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(dimensions)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveState()
|
// saveState()
|
||||||
// Saves the current state of the terminal
|
// Saves the current state of the terminal
|
||||||
func termsaveState(L *lua.LState) int {
|
func termsaveState(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
state, err := term.GetState(int(os.Stdin.Fd()))
|
state, err := term.GetState(int(os.Stdin.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.RaiseError(err.Error())
|
return nil, err
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
termState = state
|
termState = state
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreState()
|
// restoreState()
|
||||||
// Restores the last saved state of the terminal
|
// Restores the last saved state of the terminal
|
||||||
func termrestoreState(L *lua.LState) int {
|
func termrestoreState(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
err := term.Restore(int(os.Stdin.Fd()), termState)
|
err := term.Restore(int(os.Stdin.Fd()), termState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.RaiseError(err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setRaw()
|
// setRaw()
|
||||||
// Puts the terminal in raw mode
|
// Puts the terminal in raw mode
|
||||||
func termraw(L *lua.LState) int {
|
func termsetRaw(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
_, err := term.MakeRaw(int(os.Stdin.Fd()))
|
_, err := term.MakeRaw(int(os.Stdin.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
L.RaiseError(err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
72
job.go
72
job.go
|
@ -4,7 +4,9 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/yuin/gopher-lua"
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var jobs *jobHandler
|
var jobs *jobHandler
|
||||||
|
@ -38,29 +40,28 @@ func (j *job) setHandle(handle *os.Process) {
|
||||||
j.proc = handle
|
j.proc = handle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) lua() *lua.LTable {
|
func (j *job) lua() rt.Value {
|
||||||
// returns lua table for job
|
jobFuncs := map[string]util.LuaExport{
|
||||||
// because userdata is gross
|
"stop": {j.luaStop, 0, false},
|
||||||
jobFuncs := map[string]lua.LGFunction{
|
|
||||||
"stop": j.luaStop,
|
|
||||||
}
|
}
|
||||||
luaJob := l.SetFuncs(l.NewTable(), jobFuncs)
|
luaJob := rt.NewTable()
|
||||||
|
util.SetExports(l, luaJob, jobFuncs)
|
||||||
|
|
||||||
l.SetField(luaJob, "cmd", lua.LString(j.cmd))
|
luaJob.Set(rt.StringValue("cmd"), rt.StringValue(j.cmd))
|
||||||
l.SetField(luaJob, "running", lua.LBool(j.running))
|
luaJob.Set(rt.StringValue("running"), rt.BoolValue(j.running))
|
||||||
l.SetField(luaJob, "id", lua.LNumber(j.id))
|
luaJob.Set(rt.StringValue("id"), rt.IntValue(int64(j.id)))
|
||||||
l.SetField(luaJob, "pid", lua.LNumber(j.pid))
|
luaJob.Set(rt.StringValue("pid"), rt.IntValue(int64(j.pid)))
|
||||||
l.SetField(luaJob, "exitCode", lua.LNumber(j.exitCode))
|
luaJob.Set(rt.StringValue("exitCode"), rt.IntValue(int64(j.exitCode)))
|
||||||
|
|
||||||
return luaJob
|
return rt.TableValue(luaJob)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) luaStop(L *lua.LState) int {
|
func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if j.running {
|
if j.running {
|
||||||
j.stop()
|
j.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type jobHandler struct {
|
type jobHandler struct {
|
||||||
|
@ -96,41 +97,46 @@ func (j *jobHandler) getLatest() *job {
|
||||||
return j.jobs[j.latestID]
|
return j.jobs[j.latestID]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
|
||||||
func (j *jobHandler) loader(L *lua.LState) *lua.LTable {
|
jobFuncs := map[string]util.LuaExport{
|
||||||
jobFuncs := map[string]lua.LGFunction{
|
"all": {j.luaAllJobs, 0, false},
|
||||||
"all": j.luaAllJobs,
|
"get": {j.luaGetJob, 1, false},
|
||||||
"get": j.luaGetJob,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
luaJob := l.SetFuncs(l.NewTable(), jobFuncs)
|
luaJob := rt.NewTable()
|
||||||
|
util.SetExports(rtm, luaJob, jobFuncs)
|
||||||
|
|
||||||
return luaJob
|
return luaJob
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jobHandler) luaGetJob(L *lua.LState) int {
|
func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
j.mu.RLock()
|
j.mu.RLock()
|
||||||
defer j.mu.RUnlock()
|
defer j.mu.RUnlock()
|
||||||
|
|
||||||
jobID := L.CheckInt(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
job := j.jobs[jobID]
|
return nil, err
|
||||||
if job != nil {
|
}
|
||||||
return 0
|
jobID, err := c.IntArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
L.Push(job.lua())
|
|
||||||
|
|
||||||
return 1
|
job := j.jobs[int(jobID)]
|
||||||
|
if job == nil {
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, job.lua()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jobHandler) luaAllJobs(L *lua.LState) int {
|
func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
j.mu.RLock()
|
j.mu.RLock()
|
||||||
defer j.mu.RUnlock()
|
defer j.mu.RUnlock()
|
||||||
|
|
||||||
jobTbl := L.NewTable()
|
jobTbl := rt.NewTable()
|
||||||
for id, job := range j.jobs {
|
for id, job := range j.jobs {
|
||||||
jobTbl.Insert(id, job.lua())
|
jobTbl.Set(rt.IntValue(int64(id)), job.lua())
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(jobTbl)
|
return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,21 +89,25 @@ end
|
||||||
|
|
||||||
ansikit.print = function(text)
|
ansikit.print = function(text)
|
||||||
io.write(ansikit.format(text))
|
io.write(ansikit.format(text))
|
||||||
|
io.flush()
|
||||||
return ansikit
|
return ansikit
|
||||||
end
|
end
|
||||||
|
|
||||||
ansikit.printCode = function(code, terminate)
|
ansikit.printCode = function(code, terminate)
|
||||||
io.write(ansikit.getCode(code, terminate))
|
io.write(ansikit.getCode(code, terminate))
|
||||||
|
io.flush()
|
||||||
return ansikit
|
return ansikit
|
||||||
end
|
end
|
||||||
|
|
||||||
ansikit.printCSI = function(code, endc)
|
ansikit.printCSI = function(code, endc)
|
||||||
io.write(ansikit.getCSI(code, endc))
|
io.write(ansikit.getCSI(code, endc))
|
||||||
|
io.flush()
|
||||||
return ansikit
|
return ansikit
|
||||||
end
|
end
|
||||||
|
|
||||||
ansikit.println = function(text)
|
ansikit.println = function(text)
|
||||||
print(ansikit.print(text))
|
io.write(ansikit.format(text) .. "\n")
|
||||||
|
io.flush()
|
||||||
return ansikit
|
return ansikit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
45
lua.go
45
lua.go
|
@ -4,40 +4,42 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
|
||||||
"github.com/yuin/gopher-lua"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
var minimalconf = `hilbish.prompt '& '`
|
var minimalconf = `hilbish.prompt '& '`
|
||||||
|
|
||||||
func luaInit() {
|
func luaInit() {
|
||||||
l = lua.NewState()
|
l = rt.New(os.Stdout)
|
||||||
l.OpenLibs()
|
lib.LoadAll(l)
|
||||||
|
|
||||||
|
lib.LoadLibs(l, hilbishLoader)
|
||||||
// yes this is stupid, i know
|
// yes this is stupid, i know
|
||||||
l.PreloadModule("hilbish", hilbishLoader)
|
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
|
||||||
l.PreloadModule("fs", fs.Loader)
|
lib.LoadLibs(l, fs.Loader)
|
||||||
l.PreloadModule("terminal", terminal.Loader)
|
lib.LoadLibs(l, terminal.Loader)
|
||||||
|
|
||||||
cmds := commander.New()
|
cmds := commander.New()
|
||||||
// When a command from Lua is added, register it for use
|
// When a command from Lua is added, register it for use
|
||||||
cmds.Events.On("commandRegister", func(cmdName string, cmd *lua.LFunction) {
|
cmds.Events.On("commandRegister", func(cmdName string, cmd *rt.Closure) {
|
||||||
commands[cmdName] = cmd
|
commands[cmdName] = cmd
|
||||||
})
|
})
|
||||||
cmds.Events.On("commandDeregister", func(cmdName string) {
|
cmds.Events.On("commandDeregister", func(cmdName string) {
|
||||||
delete(commands, cmdName)
|
delete(commands, cmdName)
|
||||||
})
|
})
|
||||||
l.PreloadModule("commander", cmds.Loader)
|
lib.LoadLibs(l, cmds.Loader)
|
||||||
|
|
||||||
hooks = bait.New()
|
hooks = bait.New()
|
||||||
l.PreloadModule("bait", hooks.Loader)
|
lib.LoadLibs(l, hooks.Loader)
|
||||||
|
|
||||||
// Add Ctrl-C handler
|
// Add Ctrl-C handler
|
||||||
hooks.Em.On("signal.sigint", func() {
|
hooks.Em.On("signal.sigint", func() {
|
||||||
|
@ -47,26 +49,27 @@ func luaInit() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add more paths that Lua can require from
|
// Add more paths that Lua can require from
|
||||||
l.DoString("package.path = package.path .. " + requirePaths)
|
err := util.DoString(l, "package.path = package.path .. " + requirePaths)
|
||||||
|
|
||||||
err := l.DoFile("prelude/init.lua")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = l.DoFile(preloadPath)
|
fmt.Fprintln(os.Stderr, "Could not add preload paths! Libraries will be missing. This shouldn't happen.")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = util.DoFile(l, "prelude/init.lua")
|
||||||
|
if err != nil {
|
||||||
|
err = util.DoFile(l, preloadPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr,
|
fmt.Fprintln(os.Stderr, "Missing preload file, builtins may be missing.")
|
||||||
"Missing preload file, builtins may be missing.")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runConfig(confpath string) {
|
func runConfig(confpath string) {
|
||||||
if !interactive {
|
if !interactive {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := l.DoFile(confpath)
|
err := util.DoFile(l, confpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err,
|
fmt.Fprintln(os.Stderr, err, "\nAn error has occured while loading your config! Falling back to minimal default config.")
|
||||||
"\nAn error has occured while loading your config! Falling back to minimal default config.")
|
util.DoString(l, minimalconf)
|
||||||
|
|
||||||
l.DoString(minimalconf)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
main.go
19
main.go
|
@ -10,20 +10,21 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"hilbish/util"
|
||||||
"hilbish/golibs/bait"
|
"hilbish/golibs/bait"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
"github.com/pborman/getopt"
|
"github.com/pborman/getopt"
|
||||||
"github.com/yuin/gopher-lua"
|
|
||||||
"github.com/maxlandon/readline"
|
"github.com/maxlandon/readline"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
l *lua.LState
|
l *rt.Runtime
|
||||||
lr *lineReader
|
lr *lineReader
|
||||||
|
|
||||||
commands = map[string]*lua.LFunction{}
|
commands = map[string]*rt.Closure{}
|
||||||
luaCompletions = map[string]*lua.LFunction{}
|
luaCompletions = map[string]*rt.Closure{}
|
||||||
|
|
||||||
confDir string
|
confDir string
|
||||||
userDataDir string
|
userDataDir string
|
||||||
|
@ -151,13 +152,13 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if getopt.NArgs() > 0 {
|
if getopt.NArgs() > 0 {
|
||||||
luaArgs := l.NewTable()
|
luaArgs := rt.NewTable()
|
||||||
for _, arg := range getopt.Args() {
|
for i, arg := range getopt.Args() {
|
||||||
luaArgs.Append(lua.LString(arg))
|
luaArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
l.SetGlobal("args", luaArgs)
|
l.GlobalEnv().Set(rt.StringValue("args"), rt.TableValue(luaArgs))
|
||||||
err := l.DoFile(getopt.Arg(0))
|
err := util.DoFile(l, getopt.Arg(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -8,7 +8,7 @@ local _ = require 'succulent' -- Function additions
|
||||||
local oldDir = hilbish.cwd()
|
local oldDir = hilbish.cwd()
|
||||||
|
|
||||||
local shlvl = tonumber(os.getenv 'SHLVL')
|
local shlvl = tonumber(os.getenv 'SHLVL')
|
||||||
if shlvl ~= nil then os.setenv('SHLVL', shlvl + 1) else os.setenv('SHLVL', 0) end
|
if shlvl ~= nil then os.setenv('SHLVL', tostring(shlvl + 1)) else os.setenv('SHLVL', '0') end
|
||||||
|
|
||||||
-- Builtins
|
-- Builtins
|
||||||
local recentDirs = {}
|
local recentDirs = {}
|
||||||
|
|
237
rl.go
237
rl.go
|
@ -5,18 +5,19 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"hilbish/util"
|
||||||
|
|
||||||
"github.com/maxlandon/readline"
|
"github.com/maxlandon/readline"
|
||||||
"github.com/yuin/gopher-lua"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type lineReader struct {
|
type lineReader struct {
|
||||||
rl *readline.Instance
|
rl *readline.Instance
|
||||||
}
|
}
|
||||||
var fileHist *fileHistory
|
var fileHist *fileHistory
|
||||||
var hinter lua.LValue = lua.LNil
|
var hinter *rt.Closure
|
||||||
var highlighter lua.LValue = lua.LNil
|
var highlighter *rt.Closure
|
||||||
|
|
||||||
// other gophers might hate this naming but this is local, shut up
|
|
||||||
func newLineReader(prompt string, noHist bool) *lineReader {
|
func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
rl := readline.NewInstance()
|
rl := readline.NewInstance()
|
||||||
// we don't mind hilbish.read rl instances having completion,
|
// we don't mind hilbish.read rl instances having completion,
|
||||||
|
@ -47,46 +48,38 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
hooks.Em.Emit("hilbish.vimAction", actionStr, args)
|
hooks.Em.Emit("hilbish.vimAction", actionStr, args)
|
||||||
}
|
}
|
||||||
rl.HintText = func(line []rune, pos int) []rune {
|
rl.HintText = func(line []rune, pos int) []rune {
|
||||||
if hinter == lua.LNil {
|
if hinter == nil {
|
||||||
return []rune{}
|
return []rune{}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := l.CallByParam(lua.P{
|
retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(highlighter),
|
||||||
Fn: hinter,
|
rt.StringValue(string(line)), rt.IntValue(int64(pos)))
|
||||||
NRet: 1,
|
|
||||||
Protect: true,
|
|
||||||
}, lua.LString(string(line)), lua.LNumber(pos))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return []rune{}
|
return []rune{}
|
||||||
}
|
}
|
||||||
|
|
||||||
retVal := l.Get(-1)
|
|
||||||
hintText := ""
|
hintText := ""
|
||||||
if luaStr, ok := retVal.(lua.LString); retVal != lua.LNil && ok {
|
if luaStr, ok := retVal.TryString(); ok {
|
||||||
hintText = luaStr.String()
|
hintText = luaStr
|
||||||
}
|
}
|
||||||
|
|
||||||
return []rune(hintText)
|
return []rune(hintText)
|
||||||
}
|
}
|
||||||
rl.SyntaxHighlighter = func(line []rune) string {
|
rl.SyntaxHighlighter = func(line []rune) string {
|
||||||
if highlighter == lua.LNil {
|
if highlighter == nil {
|
||||||
return string(line)
|
return string(line)
|
||||||
}
|
}
|
||||||
err := l.CallByParam(lua.P{
|
retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(highlighter),
|
||||||
Fn: highlighter,
|
rt.StringValue(string(line)))
|
||||||
NRet: 1,
|
|
||||||
Protect: true,
|
|
||||||
}, lua.LString(string(line)))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return string(line)
|
return string(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
retVal := l.Get(-1)
|
|
||||||
highlighted := ""
|
highlighted := ""
|
||||||
if luaStr, ok := retVal.(lua.LString); retVal != lua.LNil && ok {
|
if luaStr, ok := retVal.TryString(); ok {
|
||||||
highlighted = luaStr.String()
|
highlighted = luaStr
|
||||||
}
|
}
|
||||||
|
|
||||||
return highlighted
|
return highlighted
|
||||||
|
@ -122,23 +115,20 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
return prefix, compGroup
|
return prefix, compGroup
|
||||||
} else {
|
} else {
|
||||||
if completecb, ok := luaCompletions["command." + fields[0]]; ok {
|
if completecb, ok := luaCompletions["command." + fields[0]]; ok {
|
||||||
luaFields := l.NewTable()
|
luaFields := rt.NewTable()
|
||||||
for _, f := range fields {
|
for i, f := range fields {
|
||||||
luaFields.Append(lua.LString(f))
|
luaFields.Set(rt.IntValue(int64(i + 1)), rt.StringValue(f))
|
||||||
}
|
}
|
||||||
err := l.CallByParam(lua.P{
|
|
||||||
Fn: completecb,
|
// we must keep the holy 80 cols
|
||||||
NRet: 1,
|
luacompleteTable, err := rt.Call1(l.MainThread(),
|
||||||
Protect: true,
|
rt.FunctionValue(completecb), rt.StringValue(query),
|
||||||
}, lua.LString(query), lua.LString(ctx), luaFields)
|
rt.StringValue(ctx), rt.TableValue(luaFields))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", compGroup
|
return "", compGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
luacompleteTable := l.Get(-1)
|
|
||||||
l.Pop(1)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
as an example with git,
|
as an example with git,
|
||||||
completion table should be structured like:
|
completion table should be structured like:
|
||||||
|
@ -163,50 +153,86 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
it is the responsibility of the completer
|
it is the responsibility of the completer
|
||||||
to work on subcommands and subcompletions
|
to work on subcommands and subcompletions
|
||||||
*/
|
*/
|
||||||
if cmpTbl, ok := luacompleteTable.(*lua.LTable); ok {
|
if cmpTbl, ok := luacompleteTable.TryTable(); ok {
|
||||||
cmpTbl.ForEach(func(key lua.LValue, value lua.LValue) {
|
nextVal := rt.NilValue
|
||||||
if key.Type() == lua.LTNumber {
|
for {
|
||||||
// completion group
|
next, val, ok := cmpTbl.Next(nextVal)
|
||||||
if value.Type() == lua.LTTable {
|
if next == rt.NilValue {
|
||||||
luaCmpGroup := value.(*lua.LTable)
|
break
|
||||||
compType := luaCmpGroup.RawGet(lua.LString("type"))
|
}
|
||||||
compItems := luaCmpGroup.RawGet(lua.LString("items"))
|
nextVal = next
|
||||||
if compType.Type() != lua.LTString {
|
|
||||||
l.RaiseError("bad type name for completion (expected string, got %v)", compType.Type().String())
|
|
||||||
}
|
|
||||||
if compItems.Type() != lua.LTTable {
|
|
||||||
l.RaiseError("bad items for completion (expected table, got %v)", compItems.Type().String())
|
|
||||||
}
|
|
||||||
var items []string
|
|
||||||
itemDescriptions := make(map[string]string)
|
|
||||||
compItems.(*lua.LTable).ForEach(func(k lua.LValue, v lua.LValue) {
|
|
||||||
if k.Type() == lua.LTString {
|
|
||||||
// ['--flag'] = {'description', '--flag-alias'}
|
|
||||||
itm := v.(*lua.LTable)
|
|
||||||
items = append(items, k.String())
|
|
||||||
itemDescriptions[k.String()] = itm.RawGet(lua.LNumber(1)).String()
|
|
||||||
} else {
|
|
||||||
items = append(items, v.String())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var dispType readline.TabDisplayType
|
_, ok = next.TryInt()
|
||||||
switch compType.String() {
|
valTbl, okk := val.TryTable()
|
||||||
case "grid": dispType = readline.TabDisplayGrid
|
if !ok || !okk {
|
||||||
case "list": dispType = readline.TabDisplayList
|
// TODO: error?
|
||||||
// need special cases, will implement later
|
break
|
||||||
//case "map": dispType = readline.TabDisplayMap
|
}
|
||||||
|
|
||||||
|
luaCompType := valTbl.Get(rt.StringValue("type"))
|
||||||
|
luaCompItems := valTbl.Get(rt.StringValue("items"))
|
||||||
|
|
||||||
|
compType, ok := luaCompType.TryString()
|
||||||
|
compItems, okk := luaCompItems.TryTable()
|
||||||
|
if !ok || !okk {
|
||||||
|
// TODO: error
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []string
|
||||||
|
itemDescriptions := make(map[string]string)
|
||||||
|
nxVal := rt.NilValue
|
||||||
|
for {
|
||||||
|
nx, vl, _ := compItems.Next(nxVal)
|
||||||
|
if nx == rt.NilValue {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nxVal = nx
|
||||||
|
|
||||||
|
if tstr := nx.Type(); tstr == rt.StringType {
|
||||||
|
// ['--flag'] = {'description', '--flag-alias'}
|
||||||
|
nxStr, ok := nx.TryString()
|
||||||
|
vlTbl, okk := vl.TryTable()
|
||||||
|
if !ok || !okk {
|
||||||
|
// TODO: error
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
compGroup = append(compGroup, &readline.CompletionGroup{
|
items = append(items, nxStr)
|
||||||
DisplayType: dispType,
|
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
|
||||||
Descriptions: itemDescriptions,
|
if !ok {
|
||||||
Suggestions: items,
|
// TODO: error
|
||||||
TrimSlash: false,
|
continue
|
||||||
NoSpace: true,
|
}
|
||||||
})
|
itemDescriptions[nxStr] = itemDescription
|
||||||
|
} else if tstr == rt.IntType {
|
||||||
|
vlStr, okk := vl.TryString()
|
||||||
|
if !okk {
|
||||||
|
// TODO: error
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
items = append(items, vlStr)
|
||||||
|
} else {
|
||||||
|
// TODO: error
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
var dispType readline.TabDisplayType
|
||||||
|
switch compType {
|
||||||
|
case "grid": dispType = readline.TabDisplayGrid
|
||||||
|
case "list": dispType = readline.TabDisplayList
|
||||||
|
// need special cases, will implement later
|
||||||
|
//case "map": dispType = readline.TabDisplayMap
|
||||||
|
}
|
||||||
|
|
||||||
|
compGroup = append(compGroup, &readline.CompletionGroup{
|
||||||
|
DisplayType: dispType,
|
||||||
|
Descriptions: itemDescriptions,
|
||||||
|
Suggestions: items,
|
||||||
|
TrimSlash: false,
|
||||||
|
NoSpace: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,56 +294,65 @@ func (lr *lineReader) Resize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua module
|
// lua module
|
||||||
func (lr *lineReader) Loader(L *lua.LState) *lua.LTable {
|
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
|
||||||
lrLua := map[string]lua.LGFunction{
|
lrLua := map[string]util.LuaExport{
|
||||||
"add": lr.luaAddHistory,
|
"add": {lr.luaAddHistory, 1, false},
|
||||||
"all": lr.luaAllHistory,
|
"all": {lr.luaAllHistory, 0, false},
|
||||||
"clear": lr.luaClearHistory,
|
"clear": {lr.luaClearHistory, 0, false},
|
||||||
"get": lr.luaGetHistory,
|
"get": {lr.luaGetHistory, 1, false},
|
||||||
"size": lr.luaSize,
|
"size": {lr.luaSize, 0, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
mod := l.SetFuncs(l.NewTable(), lrLua)
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, lrLua)
|
||||||
|
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaAddHistory(l *lua.LState) int {
|
func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cmd := l.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
lr.AddHistory(cmd)
|
lr.AddHistory(cmd)
|
||||||
|
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaSize(L *lua.LState) int {
|
func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
L.Push(lua.LNumber(fileHist.Len()))
|
return c.PushingNext1(t.Runtime, rt.IntValue(int64(fileHist.Len()))), nil
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaGetHistory(L *lua.LState) int {
|
func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
idx := L.CheckInt(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
cmd, _ := fileHist.GetLine(idx)
|
return nil, err
|
||||||
L.Push(lua.LString(cmd))
|
}
|
||||||
|
idx, err := c.IntArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return 1
|
cmd, _ := fileHist.GetLine(int(idx))
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaAllHistory(L *lua.LState) int {
|
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
tbl := L.NewTable()
|
tbl := rt.NewTable()
|
||||||
size := fileHist.Len()
|
size := fileHist.Len()
|
||||||
|
|
||||||
for i := 1; i < size; i++ {
|
for i := 1; i < size; i++ {
|
||||||
cmd, _ := fileHist.GetLine(i)
|
cmd, _ := fileHist.GetLine(i)
|
||||||
tbl.Append(lua.LString(cmd))
|
tbl.Set(rt.IntValue(int64(i)), rt.StringValue(cmd))
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(tbl)
|
return c.PushingNext1(t.Runtime, rt.TableValue(tbl)), nil
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaClearHistory(l *lua.LState) int {
|
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
fileHist.clear()
|
fileHist.clear()
|
||||||
return 0
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,56 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/yuin/gopher-lua"
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runnerModeLoader(L *lua.LState) *lua.LTable {
|
func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
exports := map[string]lua.LGFunction{
|
exports := map[string]util.LuaExport{
|
||||||
"sh": shRunner,
|
"sh": {shRunner, 1, false},
|
||||||
"lua": luaRunner,
|
"lua": {luaRunner, 1, false},
|
||||||
"setMode": hlrunnerMode,
|
"setMode": {hlrunnerMode, 1, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
mod := L.SetFuncs(L.NewTable(), exports)
|
mod := rt.NewTable()
|
||||||
L.SetField(mod, "mode", runnerMode)
|
util.SetExports(rtm, mod, exports)
|
||||||
|
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func shRunner(L *lua.LState) int {
|
func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cmd := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
exitCode, err := handleSh(cmd)
|
exitCode, err := handleSh(cmd)
|
||||||
var luaErr lua.LValue = lua.LNil
|
var luaErr rt.Value = rt.NilValue
|
||||||
if err != nil {
|
if err != nil {
|
||||||
luaErr = lua.LString(err.Error())
|
luaErr = rt.StringValue(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(lua.LNumber(exitCode))
|
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitCode)), luaErr), nil
|
||||||
L.Push(luaErr)
|
|
||||||
|
|
||||||
return 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func luaRunner(L *lua.LState) int {
|
func luaRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cmd := L.CheckString(1)
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmd, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
exitCode, err := handleLua(cmd)
|
exitCode, err := handleLua(cmd)
|
||||||
var luaErr lua.LValue = lua.LNil
|
var luaErr rt.Value = rt.NilValue
|
||||||
if err != nil {
|
if err != nil {
|
||||||
luaErr = lua.LString(err.Error())
|
luaErr = rt.StringValue(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Push(lua.LNumber(exitCode))
|
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitCode)), luaErr), nil
|
||||||
L.Push(luaErr)
|
|
||||||
|
|
||||||
return 2
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LuaExport represents a Go function which can be exported to Lua.
|
||||||
|
type LuaExport struct {
|
||||||
|
Function rt.GoFunctionFunc
|
||||||
|
ArgNum int
|
||||||
|
Variadic bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExports puts the Lua function exports in the table.
|
||||||
|
func SetExports(rtm *rt.Runtime, tbl *rt.Table, exports map[string]LuaExport) {
|
||||||
|
for name, export := range exports {
|
||||||
|
rtm.SetEnvGoFunc(tbl, name, export.Function, export.ArgNum, export.Variadic)
|
||||||
|
}
|
||||||
|
}
|
122
util/util.go
122
util/util.go
|
@ -1,32 +1,120 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import "github.com/yuin/gopher-lua"
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
// Document adds a documentation string to a module.
|
// Document adds a documentation string to a module.
|
||||||
// It is accessible via the __doc metatable.
|
// It is accessible via the __doc metatable.
|
||||||
func Document(L *lua.LState, module lua.LValue, doc string) {
|
func Document(module *rt.Table, doc string) {
|
||||||
mt := L.GetMetatable(module)
|
mt := module.Metatable()
|
||||||
if mt == lua.LNil {
|
|
||||||
mt = L.NewTable()
|
if mt == nil {
|
||||||
L.SetMetatable(module, mt)
|
mt = rt.NewTable()
|
||||||
|
module.SetMetatable(mt)
|
||||||
}
|
}
|
||||||
L.SetField(mt, "__doc", lua.LString(doc))
|
|
||||||
|
mt.Set(rt.StringValue("__doc"), rt.StringValue(doc))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(L *lua.LState, module lua.LValue, field string, value lua.LValue, doc string) {
|
func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, doc string) {
|
||||||
mt := L.GetMetatable(module)
|
// TODO: ^ rtm isnt needed, i should remove it
|
||||||
if mt == lua.LNil {
|
mt := module.Metatable()
|
||||||
mt = L.NewTable()
|
|
||||||
docProp := L.NewTable()
|
if mt == nil {
|
||||||
L.SetField(mt, "__docProp", docProp)
|
mt = rt.NewTable()
|
||||||
|
docProp := rt.NewTable()
|
||||||
|
mt.Set(rt.StringValue("__docProp"), rt.TableValue(docProp))
|
||||||
|
|
||||||
L.SetMetatable(module, mt)
|
module.SetMetatable(mt)
|
||||||
}
|
}
|
||||||
docProp := L.GetTable(mt, lua.LString("__docProp"))
|
docProp := mt.Get(rt.StringValue("__docProp"))
|
||||||
|
|
||||||
L.SetField(docProp, field, lua.LString(doc))
|
docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc))
|
||||||
L.SetField(module, field, value)
|
module.Set(rt.StringValue(field), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DoString runs the code string in the Lua runtime.
|
||||||
|
func DoString(rtm *rt.Runtime, code string) error {
|
||||||
|
chunk, err := rtm.CompileAndLoadLuaChunk("<string>", []byte(code), rt.TableValue(rtm.GlobalEnv()))
|
||||||
|
if chunk != nil {
|
||||||
|
_, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(chunk))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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...)
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk, err := rtm.CompileAndLoadLuaChunk(path, buf, rt.TableValue(rtm.GlobalEnv()))
|
||||||
|
if chunk != nil {
|
||||||
|
_, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(chunk))
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleStrCallback handles function parameters for Go functions which take
|
||||||
|
// a string and a closure.
|
||||||
|
func HandleStrCallback(t *rt.Thread, c *rt.GoCont) (string, *rt.Closure, error) {
|
||||||
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
name, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
cb, err := c.ClosureArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return name, cb, err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue