Compare commits

..

No commits in common. "802f444ba6ebb7e1e642d25762c89da7090f8f04" and "96c1487bfa5f74183107e467ea728922d56b7a03" have entirely different histories.

6 changed files with 21 additions and 209 deletions

33
api.go
View File

@ -26,7 +26,6 @@ var exports = map[string]lua.LGFunction {
"complete": hlcomplete,
"cwd": hlcwd,
"exec": hlexec,
"runnerMode": hlrunnerMode,
"goro": hlgoro,
"multiprompt": hlmlprompt,
"prependPath": hlprependPath,
@ -107,10 +106,6 @@ Check out the {blue}{bold}guide{reset} command to get started.
util.Document(L, hshcomp, "Completions interface for Hilbish.")
L.SetField(mod, "completion", hshcomp)
runnerModule := runnerModeLoader(L)
util.Document(L, runnerModule, "Runner/exec interface for Hilbish.")
L.SetField(mod, "runner", runnerModule)
jobs = newJobHandler()
L.Push(mod)
@ -177,7 +172,7 @@ func unsetVimMode() {
func hlrun(L *lua.LState) int {
var exitcode uint8
cmd := L.CheckString(1)
err := execCommand(cmd)
err := execCommand(cmd, true)
if code, ok := interp.IsExitStatus(err); ok {
exitcode = code
@ -471,29 +466,3 @@ func hlinputMode(L *lua.LState) int {
}
return 0
}
// 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.
// Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
// sh, and lua. It also accepts a function, to which if it is passed one
// will call it to execute user input instead.
func hlrunnerMode(L *lua.LState) int {
mode := L.CheckAny(1)
switch mode.Type() {
case lua.LTString:
switch mode.String() {
// 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 lua.LTFunction: runnerMode = mode
default: L.RaiseError("execMode: expected either a function or hybrid, hybridRev, lua, sh. Received %v", mode)
}
return 0
}

View File

@ -37,12 +37,6 @@ Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which s
run(cmd) > Runs `cmd` in Hilbish's sh interpreter.
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.
Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
sh, and lua. It also accepts a function, to which if it is passed one
will call it to execute user input instead.
timeout(cb, time) > Runs the `cb` function after `time` in milliseconds
which(binName) > Searches for an executable called `binName` in the directories of $PATH

View File

@ -1,33 +0,0 @@
Hilbish is *unique,* when interactive it first attempts to run input as
Lua and then tries shell script. But if you're normal, you wouldn't
really be using Hilbish anyway but you'd also not want this
(or maybe want Lua only in some cases.)
The "runner mode" of Hilbish is customizable via `hilbish.runnerMode`,
which determines how Hilbish will run user input. By default, this is
set to `hybrid` which is the previously mentioned behaviour of running Lua
first then going to shell script. If you want the reverse order, you can
set it to `hybridRev` and for isolated modes there is `sh` and `lua`
respectively.
You can also set it to a function, which will be called everytime Hilbish
needs to run interactive input. For example, you can set this to a simple
function to compile and evaluate Fennel, and now you can run Fennel.
You can even mix it with sh to make a hybrid mode with Lua replaced by
Fennel.
An example:
hilbish.runnerMode(function(input)
local ok = pcall(fennel.eval, input)
if ok then
return 0, nil
end
return hilbish.runner.sh(input)
end)
The `hilbish.runner` interface is an alternative to using `hilbish.runnerMode`
and also provides the sh and Lua runner functions that Hilbish itself uses.
A runner function is expected to return 2 values: the exit code, and an error.
The exit code has to be a number, it will be 0 otherwise and the error can be
`nil` to indicate no error.

View File

@ -69,13 +69,6 @@ function hilbish.read(prompt) end
--- @param cmd string
function hilbish.run(cmd) end
--- 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.
--- Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
--- sh, and lua. It also accepts a function, to which if it is passed one
--- will call it to execute user input instead.
function hilbish.runnerMode() end
--- Runs the `cb` function after `time` in milliseconds
--- @param cb function
--- @param time number

105
exec.go
View File

@ -24,80 +24,13 @@ import (
)
var errNotExec = errors.New("not executable")
var runnerMode lua.LValue = lua.LString("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() {
case "hybrid":
_, err := handleLua(cmdString)
if err == nil {
cmdFinish(0, cmdString, priv)
return
}
exitCode, err := handleSh(cmdString)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
cmdFinish(exitCode, cmdString, priv)
case "hybridRev":
_, err := handleSh(cmdString)
if err == nil {
cmdFinish(0, cmdString, priv)
return
}
exitCode, err := handleLua(cmdString)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
cmdFinish(exitCode, cmdString, priv)
case "lua":
exitCode, err := handleLua(cmdString)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
cmdFinish(exitCode, cmdString, priv)
case "sh":
exitCode, err := handleSh(cmdString)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
cmdFinish(exitCode, cmdString, priv)
}
} else {
// can only be a string or function so
err := l.CallByParam(lua.P{
Fn: runnerMode,
NRet: 2,
Protect: true,
}, lua.LString(cmdString))
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)
var exitCode uint8
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
exitCode = uint8(code)
}
if runErr != lua.LNil {
fmt.Fprintln(os.Stderr, runErr)
}
cmdFinish(exitCode, cmdString, priv)
}
}
func handleLua(cmdString string) (uint8, error) {
// First try to load input, essentially compiling to bytecode
fn, err := l.LoadString(cmdString)
if err != nil && noexecute {
@ -108,7 +41,7 @@ func handleLua(cmdString string) (uint8, error) {
}
}
*/
return 125, err
return
}
// And if there's no syntax errors and -n isnt provided, run
if !noexecute {
@ -116,14 +49,12 @@ func handleLua(cmdString string) (uint8, error) {
err = l.PCall(0, lua.MultRet, nil)
}
if err == nil {
return 0, nil
cmdFinish(0, cmdString, priv)
return
}
return 125, err
}
func handleSh(cmdString string) (uint8, error) {
err := execCommand(cmdString)
// Last option: use sh interpreter
err = execCommand(cmdString, priv)
if err != nil {
// If input is incomplete, start multiline prompting
if syntax.IsIncomplete(err) {
@ -132,31 +63,34 @@ func handleSh(cmdString string) (uint8, error) {
if err != nil {
break
}
err = execCommand(cmdString)
if syntax.IsIncomplete(err) || strings.HasSuffix(cmdString, "\\") {
err = execCommand(cmdString, priv)
if syntax.IsIncomplete(err) || strings.HasSuffix(input, "\\") {
continue
} else if code, ok := interp.IsExitStatus(err); ok {
return code, nil
cmdFinish(code, cmdString, priv)
} else if err != nil {
return 126, err
cmdFinish(1, cmdString, priv)
fmt.Fprintln(os.Stderr, err)
} else {
return 0, nil
cmdFinish(0, cmdString, priv)
}
break
}
} else {
if code, ok := interp.IsExitStatus(err); ok {
return code, nil
cmdFinish(code, cmdString, priv)
} else {
return 126, err
cmdFinish(126, cmdString, priv)
fmt.Fprintln(os.Stderr, err)
}
}
} else {
cmdFinish(0, cmdString, priv)
}
return 0, nil
}
// Run command in sh interpreter
func execCommand(cmd string) error {
func execCommand(cmd string, priv bool) error {
file, err := syntax.NewParser().Parse(strings.NewReader(cmd), "")
if err != nil {
return err
@ -207,6 +141,7 @@ func execCommand(cmd string) error {
exitcode = uint8(code)
}
cmdFinish(exitcode, argstring, priv)
return interp.NewExitStatus(exitcode)
}

View File

@ -1,46 +0,0 @@
package main
import (
"github.com/yuin/gopher-lua"
)
func runnerModeLoader(L *lua.LState) *lua.LTable {
exports := map[string]lua.LGFunction{
"sh": shRunner,
"lua": luaRunner,
"setMode": hlrunnerMode,
}
mod := L.SetFuncs(L.NewTable(), exports)
L.SetField(mod, "mode", runnerMode)
return mod
}
func shRunner(L *lua.LState) int {
cmd := L.CheckString(1)
exitCode, err := handleSh(cmd)
var luaErr lua.LValue = lua.LNil
if err != nil {
luaErr = lua.LString(err.Error())
}
L.Push(lua.LNumber(exitCode))
L.Push(luaErr)
return 2
}
func luaRunner(L *lua.LState) int {
cmd := L.CheckString(1)
exitCode, err := handleLua(cmd)
var luaErr lua.LValue = lua.LNil
if err != nil {
luaErr = lua.LString(err.Error())
}
L.Push(lua.LNumber(exitCode))
L.Push(luaErr)
return 2
}