diff --git a/api.go b/api.go index 95f9608..f0de5f0 100644 --- a/api.go +++ b/api.go @@ -15,6 +15,7 @@ import ( "hilbish/util" "github.com/yuin/gopher-lua" + "github.com/maxlandon/readline" "mvdan.cc/sh/v3/interp" ) @@ -26,6 +27,7 @@ var exports = map[string]lua.LGFunction { "multiprompt": hlmlprompt, "prependPath": hlprependPath, "prompt": hlprompt, + "inputMode": hlinputMode, "interval": hlinterval, "read": hlread, "run": hlrun, @@ -34,9 +36,11 @@ var exports = map[string]lua.LGFunction { } var greeting string +var hshMod *lua.LTable func hilbishLoader(L *lua.LState) int { mod := L.SetFuncs(L.NewTable(), exports) + hshMod = mod host, _ := os.Hostname() username := curuser.Username @@ -57,6 +61,7 @@ The nice lil shell for {blue}Lua{reset} fanatics! util.SetField(L, mod, "interactive", lua.LBool(interactive), "If this is an interactive shell") util.SetField(L, mod, "login", lua.LBool(interactive), "Whether this is a login shell") util.SetField(L, mod, "greeting", lua.LString(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.") + util.SetField(l, mod, "vimMode", lua.LNil, "Current Vim mode of Hilbish (nil if not in Vim mode)") util.Document(L, mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.") // hilbish.userDir table @@ -83,6 +88,15 @@ The nice lil shell for {blue}Lua{reset} fanatics! return 1 } +func setVimMode(mode string) { + hooks.Em.Emit("hilbish.vimMode", mode) + util.SetField(l, hshMod, "vimMode", lua.LString(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)") +} + +func unsetVimMode() { + util.SetField(l, hshMod, "vimMode", lua.LNil, "Current Vim mode of Hilbish (nil if not in Vim mode)") +} + // run(cmd) // Runs `cmd` in Hilbish's sh interpreter. // --- @param cmd string @@ -150,6 +164,9 @@ These will be formatted and replaced with the appropriate values. */ func hlprompt(L *lua.LState) int { prompt = L.CheckString(1) + if lr != nil { + lr.SetPrompt(fmtPrompt()) + } return 0 } @@ -346,3 +363,19 @@ func hlwhich(L *lua.LState) int { l.Push(lua.LString(path)) return 1 } + +// inputMode(mode) +// Sets the input mode for Hilbish's line reader. Accepts either emacs for vim +func hlinputMode(L *lua.LState) int { + mode := L.CheckString(1) + switch mode { + case "emacs": + unsetVimMode() + lr.rl.InputMode = readline.Emacs + case "vim": + setVimMode("insert") + lr.rl.InputMode = readline.Vim + default: L.RaiseError("inputMode: expected vim or emacs, received " + mode) + } + return 0 +} diff --git a/go.mod b/go.mod index 1ad076c..02f6bc6 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,6 @@ require ( replace mvdan.cc/sh/v3 => github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20211022004519-f67a49cb50f5 -replace github.com/maxlandon/readline => github.com/Rosettea/readline-1 v0.1.0-beta.0.20220228022904-61f5e4493011 +replace github.com/maxlandon/readline => github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7 replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10 diff --git a/go.sum b/go.sum index 505a028..483de90 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7 h1:LoY+kBKqMQqBcilRpVvifBTVve84asa3btpx3D/+IvM= +github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs= github.com/Rosettea/readline-1 v0.1.0-beta.0.20211207003625-341c7985ad7d h1:KBttN41h/tPahmpaZavviwQ8q4rCkt5CD0HdVmfgPVA= github.com/Rosettea/readline-1 v0.1.0-beta.0.20211207003625-341c7985ad7d/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs= github.com/Rosettea/readline-1 v0.1.0-beta.0.20220228022904-61f5e4493011 h1:+a61iNamZiO3Xru+l/1qtpKqqltVfWEm2r/rxH9hXxY= diff --git a/rl.go b/rl.go index c8f5c32..a68189a 100644 --- a/rl.go +++ b/rl.go @@ -18,7 +18,18 @@ type lineReader struct { // other gophers might hate this naming but this is local, shut up func newLineReader(prompt string) *lineReader { rl := readline.NewInstance() - rl.Multiline = true + rl.ShowVimMode = false + rl.ViModeCallback = func(mode readline.ViMode) { + modeStr := "" + switch mode { + case readline.VimKeys: modeStr = "normal" + case readline.VimInsert: modeStr = "insert" + case readline.VimDelete: modeStr = "delete" + case readline.VimReplaceOnce: + case readline.VimReplaceMany: modeStr = "replace" + } + setVimMode(modeStr) + } rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) { ctx := string(line) var completions []string @@ -196,6 +207,7 @@ func (lr *lineReader) Read() (string, error) { s, err := lr.rl.Readline() // this is so dumb if err == readline.EOF { + fmt.Println("") return "", io.EOF } @@ -209,10 +221,13 @@ func (lr *lineReader) SetPrompt(prompt string) { lr.rl.MultilinePrompt = halfPrompt[len(halfPrompt) - 1:][0] } else { // print cursor up ansi code - fmt.Printf("\033[1A") + //fmt.Printf("\033[1A") lr.rl.SetPrompt("") lr.rl.MultilinePrompt = halfPrompt[len(halfPrompt) - 1:][0] } + if !running { + lr.rl.RefreshPromptInPlace("") + } } func (lr *lineReader) AddHistory(cmd string) {