mirror of https://github.com/Hilbis/Hilbish
chore: merge from master
commit
1e2c88f4a4
|
@ -70,6 +70,11 @@ set `hilbish.opts.motd` to false.
|
|||
disables commands being added to history.
|
||||
- `hilbish.rawInput` hook for input from the readline library
|
||||
- Completion of files in quotes
|
||||
- A new and "safer" event emitter has been added. This causes a performance deficit, but avoids a lot of
|
||||
random errors introduced with the new Lua runtime (see [#197])
|
||||
- `bait.release(name, catcher)` removes `handler` for the named `event`
|
||||
|
||||
[#197]: https://github.com/Rosettea/Hilbish/issues/197
|
||||
|
||||
### Changed
|
||||
- **Breaking Change:** Upgraded to Lua 5.4.
|
||||
|
@ -138,6 +143,8 @@ menu is open.
|
|||
- `hilbish.dataDir` now has tilde (`~`) expanded.
|
||||
- Arrow keys now work on Windows terminals.
|
||||
- Escape codes now work.
|
||||
- Escape percentage symbols in completion entries, so you will no longer see
|
||||
an error of missing format variable
|
||||
|
||||
## [1.2.0] - 2022-03-17
|
||||
### Added
|
||||
|
|
2
api.go
2
api.go
|
@ -193,7 +193,7 @@ func getenv(key, fallback string) string {
|
|||
|
||||
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)
|
||||
hooks.Emit("hilbish.vimMode", mode)
|
||||
}
|
||||
|
||||
func unsetVimMode() {
|
||||
|
|
|
@ -27,6 +27,9 @@ func splitQuote(str string) []string {
|
|||
sb.WriteRune(r)
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(str, " ") {
|
||||
split = append(split, "")
|
||||
}
|
||||
|
||||
if sb.Len() > 0 {
|
||||
split = append(split, sb.String())
|
||||
|
|
|
@ -2,5 +2,9 @@ catch(name, cb) > Catches a hook with `name`. Runs the `cb` when it is thrown
|
|||
|
||||
catchOnce(name, cb) > Same as catch, but only runs the `cb` once and then removes the hook
|
||||
|
||||
release(name, catcher) > Removes the `catcher` for the event with `name`
|
||||
For this to work, `catcher` has to be the same function used to catch
|
||||
an event, like one saved to a variable.
|
||||
|
||||
throw(name, ...args) > Throws a hook with `name` with the provided `args`
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ func editorLoader(rtm *rt.Runtime) *rt.Table {
|
|||
"insert": {editorInsert, 1, false},
|
||||
"setVimRegister": {editorSetRegister, 1, false},
|
||||
"getVimRegister": {editorGetRegister, 2, false},
|
||||
"getLine": {editorGetLine, 0, false},
|
||||
}
|
||||
|
||||
mod := rt.NewTable()
|
||||
|
@ -68,3 +69,9 @@ func editorGetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
|
||||
return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil
|
||||
}
|
||||
|
||||
func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
buf := lr.rl.GetLine()
|
||||
|
||||
return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ function bait.catch(name, cb) end
|
|||
--- @param cb function
|
||||
function bait.catchOnce(name, cb) end
|
||||
|
||||
--- Removes the `catcher` for the event with `name`
|
||||
--- For this to work, `catcher` has to be the same function used to catch
|
||||
--- an event, like one saved to a variable.
|
||||
function bait.release() end
|
||||
|
||||
--- Throws a hook with `name` with the provided `args`
|
||||
--- @param name string
|
||||
--- @vararg any
|
||||
|
|
23
exec.go
23
exec.go
|
@ -85,7 +85,7 @@ func isExecError(err error) (execError, bool) {
|
|||
func runInput(input string, priv bool) {
|
||||
running = true
|
||||
cmdString := aliases.Resolve(input)
|
||||
hooks.Em.Emit("command.preexec", input, cmdString)
|
||||
hooks.Emit("command.preexec", input, cmdString)
|
||||
|
||||
rerun:
|
||||
var exitCode uint8
|
||||
|
@ -101,7 +101,7 @@ func runInput(input string, priv bool) {
|
|||
cmdFinish(0, input, priv)
|
||||
return
|
||||
}
|
||||
input, exitCode, cont, err = handleSh(input)
|
||||
input, exitCode, cont, err = handleSh(cmdString)
|
||||
case "hybridRev":
|
||||
_, _, _, err = handleSh(input)
|
||||
if err == nil {
|
||||
|
@ -112,7 +112,7 @@ func runInput(input string, priv bool) {
|
|||
case "lua":
|
||||
input, exitCode, err = handleLua(cmdString)
|
||||
case "sh":
|
||||
input, exitCode, cont, err = handleSh(input)
|
||||
input, exitCode, cont, err = handleSh(cmdString)
|
||||
}
|
||||
} else {
|
||||
// can only be a string or function so
|
||||
|
@ -140,7 +140,7 @@ func runInput(input string, priv bool) {
|
|||
|
||||
if err != nil {
|
||||
if exErr, ok := isExecError(err); ok {
|
||||
hooks.Em.Emit("command." + exErr.typ, exErr.cmd)
|
||||
hooks.Emit("command." + exErr.typ, exErr.cmd)
|
||||
err = exErr.sprint()
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
@ -152,6 +152,7 @@ func reprompt(input string) (string, error) {
|
|||
for {
|
||||
in, err := continuePrompt(strings.TrimSuffix(input, "\\"))
|
||||
if err != nil {
|
||||
lr.SetPrompt(fmtPrompt(prompt))
|
||||
return input, err
|
||||
}
|
||||
|
||||
|
@ -220,7 +221,17 @@ func handleLua(cmdString string) (string, uint8, error) {
|
|||
return cmdString, 125, err
|
||||
}
|
||||
|
||||
func handleSh(cmdString string) (string, uint8, bool, error) {
|
||||
func handleSh(cmdString string) (input string, exitCode uint8, cont bool, runErr error) {
|
||||
shRunner := hshMod.Get(rt.StringValue("runner")).AsTable().Get(rt.StringValue("sh"))
|
||||
var err error
|
||||
input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString)
|
||||
if err != nil {
|
||||
runErr = err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func execSh(cmdString string) (string, uint8, bool, error) {
|
||||
_, _, err := execCommand(cmdString, true)
|
||||
if err != nil {
|
||||
// If input is incomplete, start multiline prompting
|
||||
|
@ -544,5 +555,5 @@ func cmdFinish(code uint8, cmdstr string, private bool) {
|
|||
// 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, private)
|
||||
hooks.Emit("command.exit", rt.IntValue(int64(code)), cmdstr, private)
|
||||
}
|
||||
|
|
|
@ -1,27 +1,41 @@
|
|||
package bait
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hilbish/util"
|
||||
|
||||
rt "github.com/arnodel/golua/runtime"
|
||||
"github.com/arnodel/golua/lib/packagelib"
|
||||
"github.com/chuckpreslar/emission"
|
||||
)
|
||||
|
||||
type Bait struct{
|
||||
Em *emission.Emitter
|
||||
Loader packagelib.Loader
|
||||
type listenerType int
|
||||
const (
|
||||
goListener listenerType = iota
|
||||
luaListener
|
||||
)
|
||||
|
||||
// Recoverer is a function which is called when a panic occurs in an event.
|
||||
type Recoverer func(event string, handler *Listener, err interface{})
|
||||
|
||||
// Listener is a struct that holds the handler for an event.
|
||||
type Listener struct{
|
||||
typ listenerType
|
||||
once bool
|
||||
caller func(...interface{})
|
||||
luaCaller *rt.Closure
|
||||
}
|
||||
|
||||
func New() Bait {
|
||||
emitter := emission.NewEmitter()
|
||||
emitter.RecoverWith(func(hookname, hookfunc interface{}, err error) {
|
||||
emitter.Off(hookname, hookfunc)
|
||||
fmt.Println(err)
|
||||
})
|
||||
b := Bait{
|
||||
Em: emitter,
|
||||
type Bait struct{
|
||||
Loader packagelib.Loader
|
||||
recoverer Recoverer
|
||||
handlers map[string][]*Listener
|
||||
rtm *rt.Runtime
|
||||
}
|
||||
|
||||
// New creates a new Bait instance.
|
||||
func New(rtm *rt.Runtime) *Bait {
|
||||
b := &Bait{
|
||||
handlers: make(map[string][]*Listener),
|
||||
rtm: rtm,
|
||||
}
|
||||
b.Loader = packagelib.Loader{
|
||||
Load: b.loaderFunc,
|
||||
|
@ -31,11 +45,148 @@ func New() Bait {
|
|||
return b
|
||||
}
|
||||
|
||||
// Emit throws an event.
|
||||
func (b *Bait) Emit(event string, args ...interface{}) {
|
||||
handles := b.handlers[event]
|
||||
if handles == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for idx, handle := range handles {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
b.callRecoverer(event, handle, err)
|
||||
}
|
||||
}()
|
||||
|
||||
if handle.typ == luaListener {
|
||||
funcVal := rt.FunctionValue(handle.luaCaller)
|
||||
var luaArgs []rt.Value
|
||||
for _, arg := range args {
|
||||
var luarg rt.Value
|
||||
switch arg.(type) {
|
||||
case rt.Value: luarg = arg.(rt.Value)
|
||||
default: luarg = rt.AsValue(arg)
|
||||
}
|
||||
luaArgs = append(luaArgs, luarg)
|
||||
}
|
||||
_, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...)
|
||||
if err != nil {
|
||||
// panicking here won't actually cause hilbish to panic and instead will
|
||||
// print the error and remove the hook. reference the recoverer function in lua.go
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
handle.caller(args...)
|
||||
}
|
||||
|
||||
if handle.once {
|
||||
b.removeListener(event, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// On adds a Go function handler for an event.
|
||||
func (b *Bait) On(event string, handler func(...interface{})) *Listener {
|
||||
listener := &Listener{
|
||||
typ: goListener,
|
||||
caller: handler,
|
||||
}
|
||||
|
||||
b.addListener(event, listener)
|
||||
return listener
|
||||
}
|
||||
|
||||
// OnLua adds a Lua function handler for an event.
|
||||
func (b *Bait) OnLua(event string, handler *rt.Closure) *Listener {
|
||||
listener :=&Listener{
|
||||
typ: luaListener,
|
||||
luaCaller: handler,
|
||||
}
|
||||
b.addListener(event, listener)
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
// Off removes a Go function handler for an event.
|
||||
func (b *Bait) Off(event string, listener *Listener) {
|
||||
handles := b.handlers[event]
|
||||
|
||||
for i, handle := range handles {
|
||||
if handle == listener {
|
||||
b.removeListener(event, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OffLua removes a Lua function handler for an event.
|
||||
func (b *Bait) OffLua(event string, handler *rt.Closure) {
|
||||
handles := b.handlers[event]
|
||||
|
||||
for i, handle := range handles {
|
||||
if handle.luaCaller == handler {
|
||||
b.removeListener(event, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Once adds a Go function listener for an event that only runs once.
|
||||
func (b *Bait) Once(event string, handler func(...interface{})) *Listener {
|
||||
listener := &Listener{
|
||||
typ: goListener,
|
||||
once: true,
|
||||
caller: handler,
|
||||
}
|
||||
b.addListener(event, listener)
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
// OnceLua adds a Lua function listener for an event that only runs once.
|
||||
func (b *Bait) OnceLua(event string, handler *rt.Closure) *Listener {
|
||||
listener := &Listener{
|
||||
typ: luaListener,
|
||||
once: true,
|
||||
luaCaller: handler,
|
||||
}
|
||||
b.addListener(event, listener)
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
// SetRecoverer sets the function to be executed when a panic occurs in an event.
|
||||
func (b *Bait) SetRecoverer(recoverer Recoverer) {
|
||||
b.recoverer = recoverer
|
||||
}
|
||||
|
||||
func (b *Bait) addListener(event string, listener *Listener) {
|
||||
if b.handlers[event] == nil {
|
||||
b.handlers[event] = []*Listener{}
|
||||
}
|
||||
|
||||
b.handlers[event] = append(b.handlers[event], listener)
|
||||
}
|
||||
|
||||
|
||||
func (b *Bait) removeListener(event string, idx int) {
|
||||
b.handlers[event][idx] = b.handlers[event][len(b.handlers[event]) - 1]
|
||||
|
||||
b.handlers[event] = b.handlers[event][:len(b.handlers[event]) - 1]
|
||||
}
|
||||
|
||||
func (b *Bait) callRecoverer(event string, handler *Listener, err interface{}) {
|
||||
if b.recoverer == nil {
|
||||
panic(err)
|
||||
}
|
||||
b.recoverer(event, handler, err)
|
||||
}
|
||||
|
||||
func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||
exports := map[string]util.LuaExport{
|
||||
"catch": util.LuaExport{b.bcatch, 2, false},
|
||||
"catchOnce": util.LuaExport{b.bcatchOnce, 2, false},
|
||||
"throw": util.LuaExport{b.bthrow, 1, true},
|
||||
"release": util.LuaExport{b.brelease, 2, false},
|
||||
}
|
||||
mod := rt.NewTable()
|
||||
util.SetExports(rtm, mod, exports)
|
||||
|
@ -89,7 +240,7 @@ func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
for i, v := range c.Etc() {
|
||||
ifaceSlice[i] = v
|
||||
}
|
||||
b.Em.Emit(name, ifaceSlice...)
|
||||
b.Emit(name, ifaceSlice...)
|
||||
|
||||
return c.Next(), nil
|
||||
}
|
||||
|
@ -104,9 +255,7 @@ func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
b.Em.On(name, func(args ...interface{}) {
|
||||
handleHook(t, c, name, catcher, args...)
|
||||
})
|
||||
b.OnLua(name, catcher)
|
||||
|
||||
return c.Next(), nil
|
||||
}
|
||||
|
@ -121,9 +270,22 @@ func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
b.Em.Once(name, func(args ...interface{}) {
|
||||
handleHook(t, c, name, catcher, args...)
|
||||
})
|
||||
b.OnceLua(name, catcher)
|
||||
|
||||
return c.Next(), nil
|
||||
}
|
||||
|
||||
// release(name, catcher)
|
||||
// Removes the `catcher` for the event with `name`
|
||||
// For this to work, `catcher` has to be the same function used to catch
|
||||
// an event, like one saved to a variable.
|
||||
func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
name, catcher, err := util.HandleStrCallback(t, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.OffLua(name, catcher)
|
||||
|
||||
return c.Next(), nil
|
||||
}
|
||||
|
|
|
@ -2,20 +2,20 @@ package commander
|
|||
|
||||
import (
|
||||
"hilbish/util"
|
||||
"hilbish/golibs/bait"
|
||||
|
||||
rt "github.com/arnodel/golua/runtime"
|
||||
"github.com/arnodel/golua/lib/packagelib"
|
||||
"github.com/chuckpreslar/emission"
|
||||
)
|
||||
|
||||
type Commander struct{
|
||||
Events *emission.Emitter
|
||||
Events *bait.Bait
|
||||
Loader packagelib.Loader
|
||||
}
|
||||
|
||||
func New() Commander {
|
||||
func New(rtm *rt.Runtime) Commander {
|
||||
c := Commander{
|
||||
Events: emission.NewEmitter(),
|
||||
Events: bait.New(rtm),
|
||||
}
|
||||
c.Loader = packagelib.Loader{
|
||||
Load: c.loaderFunc,
|
||||
|
|
6
job.go
6
job.go
|
@ -67,7 +67,7 @@ func (j *job) start() error {
|
|||
j.pid = proc.Pid
|
||||
j.running = true
|
||||
|
||||
hooks.Em.Emit("job.start", rt.UserDataValue(j.ud))
|
||||
hooks.Emit("job.start", rt.UserDataValue(j.ud))
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ func (j *job) stop() {
|
|||
|
||||
func (j *job) finish() {
|
||||
j.running = false
|
||||
hooks.Em.Emit("job.done", rt.UserDataValue(j.ud))
|
||||
hooks.Emit("job.done", rt.UserDataValue(j.ud))
|
||||
}
|
||||
|
||||
func (j *job) wait() {
|
||||
|
@ -236,7 +236,7 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job {
|
|||
jb.ud = jobUserData(jb)
|
||||
|
||||
j.jobs[j.latestID] = jb
|
||||
hooks.Em.Emit("job.add", rt.UserDataValue(jb.ud))
|
||||
hooks.Emit("job.add", rt.UserDataValue(jb.ud))
|
||||
|
||||
return jb
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d60cd77c73875b5bb55e5a2fdc30bae01a7ac499
|
||||
Subproject commit 8467b87dd8d49c68b4100b2d129d5f071544b8cf
|
22
lua.go
22
lua.go
|
@ -32,28 +32,38 @@ func luaInit() {
|
|||
lib.LoadLibs(l, fs.Loader)
|
||||
lib.LoadLibs(l, terminal.Loader)
|
||||
|
||||
cmds := commander.New()
|
||||
cmds := commander.New(l)
|
||||
// When a command from Lua is added, register it for use
|
||||
cmds.Events.On("commandRegister", func(cmdName string, cmd *rt.Closure) {
|
||||
cmds.Events.On("commandRegister", func(args ...interface{}) {
|
||||
cmdName := args[0].(string)
|
||||
cmd := args[1].(*rt.Closure)
|
||||
|
||||
commands[cmdName] = cmd
|
||||
})
|
||||
cmds.Events.On("commandDeregister", func(cmdName string) {
|
||||
cmds.Events.On("commandDeregister", func(args ...interface{}) {
|
||||
cmdName := args[0].(string)
|
||||
|
||||
delete(commands, cmdName)
|
||||
})
|
||||
lib.LoadLibs(l, cmds.Loader)
|
||||
|
||||
hooks = bait.New()
|
||||
hooks = bait.New(l)
|
||||
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
|
||||
fmt.Println("Error in", event, "event:", err)
|
||||
hooks.Off(event, handler)
|
||||
})
|
||||
|
||||
lib.LoadLibs(l, hooks.Loader)
|
||||
|
||||
// Add Ctrl-C handler
|
||||
hooks.Em.On("signal.sigint", func() {
|
||||
hooks.On("signal.sigint", func(...interface{}) {
|
||||
if !interactive {
|
||||
os.Exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
lr.rl.RawInputCallback = func(r []rune) {
|
||||
hooks.Em.Emit("hilbish.rawInput", string(r))
|
||||
hooks.Emit("hilbish.rawInput", string(r))
|
||||
}
|
||||
|
||||
// Add more paths that Lua can require from
|
||||
|
|
10
main.go
10
main.go
|
@ -30,7 +30,7 @@ var (
|
|||
userDataDir string
|
||||
curuser *user.User
|
||||
|
||||
hooks bait.Bait
|
||||
hooks *bait.Bait
|
||||
defaultConfPath string
|
||||
defaultHistPath string
|
||||
)
|
||||
|
@ -138,7 +138,7 @@ func main() {
|
|||
} else {
|
||||
runConfig(*configflag)
|
||||
}
|
||||
hooks.Em.Emit("hilbish.init")
|
||||
hooks.Emit("hilbish.init")
|
||||
|
||||
if fileInfo, _ := os.Stdin.Stat(); (fileInfo.Mode() & os.ModeCharDevice) == 0 {
|
||||
scanner := bufio.NewScanner(bufio.NewReader(os.Stdin))
|
||||
|
@ -177,7 +177,7 @@ input:
|
|||
|
||||
if err == io.EOF {
|
||||
// Exit if user presses ^D (ctrl + d)
|
||||
hooks.Em.Emit("hilbish.exit")
|
||||
hooks.Emit("hilbish.exit")
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -196,7 +196,7 @@ input:
|
|||
input = strings.TrimSpace(input)
|
||||
if len(input) == 0 {
|
||||
running = true
|
||||
hooks.Em.Emit("command.exit", 0)
|
||||
hooks.Emit("command.exit", 0)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ input:
|
|||
}
|
||||
|
||||
func continuePrompt(prev string) (string, error) {
|
||||
hooks.Em.Emit("multiline", nil)
|
||||
hooks.Emit("multiline", nil)
|
||||
lr.SetPrompt(multilinePrompt)
|
||||
cont, err := lr.Read()
|
||||
if err != nil {
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
-- Add command builtins
|
||||
require 'nature.commands.cd'
|
||||
require 'nature.commands.cdr'
|
||||
require 'nature.commands.doc'
|
||||
require 'nature.commands.exit'
|
||||
require 'nature.commands.disown'
|
||||
require 'nature.commands.fg'
|
||||
require 'nature.commands.bg'
|
||||
local fs = require 'fs'
|
||||
|
||||
-- explanation: this specific function gives to us info about
|
||||
-- the currently running source. this includes a path to the
|
||||
-- source file (info.source)
|
||||
-- we will use that to automatically load all commands by reading
|
||||
-- all the files in this dir and just requiring it.
|
||||
local info = debug.getinfo(1)
|
||||
local commandDir = fs.dir(info.source)
|
||||
if commandDir == '.' then return end
|
||||
|
||||
local commands = fs.readdir(commandDir)
|
||||
for _, command in ipairs(commands) do
|
||||
local name = command:gsub('%.lua', '') -- chop off extension
|
||||
if name ~= 'init' then
|
||||
-- skip this file (for obvious reasons)
|
||||
require('nature.commands.' .. name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
local fs = require 'fs'
|
||||
|
||||
function cdHandle(inp)
|
||||
local res = hilbish.runner.lua(inp)
|
||||
|
||||
if not res.err then
|
||||
return res
|
||||
end
|
||||
|
||||
res = hilbish.runner.sh(inp)
|
||||
local oldShRunner = hilbish.runner.sh
|
||||
function hilbish.runner.sh(input)
|
||||
local res = oldShRunner(input)
|
||||
|
||||
if res.exit ~= 0 and hilbish.opts.autocd then
|
||||
local ok, stat = pcall(fs.stat, res.input)
|
||||
|
@ -21,5 +16,3 @@ function cdHandle(inp)
|
|||
|
||||
return res
|
||||
end
|
||||
|
||||
hilbish.runner.setMode(cdHandle)
|
||||
|
|
|
@ -7,7 +7,7 @@ anymore, that will definitely be why! A MOTD, very message, much day.
|
|||
]]
|
||||
|
||||
bait.catch('hilbish.init', function()
|
||||
if hilbish.opts.motd then
|
||||
if hilbish.interactive and hilbish.opts.motd then
|
||||
print(lunacolors.format(hilbish.motd))
|
||||
end
|
||||
end)
|
||||
|
|
|
@ -99,7 +99,7 @@ func (g *CompletionGroup) writeGrid(rl *Instance) (comp string) {
|
|||
|
||||
// If group title, print it and adjust offset.
|
||||
if g.Name != "" {
|
||||
comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, g.Name, RESET)
|
||||
comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, fmtEscape(g.Name), RESET)
|
||||
rl.tcUsedY++
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ func (g *CompletionGroup) writeGrid(rl *Instance) (comp string) {
|
|||
comp += seqInvert
|
||||
}
|
||||
|
||||
comp += fmt.Sprintf("%-"+cellWidth+"s %s", g.Suggestions[i], seqReset)
|
||||
comp += fmt.Sprintf("%-"+cellWidth+"s %s", fmtEscape(g.Suggestions[i]), seqReset)
|
||||
}
|
||||
|
||||
// Always add a newline to the group if the end if not punctuated with one
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package readline
|
||||
|
||||
import "strings"
|
||||
|
||||
// CompletionGroup - A group/category of items offered to completion, with its own
|
||||
// name, descriptions and completion display format/type.
|
||||
// The output, if there are multiple groups available for a given completion input,
|
||||
|
@ -285,3 +287,7 @@ func (g *CompletionGroup) goLastCell() {
|
|||
g.tcPosX = 0
|
||||
}
|
||||
}
|
||||
|
||||
func fmtEscape(s string) string {
|
||||
return strings.Replace(s, "%", "%%", -1)
|
||||
}
|
||||
|
|
|
@ -206,12 +206,12 @@ func (g *CompletionGroup) writeList(rl *Instance) (comp string) {
|
|||
if len(item) > maxLength {
|
||||
item = item[:maxLength-3] + "..."
|
||||
}
|
||||
sugg := fmt.Sprintf("\r%s%-"+cellWidth+"s", highlight(y, 0), item)
|
||||
sugg := fmt.Sprintf("\r%s%-"+cellWidth+"s", highlight(y, 0), fmtEscape(item))
|
||||
|
||||
// Alt suggestion
|
||||
alt, ok := g.Aliases[item]
|
||||
if ok {
|
||||
alt = fmt.Sprintf(" %s%"+cellWidthAlt+"s", highlight(y, 1), alt)
|
||||
alt = fmt.Sprintf(" %s%"+cellWidthAlt+"s", highlight(y, 1), fmtEscape(alt))
|
||||
} else {
|
||||
// Else, make an empty cell
|
||||
alt = strings.Repeat(" ", maxLengthAlt+1) // + 2 to keep account of spaces
|
||||
|
|
|
@ -76,7 +76,7 @@ func (g *CompletionGroup) writeMap(rl *Instance) (comp string) {
|
|||
|
||||
if g.Name != "" {
|
||||
// Print group title (changes with line returns depending on type)
|
||||
comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, g.Name, RESET)
|
||||
comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, fmtEscape(g.Name), RESET)
|
||||
rl.tcUsedY++
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ func (g *CompletionGroup) writeMap(rl *Instance) (comp string) {
|
|||
}
|
||||
|
||||
comp += fmt.Sprintf("\r%-"+cellWidth+"s %s %-"+itemWidth+"s %s\n",
|
||||
description, highlight(y), item, seqReset)
|
||||
description, highlight(y), fmtEscape(item), seqReset)
|
||||
}
|
||||
|
||||
// Add the equivalent of this group's size to final screen clearing
|
||||
|
|
|
@ -18,7 +18,7 @@ func (rl *Instance) updateLine(line []rune) {
|
|||
|
||||
// getLine - In many places we need the current line input. We either return the real line,
|
||||
// or the one that includes the current completion candidate, if there is any.
|
||||
func (rl *Instance) getLine() []rune {
|
||||
func (rl *Instance) GetLine() []rune {
|
||||
if len(rl.currentComp) > 0 {
|
||||
return rl.lineComp
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
ansi "github.com/acarl005/stripansi"
|
||||
"github.com/rivo/uniseg"
|
||||
)
|
||||
|
||||
// SetPrompt will define the readline prompt string.
|
||||
|
@ -209,7 +208,7 @@ func (rl *Instance) colorizeVimPrompt(p []rune) (cp []rune) {
|
|||
// getting its real-printed length.
|
||||
func getRealLength(s string) (l int) {
|
||||
stripped := ansi.Strip(s)
|
||||
return uniseg.GraphemeClusterCount(stripped)
|
||||
return getWidth([]rune(stripped))
|
||||
}
|
||||
|
||||
func (rl *Instance) echoRightPrompt() {
|
||||
|
|
|
@ -24,7 +24,7 @@ func delayedSyntaxTimer(rl *Instance, i int64) {
|
|||
// }
|
||||
|
||||
// We pass either the current line or the one with the current completion.
|
||||
newLine := rl.DelayedSyntaxWorker(rl.getLine())
|
||||
newLine := rl.DelayedSyntaxWorker(rl.GetLine())
|
||||
var sLine string
|
||||
count := atomic.LoadInt64(&rl.delayedSyntaxCount)
|
||||
if count != i {
|
||||
|
|
6
rl.go
6
rl.go
|
@ -48,14 +48,14 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
|||
case readline.VimActionPaste: actionStr = "paste"
|
||||
case readline.VimActionYank: actionStr = "yank"
|
||||
}
|
||||
hooks.Em.Emit("hilbish.vimAction", actionStr, args)
|
||||
hooks.Emit("hilbish.vimAction", actionStr, args)
|
||||
}
|
||||
rl.HintText = func(line []rune, pos int) []rune {
|
||||
if hinter == nil {
|
||||
return []rune{}
|
||||
}
|
||||
|
||||
retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(highlighter),
|
||||
retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(hinter),
|
||||
rt.StringValue(string(line)), rt.IntValue(int64(pos)))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -179,7 +179,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
|||
}
|
||||
|
||||
func (lr *lineReader) Read() (string, error) {
|
||||
hooks.Em.Emit("command.precmd", nil)
|
||||
hooks.Emit("command.precmd", nil)
|
||||
s, err := lr.rl.Readline()
|
||||
// this is so dumb
|
||||
if err == readline.EOF {
|
||||
|
|
|
@ -28,7 +28,7 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
input, exitCode, cont, err := handleSh(cmd)
|
||||
input, exitCode, cont, err := execSh(cmd)
|
||||
var luaErr rt.Value = rt.NilValue
|
||||
if err != nil {
|
||||
luaErr = rt.StringValue(err.Error())
|
||||
|
|
|
@ -15,11 +15,11 @@ func handleSignals() {
|
|||
|
||||
for s := range c {
|
||||
switch s {
|
||||
case os.Interrupt: hooks.Em.Emit("signal.sigint")
|
||||
case os.Interrupt: hooks.Emit("signal.sigint")
|
||||
case syscall.SIGTERM: exit(0)
|
||||
case syscall.SIGWINCH: hooks.Em.Emit("signal.resize")
|
||||
case syscall.SIGUSR1: hooks.Em.Emit("signal.sigusr1")
|
||||
case syscall.SIGUSR2: hooks.Em.Emit("signal.sigusr2")
|
||||
case syscall.SIGWINCH: hooks.Emit("signal.resize")
|
||||
case syscall.SIGUSR1: hooks.Emit("signal.sigusr1")
|
||||
case syscall.SIGUSR2: hooks.Emit("signal.sigusr2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ func handleSignals() {
|
|||
for s := range c {
|
||||
switch s {
|
||||
case os.Interrupt:
|
||||
hooks.Em.Emit("signal.sigint")
|
||||
hooks.Emit("signal.sigint")
|
||||
if !running && interactive {
|
||||
lr.ClearInput()
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ var (
|
|||
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?.lua;'`
|
||||
dataDir = util.ExpandHome("~\\Appdata\\Roaming\\Hilbish") // ~ and \ gonna cry?
|
||||
preloadPath = dataDir + "\\nature\\init.lua"
|
||||
sampleConfPath = dataDir + "\\hilbishrc.lua" // Path to default/sample config
|
||||
sampleConfPath = dataDir + "\\.hilbishrc.lua" // Path to default/sample config
|
||||
defaultConfDir = ""
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue