mirror of https://github.com/Hilbis/Hilbish
feat: lua backed history (#187)
* refactor: put file history handler in line reader instance instead of global * feat: add lua history handler in go * feat: use lua to retrieve readline history * refactor: handle history in lua this also introduces a new opt: history if it is false, command history won't get added * fix: remove nature.history require * docs: add changes in changelog * fix: add comma after history opthistory-searcher
parent
f7806f5479
commit
349380ae6b
|
@ -66,6 +66,8 @@ will be ran on startup
|
||||||
- Message of the day on startup (`hilbish.motd`), mainly intended as quick
|
- 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,
|
small news pieces for releases. It is printed by default. To disable it,
|
||||||
set `hilbish.opts.motd` to false.
|
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
|
- `hilbish.rawInput` hook for input from the readline library
|
||||||
- Completion of files in quotes
|
- 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.
|
- 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
|
- **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.
|
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
|
### Fixed
|
||||||
- If in Vim replace mode, input at the end of the line inserts instead of
|
- If in Vim replace mode, input at the end of the line inserts instead of
|
||||||
|
|
6
exec.go
6
exec.go
|
@ -540,13 +540,9 @@ func splitInput(input string) ([]string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdFinish(code uint8, cmdstr string, private bool) {
|
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")
|
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
|
// using AsValue (to convert to lua type) on an interface which is an int
|
||||||
// results in it being unknown in lua .... ????
|
// results in it being unknown in lua .... ????
|
||||||
// so we allow the hook handler to take lua runtime Values
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
56
history.go
56
history.go
|
@ -4,21 +4,69 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"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 {
|
type fileHistory struct {
|
||||||
items []string
|
items []string
|
||||||
f *os.File
|
f *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFileHistory() *fileHistory {
|
func newFileHistory(path string) *fileHistory {
|
||||||
err := os.MkdirAll(defaultHistDir, 0755)
|
dir := filepath.Dir(path)
|
||||||
|
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := os.ReadFile(defaultHistPath)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -33,7 +81,7 @@ func newFileHistory() *fileHistory {
|
||||||
}
|
}
|
||||||
itms = append(itms, l)
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
5
main.go
5
main.go
|
@ -269,11 +269,6 @@ func fmtPrompt(prompt string) string {
|
||||||
return nprompt
|
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 {
|
func removeDupes(slice []string) []string {
|
||||||
all := make(map[string]bool)
|
all := make(map[string]bool)
|
||||||
newSlice := []string{}
|
newSlice := []string{}
|
||||||
|
|
|
@ -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)
|
|
@ -21,6 +21,7 @@ end
|
||||||
|
|
||||||
local defaultOpts = {
|
local defaultOpts = {
|
||||||
autocd = false,
|
autocd = false,
|
||||||
|
history = true,
|
||||||
greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}.
|
greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}.
|
||||||
The nice lil shell for {blue}Lua{reset} fanatics!
|
The nice lil shell for {blue}Lua{reset} fanatics!
|
||||||
]], hilbish.user),
|
]], hilbish.user),
|
||||||
|
|
26
rl.go
26
rl.go
|
@ -13,18 +13,22 @@ import (
|
||||||
|
|
||||||
type lineReader struct {
|
type lineReader struct {
|
||||||
rl *readline.Instance
|
rl *readline.Instance
|
||||||
|
fileHist *fileHistory
|
||||||
}
|
}
|
||||||
var fileHist *fileHistory
|
|
||||||
var hinter *rt.Closure
|
var hinter *rt.Closure
|
||||||
var highlighter *rt.Closure
|
var highlighter *rt.Closure
|
||||||
|
|
||||||
func newLineReader(prompt string, noHist bool) *lineReader {
|
func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
rl := readline.NewInstance()
|
rl := readline.NewInstance()
|
||||||
|
lr := &lineReader{
|
||||||
|
rl: rl,
|
||||||
|
}
|
||||||
|
|
||||||
// we don't mind hilbish.read rl instances having completion,
|
// we don't mind hilbish.read rl instances having completion,
|
||||||
// but it cant have shared history
|
// but it cant have shared history
|
||||||
if !noHist {
|
if !noHist {
|
||||||
fileHist = newFileHistory()
|
lr.fileHist = newFileHistory(defaultHistPath)
|
||||||
rl.SetHistoryCtrlR("History", fileHist)
|
rl.SetHistoryCtrlR("History", &luaHistory{})
|
||||||
rl.HistoryAutoWrite = false
|
rl.HistoryAutoWrite = false
|
||||||
}
|
}
|
||||||
rl.ShowVimMode = false
|
rl.ShowVimMode = false
|
||||||
|
@ -171,9 +175,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
return pfx, compGroups
|
return pfx, compGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
return &lineReader{
|
return lr
|
||||||
rl,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) Read() (string, error) {
|
func (lr *lineReader) Read() (string, error) {
|
||||||
|
@ -212,7 +214,7 @@ func (lr *lineReader) SetRightPrompt(p string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) AddHistory(cmd string) {
|
func (lr *lineReader) AddHistory(cmd string) {
|
||||||
fileHist.Write(cmd)
|
lr.fileHist.Write(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) ClearInput() {
|
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) {
|
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) {
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd, _ := fileHist.GetLine(int(idx))
|
cmd, _ := lr.fileHist.GetLine(int(idx))
|
||||||
|
|
||||||
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
tbl := rt.NewTable()
|
tbl := rt.NewTable()
|
||||||
size := fileHist.Len()
|
size := lr.fileHist.Len()
|
||||||
|
|
||||||
for i := 1; i < size; i++ {
|
for i := 1; i < size; i++ {
|
||||||
cmd, _ := fileHist.GetLine(i)
|
cmd, _ := lr.fileHist.GetLine(i)
|
||||||
tbl.Set(rt.IntValue(int64(i)), rt.StringValue(cmd))
|
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) {
|
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
fileHist.clear()
|
lr.fileHist.clear()
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue