diff --git a/CHANGELOG.md b/CHANGELOG.md index 997d3de..c0737a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,8 @@ will be ran on startup - Message of the day on startup (`hilbish.motd`), mainly intended as quick small news pieces for releases. It is printed by default. To disable it, set `hilbish.opts.motd` to false. +- `history` opt has been added and is true by default. Setting it to false +disables commands being added to history. - `hilbish.rawInput` hook for input from the readline library - Completion of files in quotes @@ -90,6 +92,8 @@ of a dot. (ie. `job.stop()` -> `job:stop()`) - All `fs` module functions which take paths now implicitly expand ~ to home. - **Breaking Change:** `hilbish.greeting` has been moved to an opt (`hilbish.opts.greeting`) and is always printed by default. To disable it, set the opt to false. +- History is now fetched from Lua, which means users can override `hilbish.history` +methods to make it act how they want. ### Fixed - If in Vim replace mode, input at the end of the line inserts instead of diff --git a/exec.go b/exec.go index cc5016a..e1862ed 100644 --- a/exec.go +++ b/exec.go @@ -540,13 +540,9 @@ func splitInput(input string) ([]string, string) { } func cmdFinish(code uint8, cmdstr string, private bool) { - // if input has space at the beginning, dont put in history - if interactive && !private { - handleHistory(cmdstr) - } util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)), "Exit code of last exected command") // using AsValue (to convert to lua type) on an interface which is an int // results in it being unknown in lua .... ???? // so we allow the hook handler to take lua runtime Values - hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr) + hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr, private) } diff --git a/history.go b/history.go index b666515..a8eb089 100644 --- a/history.go +++ b/history.go @@ -4,21 +4,69 @@ import ( "errors" "io/fs" "os" + "path/filepath" "strings" + + rt "github.com/arnodel/golua/runtime" ) +type luaHistory struct {} + +func (h *luaHistory) Write(line string) (int, error) { + histWrite := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("add")) + ln, err := rt.Call1(l.MainThread(), histWrite, rt.StringValue(line)) + + var num int64 + if ln.Type() == rt.IntType { + num = ln.AsInt() + } + + return int(num), err +} + +func (h *luaHistory) GetLine(idx int) (string, error) { + histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get")) + lcmd, err := rt.Call1(l.MainThread(), histGet, rt.IntValue(int64(idx))) + + var cmd string + if lcmd.Type() == rt.StringType { + cmd = lcmd.AsString() + } + + return cmd, err +} + +func (h *luaHistory) Len() int { + histSize := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("size")) + ln, _ := rt.Call1(l.MainThread(), histSize) + + var num int64 + if ln.Type() == rt.IntType { + num = ln.AsInt() + } + + return int(num) +} + +func (h *luaHistory) Dump() interface{} { + // hilbish.history interface already has all function, this isnt used in readline + return nil +} + type fileHistory struct { items []string f *os.File } -func newFileHistory() *fileHistory { - err := os.MkdirAll(defaultHistDir, 0755) +func newFileHistory(path string) *fileHistory { + dir := filepath.Dir(path) + + err := os.MkdirAll(dir, 0755) if err != nil { panic(err) } - data, err := os.ReadFile(defaultHistPath) + data, err := os.ReadFile(path) if err != nil { if !errors.Is(err, fs.ErrNotExist) { panic(err) @@ -33,7 +81,7 @@ func newFileHistory() *fileHistory { } itms = append(itms, l) } - f, err := os.OpenFile(defaultHistPath, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755) + f, err := os.OpenFile(path, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755) if err != nil { panic(err) } diff --git a/main.go b/main.go index 9e3068a..e53055d 100644 --- a/main.go +++ b/main.go @@ -269,11 +269,6 @@ func fmtPrompt(prompt string) string { return nprompt } -func handleHistory(cmd string) { - lr.AddHistory(cmd) - // TODO: load history again (history shared between sessions like this ye) -} - func removeDupes(slice []string) []string { all := make(map[string]bool) newSlice := []string{} diff --git a/nature/opts/history.lua b/nature/opts/history.lua new file mode 100644 index 0000000..f7ab1d7 --- /dev/null +++ b/nature/opts/history.lua @@ -0,0 +1,5 @@ +local bait = require 'bait' + +bait.catch('command.exit', function(_, cmd, priv) + if not priv and hilbish.opts.history then hilbish.history.add(cmd) end +end) diff --git a/nature/opts/init.lua b/nature/opts/init.lua index 0b32f3f..ae95ee1 100644 --- a/nature/opts/init.lua +++ b/nature/opts/init.lua @@ -21,6 +21,7 @@ end local defaultOpts = { autocd = false, + history = true, greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}. The nice lil shell for {blue}Lua{reset} fanatics! ]], hilbish.user), diff --git a/rl.go b/rl.go index 88adc65..6350aa2 100644 --- a/rl.go +++ b/rl.go @@ -13,18 +13,22 @@ import ( type lineReader struct { rl *readline.Instance + fileHist *fileHistory } -var fileHist *fileHistory var hinter *rt.Closure var highlighter *rt.Closure func newLineReader(prompt string, noHist bool) *lineReader { rl := readline.NewInstance() + lr := &lineReader{ + rl: rl, + } + // we don't mind hilbish.read rl instances having completion, // but it cant have shared history if !noHist { - fileHist = newFileHistory() - rl.SetHistoryCtrlR("History", fileHist) + lr.fileHist = newFileHistory(defaultHistPath) + rl.SetHistoryCtrlR("History", &luaHistory{}) rl.HistoryAutoWrite = false } rl.ShowVimMode = false @@ -171,9 +175,7 @@ func newLineReader(prompt string, noHist bool) *lineReader { return pfx, compGroups } - return &lineReader{ - rl, - } + return lr } func (lr *lineReader) Read() (string, error) { @@ -212,7 +214,7 @@ func (lr *lineReader) SetRightPrompt(p string) { } func (lr *lineReader) AddHistory(cmd string) { - fileHist.Write(cmd) + lr.fileHist.Write(cmd) } func (lr *lineReader) ClearInput() { @@ -253,7 +255,7 @@ func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) } func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - return c.PushingNext1(t.Runtime, rt.IntValue(int64(fileHist.Len()))), nil + return c.PushingNext1(t.Runtime, rt.IntValue(int64(lr.fileHist.Len()))), nil } func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -265,17 +267,17 @@ func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) return nil, err } - cmd, _ := fileHist.GetLine(int(idx)) + cmd, _ := lr.fileHist.GetLine(int(idx)) return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil } func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { tbl := rt.NewTable() - size := fileHist.Len() + size := lr.fileHist.Len() for i := 1; i < size; i++ { - cmd, _ := fileHist.GetLine(i) + cmd, _ := lr.fileHist.GetLine(i) tbl.Set(rt.IntValue(int64(i)), rt.StringValue(cmd)) } @@ -283,6 +285,6 @@ func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) } func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - fileHist.clear() + lr.fileHist.clear() return c.Next(), nil }