From e3c25586e42f770f85401440cb32cc6752fdfd39 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 28 May 2022 09:07:28 -0400 Subject: [PATCH 1/8] fix: broken ansi escape codes on windows cmd --- init_windows.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 init_windows.go diff --git a/init_windows.go b/init_windows.go new file mode 100644 index 0000000..ee17a6b --- /dev/null +++ b/init_windows.go @@ -0,0 +1,11 @@ +// +build windows + +package main + +import "golang.org/x/sys/windows" + +func init() { + var mode uint32 + windows.GetConsoleMode(windows.Stdout, &mode) + windows.SetConsoleMode(windows.Stdout, mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) +} From b28a2c24c1cc9dcd2df107dd76921e2790b255c7 Mon Sep 17 00:00:00 2001 From: sammyette <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 28 May 2022 19:03:44 -0400 Subject: [PATCH 2/8] refactor!: use userdata where appropriate (#157) any interface which has lua side objects that are from go side for its api (namely jobs) they will use userdata instead of always creating a table to represent the object. this might or might not bring lower ram usage since there is now only 1 single reference to an object instead of always creating a table to expose on lua breaking change since methods need to be called with a colon instead of dot --- CHANGELOG.md | 3 + api.go | 4 +- docs/jobs.txt | 7 ++- docs/timers.txt | 14 ++++- job.go | 144 +++++++++++++++++++++++++++++++++++++----------- timer.go | 46 ++++++++-------- timerhandler.go | 65 +++++++++++++++++++++- 7 files changed, 221 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a1d377..ab8a2a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,9 @@ This is probably one of (if not the) biggest things in this release. user input, exit code, and error. User input has been added to the return to account for runners wanting to prompt for continued input, and to add it properly to history. +- **Breaking Change:** Job objects and timers are now Lua userdata instead +of a table, so their functions require you to call them with a colon instead +of a dot. (ie. `job.stop()` -> `job:stop()`) - All `fs` module functions which take paths now implicitly expand ~ to home. ### Fixed diff --git a/api.go b/api.go index 9289305..3aca037 100644 --- a/api.go +++ b/api.go @@ -476,7 +476,7 @@ func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { timer := timers.create(timerTimeout, interval, cb) timer.start() - return c.PushingNext1(t.Runtime, timer.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil } // interval(cb, time) @@ -502,7 +502,7 @@ func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { timer := timers.create(timerInterval, interval, cb) timer.start() - return c.PushingNext1(t.Runtime, timer.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil } // complete(scope, cb) diff --git a/docs/jobs.txt b/docs/jobs.txt index 1dc8009..a5fee9c 100644 --- a/docs/jobs.txt +++ b/docs/jobs.txt @@ -20,8 +20,11 @@ and `execPath` is an absolute path for the command executable. - `disown(id)`: Removes a job by ID from the job table. # Job Object -A job object on the Lua side is a table with some functions. -On the under side it represents a job in the job table. +A job object is a piece of `userdata`. All the functions of a job require +you to call them with a colon, since they are *methods* for the job object. +Example: hilbish.jobs.last():foreground() +Which will foreground the last job. + You can still have a job object for a disowned job, it just won't be *working* anywhere. :^) diff --git a/docs/timers.txt b/docs/timers.txt index c5a456b..0f89718 100644 --- a/docs/timers.txt +++ b/docs/timers.txt @@ -16,9 +16,17 @@ a timer via ID. when the timer is triggered. # Timer Object -Those previously mentioned functions return a `timer` object, to which you can -stop and start a timer again. The functions of the timers interface also -return a timer object. +All those previously mentioned functions return a `timer` object, to which +you can stop and start a timer again. + +An example of usage: +local t = hilbish.timers.create(1, 5000, function() + print 'hello!' +end) + +t:stop() +print(t.running, t.duration, t.type) +t:start() ## Properties - `duration`: amount of time the timer runs for in milliseconds diff --git a/job.go b/job.go index 5ffb61f..7dd07d3 100644 --- a/job.go +++ b/job.go @@ -3,6 +3,7 @@ package main import ( "bytes" "errors" + "fmt" "io" "os" "os/exec" @@ -15,6 +16,7 @@ import ( ) var jobs *jobHandler +var jobMetaKey = rt.StringValue("hshjob") type job struct { cmd string @@ -32,6 +34,7 @@ type job struct { cmderr io.Writer stdout *bytes.Buffer stderr *bytes.Buffer + ud *rt.UserData } func (j *job) start() error { @@ -64,7 +67,7 @@ func (j *job) start() error { j.pid = proc.Pid j.running = true - hooks.Em.Emit("job.start", j.lua()) + hooks.Em.Emit("job.start", rt.UserDataValue(j.ud)) return err } @@ -79,7 +82,7 @@ func (j *job) stop() { func (j *job) finish() { j.running = false - hooks.Em.Emit("job.done", j.lua()) + hooks.Em.Emit("job.done", rt.UserDataValue(j.ud)) } func (j *job) wait() { @@ -107,28 +110,16 @@ func (j *job) getProc() *os.Process { return nil } -func (j *job) lua() rt.Value { - jobFuncs := map[string]util.LuaExport{ - "stop": {j.luaStop, 0, false}, - "start": {j.luaStart, 0, false}, - "foreground": {j.luaForeground, 0, false}, - "background": {j.luaBackground, 0, false}, +func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err } - luaJob := rt.NewTable() - util.SetExports(l, luaJob, jobFuncs) - luaJob.Set(rt.StringValue("cmd"), rt.StringValue(j.cmd)) - luaJob.Set(rt.StringValue("running"), rt.BoolValue(j.running)) - luaJob.Set(rt.StringValue("id"), rt.IntValue(int64(j.id))) - luaJob.Set(rt.StringValue("pid"), rt.IntValue(int64(j.pid))) - luaJob.Set(rt.StringValue("exitCode"), rt.IntValue(int64(j.exitCode))) - luaJob.Set(rt.StringValue("stdout"), rt.StringValue(string(j.stdout.Bytes()))) - luaJob.Set(rt.StringValue("stderr"), rt.StringValue(string(j.stderr.Bytes()))) + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } - return rt.TableValue(luaJob) -} - -func (j *job) luaStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if !j.running { err := j.start() exit := handleExecErr(err) @@ -139,7 +130,16 @@ func (j *job) luaStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { +func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } + if j.running { j.stop() j.finish() @@ -148,7 +148,16 @@ func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (j *job) luaForeground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { +func luaForegroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } + if !j.running { return nil, errors.New("job not running") } @@ -157,7 +166,7 @@ func (j *job) luaForeground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jobs.foreground = true // this is kinda funny // background continues the process incase it got suspended - err := j.background() + err = j.background() if err != nil { return nil, err } @@ -171,12 +180,21 @@ func (j *job) luaForeground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (j *job) luaBackground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { +func luaBackgroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } + if !j.running { return nil, errors.New("job not running") } - err := j.background() + err = j.background() if err != nil { return nil, err } @@ -215,8 +233,10 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job { stdout: &bytes.Buffer{}, stderr: &bytes.Buffer{}, } + jb.ud = jobUserData(jb) + j.jobs[j.latestID] = jb - hooks.Em.Emit("job.add", jb.lua()) + hooks.Em.Emit("job.add", rt.UserDataValue(jb.ud)) return jb } @@ -257,6 +277,44 @@ func (j *jobHandler) stopAll() { } func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table { + jobMethods := rt.NewTable() + jFuncs := map[string]util.LuaExport{ + "stop": {luaStopJob, 1, false}, + "start": {luaStartJob, 1, false}, + "foreground": {luaForegroundJob, 1, false}, + "background": {luaBackgroundJob, 1, false}, + } + util.SetExports(l, jobMethods, jFuncs) + + jobMeta := rt.NewTable() + jobIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + j, _ := jobArg(c, 0) + + arg := c.Arg(1) + val := jobMethods.Get(arg) + + if val != rt.NilValue { + return c.PushingNext1(t.Runtime, val), nil + } + + keyStr, _ := arg.TryString() + + switch keyStr { + case "cmd": val = rt.StringValue(j.cmd) + case "running": val = rt.BoolValue(j.running) + case "id": val = rt.IntValue(int64(j.id)) + case "pid": val = rt.IntValue(int64(j.pid)) + case "exitCode": val = rt.IntValue(int64(j.exitCode)) + case "stdout": val = rt.StringValue(string(j.stdout.Bytes())) + case "stderr": val = rt.StringValue(string(j.stderr.Bytes())) + } + + return c.PushingNext1(t.Runtime, val), nil + } + + jobMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(jobIndex, "__index", 2, false))) + l.SetRegistry(jobMetaKey, rt.TableValue(jobMeta)) + jobFuncs := map[string]util.LuaExport{ "all": {j.luaAllJobs, 0, false}, "last": {j.luaLastJob, 0, false}, @@ -271,6 +329,30 @@ func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table { return luaJob } +func jobArg(c *rt.GoCont, arg int) (*job, error) { + j, ok := valueToJob(c.Arg(arg)) + if !ok { + return nil, fmt.Errorf("#%d must be a job", arg + 1) + } + + return j, nil +} + +func valueToJob(val rt.Value) (*job, bool) { + u, ok := val.TryUserData() + if !ok { + return nil, false + } + + j, ok := u.Value().(*job) + return j, ok +} + +func jobUserData(j *job) *rt.UserData { + jobMeta := l.Registry(jobMetaKey) + return rt.NewUserData(j, jobMeta.AsTable()) +} + func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { j.mu.RLock() defer j.mu.RUnlock() @@ -288,7 +370,7 @@ func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } - return c.PushingNext1(t.Runtime, job.lua()), nil + return c.PushingNext(t.Runtime, rt.UserDataValue(job.ud)), nil } func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -317,7 +399,7 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jb := j.add(cmd, args, execPath) - return c.PushingNext1(t.Runtime, jb.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(jb.ud)), nil } func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -326,7 +408,7 @@ func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jobTbl := rt.NewTable() for id, job := range j.jobs { - jobTbl.Set(rt.IntValue(int64(id)), job.lua()) + jobTbl.Set(rt.IntValue(int64(id)), rt.UserDataValue(job.ud)) } return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil @@ -358,5 +440,5 @@ func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } - return c.PushingNext1(t.Runtime, job.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(job.ud)), nil } diff --git a/timer.go b/timer.go index a502087..74d13c4 100644 --- a/timer.go +++ b/timer.go @@ -6,8 +6,6 @@ import ( "os" "time" - "hilbish/util" - rt "github.com/arnodel/golua/runtime" ) @@ -25,6 +23,7 @@ type timer struct{ fun *rt.Closure th *timerHandler ticker *time.Ticker + ud *rt.UserData channel chan struct{} } @@ -74,8 +73,17 @@ func (t *timer) stop() error { return nil } -func (t *timer) luaStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - err := t.start() +func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + t, err := timerArg(c, 0) + if err != nil { + return nil, err + } + + err = t.start() if err != nil { return nil, err } @@ -83,26 +91,20 @@ func (t *timer) luaStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (t *timer) luaStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - err := t.stop() +func timerStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + t, err := timerArg(c, 0) if err != nil { return nil, err } - + + err = t.stop() + if err != nil { + return nil, err + } + return c.Next(), nil } - -func (t *timer) lua() rt.Value { - tExports := map[string]util.LuaExport{ - "start": {t.luaStart, 0, false}, - "stop": {t.luaStop, 0, false}, - } - luaTimer := rt.NewTable() - util.SetExports(l, luaTimer, tExports) - - luaTimer.Set(rt.StringValue("type"), rt.IntValue(int64(t.typ))) - luaTimer.Set(rt.StringValue("running"), rt.BoolValue(t.running)) - luaTimer.Set(rt.StringValue("duration"), rt.IntValue(int64(t.dur / time.Millisecond))) - - return rt.TableValue(luaTimer) -} diff --git a/timerhandler.go b/timerhandler.go index 2f2e878..64caff8 100644 --- a/timerhandler.go +++ b/timerhandler.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "sync" "time" @@ -10,6 +11,8 @@ import ( ) var timers *timerHandler +var timerMetaKey = rt.StringValue("hshtimer") + type timerHandler struct { mu *sync.RWMutex wg *sync.WaitGroup @@ -44,6 +47,8 @@ func (th *timerHandler) create(typ timerType, dur time.Duration, fun *rt.Closure th: th, id: th.latestID, } + t.ud = timerUserData(t) + th.timers[th.latestID] = t return t @@ -75,7 +80,7 @@ func (th *timerHandler) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { timerTyp := timerType(timerTypInt) tmr := th.create(timerTyp, time.Duration(ms) * time.Millisecond, cb) - return c.PushingNext1(t.Runtime, tmr.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(tmr.ud)), nil } func (th *timerHandler) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -89,13 +94,45 @@ func (th *timerHandler) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { t := th.get(int(id)) if t != nil { - return c.PushingNext1(thr.Runtime, t.lua()), nil + return c.PushingNext1(thr.Runtime, rt.UserDataValue(t.ud)), nil } return c.Next(), nil } func (th *timerHandler) loader(rtm *rt.Runtime) *rt.Table { + timerMethods := rt.NewTable() + timerFuncs := map[string]util.LuaExport{ + "start": {timerStart, 1, false}, + "stop": {timerStop, 1, false}, + } + util.SetExports(rtm, timerMethods, timerFuncs) + + timerMeta := rt.NewTable() + timerIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + ti, _ := timerArg(c, 0) + + arg := c.Arg(1) + val := timerMethods.Get(arg) + + if val != rt.NilValue { + return c.PushingNext1(t.Runtime, val), nil + } + + keyStr, _ := arg.TryString() + + switch keyStr { + case "type": val = rt.IntValue(int64(ti.typ)) + case "running": val = rt.BoolValue(ti.running) + case "duration": val = rt.IntValue(int64(ti.dur / time.Millisecond)) + } + + return c.PushingNext1(t.Runtime, val), nil + } + + timerMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(timerIndex, "__index", 2, false))) + l.SetRegistry(timerMetaKey, rt.TableValue(timerMeta)) + thExports := map[string]util.LuaExport{ "create": {th.luaCreate, 3, false}, "get": {th.luaGet, 1, false}, @@ -106,3 +143,27 @@ func (th *timerHandler) loader(rtm *rt.Runtime) *rt.Table { return luaTh } + +func timerArg(c *rt.GoCont, arg int) (*timer, error) { + j, ok := valueToTimer(c.Arg(arg)) + if !ok { + return nil, fmt.Errorf("#%d must be a timer", arg + 1) + } + + return j, nil +} + +func valueToTimer(val rt.Value) (*timer, bool) { + u, ok := val.TryUserData() + if !ok { + return nil, false + } + + j, ok := u.Value().(*timer) + return j, ok +} + +func timerUserData(j *timer) *rt.UserData { + timerMeta := l.Registry(timerMetaKey) + return rt.NewUserData(j, timerMeta.AsTable()) +} From 3990d370fa5f3a94bbc6ad07b677d18965c92adb Mon Sep 17 00:00:00 2001 From: sammyette <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 28 May 2022 19:06:18 -0400 Subject: [PATCH 3/8] feat: extend hilbish.runner interface to allow multiple runners (#159) --- CHANGELOG.md | 2 + docs/runner-mode.txt | 15 +++++- nature/init.lua | 1 + nature/runner.lua | 106 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 nature/runner.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8a2a4..3768eff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ includes git commit, branch, and (new!!) release name. - Added `fg` and `bg` builtins - `job.foreground()` and `job.background()`, when `job` is a job object, foreground and backgrounds a job respectively. +- Friendlier functions to the `hilbish.runner` interface, which also allow +having and using multiple runners. ### Changed - **Breaking Change:** Upgraded to Lua 5.4. diff --git a/docs/runner-mode.txt b/docs/runner-mode.txt index 9df1095..5765f18 100644 --- a/docs/runner-mode.txt +++ b/docs/runner-mode.txt @@ -35,8 +35,21 @@ The exit code has to be a number, it will be 0 otherwise and the error can be `nil` to indicate no error. ## Functions -These are the functions for the `hilbish.runner` interface +These are the "low level" functions for the `hilbish.runner` interface. + setMode(mode) > The same as `hilbish.runnerMode` + sh(input) -> input, code, err > Runs `input` in Hilbish's sh interpreter + lua(input) -> input, code, err > Evals `input` as Lua code + +The others here are defined in Lua and have EmmyLua documentation. +These functions should be preferred over the previous ones. ++ setCurrent(mode) > The same as `setMode`, but works with runners managed +via the functions below. ++ add(name, runner) > Adds a runner to a table of available runners. The `runner` +argument is either a function or a table with a run callback. ++ set(name, runner) > The same as `add` but requires passing a table and +overwrites if the `name`d runner already exists. ++ get(name) > runner > Gets a runner by name. It is a table with at least a +run function, to run input. ++ exec(cmd, runnerName) > Runs `cmd` with a runner. If `runnerName` isn't passed, +the current runner mode is used. diff --git a/nature/init.lua b/nature/init.lua index 7dd8953..8671087 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -8,6 +8,7 @@ require 'nature.commands' require 'nature.completions' require 'nature.opts' require 'nature.vim' +require 'nature.runner' local shlvl = tonumber(os.getenv 'SHLVL') if shlvl ~= nil then diff --git a/nature/runner.lua b/nature/runner.lua new file mode 100644 index 0000000..ed1b7dd --- /dev/null +++ b/nature/runner.lua @@ -0,0 +1,106 @@ +local currentRunner = 'hybrid' +local runners = {} + +-- lsp shut up +hilbish = hilbish + +--- Get a runner by name. +--- @param name string +--- @return table +function hilbish.runner.get(name) + local r = runners[name] + + if not r then + error(string.format('runner %s does not exist', name)) + end + + return r +end + +--- Adds a runner to the table of available runners. If runner is a table, +--- it must have the run function in it. +--- @param name string +--- @param runner function | table +function hilbish.runner.add(name, runner) + if type(name) ~= 'string' then + error 'expected runner name to be a table' + end + + if type(runner) == 'function' then + runner = {run = runner} -- this probably looks confusing + end + + if type(runner) ~= 'table' then + error 'expected runner to be a table or function' + end + + if runners[name] then + error(string.format('runner %s already exists', name)) + end + + hilbish.runner.set(name, runner) +end + +--- Sets a runner by name. The runner table must have the run function in it. +--- @param name string +--- @param runner table +function hilbish.runner.set(name, runner) + if not runner.run or type(runner.run) ~= 'function' then + error 'run function in runner missing' + end + + runners[name] = runner +end + +--- Executes cmd with a runner. If runnerName isn't passed, it uses +--- the user's current runner. +--- @param cmd string +--- @param runnerName string? +--- @return string, number, string +function hilbish.runner.exec(cmd, runnerName) + if not runnerName then runnerName = currentRunner end + + local r = hilbish.runner.get(runnerName) + + return r.run(cmd) +end + +--- Sets the current interactive/command line runner mode. +--- @param name string +function hilbish.runner.setCurrent(name) + local r = hilbish.runner.get(name) + currentRunner = name + + hilbish.runner.setMode(r.run) +end + +hilbish.runner.add('hybrid', function(input) + local cmdStr = hilbish.aliases.resolve(input) + + local _, _, err = hilbish.runner.lua(cmdStr) + if not err then + return input, 0, nil + end + + return hilbish.runner.sh(input) +end) + +hilbish.runner.add('hybridRev', function(input) + local _, _, err = hilbish.runner.sh(input) + if not err then + return input, 0, nil + end + + local cmdStr = hilbish.aliases.resolve(input) + return hilbish.runner.lua(cmdStr) +end) + +hilbish.runner.add('lua', function(input) + local cmdStr = hilbish.aliases.resolve(input) + return hilbish.runner.lua(cmdStr) +end) + +hilbish.runner.add('sh', function(input) + return hilbish.runner.sh(input) +end) + From 2faaf4e045c680f039596295f1ffd8efa3f83d1c Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 28 May 2022 20:19:39 -0400 Subject: [PATCH 4/8] fix: print err don't panic and in the case of regex compile failing on menu find --- readline/comp-group.go | 1 + readline/tabfind.go | 1 + 2 files changed, 2 insertions(+) diff --git a/readline/comp-group.go b/readline/comp-group.go index ecf59b4..6a6e7bc 100644 --- a/readline/comp-group.go +++ b/readline/comp-group.go @@ -73,6 +73,7 @@ func (g *CompletionGroup) updateTabFind(rl *Instance) { // We perform filter right here, so we create a new completion group, and populate it with our results. for i := range g.Suggestions { + if rl.regexSearch == nil { continue } if rl.regexSearch.MatchString(g.Suggestions[i]) { suggs = append(suggs, g.Suggestions[i]) } else if g.DisplayType == TabDisplayList && rl.regexSearch.MatchString(g.Descriptions[g.Suggestions[i]]) { diff --git a/readline/tabfind.go b/readline/tabfind.go index 5abe307..aa38259 100644 --- a/readline/tabfind.go +++ b/readline/tabfind.go @@ -33,6 +33,7 @@ func (rl *Instance) updateTabFind(r []rune) { var err error rl.regexSearch, err = regexp.Compile("(?i)" + string(rl.tfLine)) if err != nil { + rl.RefreshPromptLog(err.Error()) rl.infoText = []rune(Red("Failed to match search regexp")) } From b4a5746093a89dfd5729eb297acd25063115b225 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 28 May 2022 20:21:57 -0400 Subject: [PATCH 5/8] ci: use make to build for artifacts --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b357b64..08c69ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: with: go-version: '1.17.7' - name: Build - run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build + run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} make - uses: actions/upload-artifact@v2 if: matrix.goos == 'windows' with: From 1339dc4a2f2e1ecfca4289f799631ab2cd337769 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sat, 28 May 2022 21:05:03 -0400 Subject: [PATCH 6/8] fix: multiline cursor redraw --- readline/line.go | 1 + readline/prompt.go | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/readline/line.go b/readline/line.go index 974a34d..3dfa7c4 100644 --- a/readline/line.go +++ b/readline/line.go @@ -45,6 +45,7 @@ func (rl *Instance) echo() { print(seqClearScreenBelow) // Print the prompt + rl.promptInPlace("") print(string(rl.realPrompt)) // Assemble the line, taking virtual completions into account diff --git a/readline/prompt.go b/readline/prompt.go index 699abec..abda175 100644 --- a/readline/prompt.go +++ b/readline/prompt.go @@ -73,8 +73,7 @@ func (rl *Instance) RefreshPromptLog(log string) (err error) { return } -// RefreshPromptInPlace - Refreshes the prompt in the very same place he is. -func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) { +func (rl *Instance) promptInPlace(prompt string) { // We adjust cursor movement, depending on which mode we're currently in. // Prompt data intependent if !rl.modeTabCompletion { @@ -91,15 +90,11 @@ func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) { rl.SetPrompt(prompt) } - if rl.Multiline { - rl.tcUsedY += 1 - } - // Clear the input line and everything below print(seqClearLine) moveCursorUp(rl.infoY + rl.tcUsedY) moveCursorBackwards(GetTermWidth()) - print("\r\n" + seqClearScreenBelow) + print("\r" + seqClearScreenBelow) // Add a new line if needed if rl.Multiline { @@ -108,8 +103,11 @@ func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) { } else { fmt.Print(rl.mainPrompt) } +} - // Refresh the line +// RefreshPromptInPlace - Refreshes the prompt in the very same place he is. +func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) { + rl.promptInPlace(prompt) rl.updateHelpers() return From f9a2a981b463b7ce36e3318b55d8227cee107e47 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Sun, 29 May 2022 00:18:03 -0400 Subject: [PATCH 7/8] fix: revert "fix: multiline cursor redraw" This reverts commit 1339dc4a2f2e1ecfca4289f799631ab2cd337769. this caused a few issues, including history search messing up previous lines what this commit was trying to fix is unimportant anyway --- readline/line.go | 1 - readline/prompt.go | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/readline/line.go b/readline/line.go index 3dfa7c4..974a34d 100644 --- a/readline/line.go +++ b/readline/line.go @@ -45,7 +45,6 @@ func (rl *Instance) echo() { print(seqClearScreenBelow) // Print the prompt - rl.promptInPlace("") print(string(rl.realPrompt)) // Assemble the line, taking virtual completions into account diff --git a/readline/prompt.go b/readline/prompt.go index abda175..699abec 100644 --- a/readline/prompt.go +++ b/readline/prompt.go @@ -73,7 +73,8 @@ func (rl *Instance) RefreshPromptLog(log string) (err error) { return } -func (rl *Instance) promptInPlace(prompt string) { +// RefreshPromptInPlace - Refreshes the prompt in the very same place he is. +func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) { // We adjust cursor movement, depending on which mode we're currently in. // Prompt data intependent if !rl.modeTabCompletion { @@ -90,11 +91,15 @@ func (rl *Instance) promptInPlace(prompt string) { rl.SetPrompt(prompt) } + if rl.Multiline { + rl.tcUsedY += 1 + } + // Clear the input line and everything below print(seqClearLine) moveCursorUp(rl.infoY + rl.tcUsedY) moveCursorBackwards(GetTermWidth()) - print("\r" + seqClearScreenBelow) + print("\r\n" + seqClearScreenBelow) // Add a new line if needed if rl.Multiline { @@ -103,11 +108,8 @@ func (rl *Instance) promptInPlace(prompt string) { } else { fmt.Print(rl.mainPrompt) } -} -// RefreshPromptInPlace - Refreshes the prompt in the very same place he is. -func (rl *Instance) RefreshPromptInPlace(prompt string) (err error) { - rl.promptInPlace(prompt) + // Refresh the line rl.updateHelpers() return From 3f745e7e4deba7d3cf5d929967681c5287560643 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Mon, 30 May 2022 18:16:36 -0400 Subject: [PATCH 8/8] docs: update contributing info to include writing changes to changelog --- .github/pull_request_template.md | 2 +- CONTRIBUTING.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4841aec..c93c241 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,5 @@ --- - [ ] I have reviewed CONTRIBUTING.md. - [ ] My commits and title use the [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) format. -- [ ] I have documented any breaking changes according to [SemVer](https://semver.org/). +- [ ] I have documented changes and additions in the CHANGELOG.md. --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f841d98..0bf5a37 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,8 +29,9 @@ For any code contributions (Lua and/or Go), you should follow these rules: 1. Ensure that any new install or build dependencies are documented in the README.md and pull request. -2. Mention any and all changes, this includes useful file locations and -breaking changes. +2. Mention any and all changes, feature additons, removals, etc. This includes +useful file locations and breaking changes. Document them in the [changelog](CHANGELOG.md) +in the pull request. 3. We use [Semver](http://semver.org/) for versioning and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)