Compare commits

..

9 Commits

Author SHA1 Message Date
sammyette dce02e5310
chore: merge from master 2022-03-28 21:38:37 -04:00
TorchedSammy c0b08a340a
fix: make sure args to setenv are strings in prelude 2022-03-28 21:06:45 -04:00
TorchedSammy 506f90de06
chore: use custom fork of golua 2022-03-28 21:02:57 -04:00
TorchedSammy 7909aeb4b3
feat: add hilbish module functions used by prelude 2022-03-28 21:02:33 -04:00
TorchedSammy a7722fa331
feat: implement fs 2022-03-28 19:36:06 -04:00
TorchedSammy b887ad4fa9
feat: implement commander 2022-03-28 19:12:58 -04:00
TorchedSammy e466085d24
refactor: move arg handle function to util 2022-03-28 19:12:13 -04:00
TorchedSammy d2d423a4ef
refactor: use util funcs to run lua where possible 2022-03-28 18:58:56 -04:00
TorchedSammy eff942433d
fix!: remove complete global (was supposed to be gone in 1.0) 2022-03-27 21:10:13 -04:00
11 changed files with 185 additions and 137 deletions

47
api.go
View File

@ -22,24 +22,32 @@ import (
)
var exports = map[string]util.LuaExport{
/*"alias": hlalias,
/*
"alias": hlalias,
"appendPath": hlappendPath,
"complete": hlcomplete,
"cwd": hlcwd,
*/
"cwd": util.LuaExport{hlcwd, 0, false},
/*
"exec": hlexec,
"runnerMode": hlrunnerMode,
"goro": hlgoro,
"highlighter": hlhighlighter,
"hinter": hlhinter,
"multiprompt": hlmlprompt,
"prependPath": hlprependPath,*/
"prependPath": hlprependPath,
*/
"prompt": util.LuaExport{hlprompt, 1, false},
/*"inputMode": hlinputMode,
/*
"inputMode": hlinputMode,
"interval": hlinterval,
"read": hlread,
*/
"read": util.LuaExport{hlprompt, 1, false},
/*
"run": hlrun,
"timeout": hltimeout,
"which": hlwhich,*/
"which": hlwhich,
*/
}
var greeting string
@ -69,8 +77,8 @@ Check out the {blue}{bold}guide{reset} command to get started.
util.SetField(L, mod, "ver", lua.LString(version), "Hilbish version")
util.SetField(L, mod, "user", lua.LString(username), "Username of user")
util.SetField(L, mod, "host", lua.LString(host), "Host name of the machine")
util.SetField(L, mod, "home", lua.LString(curuser.HomeDir), "Home directory of the user")
*/
util.SetField(rtm, mod, "home", rt.StringValue(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, "interactive", lua.LBool(interactive), "If this is an interactive shell")
@ -218,37 +226,40 @@ func hlrun(L *lua.LState) int {
L.Push(lua.LNumber(exitcode))
return 1
}
*/
// cwd()
// Returns the current directory of the shell
func hlcwd(L *lua.LState) int {
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
cwd, _ := os.Getwd()
L.Push(lua.LString(cwd))
return 1
return c.PushingNext1(t.Runtime, rt.StringValue(cwd)), nil
}
// read(prompt) -> input?
// Read input from the user, using Hilbish's line editor/input reader.
// 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)
// --- @param prompt string
func hlread(L *lua.LState) int {
luaprompt := L.CheckString(1)
func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
luaprompt, err := c.StringArg(0)
if err != nil {
return nil, err
}
lualr := newLineReader("", true)
lualr.SetPrompt(luaprompt)
input, err := lualr.Read()
if err != nil {
L.Push(lua.LNil)
return 1
return c.Next(), nil
}
L.Push(lua.LString(input))
return 1
return c.PushingNext1(t.Runtime, rt.StringValue(input)), nil
}
*/
/*
prompt(str)

26
exec.go
View File

@ -183,37 +183,27 @@ func execCommand(cmd string) error {
}
// If command is defined in Lua then run it
/*
luacmdArgs := l.NewTable()
for _, str := range args[1:] {
luacmdArgs.Append(lua.LString(str))
luacmdArgs := rt.NewTable()
for i, str := range args[1:] {
luacmdArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(str))
}
if commands[args[0]] != nil {
err := l.CallByParam(lua.P{
Fn: commands[args[0]],
NRet: 1,
Protect: true,
}, luacmdArgs)
luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(commands[args[0]]), rt.TableValue(luacmdArgs))
if err != nil {
fmt.Fprintln(os.Stderr,
"Error in command:\n\n" + err.Error())
return interp.NewExitStatus(1)
}
luaexitcode := l.Get(-1)
var exitcode uint8
l.Pop(1)
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
if code, ok := luaexitcode.TryInt(); ok {
exitcode = uint8(code)
}
} // TODO: deregister commander if return isnt number
return interp.NewExitStatus(exitcode)
}
*/
err := lookpath(args[0])
if err == errNotExec {
@ -447,6 +437,8 @@ func cmdFinish(code uint8, cmdstr string, private bool) {
handleHistory(cmdstr)
}
// util.SetField(l, hshMod, "exitCode", lua.LNumber(code), "Exit code of last exected command")
// using AsValue on an interface which is an int results in it being unknown .... ????
// 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)
}

2
go.mod
View File

@ -20,3 +20,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 layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10
replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20220329005655-c29b74de7d20

2
go.sum
View File

@ -1,3 +1,5 @@
github.com/Rosettea/golua v0.0.0-20220329005655-c29b74de7d20 h1:i4XwNhWKlHP9+oHfpNandGsjj9XQG+uah+SdAjLknbc=
github.com/Rosettea/golua v0.0.0-20220329005655-c29b74de7d20/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE=
github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7 h1:LoY+kBKqMQqBcilRpVvifBTVve84asa3btpx3D/+IvM=
github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs=
github.com/Rosettea/readline-1 v0.0.0-20220305004552-071c22768119 h1:rGsc30WTD5hk+oiXrAKsAIwZn5qBeTAdr29y3HhJh9E=

View File

@ -4,9 +4,9 @@ import (
"fmt"
"hilbish/util"
"github.com/chuckpreslar/emission"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
"github.com/chuckpreslar/emission"
)
type Bait struct{
@ -54,22 +54,6 @@ failed, etc. To find all available hooks, see doc hooks.`)
return rt.TableValue(mod), nil
}
func handleArgs(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
}
catcher, err := c.ClosureArg(1)
if err != nil {
return "", nil, err
}
return name, catcher, err
}
func handleHook(t *rt.Thread, c *rt.GoCont, name string, catcher *rt.Closure, args ...interface{}) {
funcVal := rt.FunctionValue(catcher)
var luaArgs []rt.Value
@ -117,7 +101,7 @@ func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// --- @param name string
// --- @param cb function
func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := handleArgs(t, c)
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
return nil, err
}
@ -134,7 +118,7 @@ func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// --- @param name string
// --- @param cb function
func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := handleArgs(t, c)
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
return nil, err
}

View File

@ -3,52 +3,68 @@ package commander
import (
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
"github.com/chuckpreslar/emission"
"github.com/yuin/gopher-lua"
)
type Commander struct{
Events *emission.Emitter
Loader packagelib.Loader
}
func New() Commander {
return Commander{
c := Commander{
Events: emission.NewEmitter(),
}
c.Loader = packagelib.Loader{
Load: c.LoaderFunc,
Name: "commander",
}
return c
}
func (c *Commander) Loader(L *lua.LState) int {
exports := map[string]lua.LGFunction{
"register": c.cregister,
"deregister": c.cderegister,
func (c *Commander) LoaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
"register": util.LuaExport{c.cregister, 2, false},
"deregister": util.LuaExport{c.cderegister, 1, false},
}
mod := L.SetFuncs(L.NewTable(), exports)
util.Document(L, mod, "Commander is Hilbish's custom command library, a way to write commands in Lua.")
L.Push(mod)
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
// util.Document(L, 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 a command with `name` that runs `cb` when ran
// --- @param name string
// --- @param cb function
func (c *Commander) cregister(L *lua.LState) int {
cmdName := L.CheckString(1)
cmd := L.CheckFunction(2)
func (c *Commander) cregister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
cmdName, cmd, err := util.HandleStrCallback(t, ct)
if err != nil {
return nil, err
}
c.Events.Emit("commandRegister", cmdName, cmd)
return 0
return ct.Next(), err
}
// deregister(name)
// Deregisters any command registered with `name`
// --- @param name string
func (c *Commander) cderegister(L *lua.LState) int {
cmdName := L.CheckString(1)
func (c *Commander) cderegister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
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)
return 0
return ct.Next(), err
}

View File

@ -8,51 +8,71 @@ import (
"strings"
"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 {
mod := L.SetFuncs(L.NewTable(), exports)
var Loader = packagelib.Loader{
Load: LoaderFunc,
Name: "fs",
}
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(L, mod, `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.`)
*/
L.Push(mod)
return 1
}
var exports = map[string]lua.LGFunction{
"cd": fcd,
"mkdir": fmkdir,
"stat": fstat,
"readdir": freaddir,
return rt.TableValue(mod), nil
}
// cd(dir)
// Changes directory to `dir`
// --- @param dir string
func fcd(L *lua.LState) int {
path := L.CheckString(1)
err := os.Chdir(strings.TrimSpace(path))
func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
path, err := c.StringArg(0)
if err != nil {
e := err.(*os.PathError).Err.Error()
L.RaiseError(e + ": " + path)
return nil, err
}
return 0
err = os.Chdir(strings.TrimSpace(path))
if err != nil {
return nil, err
}
return c.Next(), err
}
// mkdir(name, recursive)
// Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
// --- @param name string
// --- @param recursive boolean
func fmkdir(L *lua.LState) int {
dirname := L.CheckString(1)
recursive := L.ToBool(2)
func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(2); err != nil {
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)
var err error
if recursive {
err = os.MkdirAll(path, 0744)
@ -60,51 +80,58 @@ func fmkdir(L *lua.LState) int {
err = os.Mkdir(path, 0744)
}
if err != nil {
L.RaiseError(err.Error() + ": " + path)
return nil, err
}
return 0
return c.Next(), err
}
// stat(path)
// Returns info about `path`
// --- @param path string
func fstat(L *lua.LState) int {
path := L.CheckString(1)
func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
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)
if err != nil {
L.RaiseError(err.Error() + ": " + path)
return 0
return nil, err
}
statTbl := L.NewTable()
L.SetField(statTbl, "name", lua.LString(pathinfo.Name()))
L.SetField(statTbl, "size", lua.LNumber(pathinfo.Size()))
L.SetField(statTbl, "mode", lua.LString("0" + strconv.FormatInt(int64(pathinfo.Mode().Perm()), 8)))
L.SetField(statTbl, "isDir", lua.LBool(pathinfo.IsDir()))
L.Push(statTbl)
return 1
statTbl := rt.NewTable()
statTbl.Set(rt.StringValue("name"), rt.StringValue(pathinfo.Name()))
statTbl.Set(rt.StringValue("size"), rt.IntValue(pathinfo.Size()))
statTbl.Set(rt.StringValue("mode"), rt.StringValue("0" + strconv.FormatInt(int64(pathinfo.Mode().Perm()), 8)))
statTbl.Set(rt.StringValue("isDir"), rt.BoolValue(pathinfo.IsDir()))
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
}
// readdir(dir)
// Returns a table of files in `dir`
// --- @param dir string
// --- @return table
func freaddir(L *lua.LState) int {
dir := L.CheckString(1)
names := L.NewTable()
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
dir, err := c.StringArg(0)
if err != nil {
return nil, err
}
names := rt.NewTable()
dirEntries, err := os.ReadDir(dir)
if err != nil {
L.RaiseError(err.Error() + ": " + dir)
return 0
return nil, err
}
for _, entry := range dirEntries {
names.Append(lua.LString(entry.Name()))
for i, entry := range dirEntries {
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
}
L.Push(names)
return 1
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
}

32
lua.go
View File

@ -6,9 +6,9 @@ import (
"hilbish/util"
"hilbish/golibs/bait"
/*
"hilbish/golibs/commander"
"hilbish/golibs/fs"
/*
"hilbish/golibs/terminal"
*/
rt "github.com/arnodel/golua/runtime"
@ -23,24 +23,23 @@ func luaInit() {
lib.LoadLibs(l, hilbishLoader)
// yes this is stupid, i know
chunk, _ := l.CompileAndLoadLuaChunk("", []byte("hilbish = require 'hilbish'"), rt.TableValue(l.GlobalEnv()))
_, err := rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
fmt.Println("hsh load", err)
util.DoString(l, "hilbish = require 'hilbish'")
// Add fs and terminal module module to Lua
/* l.PreloadModule("fs", fs.Loader)
lib.LoadLibs(l, fs.Loader)
/*
l.PreloadModule("terminal", terminal.Loader)
*/
cmds := commander.New()
// 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
})
cmds.Events.On("commandDeregister", func(cmdName string) {
delete(commands, cmdName)
})
l.PreloadModule("commander", cmds.Loader)
*/
lib.LoadLibs(l, cmds.Loader)
hooks = bait.New()
lib.LoadLibs(l, hooks.Loader)
@ -53,20 +52,19 @@ func luaInit() {
})
// Add more paths that Lua can require from
chunk, _ = l.CompileAndLoadLuaChunk("", []byte("package.path = package.path .. " + requirePaths), rt.TableValue(l.GlobalEnv()))
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
fmt.Println("package path", err)
data, err := os.ReadFile("prelude/init.lua")
err := util.DoString(l, "package.path = package.path .. " + requirePaths)
if err != nil {
data, err = os.ReadFile(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 {
fmt.Fprintln(os.Stderr, "Missing preload file, builtins may be missing.")
}
}
chunk, _ = l.CompileAndLoadLuaChunk("", data, rt.TableValue(l.GlobalEnv()))
_, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk))
fmt.Println("prelude", err)
fmt.Println(err)
}
func runConfig(confpath string) {

View File

@ -23,7 +23,7 @@ var (
l *rt.Runtime
lr *lineReader
commands = map[string]*lua.LFunction{}
commands = map[string]*rt.Closure{}
luaCompletions = map[string]*lua.LFunction{}
confDir string

View File

@ -8,7 +8,7 @@ local _ = require 'succulent' -- Function additions
local oldDir = hilbish.cwd()
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
local recentDirs = {}

View File

@ -55,3 +55,19 @@ func DoFile(rtm *rt.Runtime, filename string) error {
return DoString(rtm, string(data))
}
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
}