mirror of https://github.com/Hilbis/Hilbish
refactor!: move global functions to the hilbish module
its more organized this way and the `hilbish` lua module is now what global was before anyway a feature in this commit also is that `goro` now allows passing any amount of args to the calling functionwindows-fixes
parent
ea9c3eac30
commit
f2a2ac44d6
197
api.go
197
api.go
|
@ -4,10 +4,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
|
@ -17,10 +21,18 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var exports = map[string]lua.LGFunction {
|
var exports = map[string]lua.LGFunction {
|
||||||
"run": hlrun,
|
"alias": hlalias,
|
||||||
"flag": hlflag,
|
"appendPath": hlappendPath,
|
||||||
"cwd": hlcwd,
|
"cwd": hlcwd,
|
||||||
|
"exec": hlexec,
|
||||||
|
"flag": hlflag,
|
||||||
|
"multiprompt": hlmlprompt,
|
||||||
|
"prependPath": hlprependPath,
|
||||||
|
"prompt": hlprompt,
|
||||||
|
"interval": hlinterval,
|
||||||
"read": hlread,
|
"read": hlread,
|
||||||
|
"run": hlrun,
|
||||||
|
"timeout": hltimeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
var greeting string
|
var greeting string
|
||||||
|
@ -147,3 +159,184 @@ func hlread(L *lua.LState) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* prompt(str)
|
||||||
|
Changes the shell prompt to `str`
|
||||||
|
There are a few verbs that can be used in the prompt text.
|
||||||
|
These will be formatted and replaced with the appropriate values.
|
||||||
|
`%d` - Current working directory
|
||||||
|
`%u` - Name of current user
|
||||||
|
`%h` - Hostname of device */
|
||||||
|
func hlprompt(L *lua.LState) int {
|
||||||
|
prompt = L.CheckString(1)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiprompt(str)
|
||||||
|
// Changes the continued line prompt to `str`
|
||||||
|
func hlmlprompt(L *lua.LState) int {
|
||||||
|
multilinePrompt = L.CheckString(1)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// alias(cmd, orig)
|
||||||
|
// Sets an alias of `orig` to `cmd`
|
||||||
|
func hlalias(L *lua.LState) int {
|
||||||
|
alias := L.CheckString(1)
|
||||||
|
source := L.CheckString(2)
|
||||||
|
|
||||||
|
aliases.Add(alias, source)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendPath(dir)
|
||||||
|
// Appends `dir` to $PATH
|
||||||
|
func hlappendPath(L *lua.LState) int {
|
||||||
|
// check if dir is a table or a string
|
||||||
|
arg := L.Get(1)
|
||||||
|
fmt.Println(arg.Type())
|
||||||
|
if arg.Type() == lua.LTTable {
|
||||||
|
arg.(*lua.LTable).ForEach(func(k lua.LValue, v lua.LValue) {
|
||||||
|
appendPath(v.String())
|
||||||
|
})
|
||||||
|
} else if arg.Type() == lua.LTString {
|
||||||
|
appendPath(arg.String())
|
||||||
|
} else {
|
||||||
|
L.RaiseError("bad argument to appendPath (expected string or table, got %v)", L.Get(1).Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendPath(dir string) {
|
||||||
|
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
|
||||||
|
pathenv := os.Getenv("PATH")
|
||||||
|
|
||||||
|
// if dir isnt already in $PATH, add it
|
||||||
|
if !strings.Contains(pathenv, dir) {
|
||||||
|
os.Setenv("PATH", pathenv + string(os.PathListSeparator) + dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// exec(cmd)
|
||||||
|
// Replaces running hilbish with `cmd`
|
||||||
|
func hlexec(L *lua.LState) int {
|
||||||
|
cmd := L.CheckString(1)
|
||||||
|
cmdArgs, _ := splitInput(cmd)
|
||||||
|
cmdPath, err := exec.LookPath(cmdArgs[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
// if we get here, cmdPath will be nothing
|
||||||
|
// therefore nothing will run
|
||||||
|
}
|
||||||
|
|
||||||
|
// syscall.Exec requires an absolute path to a binary
|
||||||
|
// path, args, string slice of environments
|
||||||
|
// TODO: alternative for windows
|
||||||
|
syscall.Exec(cmdPath, cmdArgs, os.Environ())
|
||||||
|
return 0 // random thought: does this ever return?
|
||||||
|
}
|
||||||
|
|
||||||
|
// goro(fn)
|
||||||
|
// Puts `fn` in a goroutine
|
||||||
|
func hlgoroutine(L *lua.LState) int {
|
||||||
|
fn := L.CheckFunction(1)
|
||||||
|
argnum := L.GetTop()
|
||||||
|
args := make([]lua.LValue, argnum)
|
||||||
|
for i := 1; i <= argnum; i++ {
|
||||||
|
args[i - 1] = L.Get(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// call fn
|
||||||
|
go func() {
|
||||||
|
L.CallByParam(lua.P{
|
||||||
|
Fn: fn,
|
||||||
|
NRet: 0,
|
||||||
|
Protect: true,
|
||||||
|
}, args...)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeout(cb, time)
|
||||||
|
// Runs the `cb` function after `time` in milliseconds
|
||||||
|
func hltimeout(L *lua.LState) int {
|
||||||
|
cb := L.CheckFunction(1)
|
||||||
|
ms := L.CheckInt(2)
|
||||||
|
|
||||||
|
timeout := time.Duration(ms) * time.Millisecond
|
||||||
|
time.Sleep(timeout)
|
||||||
|
|
||||||
|
L.CallByParam(lua.P{
|
||||||
|
Fn: cb,
|
||||||
|
NRet: 0,
|
||||||
|
Protect: true,
|
||||||
|
})
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// interval(cb, time)
|
||||||
|
// Runs the `cb` function every `time` milliseconds
|
||||||
|
func hlinterval(L *lua.LState) int {
|
||||||
|
intervalfunc := L.CheckFunction(1)
|
||||||
|
ms := L.CheckInt(2)
|
||||||
|
interval := time.Duration(ms) * time.Millisecond
|
||||||
|
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
stop := make(chan lua.LValue)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if err := L.CallByParam(lua.P{
|
||||||
|
Fn: intervalfunc,
|
||||||
|
NRet: 0,
|
||||||
|
Protect: true,
|
||||||
|
}); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error in interval function:\n\n", err)
|
||||||
|
stop <- lua.LTrue // stop the interval
|
||||||
|
}
|
||||||
|
case <-stop:
|
||||||
|
ticker.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
L.Push(lua.LChannel(stop))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete(scope, cb)
|
||||||
|
// Registers a completion handler for `scope`.
|
||||||
|
// A `scope` is currently only expected to be `command.<cmd>`,
|
||||||
|
// replacing <cmd> with the name of the command (for example `command.git`).
|
||||||
|
// `cb` must be a function that returns a table of the entries to complete.
|
||||||
|
// Nested tables will be used as sub-completions.
|
||||||
|
func hlcomplete(L *lua.LState) int {
|
||||||
|
scope := L.CheckString(1)
|
||||||
|
cb := L.CheckFunction(2)
|
||||||
|
|
||||||
|
luaCompletions[scope] = cb
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// prependPath(dir)
|
||||||
|
// Prepends `dir` to $PATH
|
||||||
|
func hlprependPath(L *lua.LState) int {
|
||||||
|
dir := L.CheckString(1)
|
||||||
|
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
|
||||||
|
pathenv := os.Getenv("PATH")
|
||||||
|
|
||||||
|
// if dir isnt already in $PATH, add in
|
||||||
|
if !strings.Contains(pathenv, dir) {
|
||||||
|
os.Setenv("PATH", dir + string(os.PathListSeparator) + pathenv)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
alias(cmd, orig) > Sets an alias of `orig` to `cmd`
|
|
||||||
|
|
||||||
appendPath(dir) > Appends `dir` to $PATH
|
|
||||||
|
|
||||||
complete(scope, cb) > Registers a completion handler for `scope`.
|
|
||||||
A `scope` is currently only expected to be `command.<cmd>`,
|
|
||||||
replacing <cmd> with the name of the command (for example `command.git`).
|
|
||||||
`cb` must be a function that returns a table of the entries to complete.
|
|
||||||
Nested tables will be used as sub-completions.
|
|
||||||
|
|
||||||
exec(cmd) > Replaces running hilbish with `cmd`
|
|
||||||
|
|
||||||
goro(fn) > Puts `fn` in a goroutine
|
|
||||||
|
|
||||||
interval(cb, time) > Runs the `cb` function every `time` milliseconds
|
|
||||||
|
|
||||||
multiprompt(str) > Changes the continued line prompt to `str`
|
|
||||||
|
|
||||||
prependPath(dir) > Prepends `dir` to $PATH
|
|
||||||
|
|
||||||
prompt(str) > Changes the shell prompt to `str`
|
|
||||||
There are a few verbs that can be used in the prompt text.
|
|
||||||
These will be formatted and replaced with the appropriate values.
|
|
||||||
`%d` - Current working directory
|
|
||||||
`%u` - Name of current user
|
|
||||||
`%h` - Hostname of device
|
|
||||||
|
|
||||||
timeout(cb, time) > Runs the `cb` function after `time` in milliseconds
|
|
||||||
|
|
|
@ -1,10 +1,39 @@
|
||||||
|
alias(cmd, orig) > Sets an alias of `orig` to `cmd`
|
||||||
|
|
||||||
|
appendPath(dir) > Appends `dir` to $PATH
|
||||||
|
|
||||||
|
complete(scope, cb) > Registers a completion handler for `scope`.
|
||||||
|
A `scope` is currently only expected to be `command.<cmd>`,
|
||||||
|
replacing <cmd> with the name of the command (for example `command.git`).
|
||||||
|
`cb` must be a function that returns a table of the entries to complete.
|
||||||
|
Nested tables will be used as sub-completions.
|
||||||
|
|
||||||
cwd() > Returns the current directory of the shell
|
cwd() > Returns the current directory of the shell
|
||||||
|
|
||||||
|
exec(cmd) > Replaces running hilbish with `cmd`
|
||||||
|
|
||||||
flag(f) > Checks if the `f` flag has been passed to Hilbish.
|
flag(f) > Checks if the `f` flag has been passed to Hilbish.
|
||||||
|
|
||||||
|
goro(fn) > Puts `fn` in a goroutine
|
||||||
|
|
||||||
|
interval(cb, time) > Runs the `cb` function every `time` milliseconds
|
||||||
|
|
||||||
|
multiprompt(str) > Changes the continued line prompt to `str`
|
||||||
|
|
||||||
|
prependPath(dir) > Prepends `dir` to $PATH
|
||||||
|
|
||||||
|
prompt(str) > Changes the shell prompt to `str`
|
||||||
|
There are a few verbs that can be used in the prompt text.
|
||||||
|
These will be formatted and replaced with the appropriate values.
|
||||||
|
`%d` - Current working directory
|
||||||
|
`%u` - Name of current user
|
||||||
|
`%h` - Hostname of device
|
||||||
|
|
||||||
read(prompt) -> input? > Read input from the user, using Hilbish's line editor/input reader.
|
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.
|
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) > Runs `cmd` in Hilbish's sh interpreter.
|
||||||
|
|
||||||
|
timeout(cb, time) > Runs the `cb` function after `time` in milliseconds
|
||||||
|
|
||||||
|
|
173
lua.go
173
lua.go
|
@ -3,10 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"hilbish/golibs/bait"
|
"hilbish/golibs/bait"
|
||||||
"hilbish/golibs/commander"
|
"hilbish/golibs/commander"
|
||||||
|
@ -14,7 +10,6 @@ import (
|
||||||
"hilbish/golibs/terminal"
|
"hilbish/golibs/terminal"
|
||||||
|
|
||||||
"github.com/yuin/gopher-lua"
|
"github.com/yuin/gopher-lua"
|
||||||
"layeh.com/gopher-luar"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var minimalconf = `prompt '& '`
|
var minimalconf = `prompt '& '`
|
||||||
|
@ -23,16 +18,6 @@ func luaInit() {
|
||||||
l = lua.NewState()
|
l = lua.NewState()
|
||||||
l.OpenLibs()
|
l.OpenLibs()
|
||||||
|
|
||||||
l.SetGlobal("prompt", l.NewFunction(hshprompt))
|
|
||||||
l.SetGlobal("multiprompt", l.NewFunction(hshmlprompt))
|
|
||||||
l.SetGlobal("alias", l.NewFunction(hshalias))
|
|
||||||
l.SetGlobal("appendPath", l.NewFunction(hshappendPath))
|
|
||||||
l.SetGlobal("prependPath", l.NewFunction(hshprependPath))
|
|
||||||
l.SetGlobal("exec", l.NewFunction(hshexec))
|
|
||||||
l.SetGlobal("goro", luar.New(l, hshgoroutine))
|
|
||||||
l.SetGlobal("timeout", luar.New(l, hshtimeout))
|
|
||||||
l.SetGlobal("interval", l.NewFunction(hshinterval))
|
|
||||||
|
|
||||||
// yes this is stupid, i know
|
// yes this is stupid, i know
|
||||||
l.PreloadModule("hilbish", hilbishLoader)
|
l.PreloadModule("hilbish", hilbishLoader)
|
||||||
l.DoString("hilbish = require 'hilbish'")
|
l.DoString("hilbish = require 'hilbish'")
|
||||||
|
@ -61,7 +46,7 @@ func luaInit() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
l.SetGlobal("complete", l.NewFunction(hshcomplete))
|
l.SetGlobal("complete", l.NewFunction(hlcomplete))
|
||||||
|
|
||||||
// Add more paths that Lua can require from
|
// Add more paths that Lua can require from
|
||||||
l.DoString("package.path = package.path .. " + requirePaths)
|
l.DoString("package.path = package.path .. " + requirePaths)
|
||||||
|
@ -102,159 +87,3 @@ func runLogin() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prompt(str)
|
|
||||||
Changes the shell prompt to `str`
|
|
||||||
There are a few verbs that can be used in the prompt text.
|
|
||||||
These will be formatted and replaced with the appropriate values.
|
|
||||||
`%d` - Current working directory
|
|
||||||
`%u` - Name of current user
|
|
||||||
`%h` - Hostname of device */
|
|
||||||
func hshprompt(L *lua.LState) int {
|
|
||||||
prompt = L.CheckString(1)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiprompt(str)
|
|
||||||
// Changes the continued line prompt to `str`
|
|
||||||
func hshmlprompt(L *lua.LState) int {
|
|
||||||
multilinePrompt = L.CheckString(1)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// alias(cmd, orig)
|
|
||||||
// Sets an alias of `orig` to `cmd`
|
|
||||||
func hshalias(L *lua.LState) int {
|
|
||||||
alias := L.CheckString(1)
|
|
||||||
source := L.CheckString(2)
|
|
||||||
|
|
||||||
aliases.Add(alias, source)
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendPath(dir)
|
|
||||||
// Appends `dir` to $PATH
|
|
||||||
func hshappendPath(L *lua.LState) int {
|
|
||||||
// check if dir is a table or a string
|
|
||||||
arg := L.Get(1)
|
|
||||||
fmt.Println(arg.Type())
|
|
||||||
if arg.Type() == lua.LTTable {
|
|
||||||
arg.(*lua.LTable).ForEach(func(k lua.LValue, v lua.LValue) {
|
|
||||||
appendPath(v.String())
|
|
||||||
})
|
|
||||||
} else if arg.Type() == lua.LTString {
|
|
||||||
appendPath(arg.String())
|
|
||||||
} else {
|
|
||||||
L.RaiseError("bad argument to appendPath (expected string or table, got %v)", L.Get(1).Type().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendPath(dir string) {
|
|
||||||
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
|
|
||||||
pathenv := os.Getenv("PATH")
|
|
||||||
|
|
||||||
// if dir isnt already in $PATH, add it
|
|
||||||
if !strings.Contains(pathenv, dir) {
|
|
||||||
os.Setenv("PATH", pathenv + string(os.PathListSeparator) + dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// exec(cmd)
|
|
||||||
// Replaces running hilbish with `cmd`
|
|
||||||
func hshexec(L *lua.LState) int {
|
|
||||||
cmd := L.CheckString(1)
|
|
||||||
cmdArgs, _ := splitInput(cmd)
|
|
||||||
cmdPath, err := exec.LookPath(cmdArgs[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
// if we get here, cmdPath will be nothing
|
|
||||||
// therefore nothing will run
|
|
||||||
}
|
|
||||||
|
|
||||||
// syscall.Exec requires an absolute path to a binary
|
|
||||||
// path, args, string slice of environments
|
|
||||||
// TODO: alternative for windows
|
|
||||||
syscall.Exec(cmdPath, cmdArgs, os.Environ())
|
|
||||||
return 0 // random thought: does this ever return?
|
|
||||||
}
|
|
||||||
|
|
||||||
// goro(fn)
|
|
||||||
// Puts `fn` in a goroutine
|
|
||||||
func hshgoroutine(gofunc func()) {
|
|
||||||
go gofunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// timeout(cb, time)
|
|
||||||
// Runs the `cb` function after `time` in milliseconds
|
|
||||||
func hshtimeout(timeoutfunc func(), ms int) {
|
|
||||||
timeout := time.Duration(ms) * time.Millisecond
|
|
||||||
time.Sleep(timeout)
|
|
||||||
timeoutfunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// interval(cb, time)
|
|
||||||
// Runs the `cb` function every `time` milliseconds
|
|
||||||
func hshinterval(L *lua.LState) int {
|
|
||||||
intervalfunc := L.CheckFunction(1)
|
|
||||||
ms := L.CheckInt(2)
|
|
||||||
interval := time.Duration(ms) * time.Millisecond
|
|
||||||
|
|
||||||
ticker := time.NewTicker(interval)
|
|
||||||
stop := make(chan lua.LValue)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
if err := L.CallByParam(lua.P{
|
|
||||||
Fn: intervalfunc,
|
|
||||||
NRet: 0,
|
|
||||||
Protect: true,
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error in interval function:\n\n", err)
|
|
||||||
stop <- lua.LTrue // stop the interval
|
|
||||||
}
|
|
||||||
case <-stop:
|
|
||||||
ticker.Stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
L.Push(lua.LChannel(stop))
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// complete(scope, cb)
|
|
||||||
// Registers a completion handler for `scope`.
|
|
||||||
// A `scope` is currently only expected to be `command.<cmd>`,
|
|
||||||
// replacing <cmd> with the name of the command (for example `command.git`).
|
|
||||||
// `cb` must be a function that returns a table of the entries to complete.
|
|
||||||
// Nested tables will be used as sub-completions.
|
|
||||||
func hshcomplete(L *lua.LState) int {
|
|
||||||
scope := L.CheckString(1)
|
|
||||||
cb := L.CheckFunction(2)
|
|
||||||
|
|
||||||
luaCompletions[scope] = cb
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// prependPath(dir)
|
|
||||||
// Prepends `dir` to $PATH
|
|
||||||
func hshprependPath(L *lua.LState) int {
|
|
||||||
dir := L.CheckString(1)
|
|
||||||
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
|
|
||||||
pathenv := os.Getenv("PATH")
|
|
||||||
|
|
||||||
// if dir isnt already in $PATH, add in
|
|
||||||
if !strings.Contains(pathenv, dir) {
|
|
||||||
os.Setenv("PATH", dir + string(os.PathListSeparator) + pathenv)
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue