From 7d503750c03d06d156a8b95b88106ea6b835d399 Mon Sep 17 00:00:00 2001 From: sammy-ette Date: Sun, 15 Jun 2025 18:29:54 -0400 Subject: [PATCH] refactor: fully implement hilbish.runner in lua --- api.go | 4 --- exec.go | 27 -------------- main.go | 31 ---------------- nature/runner.lua | 74 +++++++++++++++++++++++++++++++++++++- runnermode.go | 90 ----------------------------------------------- 5 files changed, 73 insertions(+), 153 deletions(-) delete mode 100644 runnermode.go diff --git a/api.go b/api.go index b64b43c2..7cd26ef0 100644 --- a/api.go +++ b/api.go @@ -110,10 +110,6 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp)) mod.Set(rt.StringValue("completions"), rt.TableValue(hshcomp)) - // hilbish.runner table - runnerModule := runnerModeLoader(rtm) - mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule)) - // hilbish.jobs table jobs = newJobHandler() jobModule := jobs.loader(rtm) diff --git a/exec.go b/exec.go index 647bbf9a..b8c6409d 100644 --- a/exec.go +++ b/exec.go @@ -18,33 +18,6 @@ func runInput(input string, priv bool) { } } -func handleLua(input string) (string, uint8, error) { - cmdString := aliases.Resolve(input) - // First try to load input, essentially compiling to bytecode - chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv())) - if err != nil && noexecute { - fmt.Println(err) - /* if lerr, ok := err.(*lua.ApiError); ok { - if perr, ok := lerr.Cause.(*parse.Error); ok { - print(perr.Pos.Line == parse.EOF) - } - } - */ - return cmdString, 125, err - } - // And if there's no syntax errors and -n isnt provided, run - if !noexecute { - if chunk != nil { - _, err = rt.Call1(l.MainThread(), rt.FunctionValue(chunk)) - } - } - if err == nil { - return cmdString, 0, nil - } - - return cmdString, 125, err -} - func splitInput(input string) ([]string, string) { // end my suffering // TODO: refactor this garbage diff --git a/main.go b/main.go index d02393ed..7e62a307 100644 --- a/main.go +++ b/main.go @@ -251,37 +251,6 @@ func continuePrompt(prev string, newline bool) (string, error) { } */ -// This semi cursed function formats our prompt (obviously) -func fmtPrompt(prompt string) string { - host, _ := os.Hostname() - cwd, _ := os.Getwd() - - cwd = util.AbbrevHome(cwd) - username := curuser.Username - // this will be baked into binary since GOOS is a constant - if runtime.GOOS == "windows" { - username = strings.Split(username, "\\")[1] // for some reason Username includes the hostname on windows - } - - args := []string{ - "d", cwd, - "D", filepath.Base(cwd), - "h", host, - "u", username, - } - - for i, v := range args { - if i%2 == 0 { - args[i] = "%" + v - } - } - - r := strings.NewReplacer(args...) - nprompt := r.Replace(prompt) - - return nprompt -} - func removeDupes(slice []string) []string { all := make(map[string]bool) newSlice := []string{} diff --git a/nature/runner.lua b/nature/runner.lua index cc5b67e0..0803c765 100644 --- a/nature/runner.lua +++ b/nature/runner.lua @@ -1,10 +1,53 @@ -- @module hilbish.runner +--- interactive command runner customization +--- The runner interface contains functions that allow the user to change +--- how Hilbish interprets interactive input. +--- Users can add and change the default runner for interactive input to any +--- language or script of their choosing. A good example is using it to +--- write command in Fennel. +--- +--- Runners are functions that evaluate user input. The default runners in +--- Hilbish can run shell script and Lua code. +--- +--- A runner is passed the input and has to return a table with these values. +--- All are not required, only the useful ones the runner needs to return. +--- (So if there isn't an error, just omit `err`.) +--- +--- - `exitCode` (number): Exit code of the command +--- - `input` (string): The text input of the user. This is used by Hilbish to append extra input, in case +--- more is requested. +--- - `err` (string): A string that represents an error from the runner. +--- This should only be set when, for example, there is a syntax error. +--- It can be set to a few special values for Hilbish to throw the right +--- hooks and have a better looking message. +--- - `: not-found` will throw a `command.not-found` hook +--- based on what `` is. +--- - `: not-executable` will throw a `command.not-executable` hook. +--- - `continue` (boolean): Whether Hilbish should prompt the user for no input +--- - `newline` (boolean): Whether a newline should be added at the end of `input`. +--- +--- Here is a simple example of a fennel runner. It falls back to +--- shell script if fennel eval has an error. +--- ```lua +--- local fennel = require 'fennel' +--- +--- hilbish.runnerMode(function(input) +--- local ok = pcall(fennel.eval, input) +--- if ok then +--- return { +--- input = input +--- } +--- end +--- +--- return hilbish.runner.sh(input) +--- end) +--- ``` local snail = require 'snail' local currentRunner = 'hybrid' local runners = {} -- lsp shut up -hilbish = hilbish +hilbish.runner = {} --- Get a runner by name. --- @param name string Name of the runner to retrieve. @@ -167,6 +210,35 @@ function hilbish.runner.sh(input) return hilbish.snail:run(input) end +--- lua(cmd) +--- Evaluates `cmd` as Lua input. This is the same as using `dofile` +--- or `load`, but is appropriated for the runner interface. +-- @param cmd string +function hilbish.runner.lua(input) + local fun, err = load(input) + if err then + return { + input = input, + exitCode = 125, + err = err + } + end + + local ok = pcall(fun) + if not ok then + return { + input = input, + exitCode = 126, + err = err + } + end + + return { + input = input, + exitCode = 0, + } +end + hilbish.runner.add('hybrid', function(input) local cmdStr = hilbish.aliases.resolve(input) diff --git a/runnermode.go b/runnermode.go deleted file mode 100644 index 9e7a3ffd..00000000 --- a/runnermode.go +++ /dev/null @@ -1,90 +0,0 @@ -package main - -import ( - "hilbish/util" - - rt "github.com/arnodel/golua/runtime" -) - -// #interface runner -// interactive command runner customization -/* The runner interface contains functions that allow the user to change -how Hilbish interprets interactive input. -Users can add and change the default runner for interactive input to any -language or script of their choosing. A good example is using it to -write command in Fennel. - -Runners are functions that evaluate user input. The default runners in -Hilbish can run shell script and Lua code. - -A runner is passed the input and has to return a table with these values. -All are not required, only the useful ones the runner needs to return. -(So if there isn't an error, just omit `err`.) - -- `exitCode` (number): Exit code of the command -- `input` (string): The text input of the user. This is used by Hilbish to append extra input, in case -more is requested. -- `err` (string): A string that represents an error from the runner. -This should only be set when, for example, there is a syntax error. -It can be set to a few special values for Hilbish to throw the right -hooks and have a better looking message. - - `: not-found` will throw a `command.not-found` hook - based on what `` is. - - `: not-executable` will throw a `command.not-executable` hook. -- `continue` (boolean): Whether Hilbish should prompt the user for no input -- `newline` (boolean): Whether a newline should be added at the end of `input`. - -Here is a simple example of a fennel runner. It falls back to -shell script if fennel eval has an error. -```lua -local fennel = require 'fennel' - -hilbish.runnerMode(function(input) - local ok = pcall(fennel.eval, input) - if ok then - return { - input = input - } - end - - return hilbish.runner.sh(input) -end) -``` -*/ -func runnerModeLoader(rtm *rt.Runtime) *rt.Table { - exports := map[string]util.LuaExport{ - "lua": {luaRunner, 1, false}, - } - - mod := rt.NewTable() - util.SetExports(rtm, mod, exports) - - return mod -} - -// #interface runner -// lua(cmd) -// Evaluates `cmd` as Lua input. This is the same as using `dofile` -// or `load`, but is appropriated for the runner interface. -// #param cmd string -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 - } - - input, exitCode, err := handleLua(cmd) - var luaErr rt.Value = rt.NilValue - if err != nil { - luaErr = rt.StringValue(err.Error()) - } - runnerRet := rt.NewTable() - runnerRet.Set(rt.StringValue("input"), rt.StringValue(input)) - runnerRet.Set(rt.StringValue("exitCode"), rt.IntValue(int64(exitCode))) - runnerRet.Set(rt.StringValue("err"), luaErr) - - return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil -}