diff --git a/CHANGELOG.md b/CHANGELOG.md index 522c8d5..49904ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/api.go b/api.go index 67b2a1c..cfa3d06 100644 --- a/api.go +++ b/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() { diff --git a/complete.go b/complete.go index 3a2899d..76d65f7 100644 --- a/complete.go +++ b/complete.go @@ -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()) diff --git a/docs/bait.txt b/docs/bait.txt index 9f1e54b..fdc712f 100644 --- a/docs/bait.txt +++ b/docs/bait.txt @@ -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` diff --git a/editor.go b/editor.go index 323f50b..868f458 100644 --- a/editor.go +++ b/editor.go @@ -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 +} diff --git a/emmyLuaDocs/bait.lua b/emmyLuaDocs/bait.lua index 01ca774..a5ecebd 100644 --- a/emmyLuaDocs/bait.lua +++ b/emmyLuaDocs/bait.lua @@ -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 diff --git a/exec.go b/exec.go index e1862ed..6e24719 100644 --- a/exec.go +++ b/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) } diff --git a/golibs/bait/bait.go b/golibs/bait/bait.go index 3112903..89e0c4a 100644 --- a/golibs/bait/bait.go +++ b/golibs/bait/bait.go @@ -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 } diff --git a/golibs/commander/commander.go b/golibs/commander/commander.go index d279e0c..24f1c03 100644 --- a/golibs/commander/commander.go +++ b/golibs/commander/commander.go @@ -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, diff --git a/job.go b/job.go index 7dd07d3..709cc1f 100644 --- a/job.go +++ b/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 } diff --git a/libs/lunacolors b/libs/lunacolors index d60cd77..8467b87 160000 --- a/libs/lunacolors +++ b/libs/lunacolors @@ -1 +1 @@ -Subproject commit d60cd77c73875b5bb55e5a2fdc30bae01a7ac499 +Subproject commit 8467b87dd8d49c68b4100b2d129d5f071544b8cf diff --git a/lua.go b/lua.go index 92ece05..419970c 100644 --- a/lua.go +++ b/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 diff --git a/main.go b/main.go index e53055d..ee0f584 100644 --- a/main.go +++ b/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 { diff --git a/nature/commands/init.lua b/nature/commands/init.lua index 13b33be..93113cd 100644 --- a/nature/commands/init.lua +++ b/nature/commands/init.lua @@ -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 diff --git a/nature/opts/autocd.lua b/nature/opts/autocd.lua index ac32f32..ce68230 100644 --- a/nature/opts/autocd.lua +++ b/nature/opts/autocd.lua @@ -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) diff --git a/nature/opts/motd.lua b/nature/opts/motd.lua index b22f5a2..5f30a6c 100644 --- a/nature/opts/motd.lua +++ b/nature/opts/motd.lua @@ -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) diff --git a/readline/comp-grid.go b/readline/comp-grid.go index 2679835..48a2039 100644 --- a/readline/comp-grid.go +++ b/readline/comp-grid.go @@ -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 diff --git a/readline/comp-group.go b/readline/comp-group.go index 6a6e7bc..0c53ed1 100644 --- a/readline/comp-group.go +++ b/readline/comp-group.go @@ -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) +} diff --git a/readline/comp-list.go b/readline/comp-list.go index 42add2f..cdcda8f 100644 --- a/readline/comp-list.go +++ b/readline/comp-list.go @@ -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 diff --git a/readline/comp-map.go b/readline/comp-map.go index 42b56cf..ec985ff 100644 --- a/readline/comp-map.go +++ b/readline/comp-map.go @@ -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 diff --git a/readline/line.go b/readline/line.go index 974a34d..2024bb0 100644 --- a/readline/line.go +++ b/readline/line.go @@ -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 } diff --git a/readline/prompt.go b/readline/prompt.go index 79f7c71..0f6ca5a 100644 --- a/readline/prompt.go +++ b/readline/prompt.go @@ -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() { diff --git a/readline/timer.go b/readline/timer.go index dc53ca9..76eab23 100644 --- a/readline/timer.go +++ b/readline/timer.go @@ -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 { diff --git a/rl.go b/rl.go index 6350aa2..f6cb6cd 100644 --- a/rl.go +++ b/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 { diff --git a/runnermode.go b/runnermode.go index eca33ba..b8995cd 100644 --- a/runnermode.go +++ b/runnermode.go @@ -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()) diff --git a/signal_unix.go b/signal_unix.go index bd5984c..2e6c885 100644 --- a/signal_unix.go +++ b/signal_unix.go @@ -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") } } } diff --git a/signal_windows.go b/signal_windows.go index 9f67537..42a9fff 100644 --- a/signal_windows.go +++ b/signal_windows.go @@ -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() } diff --git a/vars_windows.go b/vars_windows.go index 403941f..d1bd7b6 100644 --- a/vars_windows.go +++ b/vars_windows.go @@ -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 = "" )