feat: use custom exec handler for sh interpreter

so, here we use a custom function for the sh interpreter to run
individual commands now. what does this mean?
1. aliases will work not only on the 1st command, since it was
replaced in the beginning before.
want to run `cmd; alias`? now you can!
2. custom error message when a command isnt found :} i can also
add the command.not-found hook (will do in next commit)
3. sh and lua can be mixed (not in this commit, but itll work)

this means all code for handling commands is in the single `execCommand`
function in shell.go and will probably able to clean things up soon,
ditching the `RunInput` function entirely
pull/59/head
sammyette 2021-05-18 20:41:54 -04:00
parent aa7de15997
commit a655ff00ce
No known key found for this signature in database
GPG Key ID: 50EE40A2809851F5
1 changed files with 54 additions and 39 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"time"
// "github.com/bobappleyard/readline" // "github.com/bobappleyard/readline"
"github.com/yuin/gopher-lua" "github.com/yuin/gopher-lua"
@ -15,18 +16,7 @@ import (
) )
func RunInput(input string) { func RunInput(input string) {
cmdArgs, cmdString := splitInput(input) _, cmdString := splitInput(input)
// If alias was found, use command alias
for aliases[cmdArgs[0]] != "" {
alias := aliases[cmdArgs[0]]
cmdString = alias + strings.TrimPrefix(cmdString, cmdArgs[0])
cmdArgs, cmdString = splitInput(cmdString)
if aliases[cmdArgs[0]] != "" {
continue
}
}
// First try to load input, essentially compiling to bytecode // First try to load input, essentially compiling to bytecode
fn, err := l.LoadString(cmdString) fn, err := l.LoadString(cmdString)
@ -49,33 +39,6 @@ func RunInput(input string) {
return return
} }
// If command is defined in Lua then run it
if commands[cmdArgs[0]] {
err := l.CallByParam(lua.P{
Fn: l.GetField(
l.GetTable(
l.GetGlobal("commanding"),
lua.LString("__commands")),
cmdArgs[0]),
NRet: 1,
Protect: true,
}, luar.New(l, cmdArgs[1:]))
luaexitcode := l.Get(-1)
exitcode := lua.LNumber(0)
l.Pop(1)
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
exitcode = code
}
if err != nil {
fmt.Fprintln(os.Stderr,
"Error in command:\n\n" + err.Error())
}
hooks.Em.Emit("command.exit", exitcode)
return
}
// Last option: use sh interpreter // Last option: use sh interpreter
err = execCommand(cmdString) err = execCommand(cmdString)
if err != nil { if err != nil {
@ -115,8 +78,60 @@ func execCommand(cmd string) error {
if err != nil { if err != nil {
return err return err
} }
exechandle := func(ctx context.Context, args []string) error {
hc := interp.HandlerCtx(ctx)
args, argstring := splitInput(strings.Join(args, " "))
// If alias was found, use command alias
for aliases[args[0]] != "" {
alias := aliases[args[0]]
argstring = alias + strings.TrimPrefix(argstring, args[0])
args, argstring = splitInput(argstring)
if aliases[args[0]] != "" {
continue
}
}
// If command is defined in Lua then run it
if commands[args[0]] {
err := l.CallByParam(lua.P{
Fn: l.GetField(
l.GetTable(
l.GetGlobal("commanding"),
lua.LString("__commands")),
args[0]),
NRet: 1,
Protect: true,
}, luar.New(l, args[1:]))
luaexitcode := l.Get(-1)
var exitcode uint8 = 0
l.Pop(1)
if code, ok := luaexitcode.(lua.LNumber); luaexitcode != lua.LNil && ok {
exitcode = uint8(code)
}
if err != nil {
fmt.Fprintln(os.Stderr,
"Error in command:\n\n" + err.Error())
}
hooks.Em.Emit("command.exit", exitcode)
return interp.NewExitStatus(exitcode)
}
if _, err := interp.LookPathDir(hc.Dir, hc.Env, args[0]); err != nil {
fmt.Printf("hilbish: %s not found\n", args[0])
return interp.NewExitStatus(127)
}
return interp.DefaultExecHandler(2*time.Second)(ctx, args)
}
runner, _ := interp.New( runner, _ := interp.New(
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
interp.ExecHandler(exechandle),
) )
err = runner.Run(context.TODO(), file) err = runner.Run(context.TODO(), file)