Compare commits

..

6 Commits

Author SHA1 Message Date
TorchedSammy 284248fc08 docs: [ci] generate new docs 2022-03-02 02:16:12 +00:00
TorchedSammy 7bde025c8e
chore: merge 2022-03-01 22:15:35 -04:00
TorchedSammy e8d0ea12cc
fix: add substitute for exec syscall on windows 2022-03-01 22:14:55 -04:00
TorchedSammy c175bb4d8a
docs: add emmylua doc comments for hilbish module functions 2022-03-01 22:12:48 -04:00
TorchedSammy b3981b5a4e docs: [ci] generate new docs 2022-03-02 02:01:22 +00:00
TorchedSammy 065d752b82
feat: accessible vim input mode (closes #95) 2022-03-01 22:00:46 -04:00
6 changed files with 90 additions and 16 deletions

67
api.go
View File

@ -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
}
@ -212,18 +229,27 @@ func appendPath(dir string) {
func hlexec(L *lua.LState) int {
cmd := L.CheckString(1)
cmdArgs, _ := splitInput(cmd)
cmdPath, err := exec.LookPath(cmdArgs[0])
if err != nil {
fmt.Println(err)
// if we get here, cmdPath will be nothing
// therefore nothing will run
if runtime.GOOS != "windows" {
cmdPath, err := exec.LookPath(cmdArgs[0])
if err != nil {
fmt.Println(err)
// if we get here, cmdPath will be nothing
// therefore nothing will run
}
// syscall.Exec requires an absolute path to a binary
// path, args, string slice of environments
syscall.Exec(cmdPath, cmdArgs, os.Environ())
} else {
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Run()
os.Exit(0)
}
// syscall.Exec requires an absolute path to a binary
// path, args, string slice of environments
// TODO: alternative for windows
syscall.Exec(cmdPath, cmdArgs, os.Environ())
return 0 // random thought: does this ever return?
return 0
}
// goro(fn)
@ -309,6 +335,8 @@ func hlinterval(L *lua.LState) int {
// replacing <cmd> with the name of the command (for example `command.git`).
// `cb` must be a function that returns a table of the entries to complete.
// Nested tables will be used as sub-completions.
// --- @param scope string
// --- @param cb function
func hlcomplete(L *lua.LState) int {
scope := L.CheckString(1)
cb := L.CheckFunction(2)
@ -320,6 +348,7 @@ func hlcomplete(L *lua.LState) int {
// prependPath(dir)
// Prepends `dir` to $PATH
// --- @param dir string
func hlprependPath(L *lua.LState) int {
dir := L.CheckString(1)
dir = strings.Replace(dir, "~", curuser.HomeDir, 1)
@ -335,6 +364,7 @@ func hlprependPath(L *lua.LState) int {
// which(binName)
// Searches for an executable called `binName` in the directories of $PATH
// --- @param binName string
func hlwhich(L *lua.LState) int {
binName := L.CheckString(1)
path, err := exec.LookPath(binName)
@ -346,3 +376,20 @@ 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
// --- @param mode string
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
}

View File

@ -14,6 +14,8 @@ exec(cmd) > Replaces running hilbish with `cmd`
goro(fn) > Puts `fn` in a goroutine
inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
interval(cb, time) > Runs the `cb` function every `time` milliseconds
multiprompt(str) > Changes the continued line prompt to `str`

View File

@ -16,7 +16,9 @@ function hilbish.appendPath(dir) end
--- replacing <cmd> with the name of the command (for example `command.git`).
--- `cb` must be a function that returns a table of the entries to complete.
--- Nested tables will be used as sub-completions.
function hilbish.complete() end
--- @param scope string
--- @param cb function
function hilbish.complete(scope, cb) end
--- Returns the current directory of the shell
function hilbish.cwd() end
@ -29,6 +31,10 @@ function hilbish.exec(cmd) end
--- @param fn function
function hilbish.goroutine(fn) end
--- Sets the input mode for Hilbish's line reader. Accepts either emacs for vim
--- @param mode string
function hilbish.inputMode(mode) end
--- Runs the `cb` function every `time` milliseconds
--- @param cb function
--- @param time number
@ -39,7 +45,8 @@ function hilbish.interval(cb, time) end
function hilbish.mlprompt(str) end
--- Prepends `dir` to $PATH
function hilbish.prependPath() end
--- @param dir string
function hilbish.prependPath(dir) end
--- Changes the shell prompt to `str`
--- There are a few verbs that can be used in the prompt text.
@ -66,6 +73,7 @@ function hilbish.run(cmd) end
function hilbish.timeout(cb, time) end
--- Searches for an executable called `binName` in the directories of $PATH
function hilbish.which() end
--- @param binName string
function hilbish.which(binName) end
return hilbish

2
go.mod
View File

@ -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

2
go.sum
View File

@ -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=

19
rl.go
View File

@ -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) {