From a89d3e59d6a5fdf9416d8029ae22d50da2deaae1 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 12:19:11 -0400 Subject: [PATCH 01/44] docs: fix typo in hilbish.inputMode doc (closes #147) --- api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.go b/api.go index aa141d6..c32bf5d 100644 --- a/api.go +++ b/api.go @@ -601,7 +601,7 @@ func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { } // inputMode(mode) -// Sets the input mode for Hilbish's line reader. Accepts either emacs for vim +// Sets the input mode for Hilbish's line reader. Accepts either emacs or vim // --- @param mode string func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { From 86aa40af6469a58bc0592581e5d2b7fc927d6396 Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Thu, 21 Apr 2022 16:19:31 +0000 Subject: [PATCH 02/44] docs: [ci] generate new docs --- docs/hilbish.txt | 2 +- emmyLuaDocs/hilbish.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hilbish.txt b/docs/hilbish.txt index e86af79..922b866 100644 --- a/docs/hilbish.txt +++ b/docs/hilbish.txt @@ -26,7 +26,7 @@ what text to use as an inline hint. The callback is passed 2 arguments: the current line and the position. It is expected to return a string which will be used for the hint. -inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs for vim +inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs or vim interval(cb, time) > Runs the `cb` function every `time` milliseconds. Returns a `timer` object (see `doc timers`). diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index f8c4380..0bcc84c 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -47,7 +47,7 @@ function hilbish.highlighter(cb) end --- @param cb function function hilbish.hinter(cb) end ---- Sets the input mode for Hilbish's line reader. Accepts either emacs for vim +--- Sets the input mode for Hilbish's line reader. Accepts either emacs or vim --- @param mode string function hilbish.inputMode(mode) end From bd35e3b87163ad9516b0955b16143aff766e2e57 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 14:01:59 -0400 Subject: [PATCH 03/44] refactor: use foreach function to loop over lua tables --- api.go | 87 ++----------------------------------------- complete.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ rl.go | 70 +++++++++++++--------------------- util/util.go | 14 +++++++ 4 files changed, 147 insertions(+), 127 deletions(-) diff --git a/api.go b/api.go index c32bf5d..5a72ddf 100644 --- a/api.go +++ b/api.go @@ -148,75 +148,6 @@ func getenv(key, fallback string) string { return value } -func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - query, ctx, fds, err := getCompleteParams(t, c) - if err != nil { - return nil, err - } - - completions, _ := fileComplete(query, ctx, fds) - luaComps := rt.NewTable() - - for i, comp := range completions { - luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp)) - } - - return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil -} - -func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - query, ctx, fds, err := getCompleteParams(t, c) - if err != nil { - return nil, err - } - - completions, _ := binaryComplete(query, ctx, fds) - luaComps := rt.NewTable() - - for i, comp := range completions { - luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp)) - } - - return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil -} - -func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) { - if err := c.CheckNArgs(3); err != nil { - return "", "", []string{}, err - } - query, err := c.StringArg(0) - if err != nil { - return "", "", []string{}, err - } - ctx, err := c.StringArg(1) - if err != nil { - return "", "", []string{}, err - } - fields, err := c.TableArg(2) - if err != nil { - return "", "", []string{}, err - } - - var fds []string - nextVal := rt.NilValue - for { - next, val, ok := fields.Next(nextVal) - if next == rt.NilValue { - break - } - nextVal = next - - valStr, ok := val.TryString() - if !ok { - continue - } - - fds = append(fds, valStr) - } - - return query, ctx, fds, err -} - func setVimMode(mode string) { util.SetField(l, hshMod, "vimMode", rt.StringValue(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)") hooks.Em.Emit("hilbish.vimMode", mode) @@ -395,21 +326,11 @@ func hlappendPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // check if dir is a table or a string if arg.Type() == rt.TableType { - nextVal := rt.NilValue - for { - next, val, ok := arg.AsTable().Next(nextVal) - if next == rt.NilValue { - break + util.ForEach(arg.AsTable(), func(k rt.Value, v rt.Value) { + if v.Type() == rt.StringType { + appendPath(v.AsString()) } - nextVal = next - - valStr, ok := val.TryString() - if !ok { - continue - } - - appendPath(valStr) - } + }) } else if arg.Type() == rt.StringType { appendPath(arg.AsString()) } else { diff --git a/complete.go b/complete.go index 04f9095..68f5d67 100644 --- a/complete.go +++ b/complete.go @@ -1,9 +1,14 @@ package main import ( + "errors" "path/filepath" "strings" "os" + + "hilbish/util" + + rt "github.com/arnodel/golua/runtime" ) func fileComplete(query, ctx string, fields []string) ([]string, string) { @@ -111,3 +116,101 @@ func escapeFilename(fname string) string { r := strings.NewReplacer(args...) return r.Replace(fname) } + +func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.CheckNArgs(4); err != nil { + return nil, err + } + completer, err := c.StringArg(0) + if err != nil { + return nil, err + } + query, err := c.StringArg(1) + if err != nil { + return nil, err + } + ctx, err := c.StringArg(2) + if err != nil { + return nil, err + } + fields, err := c.TableArg(3) + if err != nil { + return nil, err + } + + var completecb *rt.Closure + var ok bool + if completecb, ok = luaCompletions[completer]; !ok { + return nil, errors.New("completer " + completer + " does not exist") + } + + // we must keep the holy 80 cols + completerReturn, err := rt.Call1(l.MainThread(), + rt.FunctionValue(completecb), rt.StringValue(query), + rt.StringValue(ctx), rt.TableValue(fields)) + + if err != nil { + return nil, err + } + + return c.PushingNext1(t.Runtime, completerReturn), nil +} + +func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + query, ctx, fds, err := getCompleteParams(t, c) + if err != nil { + return nil, err + } + + completions, _ := fileComplete(query, ctx, fds) + luaComps := rt.NewTable() + + for i, comp := range completions { + luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp)) + } + + return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil +} + +func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + query, ctx, fds, err := getCompleteParams(t, c) + if err != nil { + return nil, err + } + + completions, _ := binaryComplete(query, ctx, fds) + luaComps := rt.NewTable() + + for i, comp := range completions { + luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp)) + } + + return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil +} + +func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) { + if err := c.CheckNArgs(3); err != nil { + return "", "", []string{}, err + } + query, err := c.StringArg(0) + if err != nil { + return "", "", []string{}, err + } + ctx, err := c.StringArg(1) + if err != nil { + return "", "", []string{}, err + } + fields, err := c.TableArg(2) + if err != nil { + return "", "", []string{}, err + } + + var fds []string + util.ForEach(fields, func(k rt.Value, v rt.Value) { + if v.Type() == rt.StringType { + fds = append(fds, v.AsString()) + } + }) + + return query, ctx, fds, err +} diff --git a/rl.go b/rl.go index 8093273..cd1f4eb 100644 --- a/rl.go +++ b/rl.go @@ -34,8 +34,7 @@ func newLineReader(prompt string, noHist bool) *lineReader { case readline.VimKeys: modeStr = "normal" case readline.VimInsert: modeStr = "insert" case readline.VimDelete: modeStr = "delete" - case readline.VimReplaceOnce: - case readline.VimReplaceMany: modeStr = "replace" + case readline.VimReplaceOnce, readline.VimReplaceMany: modeStr = "replace" } setVimMode(modeStr) } @@ -153,71 +152,54 @@ func newLineReader(prompt string, noHist bool) *lineReader { to work on subcommands and subcompletions */ if cmpTbl, ok := luacompleteTable.TryTable(); ok { - nextVal := rt.NilValue - for { - next, val, ok := cmpTbl.Next(nextVal) - if next == rt.NilValue { - break - } - nextVal = next - - _, ok = next.TryInt() - valTbl, okk := val.TryTable() - if !ok || !okk { - // TODO: error? - break + util.ForEach(cmpTbl, func(key rt.Value, val rt.Value) { + if key.Type() != rt.IntType && val.Type() != rt.TableType { + return } + valTbl := val.AsTable() luaCompType := valTbl.Get(rt.StringValue("type")) luaCompItems := valTbl.Get(rt.StringValue("items")) - compType, ok := luaCompType.TryString() - compItems, okk := luaCompItems.TryTable() - if !ok || !okk { - // TODO: error - break + if luaCompType.Type() != rt.StringType && luaCompItems.Type() != rt.TableType { + return } - var items []string + items := []string{} itemDescriptions := make(map[string]string) - nxVal := rt.NilValue - for { - nx, vl, _ := compItems.Next(nxVal) - if nx == rt.NilValue { - break - } - nxVal = nx - if tstr := nx.Type(); tstr == rt.StringType { + util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) { + if keytyp := lkey.Type(); keytyp == rt.StringType { // ['--flag'] = {'description', '--flag-alias'} - nxStr, ok := nx.TryString() - vlTbl, okk := vl.TryTable() - if !ok || !okk { + itemName, ok := lkey.TryString() + vlTbl, okk := lval.TryTable() + if !ok && !okk { // TODO: error - continue + return } - items = append(items, nxStr) + + items = append(items, itemName) itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString() if !ok { // TODO: error - continue + return } - itemDescriptions[nxStr] = itemDescription - } else if tstr == rt.IntType { - vlStr, okk := vl.TryString() - if !okk { + itemDescriptions[itemName] = itemDescription + } else if keytyp == rt.IntType { + vlStr, ok := lval.TryString() + if !ok { // TODO: error - continue + return } items = append(items, vlStr) } else { // TODO: error - continue + return } - } + }) var dispType readline.TabDisplayType - switch compType { + switch luaCompType.AsString() { case "grid": dispType = readline.TabDisplayGrid case "list": dispType = readline.TabDisplayList // need special cases, will implement later @@ -231,7 +213,7 @@ func newLineReader(prompt string, noHist bool) *lineReader { TrimSlash: false, NoSpace: true, }) - } + }) } } diff --git a/util/util.go b/util/util.go index b8c267a..c1688e0 100644 --- a/util/util.go +++ b/util/util.go @@ -118,3 +118,17 @@ func HandleStrCallback(t *rt.Thread, c *rt.GoCont) (string, *rt.Closure, error) return name, cb, err } + +// ForEach loops through a Lua table. +func ForEach(tbl *rt.Table, cb func(key rt.Value, val rt.Value)) { + nextVal := rt.NilValue + for { + key, val, _ := tbl.Next(nextVal) + if key == rt.NilValue { + break + } + nextVal = key + + cb(key, val) + } +} From abfd4e5196da3569372598f058fc0ddf4ab3311e Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 20:33:32 -0400 Subject: [PATCH 04/44] fix(util): SetField on a table with a metatable causing panic --- util/util.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util/util.go b/util/util.go index c1688e0..e46d4b2 100644 --- a/util/util.go +++ b/util/util.go @@ -29,12 +29,16 @@ func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, d if mt == nil { mt = rt.NewTable() - docProp := rt.NewTable() - mt.Set(rt.StringValue("__docProp"), rt.TableValue(docProp)) module.SetMetatable(mt) } + docProp := mt.Get(rt.StringValue("__docProp")) + if docProp == rt.NilValue { + docPropTbl := rt.NewTable() + mt.Set(rt.StringValue("__docProp"), rt.TableValue(docPropTbl)) + docProp = mt.Get(rt.StringValue("__docProp")) + } docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc)) module.Set(rt.StringValue(field), value) From 37e1b12b8126ec4281dee1e501eddef7064a1f35 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 20:39:06 -0400 Subject: [PATCH 05/44] feat: add hilbish.completion.call to call a completer --- api.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api.go b/api.go index 5a72ddf..b2e4530 100644 --- a/api.go +++ b/api.go @@ -76,7 +76,7 @@ Check out the {blue}{bold}guide{reset} command to get started. 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(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.SetField(rtm, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command") util.Document(mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.") // hilbish.userDir table @@ -118,6 +118,10 @@ Check out the {blue}{bold}guide{reset} command to get started. rt.FunctionValue(rt.NewGoFunction(luaBinaryComplete, "bins", 3, false)), "Completer for executables/binaries") + util.SetField(rtm, hshcomp, "call", + rt.FunctionValue(rt.NewGoFunction(callLuaCompleter, "call", 4, false)), + "Calls a completer and get its entries for completions") + util.Document(hshcomp, "Completions interface for Hilbish.") mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp)) From 3d525aa7da4c58b9eba91fe65e302e9958c76755 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 20:39:38 -0400 Subject: [PATCH 06/44] fix: dont allow overrides on hilbish table --- api.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/api.go b/api.go index b2e4530..658494c 100644 --- a/api.go +++ b/api.go @@ -52,7 +52,30 @@ var hilbishLoader = packagelib.Loader{ } func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { + fakeMod := rt.NewTable() + modmt := rt.NewTable() mod := rt.NewTable() + + modIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + arg := c.Arg(1) + val := mod.Get(arg) + + return c.PushingNext1(t.Runtime, val), nil + } + modNewIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + k := c.Arg(1) + v := c.Arg(2) + if modVal := mod.Get(k); modVal != rt.NilValue { + return nil, errors.New("not allowed to override in hilbish table") + } + mod.Set(k, v) + + return c.Next(), nil + } + modmt.Set(rt.StringValue("__newindex"), rt.FunctionValue(rt.NewGoFunction(modNewIndex, "__newindex", 3, false))) + modmt.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(modIndex, "__index", 2, false))) + fakeMod.SetMetatable(modmt) + util.SetExports(rtm, mod, exports) hshMod = mod @@ -141,7 +164,7 @@ Check out the {blue}{bold}guide{reset} command to get started. util.Document(timerModule, "Timer interface, for control of all intervals and timeouts.") mod.Set(rt.StringValue("timers"), rt.TableValue(timerModule)) - return rt.TableValue(mod), nil + return rt.TableValue(fakeMod), nil } func getenv(key, fallback string) string { From 57d75273567f046c2d4eb7e3ed460175350ee59f Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 22:16:04 -0400 Subject: [PATCH 07/44] fix: make hilbish.which work with aliases and commanders --- api.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/api.go b/api.go index 658494c..eb7cc44 100644 --- a/api.go +++ b/api.go @@ -529,18 +529,27 @@ func hlprependPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -// which(binName) -// Searches for an executable called `binName` in the directories of $PATH +// which(name) +// Checks if `name` is a valid command // --- @param binName string func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { return nil, err } - binName, err := c.StringArg(0) + name, err := c.StringArg(0) if err != nil { return nil, err } - path, err := exec.LookPath(binName) + + cmd := aliases.Resolve(name) + + // check for commander + if commands[cmd] != nil { + // they dont resolve to a path, so just send the cmd + return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil + } + + path, err := exec.LookPath(cmd) if err != nil { return c.Next(), nil } From 1a4008fcfb9e5d31bea42448d582e4bb7824726f Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Fri, 22 Apr 2022 02:17:00 +0000 Subject: [PATCH 08/44] docs: [ci] generate new docs --- docs/hilbish.txt | 2 +- emmyLuaDocs/hilbish.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hilbish.txt b/docs/hilbish.txt index 922b866..80dad96 100644 --- a/docs/hilbish.txt +++ b/docs/hilbish.txt @@ -59,5 +59,5 @@ will call it to execute user input instead. timeout(cb, time) > Runs the `cb` function after `time` in milliseconds Returns a `timer` object (see `doc timers`). -which(binName) > Searches for an executable called `binName` in the directories of $PATH +which(name) > Checks if `name` is a valid command diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index 0bcc84c..64f6f9c 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -103,7 +103,7 @@ function hilbish.runnerMode(mode) end --- @return table function hilbish.timeout(cb, time) end ---- Searches for an executable called `binName` in the directories of $PATH +--- Checks if `name` is a valid command --- @param binName string function hilbish.which(binName) end From 0af36db6ff13f64d543f2b1363e61bbaf091ad83 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 22:19:27 -0400 Subject: [PATCH 09/44] fix!: change the way highlighter and hinter are set with the change of blocking changes to the hilbish table, i took an opportunity to make the highlighter and hinter callbacks set in a more natural way. instead of being a function which takes a callback, you set the function itself. --- api.go | 74 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/api.go b/api.go index eb7cc44..bdab365 100644 --- a/api.go +++ b/api.go @@ -63,12 +63,29 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { return c.PushingNext1(t.Runtime, val), nil } modNewIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - k := c.Arg(1) + k, err := c.StringArg(1) + if err != nil { + return nil, err + } + v := c.Arg(2) - if modVal := mod.Get(k); modVal != rt.NilValue { + if k == "highlighter" { + var err error + // fine to assign, since itll be either nil or a closure + highlighter, err = c.ClosureArg(2) + if err != nil { + return nil, errors.New("hilbish.highlighter has to be a function") + } + } else if k == "hinter" { + var err error + hinter, err = c.ClosureArg(2) + if err != nil { + return nil, errors.New("hilbish.hinter has to be a function") + } + } else if modVal := mod.Get(rt.StringValue(k)); modVal != rt.NilValue { return nil, errors.New("not allowed to override in hilbish table") } - mod.Set(k, v) + mod.Set(rt.StringValue(k), v) return c.Next(), nil } @@ -493,7 +510,7 @@ func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // replacing with the name of the command (for example `command.git`). // `cb` must be a function that returns a table of "completion groups." // A completion group is a table with the keys `items` and `type`. -// `items` being a table of items and `type` being the display type of +// `items` being a table of items and `type` being the display type, which is // `grid` (the normal file completion display) or `list` (with a description) // --- @param scope string // --- @param cb function @@ -599,7 +616,6 @@ func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { switch mode.Type() { case rt.StringType: switch mode.AsString() { - // no fallthrough doesnt work so eh 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()) } @@ -610,40 +626,24 @@ func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -// hinter(cb) -// Sets the hinter function. This will be called on every key insert to determine -// what text to use as an inline hint. The callback is passed 2 arguments: -// the current line and the position. It is expected to return a string -// which will be used for the hint. -// --- @param cb function +// hinter(line, pos) +// The command line hint handler. It gets called on every key insert to +// determine what text to use as an inline hint. It is passed the current +// line and cursor position. It is expected to return a string which is used +// as the text for the hint. This is by default a shim. To set hints, +// override this function with your custom handler. +// --- @param line string +// --- @param pos int 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 c.Next(), err + return c.Next(), nil } -// highlighter(cb) -// Sets the highlighter function. This is mainly for syntax hightlighting, but in -// reality could set the input of the prompt to display anything. The callback -// 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 +// highlighter(line) +// Line highlighter handler. This is mainly for syntax highlighting, but in +// reality could set the input of the prompt to *display* anything. The +// callback is passed the current line and is expected to return a line that +// will be used as the input display. +// --- @param line string 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 c.Next(), err + return c.Next(), nil } From 1274811739d05214975d941dbdef9e867be5a7db Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Fri, 22 Apr 2022 02:22:20 +0000 Subject: [PATCH 10/44] docs: [ci] generate new docs --- docs/hilbish.txt | 19 ++++++++++--------- emmyLuaDocs/hilbish.lua | 28 +++++++++++++++------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/docs/hilbish.txt b/docs/hilbish.txt index 80dad96..7b8dfea 100644 --- a/docs/hilbish.txt +++ b/docs/hilbish.txt @@ -7,7 +7,7 @@ A `scope` is currently only expected to be `command.`, replacing with the name of the command (for example `command.git`). `cb` must be a function that returns a table of "completion groups." A completion group is a table with the keys `items` and `type`. -`items` being a table of items and `type` being the display type of +`items` being a table of items and `type` being the display type, which is `grid` (the normal file completion display) or `list` (with a description) cwd() > Returns the current directory of the shell @@ -16,15 +16,16 @@ exec(cmd) > Replaces running hilbish with `cmd` goro(fn) > Puts `fn` in a goroutine -highlighter(cb) > Sets the highlighter function. This is mainly for syntax hightlighting, but in -reality could set the input of the prompt to display anything. The callback -is passed the current line as typed and is expected to return a line that will -be used to display in the line. +highlighter(line) > Line highlighter handler. This is mainly for syntax highlighting, but in +reality could set the input of the prompt to *display* anything. The +callback is passed the current line and is expected to return a line that +will be used as the input display. -hinter(cb) > Sets the hinter function. This will be called on every key insert to determine -what text to use as an inline hint. The callback is passed 2 arguments: -the current line and the position. It is expected to return a string -which will be used for the hint. +hinter(line, pos) > The command line hint handler. It gets called on every key insert to +determine what text to use as an inline hint. It is passed the current +line and cursor position. It is expected to return a string which is used +as the text for the hint. This is by default a shim. To set hints, +override this function with your custom handler. inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs or vim diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index 64f6f9c..b2848d1 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -16,7 +16,7 @@ function hilbish.appendPath(dir) end --- replacing with the name of the command (for example `command.git`). --- `cb` must be a function that returns a table of "completion groups." --- A completion group is a table with the keys `items` and `type`. ---- `items` being a table of items and `type` being the display type of +--- `items` being a table of items and `type` being the display type, which is --- `grid` (the normal file completion display) or `list` (with a description) --- @param scope string --- @param cb function @@ -33,19 +33,21 @@ function hilbish.exec(cmd) end --- @param fn function function hilbish.goro(fn) end ---- Sets the highlighter function. This is mainly for syntax hightlighting, but in ---- reality could set the input of the prompt to display anything. The callback ---- 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 -function hilbish.highlighter(cb) end +--- Line highlighter handler. This is mainly for syntax highlighting, but in +--- reality could set the input of the prompt to *display* anything. The +--- callback is passed the current line and is expected to return a line that +--- will be used as the input display. +--- @param line string +function hilbish.highlighter(line) end ---- Sets the hinter function. This will be called on every key insert to determine ---- what text to use as an inline hint. The callback is passed 2 arguments: ---- the current line and the position. It is expected to return a string ---- which will be used for the hint. ---- @param cb function -function hilbish.hinter(cb) end +--- The command line hint handler. It gets called on every key insert to +--- determine what text to use as an inline hint. It is passed the current +--- line and cursor position. It is expected to return a string which is used +--- as the text for the hint. This is by default a shim. To set hints, +--- override this function with your custom handler. +--- @param line string +--- @param pos int +function hilbish.hinter(line, pos) end --- Sets the input mode for Hilbish's line reader. Accepts either emacs or vim --- @param mode string From 1ba88fea88b4cdcd6b4bf2ec843271c56a04e7db Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Thu, 21 Apr 2022 23:41:49 -0400 Subject: [PATCH 11/44] fix: correct custom runner mode handling with recent changes --- exec.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exec.go b/exec.go index 90498ab..fcedf62 100644 --- a/exec.go +++ b/exec.go @@ -73,7 +73,7 @@ func runInput(input string, priv bool) { } } else { // can only be a string or function so - term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false) + term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 3, false) err := rt.Call(l.MainThread(), runnerMode, []rt.Value{rt.StringValue(cmdString)}, term) if err != nil { fmt.Fprintln(os.Stderr, err) @@ -81,9 +81,9 @@ func runInput(input string, priv bool) { return } - luaexitcode := term.Get(0) - runErr := term.Get(1) - luaInput := term.Get(1) + luaInput := term.Get(0) + luaexitcode := term.Get(1) + runErr := term.Get(2) var exitCode uint8 if code, ok := luaexitcode.TryInt(); ok { From 3194add3dccbfbdb27a3cf04ce028dcabbc53adf Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 10:42:04 -0400 Subject: [PATCH 12/44] fix: restore doc related metafields on hilbish table --- api.go | 22 +++++++++++----------- util/util.go | 22 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/api.go b/api.go index bdab365..94263a2 100644 --- a/api.go +++ b/api.go @@ -107,17 +107,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(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(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(rtm, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)") - util.SetField(rtm, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command") - util.Document(mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.") + util.SetFieldProtected(fakeMod, mod, "ver", rt.StringValue(version), "Hilbish version") + util.SetFieldProtected(fakeMod, mod, "user", rt.StringValue(username), "Username of user") + util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host), "Host name of the machine") + util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir), "Home directory of the user") + util.SetFieldProtected(fakeMod, mod, "dataDir", rt.StringValue(dataDir), "Directory for Hilbish's data files") + util.SetFieldProtected(fakeMod, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive shell") + util.SetFieldProtected(fakeMod, mod, "login", rt.BoolValue(login), "Whether this is a login shell") + util.SetFieldProtected(fakeMod, mod, "greeting", rt.StringValue(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.") + util.SetFieldProtected(fakeMod, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)") + util.SetFieldProtected(fakeMod, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command") + util.Document(fakeMod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.") // hilbish.userDir table hshuser := rt.NewTable() diff --git a/util/util.go b/util/util.go index e46d4b2..6b5860e 100644 --- a/util/util.go +++ b/util/util.go @@ -25,14 +25,20 @@ func Document(module *rt.Table, doc string) { // It is accessible via the __docProp metatable. It is a table of the names of the fields. func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, doc string) { // TODO: ^ rtm isnt needed, i should remove it + SetFieldDoc(module, field, doc) + module.Set(rt.StringValue(field), value) +} + +// SetFieldDoc sets the __docProp metatable for a field on the +// module. +func SetFieldDoc(module *rt.Table, field, doc string) { mt := module.Metatable() - + if mt == nil { mt = rt.NewTable() - module.SetMetatable(mt) } - + docProp := mt.Get(rt.StringValue("__docProp")) if docProp == rt.NilValue { docPropTbl := rt.NewTable() @@ -41,7 +47,15 @@ func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, d } docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc)) - module.Set(rt.StringValue(field), value) +} + +// SetFieldProtected sets a field in a protected table. A protected table +// is one which has a metatable proxy to ensure no overrides happen to it. +// It sets the field in the table and sets the __docProp metatable on the +// user facing table. +func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Value, doc string) { + SetFieldDoc(module, field, doc) + realModule.Set(rt.StringValue(field), value) } // DoString runs the code string in the Lua runtime. From abfbeb5f84d1c97f08c399b226c5191c22aed12f Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:16:35 -0400 Subject: [PATCH 13/44] feat: allow overwrite of completion handler (closes #122) this also makes the completion functions `bins` and `files` also return the prefix to pass to the completion handler. this is an overhaul to the completion system, which gets the completion handler from lua instead of being made to only have lua provided *command* completions. it does not have any performance deficit, even though it calls in to golua for completions. --- api.go | 14 +--- complete.go | 104 +++++++++++++++++++++++++- rl.go | 206 +++++++++++++++++++--------------------------------- 3 files changed, 174 insertions(+), 150 deletions(-) diff --git a/api.go b/api.go index 94263a2..d454b8e 100644 --- a/api.go +++ b/api.go @@ -149,19 +149,7 @@ Check out the {blue}{bold}guide{reset} command to get started. util.Document(historyModule, "History interface for Hilbish.") // hilbish.completion table - hshcomp := rt.NewTable() - util.SetField(rtm, hshcomp, "files", - rt.FunctionValue(rt.NewGoFunction(luaFileComplete, "files", 3, false)), - "Completer for files") - - util.SetField(rtm, hshcomp, "bins", - rt.FunctionValue(rt.NewGoFunction(luaBinaryComplete, "bins", 3, false)), - "Completer for executables/binaries") - - util.SetField(rtm, hshcomp, "call", - rt.FunctionValue(rt.NewGoFunction(callLuaCompleter, "call", 4, false)), - "Calls a completer and get its entries for completions") - + hshcomp := completionLoader(rtm) util.Document(hshcomp, "Completions interface for Hilbish.") mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp)) diff --git a/complete.go b/complete.go index 68f5d67..1e36681 100644 --- a/complete.go +++ b/complete.go @@ -11,6 +11,8 @@ import ( rt "github.com/arnodel/golua/runtime" ) +var completer rt.Value + func fileComplete(query, ctx string, fields []string) ([]string, string) { return matchPath(query) } @@ -117,6 +119,100 @@ func escapeFilename(fname string) string { return r.Replace(fname) } +func completionLoader(rtm *rt.Runtime) *rt.Table { + exports := map[string]util.LuaExport{ + "files": {luaFileComplete, 3, false}, + "bins": {luaBinaryComplete, 3, false}, + "call": {callLuaCompleter, 4, false}, + "handler": {completionHandler, 2, false}, + } + + mod := rt.NewTable() + util.SetExports(rtm, mod, exports) + + return mod +} + +func completionHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.CheckNArgs(2); err != nil { + return nil, err + } + line, err := c.StringArg(0) + if err != nil { + return nil, err + } + // just for validation + _, err = c.IntArg(1) + if err != nil { + return nil, err + } + + ctx := strings.TrimLeft(line, " ") + if len(ctx) == 0 { + return c.PushingNext(t.Runtime, rt.TableValue(rt.NewTable()), rt.StringValue("")), nil + } + + ctx = aliases.Resolve(ctx) + fields := strings.Split(ctx, " ") + query := fields[len(fields) - 1] + + luaFields := rt.NewTable() + + for i, f := range fields { + luaFields.Set(rt.IntValue(int64(i + 1)), rt.StringValue(f)) + } + + compMod := hshMod.Get(rt.StringValue("completion")).AsTable() + var term *rt.Termination + if len(fields) == 1 { + term = rt.NewTerminationWith(t.CurrentCont(), 2, false) + err := rt.Call(t, compMod.Get(rt.StringValue("bins")), []rt.Value{ + rt.StringValue(query), + rt.StringValue(ctx), + rt.TableValue(luaFields), + }, term) + + if err != nil { + return nil, err + } + } else { + gterm := rt.NewTerminationWith(t.CurrentCont(), 2, false) + err := rt.Call(t, compMod.Get(rt.StringValue("call")), []rt.Value{ + rt.StringValue("commands." + fields[0]), + rt.StringValue(query), + rt.StringValue(ctx), + rt.TableValue(luaFields), + }, gterm) + + if err == nil { + groups := gterm.Get(0) + pfx := gterm.Get(1) + + return c.PushingNext(t.Runtime, groups, pfx), nil + } + + // error means there isnt a command handler - default to files in that case + term = rt.NewTerminationWith(t.CurrentCont(), 2, false) + err = rt.Call(t, compMod.Get(rt.StringValue("files")), []rt.Value{ + rt.StringValue(query), + rt.StringValue(ctx), + rt.TableValue(luaFields), + }, term) + } + + comps := term.Get(0) + pfx := term.Get(1) + + groups := rt.NewTable() + + compGroup := rt.NewTable() + compGroup.Set(rt.StringValue("items"), comps) + compGroup.Set(rt.StringValue("type"), rt.StringValue("grid")) + + groups.Set(rt.IntValue(1), rt.TableValue(compGroup)) + return c.PushingNext(t.Runtime, rt.TableValue(groups), pfx), nil +} + func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.CheckNArgs(4); err != nil { return nil, err @@ -162,14 +258,14 @@ func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return nil, err } - completions, _ := fileComplete(query, ctx, fds) + completions, pfx := fileComplete(query, ctx, fds) luaComps := rt.NewTable() for i, comp := range completions { luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp)) } - return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil + return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil } func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -178,14 +274,14 @@ func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return nil, err } - completions, _ := binaryComplete(query, ctx, fds) + completions, pfx := binaryComplete(query, ctx, fds) luaComps := rt.NewTable() for i, comp := range completions { luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp)) } - return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil + return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil } func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) { diff --git a/rl.go b/rl.go index cd1f4eb..88adc65 100644 --- a/rl.go +++ b/rl.go @@ -84,151 +84,91 @@ func newLineReader(prompt string, noHist bool) *lineReader { return highlighted } rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) { - ctx := string(line) + term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false) + compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler")) + err := rt.Call(l.MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)), + rt.IntValue(int64(pos))}, term) - var compGroup []*readline.CompletionGroup - - ctx = strings.TrimLeft(ctx, " ") - if len(ctx) == 0 { - return "", compGroup + var compGroups []*readline.CompletionGroup + if err != nil { + return "", compGroups } - fields := strings.Split(ctx, " ") - if len(fields) == 0 { - return "", compGroup + luaCompGroups := term.Get(0) + luaPrefix := term.Get(1) + + if luaCompGroups.Type() != rt.TableType { + return "", compGroups } - query := fields[len(fields) - 1] - ctx = aliases.Resolve(ctx) + groups := luaCompGroups.AsTable() + // prefix is optional + pfx, _ := luaPrefix.TryString() - if len(fields) == 1 { - completions, prefix := binaryComplete(query, ctx, fields) + util.ForEach(groups, func(key rt.Value, val rt.Value) { + if key.Type() != rt.IntType || val.Type() != rt.TableType { + return + } - compGroup = append(compGroup, &readline.CompletionGroup{ - TrimSlash: false, - NoSpace: true, - Suggestions: completions, + valTbl := val.AsTable() + luaCompType := valTbl.Get(rt.StringValue("type")) + luaCompItems := valTbl.Get(rt.StringValue("items")) + + if luaCompType.Type() != rt.StringType || luaCompItems.Type() != rt.TableType { + return + } + + items := []string{} + itemDescriptions := make(map[string]string) + + util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) { + if keytyp := lkey.Type(); keytyp == rt.StringType { + // ['--flag'] = {'description', '--flag-alias'} + itemName, ok := lkey.TryString() + vlTbl, okk := lval.TryTable() + if !ok && !okk { + // TODO: error + return + } + + items = append(items, itemName) + itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString() + if !ok { + // TODO: error + return + } + itemDescriptions[itemName] = itemDescription + } else if keytyp == rt.IntType { + vlStr, ok := lval.TryString() + if !ok { + // TODO: error + return + } + items = append(items, vlStr) + } else { + // TODO: error + return + } }) - return prefix, compGroup - } else { - if completecb, ok := luaCompletions["command." + fields[0]]; ok { - luaFields := rt.NewTable() - for i, f := range fields { - luaFields.Set(rt.IntValue(int64(i + 1)), rt.StringValue(f)) - } - - // we must keep the holy 80 cols - luacompleteTable, err := rt.Call1(l.MainThread(), - rt.FunctionValue(completecb), rt.StringValue(query), - rt.StringValue(ctx), rt.TableValue(luaFields)) - - if err != nil { - return "", compGroup - } - - /* - as an example with git, - completion table should be structured like: - { - { - items = { - 'add', - 'clone', - 'init' - }, - type = 'grid' - }, - { - items = { - '-c', - '--git-dir' - }, - type = 'list' - } - } - ^ a table of completion groups. - it is the responsibility of the completer - to work on subcommands and subcompletions - */ - if cmpTbl, ok := luacompleteTable.TryTable(); ok { - util.ForEach(cmpTbl, func(key rt.Value, val rt.Value) { - if key.Type() != rt.IntType && val.Type() != rt.TableType { - return - } - - valTbl := val.AsTable() - luaCompType := valTbl.Get(rt.StringValue("type")) - luaCompItems := valTbl.Get(rt.StringValue("items")) - - if luaCompType.Type() != rt.StringType && luaCompItems.Type() != rt.TableType { - return - } - - items := []string{} - itemDescriptions := make(map[string]string) - - util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) { - if keytyp := lkey.Type(); keytyp == rt.StringType { - // ['--flag'] = {'description', '--flag-alias'} - itemName, ok := lkey.TryString() - vlTbl, okk := lval.TryTable() - if !ok && !okk { - // TODO: error - return - } - - items = append(items, itemName) - itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString() - if !ok { - // TODO: error - return - } - itemDescriptions[itemName] = itemDescription - } else if keytyp == rt.IntType { - vlStr, ok := lval.TryString() - if !ok { - // TODO: error - return - } - items = append(items, vlStr) - } else { - // TODO: error - return - } - }) - - var dispType readline.TabDisplayType - switch luaCompType.AsString() { - case "grid": dispType = readline.TabDisplayGrid - case "list": dispType = readline.TabDisplayList - // need special cases, will implement later - //case "map": dispType = readline.TabDisplayMap - } - - compGroup = append(compGroup, &readline.CompletionGroup{ - DisplayType: dispType, - Descriptions: itemDescriptions, - Suggestions: items, - TrimSlash: false, - NoSpace: true, - }) - }) - } + var dispType readline.TabDisplayType + switch luaCompType.AsString() { + case "grid": dispType = readline.TabDisplayGrid + case "list": dispType = readline.TabDisplayList + // need special cases, will implement later + //case "map": dispType = readline.TabDisplayMap } - if len(compGroup) == 0 { - completions, p := fileComplete(query, ctx, fields) - fcompGroup := []*readline.CompletionGroup{{ - TrimSlash: false, - NoSpace: true, - Suggestions: completions, - }} + compGroups = append(compGroups, &readline.CompletionGroup{ + DisplayType: dispType, + Descriptions: itemDescriptions, + Suggestions: items, + TrimSlash: false, + NoSpace: true, + }) + }) - return p, fcompGroup - } - } - return "", compGroup + return pfx, compGroups } return &lineReader{ From 03a57fce5bcd79f5cbd2fd9b997b2e703b1b81dc Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:25:39 -0400 Subject: [PATCH 14/44] docs: add more documentation for completions --- api.go | 4 +--- docs/completions.txt | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 docs/completions.txt diff --git a/api.go b/api.go index d454b8e..5510717 100644 --- a/api.go +++ b/api.go @@ -497,9 +497,7 @@ func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // A `scope` is currently only expected to be `command.`, // replacing with the name of the command (for example `command.git`). // `cb` must be a function that returns a table of "completion groups." -// A completion group is a table with the keys `items` and `type`. -// `items` being a table of items and `type` being the display type, which is -// `grid` (the normal file completion display) or `list` (with a description) +// Check `doc completions` for more information. // --- @param scope string // --- @param cb function func hlcomplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { diff --git a/docs/completions.txt b/docs/completions.txt new file mode 100644 index 0000000..1354dc0 --- /dev/null +++ b/docs/completions.txt @@ -0,0 +1,44 @@ +Hilbish has a pretty good completion system. It has a nice looking menu, +with 2 types of menus: grid (like file completions) or list. + +Like most parts of Hilbish, it's made to be extensible and customizable. +The default handler for completions in general can be overwritten to provide +more advanced completions if needed. + +# Completion Handler +By default, it provides 3 things: for the first argument, binaries (with a +plain name requested to complete, those in $PATH), files, or command +completions. With the default completion handler, it will try to run a +handler for the command or fallback to file completions. + +To overwrite it, just assign a function to `hilbish.completion.handler` +like so: +function hilbish.completion.handler(line, pos) + -- do things +end +It is passed 2 arguments, the entire line, and the current cursor position. +The functions in the completion interface take 3 arguments: query, ctx, +and fields. The `query`, which what the user is currently trying to complete, +`ctx`, being just the entire line, and `fields` being a table of arguments. +It's just `ctx` split up, delimited by spaces. +It's expected to return 2 things: a table of completion groups, and a prefix. +A completion group is defined as a table with 2 keys: `items` and `type`. +The `items` field is just a table of items to use for completions. +The `type` is for the completion menu type, being either `grid` or `list`. +The prefix is what all the completions start with. It should be empty +if the user doesn't have a query. If the beginning of the completion +item does not match the prefix, it will be replaced and fixed properly +in the line. It is case sensitive. + +If you want to overwrite the functionality of the general completion handler, +or make your command completion have files as well (and filter them), +then there is the `files` function, which is mentioned below. + +# Completion Interface +## Functions +- `files(query, ctx, fields)` -> table, prefix: get file completions, based +on the user's query. +- `bins(query, ctx, fields)` -> table, prefix: get binary/executable +completions, based on user query. +- `call(scope, query, ctx, fields)` -> table, prefix: call a completion handler +with `scope`, usually being in the form of `command.` From dbb27f77396079535399c3211683c51a5bbaa133 Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Sat, 23 Apr 2022 01:26:03 +0000 Subject: [PATCH 15/44] docs: [ci] generate new docs --- docs/hilbish.txt | 4 +--- emmyLuaDocs/hilbish.lua | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/hilbish.txt b/docs/hilbish.txt index 7b8dfea..d9763a0 100644 --- a/docs/hilbish.txt +++ b/docs/hilbish.txt @@ -6,9 +6,7 @@ complete(scope, cb) > Registers a completion handler for `scope`. A `scope` is currently only expected to be `command.`, replacing with the name of the command (for example `command.git`). `cb` must be a function that returns a table of "completion groups." -A completion group is a table with the keys `items` and `type`. -`items` being a table of items and `type` being the display type, which is -`grid` (the normal file completion display) or `list` (with a description) +Check `doc completions` for more information. cwd() > Returns the current directory of the shell diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index b2848d1..ca34425 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -15,9 +15,7 @@ function hilbish.appendPath(dir) end --- A `scope` is currently only expected to be `command.`, --- replacing with the name of the command (for example `command.git`). --- `cb` must be a function that returns a table of "completion groups." ---- A completion group is a table with the keys `items` and `type`. ---- `items` being a table of items and `type` being the display type, which is ---- `grid` (the normal file completion display) or `list` (with a description) +--- Check `doc completions` for more information. --- @param scope string --- @param cb function function hilbish.complete(scope, cb) end From 27ac60b856b87cdc93ce0d69ec194f91595bd2c2 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:26:48 -0400 Subject: [PATCH 16/44] fix: remove unused var --- complete.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/complete.go b/complete.go index 1e36681..561f579 100644 --- a/complete.go +++ b/complete.go @@ -11,8 +11,6 @@ import ( rt "github.com/arnodel/golua/runtime" ) -var completer rt.Value - func fileComplete(query, ctx string, fields []string) ([]string, string) { return matchPath(query) } From bca89197ad584797c70272ee45f9165a99145b74 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:31:24 -0400 Subject: [PATCH 17/44] fix: add io flush after doc help message --- prelude/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/prelude/init.lua b/prelude/init.lua index a5b6568..21467b0 100644 --- a/prelude/init.lua +++ b/prelude/init.lua @@ -135,6 +135,7 @@ Usage: doc
[subdoc] A section is a module or a literal section and a subdoc is a subsection for it. Available sections: ]] + io.flush() print(table.concat(modules, ', ')) end) From 1714aeac368f14ede6813206743e8291292d1709 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 23:35:26 -0400 Subject: [PATCH 18/44] feat: add fs.abs --- golibs/fs/fs.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/golibs/fs/fs.go b/golibs/fs/fs.go index 042f2a8..eda1671 100644 --- a/golibs/fs/fs.go +++ b/golibs/fs/fs.go @@ -1,6 +1,7 @@ package fs import ( + "path/filepath" "strconv" "os" "strings" @@ -22,6 +23,7 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { "mkdir": util.LuaExport{fmkdir, 2, false}, "stat": util.LuaExport{fstat, 1, false}, "readdir": util.LuaExport{freaddir, 1, false}, + "abs": util.LuaExport{fabs, 1, false}, } mod := rt.NewTable() util.SetExports(rtm, mod, exports) @@ -132,3 +134,20 @@ func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil } + +// abs(path) +// Gives an absolute version of `path`. +// --- @param path string +func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + path, err := c.StringArg(0) + if err != nil { + return nil, err + } + + abspath, err := filepath.Abs(path) + if err != nil { + return nil, err + } + + return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil +} From f00324963206598b28eff0472e494846163e5fa5 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 23:45:28 -0400 Subject: [PATCH 19/44] docs: update doc reference for vim mode actions --- docs/hooks/hilbish.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hooks/hilbish.txt b/docs/hooks/hilbish.txt index 7a438f6..d6d5542 100644 --- a/docs/hooks/hilbish.txt +++ b/docs/hooks/hilbish.txt @@ -4,4 +4,4 @@ `modeName` is the name of the mode changed to (can be `insert`, `normal`, `delete` or `replace`). + `hilbish.vimAction` -> actionName, args > Sent when the user does a "vim action," being something -like yanking or pasting text. See `doc vimMode actions` for more info. +like yanking or pasting text. See `doc vim-mode actions` for more info. From 9e596dc271d18b7f8be9b07c7bce2028357857d2 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 22 Apr 2022 23:56:57 -0400 Subject: [PATCH 20/44] refactor: (re)organize and change prelude path and structure prelude is no longer. it is now nature. organized the single file prelude into multiple source files and renamed it to nature. this is coming after thought that it can turn into a general hilbish lua core, with user facing modules as well. this introduces the `nature.dirs` module, to interact and get recently changed to directories and last/old cwd. --- Makefile | 2 +- lua.go | 2 +- nature/commands/cd.lua | 35 +++++ nature/commands/cdr.lua | 39 ++++++ nature/commands/doc.lua | 93 +++++++++++++ nature/commands/exit.lua | 7 + nature/commands/guide.lua | 54 ++++++++ nature/commands/init.lua | 6 + nature/dirs.lua | 75 +++++++++++ nature/hooks.lua | 11 ++ nature/init.lua | 44 +++++++ prelude/init.lua | 265 -------------------------------------- vars_darwin.go | 2 +- vars_linux.go | 2 +- vars_windows.go | 2 +- 15 files changed, 369 insertions(+), 270 deletions(-) create mode 100644 nature/commands/cd.lua create mode 100644 nature/commands/cdr.lua create mode 100644 nature/commands/doc.lua create mode 100644 nature/commands/exit.lua create mode 100644 nature/commands/guide.lua create mode 100644 nature/commands/init.lua create mode 100644 nature/dirs.lua create mode 100644 nature/hooks.lua create mode 100644 nature/init.lua delete mode 100644 prelude/init.lua diff --git a/Makefile b/Makefile index 660bc58..a0c6580 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ build: install: install -v -d "$(DESTDIR)$(BINDIR)/" && install -m 0755 -v hilbish "$(DESTDIR)$(BINDIR)/hilbish" mkdir -p "$(DESTDIR)$(LIBDIR)" - cp -r libs docs emmyLuaDocs prelude .hilbishrc.lua "$(DESTDIR)$(LIBDIR)" + cp -r libs docs emmyLuaDocs nature .hilbishrc.lua "$(DESTDIR)$(LIBDIR)" grep -qxF "$(DESTDIR)$(BINDIR)/hilbish" /etc/shells || echo "$(DESTDIR)$(BINDIR)/hilbish" >> /etc/shells uninstall: diff --git a/lua.go b/lua.go index 3b925c6..838ce8a 100644 --- a/lua.go +++ b/lua.go @@ -54,7 +54,7 @@ func luaInit() { fmt.Fprintln(os.Stderr, "Could not add preload paths! Libraries will be missing. This shouldn't happen.") } - err = util.DoFile(l, "prelude/init.lua") + err = util.DoFile(l, "nature/init.lua") if err != nil { err = util.DoFile(l, preloadPath) if err != nil { diff --git a/nature/commands/cd.lua b/nature/commands/cd.lua new file mode 100644 index 0000000..509e774 --- /dev/null +++ b/nature/commands/cd.lua @@ -0,0 +1,35 @@ +local bait = require 'bait' +local commander = require 'commander' +local fs = require 'fs' +local dirs = require 'nature.dirs' + +dirs.old = hilbish.cwd() +commander.register('cd', function (args) + if #args > 1 then + print("cd: too many arguments") + return 1 + elseif #args > 0 then + local path = args[1]:gsub('$%$','\0'):gsub('${([%w_]+)}', os.getenv) + :gsub('$([%w_]+)', os.getenv):gsub('%z','$'):gsub('^%s*(.-)%s*$', '%1') + + if path == '-' then + path = dirs.old + print(path) + end + dirs.setOld(hilbish.cwd()) + dirs.push(path) + + local ok, err = pcall(function() fs.cd(path) end) + if not ok then + print(err) + return 1 + end + bait.throw('cd', path) + + return + end + fs.cd(hilbish.home) + bait.throw('cd', hilbish.home) + + dirs.addRecent(hilbish.home) +end) diff --git a/nature/commands/cdr.lua b/nature/commands/cdr.lua new file mode 100644 index 0000000..0438e6f --- /dev/null +++ b/nature/commands/cdr.lua @@ -0,0 +1,39 @@ +local commander = require 'commander' +local fs = require 'fs' +local lunacolors = require 'lunacolors' +local dirs = require 'nature.dirs' + +commander.register('cdr', function(args) + if not args[1] then + print(lunacolors.format [[ +cdr: change directory to one which has been recently visied + +usage: cdr + +to get a list of recent directories, use {green}{underline}cdr list{reset}]]) + return + end + + if args[1] == 'list' then + local recentDirs = dirs.recentDirs + if #recentDirs == 0 then + print 'No directories have been visited.' + return 1 + end + print(table.concat(recentDirs, '\n')) + return + end + + local index = tonumber(args[1]) + if not index then + print(string.format('Received %s as index, which isn\'t a number.', index)) + return 1 + end + + if not dirs.recent(index) then + print(string.format('No recent directory found at index %s.', index)) + return 1 + end + + fs.cd(dirs.recent(index)) +end) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua new file mode 100644 index 0000000..34e81ae --- /dev/null +++ b/nature/commands/doc.lua @@ -0,0 +1,93 @@ +local commander = require 'commander' +local fs = require 'fs' +local lunacolors = require 'lunacolors' + +commander.register('doc', function(args) + local moddocPath = hilbish.dataDir .. '/docs/' + local modDocFormat = [[ +%s +%s +# Functions +]] + + if #args > 0 then + local mod = args[1] + + local f = io.open(moddocPath .. mod .. '.txt', 'rb') + local funcdocs = nil + if not f then + -- assume subdir + -- dataDir/docs//.txt + moddocPath = moddocPath .. mod .. '/' + local subdocName = args[2] + if not subdocName then + subdocName = 'index' + end + f = io.open(moddocPath .. subdocName .. '.txt', 'rb') + if not f then + print('No documentation found for ' .. mod .. '.') + return + end + funcdocs = f:read '*a' + local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.txt' end) + local subdocs = table.map(moddocs, function(fname) + return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.txt', ''))) + end) + if subdocName == 'index' then + funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') + end + end + + if not funcdocs then + funcdocs = f:read '*a' + end + local desc = '' + local ok = pcall(require, mod) + local backtickOccurence = 0 + local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function() + backtickOccurence = backtickOccurence + 1 + if backtickOccurence % 2 == 0 then + return '{reset}' + else + return '{underline}{green}' + end + end)) + + if ok then + local props = {} + local propstr = '' + local modDesc = '' + local modmt = getmetatable(require(mod)) + modDesc = modmt.__doc + if modmt.__docProp then + -- not all modules have docs for properties + props = table.map(modmt.__docProp, function(v, k) + return lunacolors.underline(lunacolors.blue(k)) .. ' > ' .. v + end) + end + if #props > 0 then + propstr = '\n# Properties\n' .. table.concat(props, '\n') .. '\n' + end + desc = string.format(modDocFormat, modDesc, propstr) + end + print(desc .. formattedFuncs) + f:close() + + return + end + local modules = table.map(fs.readdir(moddocPath), function(f) + return lunacolors.underline(lunacolors.blue(string.gsub(f, '.txt', ''))) + end) + + io.write [[ +Welcome to Hilbish's doc tool! Here you can find documentation for builtin +functions and other things. + +Usage: doc
[subdoc] +A section is a module or a literal section and a subdoc is a subsection for it. + +Available sections: ]] + io.flush() + + print(table.concat(modules, ', ')) +end) diff --git a/nature/commands/exit.lua b/nature/commands/exit.lua new file mode 100644 index 0000000..421730c --- /dev/null +++ b/nature/commands/exit.lua @@ -0,0 +1,7 @@ +local bait = require 'bait' +local commander = require 'commander' + +commander.register('exit', function() + bait.throw('hilbish.exit') + os.exit(0) +end) diff --git a/nature/commands/guide.lua b/nature/commands/guide.lua new file mode 100644 index 0000000..1c1e346 --- /dev/null +++ b/nature/commands/guide.lua @@ -0,0 +1,54 @@ +local ansikit = require 'ansikit' +local commander = require 'commander' + +local helpTexts = { +[[ +Hello there! Welcome to Hilbish, the comfy and nice little shell for +Lua users and fans. Hilbish is configured with Lua, and its +scripts are also in Lua. It also runs both Lua and shell script when +interactive (aka normal usage). +]], +[[ +What does that mean for you, the user? It means that if you prefer to +use Lua for scripting instead of shell script but still have ordinary +shell usage for interactive use. +]], +[[ +If this is your first time using Hilbish and Lua, check out the +Programming in Lua book here: https://www.lua.org/pil +After (or if you already know Lua) check out the doc command. +It is an in shell tool for documentation about Hilbish provided +functions and modules. +]], +[[ +If you've updated from a pre-1.0 version (0.7.1 as an example) +you'll want to move your config from ~/.hilbishrc.lua to +]] .. +hilbish.userDir.config .. '/hilbish/init.lua' .. +[[ + +and also change all global functions (prompt, alias) to be +in the hilbish module (hilbish.prompt, hilbish.alias as examples). + +And if this is your first time (most likely), you can copy a config +from ]] .. hilbish.dataDir, +[[ +Since 1.0 is a big release, you'll want to check the changelog +at https://github.com/Rosettea/Hilbish/releases/tag/v1.0.0 +to find more breaking changes. +]] +} +commander.register('guide', function() + ansikit.clear() + ansikit.cursorTo(0, 0) + for _, text in ipairs(helpTexts) do + print(text) + local out = hilbish.read('Hit enter to continue ') + ansikit.clear() + ansikit.cursorTo(0, 0) + if not out then + return + end + end + print 'Hope you enjoy using Hilbish!' +end) diff --git a/nature/commands/init.lua b/nature/commands/init.lua new file mode 100644 index 0000000..e824c7c --- /dev/null +++ b/nature/commands/init.lua @@ -0,0 +1,6 @@ +-- Add command builtins +require 'nature.commands.cd' +require 'nature.commands.cdr' +require 'nature.commands.doc' +require 'nature.commands.exit' +require 'nature.commands.guide' diff --git a/nature/dirs.lua b/nature/dirs.lua new file mode 100644 index 0000000..5b7ec86 --- /dev/null +++ b/nature/dirs.lua @@ -0,0 +1,75 @@ +local fs = require 'fs' + +local dirs = {} + +--- Last (current working) directory. Separate from recentDirs mainly for +--- easier use. +dirs.old = '' +--- Table of recent directories. For use, look at public functions. +dirs.recentDirs = {} +--- Size of the recentDirs table. +dirs.recentSize = 10 + +--- Get (and remove) a `num` of entries from recent directories. +--- @param num number +--- @param remove boolean Whether to remove items +function dirRecents(num, remove) + num = num or 1 + local entries = {} + + if #dirs.recentDirs ~= 0 then + for i = 1, num do + local idx = remove and 1 or i + if not dirs.recentDirs[idx] then break end + table.insert(entries, dirs.recentDirs[idx]) + if remove then table.remove(dirs.recentDirs, 1) end + end + end + + if #entries == 1 then + return entries[1] + end + + return entries +end + +--- Look at `num` amount of recent directories, starting from the latest. +--- @param num? number +function dirs.peak(num) + return dirRecents(num) +end + +--- Add `d` to the recent directories. +function dirs.push(d) + dirs.recentDirs[dirs.recentSize + 1] = nil + if dirs.recentDirs[#dirs.recentDirs - 1] ~= d then + ok, d = pcall(fs.abs, d) + assert(ok, 'could not turn "' .. d .. '"into an absolute path') + + table.insert(dirs.recentDirs, 1, d) + end +end + +--- Remove `num` amount of dirs from the recent directories. +--- @param num number +function dirs.pop(num) + return dirRecents(num, true) +end + +--- Get entry from recent directories. +--- @param idx number +function dirs.recent(idx) + return dirs.recentDirs[idx] +end + +--- Sets the old directory. +--- @param d string +function dirs.setOld(d) + ok, d = pcall(fs.abs, d) + assert(ok, 'could not turn "' .. d .. '"into an absolute path') + + os.setenv('OLDPWD', d) + dirs.old = d +end + +return dirs diff --git a/nature/hooks.lua b/nature/hooks.lua new file mode 100644 index 0000000..a9bd0b1 --- /dev/null +++ b/nature/hooks.lua @@ -0,0 +1,11 @@ +local bait = require 'bait' + +-- Hook handles +bait.catch('command.not-found', function(cmd) + print(string.format('hilbish: %s not found', cmd)) +end) + +bait.catch('command.not-executable', function(cmd) + print(string.format('hilbish: %s: not executable', cmd)) +end) + diff --git a/nature/init.lua b/nature/init.lua new file mode 100644 index 0000000..5e07298 --- /dev/null +++ b/nature/init.lua @@ -0,0 +1,44 @@ +-- Prelude initializes everything else for our shell +local _ = require 'succulent' -- Function additions + +package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' +.. ';' .. hilbish.dataDir .. '/?/?.lua' + +require 'nature.hooks' +require 'nature.commands' + +local shlvl = tonumber(os.getenv 'SHLVL') +if shlvl ~= nil then + os.setenv('SHLVL', tostring(shlvl + 1)) +else + os.setenv('SHLVL', '0') +end + +do + local virt_G = { } + + setmetatable(_G, { + __index = function (_, key) + local got_virt = virt_G[key] + if got_virt ~= nil then + return got_virt + end + + virt_G[key] = os.getenv(key) + return virt_G[key] + end, + + __newindex = function (_, key, value) + if type(value) == 'string' then + os.setenv(key, value) + virt_G[key] = value + else + if type(virt_G[key]) == 'string' then + os.setenv(key, '') + end + virt_G[key] = value + end + end, + }) +end + diff --git a/prelude/init.lua b/prelude/init.lua deleted file mode 100644 index 21467b0..0000000 --- a/prelude/init.lua +++ /dev/null @@ -1,265 +0,0 @@ --- The preload file initializes everything else for our shell -local ansikit = require 'ansikit' -local bait = require 'bait' -local commander = require 'commander' -local fs = require 'fs' -local lunacolors = require 'lunacolors' -local _ = require 'succulent' -- Function additions -local oldDir = hilbish.cwd() - -local shlvl = tonumber(os.getenv 'SHLVL') -if shlvl ~= nil then os.setenv('SHLVL', tostring(shlvl + 1)) else os.setenv('SHLVL', '0') end - --- Builtins -local recentDirs = {} -commander.register('cd', function (args) - if #args > 0 then - local path = table.concat(args, ' '):gsub('$%$','\0'):gsub('${([%w_]+)}', os.getenv) - :gsub('$([%w_]+)', os.getenv):gsub('%z','$'):gsub('^%s*(.-)%s*$', '%1') - - if path == '-' then - path = oldDir - print(path) - end - oldDir = hilbish.cwd() - - local ok, err = pcall(function() fs.cd(path) end) - if not ok then - print(err:sub(17)) - return 1 - end - bait.throw('cd', path) - - -- add to table of recent dirs - recentDirs[11] = nil - if recentDirs[#recentDirs - 1] ~= path then - table.insert(recentDirs, 1, path) - end - - return - end - fs.cd(hilbish.home) - bait.throw('cd', hilbish.home) - - table.insert(recentDirs, 1, hilbish.home) - recentDirs[11] = nil -end) - -commander.register('exit', function() - bait.throw('hilbish.exit') - os.exit(0) -end) - -commander.register('doc', function(args) - local moddocPath = hilbish.dataDir .. '/docs/' - local modDocFormat = [[ -%s -%s -# Functions -]] - - if #args > 0 then - local mod = args[1] - - local f = io.open(moddocPath .. mod .. '.txt', 'rb') - local funcdocs = nil - if not f then - -- assume subdir - -- dataDir/docs//.txt - moddocPath = moddocPath .. mod .. '/' - local subdocName = args[2] - if not subdocName then - subdocName = 'index' - end - f = io.open(moddocPath .. subdocName .. '.txt', 'rb') - if not f then - print('No documentation found for ' .. mod .. '.') - return - end - funcdocs = f:read '*a' - local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.txt' end) - local subdocs = table.map(moddocs, function(fname) - return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.txt', ''))) - end) - if subdocName == 'index' then - funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') - end - end - - if not funcdocs then - funcdocs = f:read '*a' - end - local desc = '' - local ok = pcall(require, mod) - local backtickOccurence = 0 - local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function() - backtickOccurence = backtickOccurence + 1 - if backtickOccurence % 2 == 0 then - return '{reset}' - else - return '{underline}{green}' - end - end)) - - if ok then - local props = {} - local propstr = '' - local modDesc = '' - local modmt = getmetatable(require(mod)) - modDesc = modmt.__doc - if modmt.__docProp then - -- not all modules have docs for properties - props = table.map(modmt.__docProp, function(v, k) - return lunacolors.underline(lunacolors.blue(k)) .. ' > ' .. v - end) - end - if #props > 0 then - propstr = '\n# Properties\n' .. table.concat(props, '\n') .. '\n' - end - desc = string.format(modDocFormat, modDesc, propstr) - end - print(desc .. formattedFuncs) - f:close() - - return - end - local modules = table.map(fs.readdir(moddocPath), function(f) - return lunacolors.underline(lunacolors.blue(string.gsub(f, '.txt', ''))) - end) - - io.write [[ -Welcome to Hilbish's doc tool! Here you can find documentation for builtin -functions and other things. - -Usage: doc
[subdoc] -A section is a module or a literal section and a subdoc is a subsection for it. - -Available sections: ]] - io.flush() - - print(table.concat(modules, ', ')) -end) - -local helpTexts = { -[[ -Hello there! Welcome to Hilbish, the comfy and nice little shell for -Lua users and fans. Hilbish is configured with Lua, and its -scripts are also in Lua. It also runs both Lua and shell script when -interactive (aka normal usage). -]], -[[ -What does that mean for you, the user? It means that if you prefer to -use Lua for scripting instead of shell script but still have ordinary -shell usage for interactive use. -]], -[[ -If this is your first time using Hilbish and Lua, check out the -Programming in Lua book here: https://www.lua.org/pil -After (or if you already know Lua) check out the doc command. -It is an in shell tool for documentation about Hilbish provided -functions and modules. -]], -[[ -If you've updated from a pre-1.0 version (0.7.1 as an example) -you'll want to move your config from ~/.hilbishrc.lua to -]] .. -hilbish.userDir.config .. '/hilbish/init.lua' .. -[[ - -and also change all global functions (prompt, alias) to be -in the hilbish module (hilbish.prompt, hilbish.alias as examples). - -And if this is your first time (most likely), you can copy a config -from ]] .. hilbish.dataDir, -[[ -Since 1.0 is a big release, you'll want to check the changelog -at https://github.com/Rosettea/Hilbish/releases/tag/v1.0.0 -to find more breaking changes. -]] -} -commander.register('guide', function() - ansikit.clear() - ansikit.cursorTo(0, 0) - for _, text in ipairs(helpTexts) do - print(text) - local out = hilbish.read('Hit enter to continue ') - ansikit.clear() - ansikit.cursorTo(0, 0) - if not out then - return - end - end - print 'Hope you enjoy using Hilbish!' -end) - -do - local virt_G = { } - - setmetatable(_G, { - __index = function (_, key) - local got_virt = virt_G[key] - if got_virt ~= nil then - return got_virt - end - - virt_G[key] = os.getenv(key) - return virt_G[key] - end, - - __newindex = function (_, key, value) - if type(value) == 'string' then - os.setenv(key, value) - virt_G[key] = value - else - if type(virt_G[key]) == 'string' then - os.setenv(key, '') - end - virt_G[key] = value - end - end, - }) -end - -commander.register('cdr', function(args) - if not args[1] then - print(lunacolors.format [[ -cdr: change directory to one which has been recently visied - -usage: cdr - -to get a list of recent directories, use {green}{underline}cdr list{reset}]]) - return - end - - if args[1] == 'list' then - if #recentDirs == 0 then - print 'No directories have been visited.' - return 1 - end - print(table.concat(recentDirs, '\n')) - return - end - - local index = tonumber(args[1]) - if not index then - print(string.format('received %s as index, which isn\'t a number', index)) - return 1 - end - - if not recentDirs[index] then - print(string.format('no recent directory found at index %s', index)) - return 1 - end - - fs.cd(recentDirs[index]) -end) - --- Hook handles -bait.catch('command.not-found', function(cmd) - print(string.format('hilbish: %s not found', cmd)) -end) - -bait.catch('command.not-executable', function(cmd) - print(string.format('hilbish: %s: not executable', cmd)) -end) - diff --git a/vars_darwin.go b/vars_darwin.go index b780c23..8ec83ba 100644 --- a/vars_darwin.go +++ b/vars_darwin.go @@ -15,7 +15,7 @@ var ( .. hilbish.userDir.config .. '/hilbish/?/?.lua;' .. hilbish.userDir.config .. '/hilbish/?.lua'` dataDir = "/usr/local/share/hilbish" - preloadPath = dataDir + "/prelude/init.lua" + preloadPath = dataDir + "/nature/init.lua" sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config defaultConfDir = getenv("XDG_CONFIG_HOME", "~/.config") ) diff --git a/vars_linux.go b/vars_linux.go index 5ea3ac5..815ba6a 100644 --- a/vars_linux.go +++ b/vars_linux.go @@ -15,7 +15,7 @@ var ( .. hilbish.userDir.config .. '/hilbish/?/?.lua;' .. hilbish.userDir.config .. '/hilbish/?.lua'` dataDir = "/usr/share/hilbish" - preloadPath = dataDir + "/prelude/init.lua" + preloadPath = dataDir + "/nature/init.lua" sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config defaultConfDir = "" ) diff --git a/vars_windows.go b/vars_windows.go index 5e9878c..a257baf 100644 --- a/vars_windows.go +++ b/vars_windows.go @@ -9,7 +9,7 @@ var ( .. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\?.lua;' .. hilbish.userDir.config .. '\\Hilbish\\libs\\?.lua;'` dataDir = "~\\Appdata\\Roaming\\Hilbish" // ~ and \ gonna cry? - preloadPath = dataDir + "\\prelude\\init.lua" + preloadPath = dataDir + "\\nature\\init.lua" sampleConfPath = dataDir + "\\hilbishrc.lua" // Path to default/sample config defaultConfDir = "" ) From 3db6334445c3f4f4d651a2235ed632a1bfbed5da Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Sat, 23 Apr 2022 04:01:54 +0000 Subject: [PATCH 21/44] docs: [ci] generate new docs --- docs/fs.txt | 2 ++ emmyLuaDocs/fs.lua | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/docs/fs.txt b/docs/fs.txt index 648737e..e9f1548 100644 --- a/docs/fs.txt +++ b/docs/fs.txt @@ -1,3 +1,5 @@ +abs(path) > Gives an absolute version of `path`. + cd(dir) > Changes directory to `dir` mkdir(name, recursive) > Makes a directory called `name`. If `recursive` is true, it will create its parent directories. diff --git a/emmyLuaDocs/fs.lua b/emmyLuaDocs/fs.lua index f94fd2b..cd82d5c 100644 --- a/emmyLuaDocs/fs.lua +++ b/emmyLuaDocs/fs.lua @@ -2,6 +2,10 @@ local fs = {} +--- Gives an absolute version of `path`. +--- @param path string +function fs.abs(path) end + --- Changes directory to `dir` --- @param dir string function fs.cd(dir) end From 984b8a430891781618ff5ccabda227501cfa4744 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 23 Apr 2022 12:28:28 -0400 Subject: [PATCH 22/44] feat: add hilbish.aliases.resolve to resolve an alias --- aliases.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aliases.go b/aliases.go index 2af6427..3007cc3 100644 --- a/aliases.go +++ b/aliases.go @@ -72,6 +72,7 @@ func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table { "add": util.LuaExport{hlalias, 2, false}, "list": util.LuaExport{a.luaList, 0, false}, "del": util.LuaExport{a.luaDelete, 1, false}, + "resolve": util.LuaExport{a.luaResolve, 1, false}, } mod := rt.NewTable() @@ -101,3 +102,16 @@ func (a *aliasHandler) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } + +func (a *aliasHandler) luaResolve(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + alias, err := c.StringArg(0) + if err != nil { + return nil, err + } + resolved := a.Resolve(alias) + + return c.PushingNext1(t.Runtime, rt.StringValue(resolved)), nil +} From bcf02a6b0eaa2f751f50d68697e116a4648885fc Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 23 Apr 2022 23:55:04 -0400 Subject: [PATCH 23/44] fix: make custom hist dir match default by adding hilbish to the path --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index ff04430..ac79487 100644 --- a/main.go +++ b/main.go @@ -62,7 +62,7 @@ func main() { if defaultHistDir == "" { defaultHistDir = filepath.Join(userDataDir, "hilbish") } else { - defaultHistDir = expandHome(defaultHistDir) + defaultHistDir = filepath.Join(expandHome(defaultHistDir), "hilbish") } defaultHistPath = filepath.Join(defaultHistDir, ".hilbish-history") helpflag := getopt.BoolLong("help", 'h', "Prints Hilbish flags") From 4a4c4d8c74de001538c89b95200d7136c87ef2a3 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 23 Apr 2022 23:59:03 -0400 Subject: [PATCH 24/44] refactor: rewrite completion handler in lua --- complete.go | 79 ++---------------------------------------- nature/completions.lua | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+), 77 deletions(-) create mode 100644 nature/completions.lua diff --git a/complete.go b/complete.go index 561f579..dc4c5ce 100644 --- a/complete.go +++ b/complete.go @@ -131,84 +131,9 @@ func completionLoader(rtm *rt.Runtime) *rt.Table { return mod } +// left as a shim, might doc in the same way as hilbish functions func completionHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - if err := c.CheckNArgs(2); err != nil { - return nil, err - } - line, err := c.StringArg(0) - if err != nil { - return nil, err - } - // just for validation - _, err = c.IntArg(1) - if err != nil { - return nil, err - } - - ctx := strings.TrimLeft(line, " ") - if len(ctx) == 0 { - return c.PushingNext(t.Runtime, rt.TableValue(rt.NewTable()), rt.StringValue("")), nil - } - - ctx = aliases.Resolve(ctx) - fields := strings.Split(ctx, " ") - query := fields[len(fields) - 1] - - luaFields := rt.NewTable() - - for i, f := range fields { - luaFields.Set(rt.IntValue(int64(i + 1)), rt.StringValue(f)) - } - - compMod := hshMod.Get(rt.StringValue("completion")).AsTable() - var term *rt.Termination - if len(fields) == 1 { - term = rt.NewTerminationWith(t.CurrentCont(), 2, false) - err := rt.Call(t, compMod.Get(rt.StringValue("bins")), []rt.Value{ - rt.StringValue(query), - rt.StringValue(ctx), - rt.TableValue(luaFields), - }, term) - - if err != nil { - return nil, err - } - } else { - gterm := rt.NewTerminationWith(t.CurrentCont(), 2, false) - err := rt.Call(t, compMod.Get(rt.StringValue("call")), []rt.Value{ - rt.StringValue("commands." + fields[0]), - rt.StringValue(query), - rt.StringValue(ctx), - rt.TableValue(luaFields), - }, gterm) - - if err == nil { - groups := gterm.Get(0) - pfx := gterm.Get(1) - - return c.PushingNext(t.Runtime, groups, pfx), nil - } - - // error means there isnt a command handler - default to files in that case - term = rt.NewTerminationWith(t.CurrentCont(), 2, false) - err = rt.Call(t, compMod.Get(rt.StringValue("files")), []rt.Value{ - rt.StringValue(query), - rt.StringValue(ctx), - rt.TableValue(luaFields), - }, term) - } - - comps := term.Get(0) - pfx := term.Get(1) - - groups := rt.NewTable() - - compGroup := rt.NewTable() - compGroup.Set(rt.StringValue("items"), comps) - compGroup.Set(rt.StringValue("type"), rt.StringValue("grid")) - - groups.Set(rt.IntValue(1), rt.TableValue(compGroup)) - return c.PushingNext(t.Runtime, rt.TableValue(groups), pfx), nil + return c.Next(), nil } func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { diff --git a/nature/completions.lua b/nature/completions.lua new file mode 100644 index 0000000..8561e04 --- /dev/null +++ b/nature/completions.lua @@ -0,0 +1,36 @@ +function hilbish.completion.handler(line, pos) + if type(line) ~= 'string' then error '#1 must be a string' end + if type(pos) ~= 'number' then error '#2 must be a number' end + + -- trim leading whitespace + local ctx = line:gsub('^%s*(.-)$', '%1') + if ctx:len() == 0 then return {}, '' end + + ctx = hilbish.aliases.resolve(ctx) + local fields = string.split(ctx, ' ') + local query = fields[#fields] + + if #fields == 1 then + local comps, pfx = hilbish.completion.bins(query, ctx, fields) + local compGroup = { + items = comps, + type = 'grid' + } + + return {compGroup}, pfx + else + local ok, compGroups, pfx = pcall(hilbish.completion.call, + 'command.' .. #fields[1], query, ctx, fields) + if ok then + return compGroups, pfx + end + + local comps, pfx = hilbish.completion.files(query, ctx, fields) + local compGroup = { + items = comps, + type = 'grid' + } + + return {compGroup}, pfx + end +end From 4e5f8b5c806279835e930823d89d076c88afbba1 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:00:18 -0400 Subject: [PATCH 25/44] docs: add docs for nature module --- docs/nature.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/nature.txt diff --git a/docs/nature.txt b/docs/nature.txt new file mode 100644 index 0000000..6c29cbf --- /dev/null +++ b/docs/nature.txt @@ -0,0 +1,13 @@ +A bit after creation, we have the outside nature. Little plants, seeds, +growing to their final phase: a full plant. A lot of Hilbish itself is +written in Go, but there are parts made in Lua, being the `doc` command, +command not executable/found hooks to print a message in the shell, +and other things. + +Hilbish's Lua core module is called `nature`. It's handled after everything +on the Go side initializes, which is what that first sentence was from. + +# Nature Modules +Currently, `nature` provides 1 intended public module: `nature.dirs`. +It is a simple API for managing recent directories and old +current working directory. From 2790982ad123115c6ddbc5764677fdca27668cea Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sun, 24 Apr 2022 00:06:19 -0400 Subject: [PATCH 26/44] fix: no command completions if query/line is an alias basically, i have a `c` alias which is `git commit`, this would resolve to `git commit` literally to try and complete `commit`, which wouldnt match. this fixes that, and instead itll suggest commands that start with `c`. if there is a space after and completion is requested, itll use the alias properly --- nature/completions.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nature/completions.lua b/nature/completions.lua index 8561e04..d20cc59 100644 --- a/nature/completions.lua +++ b/nature/completions.lua @@ -6,8 +6,12 @@ function hilbish.completion.handler(line, pos) local ctx = line:gsub('^%s*(.-)$', '%1') if ctx:len() == 0 then return {}, '' end - ctx = hilbish.aliases.resolve(ctx) + local res = hilbish.aliases.resolve(ctx) + local resFields = string.split(res, ' ') local fields = string.split(ctx, ' ') + if #fields > 1 and #resFields > 1 then + fields = resFields + end local query = fields[#fields] if #fields == 1 then From 3bad452f95c92bfeccca1870dd2de6cf213eebb9 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sun, 24 Apr 2022 09:00:06 -0400 Subject: [PATCH 27/44] fix: load completions by default --- nature/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/nature/init.lua b/nature/init.lua index 5e07298..f914d0e 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -6,6 +6,7 @@ package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' require 'nature.hooks' require 'nature.commands' +require 'nature.completions' local shlvl = tonumber(os.getenv 'SHLVL') if shlvl ~= nil then From f12f88ed00959f602dc576d39dc4d349f66986f5 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 10:45:55 -0400 Subject: [PATCH 28/44] ci: include all required files in build artifacts --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b47706e..1a8f270 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,4 +35,4 @@ jobs: if: matrix.goos != 'windows' with: name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} - path: hilbish + path: LICENSE README.md CHANGELOG.md .hilbishrc.lua nature libs docs emmyLuaDocs From eb3123405ab462a5da1e47a6ba30394a51cd9ff5 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 10:48:32 -0400 Subject: [PATCH 29/44] ci: fix list of files for artifact build --- .github/workflows/build.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a8f270..bd0d9b2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,4 +35,12 @@ jobs: if: matrix.goos != 'windows' with: name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} - path: LICENSE README.md CHANGELOG.md .hilbishrc.lua nature libs docs emmyLuaDocs + path: | + LICENSE + README.md + CHANGELOG.md + .hilbishrc.lua + nature + libs + docs + emmyLuaDocs From d053b582049a94e31c58e19fa2023384a41eee85 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 10:50:06 -0400 Subject: [PATCH 30/44] ci: indent list of files --- .github/workflows/build.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd0d9b2..0f5eb77 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,11 +36,11 @@ jobs: with: name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} path: | - LICENSE - README.md - CHANGELOG.md - .hilbishrc.lua - nature - libs - docs - emmyLuaDocs + LICENSE + README.md + CHANGELOG.md + .hilbishrc.lua + nature + libs + docs + emmyLuaDocs From e678ef66d86189305d4aca7eab2e6baf1d5a090d Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 12:00:01 -0400 Subject: [PATCH 31/44] docS: update changelogs for master 800th commit! --- CHANGELOG.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 563eb7e..f350cff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,63 @@ # 🎀 Changelog +## Unreleased +### Added +- Inline hints, akin to fish and the others. +To make a handler for hint text, you can set the `hilbish.hinter` function. +For more info, look at its docs with the `doc hilbish` command. +- Syntax highlighting function. To make a handler for it, set +`hilbish.highlighter`. Same thing as the hinter, check `doc hilbish` for +more info/docs. +- Ctrl+K deletes from the cursor to the end of the line. ([#128](https://github.com/Rosettea/Hilbish/pull/128)) +- Alt+Backspace as an alternative of Ctrl+W to delete a word. ([#132](https://github.com/Rosettea/Hilbish/pull/132)) +- Enhanced timer API (`doc timers`) +- Don't exit until intervals are stopped/finished when running a non interactive script. +- Ctrl+D deletes character below cursor if line isn't empty instead of exiting. +- Ctrl+Delete to forward delete a word. +- Right prompt ([#140](https://github.com/Rosettea/Hilbish/pull/140)) +- Ctrl+_ to undo in Emacs input mode. +- Emacs style forward/backward word keybinds ([#139](https://github.com/Rosettea/Hilbish/pull/139)) +- `hilbish.completion.call` to call a completion handler (`doc completions`) +- `hilbish.completion.handler` to set a custom handler for completions. This +is for everything/anything as opposed to just adding a single command completion. +[#122](https://github.com/Rosettea/Hilbish/issues/122) +- `fs.abs(path)` to get absolute path. +- Nature module (`doc nature`) + +### Changed +- **Breaking Change:** Upgraded to Lua 5.4. +This is probably one of (if not the) biggest things in this release. +- **Breaking Change:** MacOS config paths now match Linux. +- Overrides on the `hilbish` table are no longer permitted. +- **Breaking Change:** Runner functions are now required to return 3 values: +user input, exit code, and error. User input has been added to the return to +account for runners wanting to prompt for continued input, and to add it +properly to history. + +### Fixed +- If in Vim replace mode, input at the end of the line inserts instead of +replacing the last character. +- Make forward delete work how its supposed to. +- Prompt refresh not working properly. +- Crashing on input in xterm. ([#131](https://github.com/Rosettea/Hilbish/pull/131)) +- Make delete key work on st ([#131](https://github.com/Rosettea/Hilbish/pull/131)) +- `hilbish.login` being the wrong value. +- Put full input in history if prompted for continued input +- Don't put alias expanded command in history (sound familiar?) +- Handle cases of stdin being nonblocking (in the case of [#130](https://github.com/Rosettea/Hilbish/issues/130)) +- Don't prompt for continued input if non interactive +- Don't insert unhandled control keys. +- Handle sh syntax error in alias +- Use invert for completion menu selection highlight instead of specific +colors. Brings an improvement on light themes, or themes that don't follow +certain color rules. +- Home/End keys now go to the actual start/end of the input. +- Input getting cut off on enter in certain cases. +- Go to the next line properly if input reaches end of terminal width. +- Cursor position with CJK characters. ([#145](https://github.com/Rosettea/Hilbish/pull/145)) +- Files with same name as parent folder in completions getting cut off [#136](https://github.com/Rosettea/Hilbish/issues/136)) +- `hilbish.which` now works with commanders and aliases. + ## [1.2.0] - 2022-03-17 ### Added - Job Management additions From c929c7602f6e5330fa7dd95c1dac0750e2c58937 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 12:00:41 -0400 Subject: [PATCH 32/44] ci: checkout submodules --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f5eb77..88295a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,9 @@ jobs: goos: windows steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@v3 + with: + submodules: true - name: Setup Go uses: actions/setup-go@v2 with: From 03cb9c06f397c38cb01c8dcf35acf6a33dd05df5 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 12:08:39 -0400 Subject: [PATCH 33/44] ci: fix release builds; make them include lua libs and nature lib --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e19ef0b..a3a2840 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,13 +30,13 @@ jobs: - goarch: arm64 goos: windows steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: - submodules: recursive + submodules: true - uses: wangyoucao577/go-release-action@v1.25 with: github_token: ${{ secrets.GITHUB_TOKEN }} goos: ${{ matrix.goos }} goarch: ${{ matrix.goarch }} binary_name: hilbish - extra_files: LICENSE README.md CHANGELOG.md .hilbishrc.lua prelude libs docs emmyLuaDocs + extra_files: LICENSE README.md CHANGELOG.md .hilbishrc.lua nature libs docs emmyLuaDocs From b210378380e9e56f3d012647dc667e3f8207dd8e Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 12:08:54 -0400 Subject: [PATCH 34/44] ci: remove .exe from windows artifact names --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88295a4..b17786e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/upload-artifact@v2 if: matrix.goos == 'windows' with: - name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }}.exe + name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} path: hilbish.exe - uses: actions/upload-artifact@v2 if: matrix.goos != 'windows' From 0642ddda365dad1c1f845f496d22de1539474e2b Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 20:28:47 -0400 Subject: [PATCH 35/44] fix: push home dir to recent dirs with correct function --- nature/commands/cd.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nature/commands/cd.lua b/nature/commands/cd.lua index 509e774..b4d1041 100644 --- a/nature/commands/cd.lua +++ b/nature/commands/cd.lua @@ -31,5 +31,5 @@ commander.register('cd', function (args) fs.cd(hilbish.home) bait.throw('cd', hilbish.home) - dirs.addRecent(hilbish.home) + dirs.push(hilbish.home) end) From c4eb3ad368aee32921109b8f5ab3b9d8e72f5c6b Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 20:31:37 -0400 Subject: [PATCH 36/44] chore: change lua init errors to make more sense --- lua.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua.go b/lua.go index 838ce8a..d2bdef3 100644 --- a/lua.go +++ b/lua.go @@ -51,14 +51,14 @@ func luaInit() { // Add more paths that Lua can require from err := util.DoString(l, "package.path = package.path .. " + requirePaths) if err != nil { - fmt.Fprintln(os.Stderr, "Could not add preload paths! Libraries will be missing. This shouldn't happen.") + fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.") } err = util.DoFile(l, "nature/init.lua") if err != nil { err = util.DoFile(l, preloadPath) if err != nil { - fmt.Fprintln(os.Stderr, "Missing preload file, builtins may be missing.") + fmt.Fprintln(os.Stderr, "Missing nature module, some functionality and builtins will be missing.") } } } From 4178b78341d002957beaf950bef9dd0973d664d9 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 21:02:36 -0400 Subject: [PATCH 37/44] fix: return other errors from sh runner makes it so that the sh runner function will return command not found and not executable errors, which makes them able to be handled via lua properly --- exec.go | 106 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 26 deletions(-) diff --git a/exec.go b/exec.go index fcedf62..9d394aa 100644 --- a/exec.go +++ b/exec.go @@ -25,8 +25,63 @@ import ( ) var errNotExec = errors.New("not executable") +var errNotFound = errors.New("not found") var runnerMode rt.Value = rt.StringValue("hybrid") +type execError struct{ + typ string + cmd string + code int + colon bool + err error +} + +func (e execError) Error() string { + return fmt.Sprintf("%s: %s", e.cmd, e.typ) +} + +func (e execError) sprint() error { + sep := " " + if e.colon { + sep = ": " + } + + return fmt.Errorf("hilbish: %s%s%s", e.cmd, sep, e.err.Error()) +} + +func isExecError(err error) (execError, bool) { + if exErr, ok := err.(execError); ok { + return exErr, true + } + + fields := strings.Split(err.Error(), ": ") + knownTypes := []string{ + "not-found", + "not-executable", + } + + if len(fields) > 1 && contains(knownTypes, fields[1]) { + var colon bool + var e error + switch fields[1] { + case "not-found": + e = errNotFound + case "not-executable": + colon = true + e = errNotExec + } + + return execError{ + cmd: fields[0], + typ: fields[1], + colon: colon, + err: e, + }, true + } + + return execError{}, false +} + func runInput(input string, priv bool) { running = true cmdString := aliases.Resolve(input) @@ -43,10 +98,6 @@ func runInput(input string, priv bool) { return } input, exitCode, err = handleSh(input) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - cmdFinish(exitCode, input, priv) case "hybridRev": _, _, err = handleSh(input) if err == nil { @@ -54,27 +105,15 @@ func runInput(input string, priv bool) { return } input, exitCode, err = handleLua(cmdString) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - cmdFinish(exitCode, input, priv) case "lua": input, exitCode, err = handleLua(cmdString) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - cmdFinish(exitCode, input, priv) case "sh": input, exitCode, err = handleSh(input) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - cmdFinish(exitCode, input, priv) } } else { // can only be a string or function so term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 3, false) - err := rt.Call(l.MainThread(), runnerMode, []rt.Value{rt.StringValue(cmdString)}, term) + err = rt.Call(l.MainThread(), runnerMode, []rt.Value{rt.StringValue(cmdString)}, term) if err != nil { fmt.Fprintln(os.Stderr, err) cmdFinish(124, input, priv) @@ -85,7 +124,6 @@ func runInput(input string, priv bool) { luaexitcode := term.Get(1) runErr := term.Get(2) - var exitCode uint8 if code, ok := luaexitcode.TryInt(); ok { exitCode = uint8(code) } @@ -94,11 +132,19 @@ func runInput(input string, priv bool) { input = inp } - if runErr != rt.NilValue { - fmt.Fprintln(os.Stderr, runErr) + if errStr, ok := runErr.TryString(); ok { + err = fmt.Errorf("%s", errStr) } - cmdFinish(exitCode, input, priv) } + + if err != nil { + if exErr, ok := isExecError(err); ok { + hooks.Em.Emit("command." + exErr.typ, exErr.cmd) + err = exErr.sprint() + } + fmt.Fprintln(os.Stderr, err) + } + cmdFinish(exitCode, input, priv) } func handleLua(cmdString string) (string, uint8, error) { @@ -255,12 +301,20 @@ func execHandle(bg bool) interp.ExecHandlerFunc { err := lookpath(args[0]) if err == errNotExec { - hooks.Em.Emit("command.no-perm", args[0]) - hooks.Em.Emit("command.not-executable", args[0]) - return interp.NewExitStatus(126) + return execError{ + typ: "not-executable", + cmd: args[0], + code: 126, + colon: true, + err: errNotExec, + } } else if err != nil { - hooks.Em.Emit("command.not-found", args[0]) - return interp.NewExitStatus(127) + return execError{ + typ: "not-found", + cmd: args[0], + code: 127, + err: errNotFound, + } } killTimeout := 2 * time.Second From a8406657f93f65bd1da6a6988090beb37fdfe6aa Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 21:05:21 -0400 Subject: [PATCH 38/44] fix: remove nature hook handles since it was only for command exec errors, and theyre handled runner side now, we dont have to handle it via hooks anymore --- nature/hooks.lua | 11 ----------- nature/init.lua | 1 - 2 files changed, 12 deletions(-) delete mode 100644 nature/hooks.lua diff --git a/nature/hooks.lua b/nature/hooks.lua deleted file mode 100644 index a9bd0b1..0000000 --- a/nature/hooks.lua +++ /dev/null @@ -1,11 +0,0 @@ -local bait = require 'bait' - --- Hook handles -bait.catch('command.not-found', function(cmd) - print(string.format('hilbish: %s not found', cmd)) -end) - -bait.catch('command.not-executable', function(cmd) - print(string.format('hilbish: %s: not executable', cmd)) -end) - diff --git a/nature/init.lua b/nature/init.lua index f914d0e..16f26ed 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -4,7 +4,6 @@ local _ = require 'succulent' -- Function additions package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' .. ';' .. hilbish.dataDir .. '/?/?.lua' -require 'nature.hooks' require 'nature.commands' require 'nature.completions' From c890b86e084d08339e96588c690d68bb82d766c0 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 30 Apr 2022 21:22:37 -0400 Subject: [PATCH 39/44] feat: add hilbish.opts and autocd opt this adds `hilbish.opts`, a table to set simple options akin to shopt or setopt on other shells. this commit specifically also includes the autocd opt, which functions the way you expect it to to set opts, simply do `hilbish.opts.name = val`, where `name` is the opt you want to set and `val` being the opt setting. ie: `hilbish.opts.autocd = true` to turn on autocd --- nature/init.lua | 1 + nature/opts/autocd.lua | 23 +++++++++++++++++++++++ nature/opts/init.lua | 28 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 nature/opts/autocd.lua create mode 100644 nature/opts/init.lua diff --git a/nature/init.lua b/nature/init.lua index 16f26ed..c70f6cc 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -6,6 +6,7 @@ package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' require 'nature.commands' require 'nature.completions' +require 'nature.opts' local shlvl = tonumber(os.getenv 'SHLVL') if shlvl ~= nil then diff --git a/nature/opts/autocd.lua b/nature/opts/autocd.lua new file mode 100644 index 0000000..b25732e --- /dev/null +++ b/nature/opts/autocd.lua @@ -0,0 +1,23 @@ +local fs = require 'fs' + +function cdHandle(inp) + local input, exit, err = hilbish.runner.lua(inp) + + if not err then + return input, exit, err + end + + input, exit, err = hilbish.runner.sh(inp) + + if exit ~= 0 and hilbish.opts.autocd then + local ok, stat = pcall(fs.stat, input) + if ok and stat.isDir then + -- discard here to not append the cd, which will be in history + _, exit, err = hilbish.runner.sh('cd ' .. input) + end + end + + return input, exit, err +end + +hilbish.runner.setMode(cdHandle) diff --git a/nature/opts/init.lua b/nature/opts/init.lua new file mode 100644 index 0000000..59d3cbd --- /dev/null +++ b/nature/opts/init.lua @@ -0,0 +1,28 @@ +local opts = {} +hilbish.opts = {} + +setmetatable(hilbish.opts, { + __newindex = function(_, k, v) + if opts[k] == nil then + error(string.format('opt %s does not exist', k)) + end + + opts[k] = v + end, + __index = function(_, k) + return opts[k] + end +}) + +local function setupOpt(name, default) + opts[name] = default + require('nature.opts.' .. name) +end + +local defaultOpts = { + autocd = false +} + +for optsName, default in pairs(defaultOpts) do + setupOpt(optsName, default) +end From db437905e07ea268e879000dddf97179e7b1f9e1 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sun, 1 May 2022 00:49:59 -0400 Subject: [PATCH 40/44] fix: implicitly expand tilde on args to all fs functions --- complete.go | 4 ++-- golibs/fs/fs.go | 12 ++++++++---- main.go | 9 ++------- util/util.go | 9 +++++++++ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/complete.go b/complete.go index dc4c5ce..01a8137 100644 --- a/complete.go +++ b/complete.go @@ -24,7 +24,7 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) { fileCompletions, filePref := matchPath(query) if len(fileCompletions) != 0 { for _, f := range fileCompletions { - fullPath, _ := filepath.Abs(expandHome(query + strings.TrimPrefix(f, filePref))) + fullPath, _ := filepath.Abs(util.ExpandHome(query + strings.TrimPrefix(f, filePref))) if err := findExecutable(fullPath, false, true); err != nil { continue } @@ -71,7 +71,7 @@ func matchPath(query string) ([]string, string) { var entries []string var baseName string - path, _ := filepath.Abs(expandHome(filepath.Dir(query))) + path, _ := filepath.Abs(util.ExpandHome(filepath.Dir(query))) if string(query) == "" { // filepath base below would give us "." // which would cause a match of only dotfiles diff --git a/golibs/fs/fs.go b/golibs/fs/fs.go index eda1671..950e966 100644 --- a/golibs/fs/fs.go +++ b/golibs/fs/fs.go @@ -30,7 +30,7 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { util.Document(mod, `The fs module provides easy and simple access to filesystem functions and other things, and acts an -addition to the Lua standard library's I/O and fs functions.`) +addition to the Lua standard library's I/O and filesystem functions.`) return rt.TableValue(mod), nil } @@ -46,8 +46,9 @@ func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err != nil { return nil, err } + path = util.ExpandHome(strings.TrimSpace(path)) - err = os.Chdir(strings.TrimSpace(path)) + err = os.Chdir(path) if err != nil { return nil, err } @@ -63,7 +64,7 @@ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.CheckNArgs(2); err != nil { return nil, err } - dirname, err := c.StringArg(0) + path, err := c.StringArg(0) if err != nil { return nil, err } @@ -71,7 +72,7 @@ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err != nil { return nil, err } - path := strings.TrimSpace(dirname) + path = util.ExpandHome(strings.TrimSpace(path)) if recursive { err = os.MkdirAll(path, 0744) @@ -96,6 +97,7 @@ func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err != nil { return nil, err } + path = util.ExpandHome(path) pathinfo, err := os.Stat(path) if err != nil { @@ -122,6 +124,7 @@ func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err != nil { return nil, err } + dir = util.ExpandHome(dir) names := rt.NewTable() dirEntries, err := os.ReadDir(dir) @@ -143,6 +146,7 @@ func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err != nil { return nil, err } + path = util.ExpandHome(path) abspath, err := filepath.Abs(path) if err != nil { diff --git a/main.go b/main.go index ac79487..c0fce06 100644 --- a/main.go +++ b/main.go @@ -56,13 +56,13 @@ func main() { defaultConfDir = filepath.Join(confDir, "hilbish") } else { // else do ~ substitution - defaultConfDir = filepath.Join(expandHome(defaultConfDir), "hilbish") + defaultConfDir = filepath.Join(util.ExpandHome(defaultConfDir), "hilbish") } defaultConfPath = filepath.Join(defaultConfDir, "init.lua") if defaultHistDir == "" { defaultHistDir = filepath.Join(userDataDir, "hilbish") } else { - defaultHistDir = filepath.Join(expandHome(defaultHistDir), "hilbish") + defaultHistDir = filepath.Join(util.ExpandHome(defaultHistDir), "hilbish") } defaultHistPath = filepath.Join(defaultHistDir, ".hilbish-history") helpflag := getopt.BoolLong("help", 'h', "Prints Hilbish flags") @@ -273,11 +273,6 @@ func handleHistory(cmd string) { // TODO: load history again (history shared between sessions like this ye) } -func expandHome(path string) string { - homedir := curuser.HomeDir - return strings.Replace(path, "~", homedir, 1) -} - func removeDupes(slice []string) []string { all := make(map[string]bool) newSlice := []string{} diff --git a/util/util.go b/util/util.go index 6b5860e..4bfecc9 100644 --- a/util/util.go +++ b/util/util.go @@ -3,7 +3,9 @@ package util import ( "bufio" "io" + "strings" "os" + "os/user" rt "github.com/arnodel/golua/runtime" ) @@ -150,3 +152,10 @@ func ForEach(tbl *rt.Table, cb func(key rt.Value, val rt.Value)) { cb(key, val) } } + +func ExpandHome(path string) string { + curuser, _ := user.Current() + homedir := curuser.HomeDir + + return strings.Replace(path, "~", homedir, 1) +} From 30b07bc98b76cd8f87d7178379cafc4e86e23e17 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sun, 1 May 2022 07:20:40 -0400 Subject: [PATCH 41/44] fix: check if path has tilde prefix when trying to expand home --- util/util.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/util/util.go b/util/util.go index 4bfecc9..713ea6a 100644 --- a/util/util.go +++ b/util/util.go @@ -153,9 +153,16 @@ func ForEach(tbl *rt.Table, cb func(key rt.Value, val rt.Value)) { } } +// ExpandHome expands ~ (tilde) in the path, changing it to the user home +// directory. func ExpandHome(path string) string { - curuser, _ := user.Current() - homedir := curuser.HomeDir + if strings.HasPrefix(path, "~") { + curuser, _ := user.Current() + homedir := curuser.HomeDir - return strings.Replace(path, "~", homedir, 1) + return strings.Replace(path, "~", homedir, 1) + } + + return path } + From 86700c0a7be5449da9612ed0cbde271bbf5dca00 Mon Sep 17 00:00:00 2001 From: sammyette <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 6 May 2022 12:20:41 -0400 Subject: [PATCH 42/44] ci: add codeql code scanning --- .github/workflows/codeql-analysis.yml | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..9d2728b --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,60 @@ +name: CodeQL +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '38 2 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 From d6bc8b51de77c656f74eb704eb25baf684d5173d Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 6 May 2022 19:06:06 -0400 Subject: [PATCH 43/44] ci: fix missing files on either oses --- .github/workflows/build.yml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b17786e..b357b64 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,14 +30,24 @@ jobs: run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build - uses: actions/upload-artifact@v2 if: matrix.goos == 'windows' - with: - name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} - path: hilbish.exe - - uses: actions/upload-artifact@v2 - if: matrix.goos != 'windows' with: name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} path: | + hilbish.exe + LICENSE + README.md + CHANGELOG.md + .hilbishrc.lua + nature + libs + docs + emmyLuaDocs + - uses: actions/upload-artifact@v2 + if: matrix.goos != 'windows' + with: + name: hilbish-${{ matrix.goos }}-${{ matrix.goarch }} + path: | + hilbish LICENSE README.md CHANGELOG.md From 0a01ed862ca8ccd097587cae3d756ca2cebc3b8c Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 6 May 2022 19:21:32 -0400 Subject: [PATCH 44/44] feat: print error if nature is missing --- lua.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lua.go b/lua.go index d2bdef3..8f3c0fb 100644 --- a/lua.go +++ b/lua.go @@ -54,11 +54,13 @@ func luaInit() { fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.") } - err = util.DoFile(l, "nature/init.lua") - if err != nil { - err = util.DoFile(l, preloadPath) - if err != nil { + err1 := util.DoFile(l, "nature/init.lua") + if err1 != nil { + err2 := util.DoFile(l, preloadPath) + if err2 != nil { fmt.Fprintln(os.Stderr, "Missing nature module, some functionality and builtins will be missing.") + fmt.Fprintln(os.Stderr, "local error:", err1) + fmt.Fprintln(os.Stderr, "global install error:", err2) } } }