Compare commits

..

8 Commits

Author SHA1 Message Date
TorchedSammy 0a5a2e727e
feat: add hilbish properties 2022-03-29 23:37:53 -04:00
TorchedSammy 8714f54915
feat: implement job management 2022-03-29 21:43:36 -04:00
TorchedSammy c46807613e
refactor: make loader functions for go modules unexported 2022-03-29 21:05:46 -04:00
TorchedSammy a45b3fe1fa
chore: fix dofile comment doc 2022-03-29 21:04:50 -04:00
TorchedSammy 245400e43d
chore: add comments to document util functions 2022-03-29 21:02:15 -04:00
TorchedSammy 6848b59cbf
feat: implement syntax highlight and hints 2022-03-29 20:57:29 -04:00
TorchedSammy ad183a7208
style: use comma separated cases instead of fallthrough 2022-03-29 20:57:05 -04:00
TorchedSammy 3bea73460a
feat: implement runner mode 2022-03-29 20:16:03 -04:00
11 changed files with 167 additions and 157 deletions

View File

@ -66,13 +66,14 @@ func (a *aliasHandler) Resolve(cmdstr string) string {
// lua section
func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
// create a lua module with our functions
hshaliasesLua := map[string]util.LuaExport{
"add": util.LuaExport{a.luaAdd, 2, false},
"list": util.LuaExport{a.luaList, 0, false},
"del": util.LuaExport{a.luaDelete, 1, false},
}
mod := rt.NewTable()
util.SetExports(rtm, mod, hshaliasesLua)

101
api.go
View File

@ -31,10 +31,14 @@ var exports = map[string]util.LuaExport{
"cwd": util.LuaExport{hlcwd, 0, false},
/*
"exec": hlexec,
"runnerMode": hlrunnerMode,
*/
"runnerMode": util.LuaExport{hlrunnerMode, 1, false},
/*
"goro": hlgoro,
"highlighter": hlhighlighter,
"hinter": hlhinter,
*/
"highlighter": util.LuaExport{hlhighlighter, 1, false},
"hinter": util.LuaExport{hlhinter, 1, false},
/*
"multiprompt": hlmlprompt,
"prependPath": hlprependPath,
*/
@ -61,7 +65,7 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
util.SetExports(rtm, mod, exports)
hshMod = mod
// host, _ := os.Hostname()
host, _ := os.Hostname()
username := curuser.Username
if runtime.GOOS == "windows" {
@ -72,22 +76,17 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
The nice lil shell for {blue}Lua{reset} fanatics!
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(rtm, mod, "ver", rt.StringValue(version), "Hilbish version")
util.SetField(rtm, mod, "user", rt.StringValue(username), "Username of user")
util.SetField(rtm, mod, "host", rt.StringValue(host), "Host name of the machine")
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")
util.SetField(L, mod, "login", lua.LBool(interactive), "Whether this is a login shell")
*/
util.SetField(rtm, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive shell")
util.SetField(rtm, mod, "login", rt.BoolValue(login), "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, "vimMode", lua.LNil, "Current Vim mode of Hilbish (nil if not in Vim mode)")
util.SetField(l, hshMod, "exitCode", lua.LNumber(0), "Exit code of last exected command")
util.Document(L, mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
*/
util.SetField(rtm, mod, "vimMode", rt.NilValue, "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.Document(rtm, mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
// hilbish.userDir table
hshuser := rt.NewTable()
@ -129,19 +128,17 @@ Check out the {blue}{bold}guide{reset} command to get started.
util.Document(L, hshcomp, "Completions interface for Hilbish.")
L.SetField(mod, "completion", hshcomp)
// hilbish.runner table
runnerModule := runnerModeLoader(L)
util.Document(L, runnerModule, "Runner/exec interface for Hilbish.")
L.SetField(mod, "runner", runnerModule)
*/
// hilbish.runner table
runnerModule := runnerModeLoader(rtm)
//util.Document(L, runnerModule, "Runner/exec interface for Hilbish.")
mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule))
// hilbish.jobs table
jobs = newJobHandler()
/*
jobModule := jobs.loader(L)
util.Document(L, jobModule, "(Background) job interface.")
L.SetField(mod, "jobs", jobModule)
*/
jobModule := jobs.loader(rtm)
// util.Document(L, jobModule, "(Background) job interface.")
mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
return rt.TableValue(mod), nil
}
@ -545,7 +542,6 @@ func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
/*
// runnerMode(mode)
// Sets the execution/runner mode for interactive Hilbish. This determines whether
// Hilbish wll try to run input as Lua and/or sh or only do one of either.
@ -553,24 +549,24 @@ func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// sh, and lua. It also accepts a function, to which if it is passed one
// will call it to execute user input instead.
// --- @param mode string|function
func hlrunnerMode(L *lua.LState) int {
mode := L.CheckAny(1)
func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
mode := c.Arg(0)
switch mode.Type() {
case lua.LTString:
switch mode.String() {
case rt.StringType:
switch mode.AsString() {
// no fallthrough doesnt work so eh
case "hybrid": fallthrough
case "hybridRev": fallthrough
case "lua": fallthrough
case "sh":
runnerMode = mode
default: L.RaiseError("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received %v", mode)
case "hybrid", "hybridRev", "lua", "sh": runnerMode = mode
default: return nil, errors.New("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received " + mode.AsString())
}
case lua.LTFunction: runnerMode = mode
default: L.RaiseError("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received %v", mode)
case rt.FunctionType: runnerMode = 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)
@ -579,11 +575,17 @@ func hlrunnerMode(L *lua.LState) int {
// the current line and the position. It is expected to return a string
// which will be used for the hint.
// --- @param cb function
func hlhinter(L *lua.LState) int {
hinterCb := L.CheckFunction(1)
func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
hinterCb, err := c.ClosureArg(0)
if err != nil {
return nil, err
}
hinter = hinterCb
return 0
return c.Next(), err
}
// highlighter(cb)
@ -592,10 +594,15 @@ func hlhinter(L *lua.LState) int {
// is passed the current line as typed and is expected to return a line that will
// be used to display in the line.
// --- @param cb function
func hlhighlighter(L *lua.LState) int {
highlighterCb := L.CheckFunction(1)
func hlhighlighter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
highlighterCb, err := c.ClosureArg(0)
if err != nil {
return nil, err
}
highlighter = highlighterCb
return 0
return c.Next(), err
}
*/

28
exec.go
View File

@ -24,15 +24,15 @@ import (
)
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) {
running = true
cmdString := aliases.Resolve(input)
hooks.Em.Emit("command.preexec", input, cmdString)
// if runnerMode.Type() == lua.LTString {
switch /*runnerMode.String()*/ "hybrid" {
if runnerMode.Type() == rt.StringType {
switch runnerMode.AsString() {
case "hybrid":
_, err := handleLua(cmdString)
if err == nil {
@ -68,35 +68,29 @@ func runInput(input string, priv bool) {
}
cmdFinish(exitCode, cmdString, priv)
}
// } else {
} else {
// can only be a string or function so
/*
err := l.CallByParam(lua.P{
Fn: runnerMode,
NRet: 2,
Protect: true,
}, lua.LString(cmdString))
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false)
err := rt.Call(l.MainThread(), runnerMode, []rt.Value{rt.StringValue(cmdString)}, term)
if err != nil {
fmt.Fprintln(os.Stderr, err)
cmdFinish(124, cmdString, priv)
return
}
luaexitcode := l.Get(-2) // first return value (makes sense right i love stacks)
runErr := l.Get(-1)
l.Pop(2)
luaexitcode := term.Get(0) // first return value (makes sense right i love stacks)
runErr := term.Get(1)
var exitCode uint8
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
if code, ok := luaexitcode.TryInt(); ok {
exitCode = uint8(code)
}
if runErr != lua.LNil {
if runErr != rt.NilValue {
fmt.Fprintln(os.Stderr, runErr)
}
cmdFinish(exitCode, cmdString, priv)
*/
// }
}
}
func handleLua(cmdString string) (uint8, error) {

View File

@ -24,14 +24,14 @@ func New() Bait {
Em: emitter,
}
b.Loader = packagelib.Loader{
Load: b.LoaderFunc,
Load: b.loaderFunc,
Name: "bait",
}
return b
}
func (b *Bait) LoaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{
"catch": util.LuaExport{b.bcatch, 2, false},
"catchOnce": util.LuaExport{b.bcatchOnce, 2, false},

View File

@ -18,14 +18,14 @@ func New() Commander {
Events: emission.NewEmitter(),
}
c.Loader = packagelib.Loader{
Load: c.LoaderFunc,
Load: c.loaderFunc,
Name: "commander",
}
return c
}
func (c *Commander) LoaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
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},

View File

@ -12,11 +12,11 @@ import (
)
var Loader = packagelib.Loader{
Load: LoaderFunc,
Load: loaderFunc,
Name: "fs",
}
func LoaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
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},

79
job.go
View File

@ -3,6 +3,10 @@ package main
import (
"sync"
"os"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
)
var jobs *jobHandler
@ -19,7 +23,7 @@ type job struct {
func (j *job) start(pid int) {
j.pid = pid
j.running = true
// hooks.Em.Emit("job.start", j.lua())
hooks.Em.Emit("job.start", j.lua())
}
func (j *job) stop() {
@ -29,39 +33,36 @@ func (j *job) stop() {
func (j *job) finish() {
j.running = false
// hooks.Em.Emit("job.done", j.lua())
hooks.Em.Emit("job.done", j.lua())
}
func (j *job) setHandle(handle *os.Process) {
j.proc = handle
}
/*
func (j *job) lua() *lua.LTable {
// returns lua table for job
// because userdata is gross
jobFuncs := map[string]lua.LGFunction{
"stop": j.luaStop,
func (j *job) lua() rt.Value {
jobFuncs := map[string]util.LuaExport{
"stop": {j.luaStop, 0, false},
}
luaJob := l.SetFuncs(l.NewTable(), jobFuncs)
luaJob := rt.NewTable()
util.SetExports(l, luaJob, jobFuncs)
l.SetField(luaJob, "cmd", lua.LString(j.cmd))
l.SetField(luaJob, "running", lua.LBool(j.running))
l.SetField(luaJob, "id", lua.LNumber(j.id))
l.SetField(luaJob, "pid", lua.LNumber(j.pid))
l.SetField(luaJob, "exitCode", lua.LNumber(j.exitCode))
luaJob.Set(rt.StringValue("cmd"), rt.StringValue(j.cmd))
luaJob.Set(rt.StringValue("running"), rt.BoolValue(j.running))
luaJob.Set(rt.StringValue("id"), rt.IntValue(int64(j.id)))
luaJob.Set(rt.StringValue("pid"), rt.IntValue(int64(j.pid)))
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 {
j.stop()
}
return 0
return c.Next(), nil
}
*/
type jobHandler struct {
jobs map[int]*job
@ -96,42 +97,46 @@ func (j *jobHandler) getLatest() *job {
return j.jobs[j.latestID]
}
/*
func (j *jobHandler) loader(L *lua.LState) *lua.LTable {
jobFuncs := map[string]lua.LGFunction{
"all": j.luaAllJobs,
"get": j.luaGetJob,
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
jobFuncs := map[string]util.LuaExport{
"all": {j.luaAllJobs, 0, false},
"get": {j.luaGetJob, 1, false},
}
luaJob := l.SetFuncs(l.NewTable(), jobFuncs)
luaJob := rt.NewTable()
util.SetExports(rtm, luaJob, jobFuncs)
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()
defer j.mu.RUnlock()
jobID := L.CheckInt(1)
job := j.jobs[jobID]
if job != nil {
return 0
if err := c.Check1Arg(); err != nil {
return nil, err
}
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()
defer j.mu.RUnlock()
jobTbl := L.NewTable()
jobTbl := rt.NewTable()
for id, job := range j.jobs {
jobTbl.Insert(id, job.lua())
jobTbl.Set(rt.IntValue(int64(id)), job.lua())
}
L.Push(jobTbl)
return 1
return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil
}
*/

36
rl.go
View File

@ -13,10 +13,8 @@ type lineReader struct {
rl *readline.Instance
}
var fileHist *fileHistory
/*
var hinter lua.LValue = lua.LNil
var highlighter lua.LValue = lua.LNil
*/
var hinter *rt.Closure
var highlighter *rt.Closure
func newLineReader(prompt string, noHist bool) *lineReader {
rl := readline.NewInstance()
@ -47,53 +45,43 @@ func newLineReader(prompt string, noHist bool) *lineReader {
}
hooks.Em.Emit("hilbish.vimAction", actionStr, args)
}
/*
rl.HintText = func(line []rune, pos int) []rune {
if hinter == lua.LNil {
if hinter == nil {
return []rune{}
}
err := l.CallByParam(lua.P{
Fn: hinter,
NRet: 1,
Protect: true,
}, lua.LString(string(line)), lua.LNumber(pos))
retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(highlighter),
rt.StringValue(string(line)), rt.IntValue(int64(pos)))
if err != nil {
fmt.Println(err)
return []rune{}
}
retVal := l.Get(-1)
hintText := ""
if luaStr, ok := retVal.(lua.LString); retVal != lua.LNil && ok {
hintText = luaStr.String()
if luaStr, ok := retVal.TryString(); ok {
hintText = luaStr
}
return []rune(hintText)
}
rl.SyntaxHighlighter = func(line []rune) string {
if highlighter == lua.LNil {
if highlighter == nil {
return string(line)
}
err := l.CallByParam(lua.P{
Fn: highlighter,
NRet: 1,
Protect: true,
}, lua.LString(string(line)))
retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(highlighter),
rt.StringValue(string(line)))
if err != nil {
fmt.Println(err)
return string(line)
}
retVal := l.Get(-1)
highlighted := ""
if luaStr, ok := retVal.(lua.LString); retVal != lua.LNil && ok {
highlighted = luaStr.String()
if luaStr, ok := retVal.TryString(); ok {
highlighted = luaStr
}
return highlighted
}
*/
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
ctx := string(line)
var completions []string

View File

@ -1,47 +1,56 @@
package main
/*
import (
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
)
func runnerModeLoader(L *lua.LState) *lua.LTable {
exports := map[string]lua.LGFunction{
"sh": shRunner,
"lua": luaRunner,
"setMode": hlrunnerMode,
func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
"sh": {shRunner, 1, false},
"lua": {luaRunner, 1, false},
"setMode": {hlrunnerMode, 1, false},
}
mod := L.SetFuncs(L.NewTable(), exports)
L.SetField(mod, "mode", runnerMode)
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
return mod
}
func shRunner(L *lua.LState) int {
cmd := L.CheckString(1)
func shRunner(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
}
exitCode, err := handleSh(cmd)
var luaErr lua.LValue = lua.LNil
var luaErr rt.Value = rt.NilValue
if err != nil {
luaErr = lua.LString(err.Error())
luaErr = rt.StringValue(err.Error())
}
L.Push(lua.LNumber(exitCode))
L.Push(luaErr)
return 2
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitCode)), luaErr), nil
}
func luaRunner(L *lua.LState) int {
cmd := L.CheckString(1)
func luaRunner(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
}
exitCode, err := handleLua(cmd)
var luaErr lua.LValue = lua.LNil
var luaErr rt.Value = rt.NilValue
if err != nil {
luaErr = lua.LString(err.Error())
luaErr = rt.StringValue(err.Error())
}
L.Push(lua.LNumber(exitCode))
L.Push(luaErr)
return 2
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitCode)), luaErr), nil
}
*/

View File

@ -4,12 +4,14 @@ 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)

View File

@ -39,6 +39,7 @@ func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, d
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("", []byte(code), rt.TableValue(rtm.GlobalEnv()))
if chunk != nil {
@ -48,6 +49,7 @@ func DoString(rtm *rt.Runtime, code string) error {
return err
}
// DoFile runs the contents of the file in the Lua runtime.
func DoFile(rtm *rt.Runtime, filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
@ -57,6 +59,8 @@ func DoFile(rtm *rt.Runtime, filename string) error {
return DoString(rtm, string(data))
}
// 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