From 3eae0f07be3acf5dafac1f9e2ea9430bcdc2d6d9 Mon Sep 17 00:00:00 2001 From: sammyette Date: Mon, 10 Jul 2023 00:06:29 -0400 Subject: [PATCH 01/13] feat: add fuzzy searching for completion and history search (#247) * feat: add fuzzy searching for completion and history search * feat: add fuzzy opt for fuzzy history searching * chore: add fuzzy opt to changelog --- CHANGELOG.md | 1 + go.mod | 1 + go.sum | 2 ++ lua.go | 2 +- nature/opts/init.lua | 5 +++-- readline/comp-group.go | 7 +++---- readline/instance.go | 21 +++++++++++++++++++++ readline/tab.go | 4 ++-- readline/tabfind.go | 11 +---------- readline/tui-effects.go | 1 + rl.go | 21 ++++++++++++++++++++- util/util.go | 7 ++++--- 12 files changed, 60 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3a2c66b..4742febf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - `read()` method for retrieving input (so now the `in` sink of commanders is useful) - `flush()` and `autoFlush()` related to flushing outputs - `pipe` property to check if a sink with input is a pipe (like stdin) +- Add fuzzy search to history search (enable via `hilbish.opts.fuzzy = true`) - Show indexes on cdr list ### Fixed diff --git a/go.mod b/go.mod index 52b274aa..c17d906f 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036 github.com/pborman/getopt v1.1.0 + github.com/sahilm/fuzzy v0.1.0 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 mvdan.cc/sh/v3 v3.5.1 diff --git a/go.sum b/go.sum index 74a351be..1917008f 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I= github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= diff --git a/lua.go b/lua.go index 0a7c1157..e46d27b1 100644 --- a/lua.go +++ b/lua.go @@ -68,7 +68,7 @@ func luaInit() { } // Add more paths that Lua can require from - err := util.DoString(l, "package.path = package.path .. " + requirePaths) + _, err := util.DoString(l, "package.path = package.path .. " + requirePaths) if err != nil { fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.") } diff --git a/nature/opts/init.lua b/nature/opts/init.lua index ae95ee1e..10af1d69 100644 --- a/nature/opts/init.lua +++ b/nature/opts/init.lua @@ -16,7 +16,7 @@ setmetatable(hilbish.opts, { local function setupOpt(name, default) opts[name] = default - require('nature.opts.' .. name) + pcall(require, 'nature.opts.' .. name) end local defaultOpts = { @@ -25,7 +25,8 @@ local defaultOpts = { greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}. The nice lil shell for {blue}Lua{reset} fanatics! ]], hilbish.user), - motd = true + motd = true, + fuzzy = false } for optsName, default in pairs(defaultOpts) do diff --git a/readline/comp-group.go b/readline/comp-group.go index 0c53ed19..b2ee4b89 100644 --- a/readline/comp-group.go +++ b/readline/comp-group.go @@ -71,10 +71,9 @@ func (g *CompletionGroup) init(rl *Instance) { // The rx parameter is passed, as the shell already checked that the search pattern is valid. func (g *CompletionGroup) updateTabFind(rl *Instance) { - suggs := make([]string, 0) - + suggs := rl.Searcher(rl.search, g.Suggestions) // We perform filter right here, so we create a new completion group, and populate it with our results. - for i := range g.Suggestions { + /*for i := range g.Suggestions { if rl.regexSearch == nil { continue } if rl.regexSearch.MatchString(g.Suggestions[i]) { suggs = append(suggs, g.Suggestions[i]) @@ -82,7 +81,7 @@ func (g *CompletionGroup) updateTabFind(rl *Instance) { // this is a list so lets also check the descriptions suggs = append(suggs, g.Suggestions[i]) } - } + }*/ // We overwrite the group's items, (will be refreshed as soon as something is typed in the search) g.Suggestions = suggs diff --git a/readline/instance.go b/readline/instance.go index 039f0401..a4772466 100644 --- a/readline/instance.go +++ b/readline/instance.go @@ -112,8 +112,10 @@ type Instance struct { modeAutoFind bool // for when invoked via ^R or ^F outside of [tab] searchMode FindMode // Used for varying hints, and underlying functions called regexSearch *regexp.Regexp // Holds the current search regex match + search string mainHist bool // Which history stdin do we want histInfo []rune // We store a piece of hist info, for dual history sources + Searcher func(string, []string) []string // // History ----------------------------------------------------------------------------------- @@ -229,6 +231,25 @@ func NewInstance() *Instance { rl.HintFormatting = "\x1b[2m" rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn) rl.TempDirectory = os.TempDir() + rl.Searcher = func(needle string, haystack []string) []string { + suggs := make([]string, 0) + + 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")) + } + + for _, hay := range haystack { + if rl.regexSearch == nil { continue } + if rl.regexSearch.MatchString(hay) { + suggs = append(suggs, hay) + } + } + + return suggs + } // Registers rl.initRegisters() diff --git a/readline/tab.go b/readline/tab.go index e6522e6e..d00decc3 100644 --- a/readline/tab.go +++ b/readline/tab.go @@ -94,7 +94,7 @@ func (rl *Instance) getTabSearchCompletion() { rl.getCurrentGroup() // Set the info for this completion mode - rl.infoText = append([]rune("Completion search: "), rl.tfLine...) + rl.infoText = append([]rune("Completion search: " + UNDERLINE + BOLD), rl.tfLine...) for _, g := range rl.tcGroups { g.updateTabFind(rl) @@ -102,7 +102,7 @@ func (rl *Instance) getTabSearchCompletion() { // If total number of matches is zero, we directly change the info, and return if comps, _, _ := rl.getCompletionCount(); comps == 0 { - rl.infoText = append(rl.infoText, []rune(DIM+RED+" ! no matches (Ctrl-G/Esc to cancel)"+RESET)...) + rl.infoText = append(rl.infoText, []rune(RESET+DIM+RED+" ! no matches (Ctrl-G/Esc to cancel)"+RESET)...) } } diff --git a/readline/tabfind.go b/readline/tabfind.go index aa382596..830dad39 100644 --- a/readline/tabfind.go +++ b/readline/tabfind.go @@ -1,9 +1,5 @@ package readline -import ( - "regexp" -) - // FindMode defines how the autocomplete suggestions display type FindMode int @@ -30,12 +26,7 @@ func (rl *Instance) updateTabFind(r []rune) { rl.tfLine = append(rl.tfLine, r...) // The search regex is common to all search modes - 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")) - } + rl.search = string(rl.tfLine) // We update and print rl.clearHelpers() diff --git a/readline/tui-effects.go b/readline/tui-effects.go index 491ef98b..5610b103 100644 --- a/readline/tui-effects.go +++ b/readline/tui-effects.go @@ -14,6 +14,7 @@ var ( // effects BOLD = "\033[1m" DIM = "\033[2m" + UNDERLINE = "\033[4m" RESET = "\033[0m" // colors RED = "\033[31m" diff --git a/rl.go b/rl.go index 96b84514..17ea4df3 100644 --- a/rl.go +++ b/rl.go @@ -7,8 +7,9 @@ import ( "hilbish/util" - "github.com/maxlandon/readline" rt "github.com/arnodel/golua/runtime" + "github.com/maxlandon/readline" + "github.com/sahilm/fuzzy" ) type lineReader struct { @@ -24,6 +25,24 @@ func newLineReader(prompt string, noHist bool) *lineReader { rl: rl, } + regexSearcher := rl.Searcher + rl.Searcher = func(needle string, haystack []string) []string { + fz, _ := util.DoString(l, "return hilbish.opts.fuzzy") + fuzz, ok := fz.TryBool() + if !fuzz || !ok { + return regexSearcher(needle, haystack) + } + + matches := fuzzy.Find(needle, haystack) + suggs := make([]string, 0) + + for _, match := range matches { + suggs = append(suggs, match.Str) + } + + return suggs + } + // we don't mind hilbish.read rl instances having completion, // but it cant have shared history if !noHist { diff --git a/util/util.go b/util/util.go index 45e33dce..0fcd4b05 100644 --- a/util/util.go +++ b/util/util.go @@ -26,13 +26,14 @@ func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Valu } // DoString runs the code string in the Lua runtime. -func DoString(rtm *rt.Runtime, code string) error { +func DoString(rtm *rt.Runtime, code string) (rt.Value, error) { chunk, err := rtm.CompileAndLoadLuaChunk("", []byte(code), rt.TableValue(rtm.GlobalEnv())) + var ret rt.Value if chunk != nil { - _, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(chunk)) + ret, err = rt.Call1(rtm.MainThread(), rt.FunctionValue(chunk)) } - return err + return ret, err } // DoFile runs the contents of the file in the Lua runtime. From c6c81ddece32158a1e1fc40d1f7dd2fb4c2cc247 Mon Sep 17 00:00:00 2001 From: sammyette Date: Mon, 10 Jul 2023 19:03:30 -0400 Subject: [PATCH 02/13] feat: add notification/message interface (#239) details in #219 --- .hilbishrc.lua | 25 ++++++ CHANGELOG.md | 5 ++ docs/hooks/command.md | 5 ++ docs/hooks/hilbish.md | 3 + nature/hummingbird.lua | 84 +++++++++++++++++++ nature/init.lua | 1 + nature/opts/init.lua | 3 +- nature/opts/notifyJobFinish.lua | 23 +++++ .../content/docs/features/notifications.md | 39 +++++++++ 9 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 nature/hummingbird.lua create mode 100644 nature/opts/notifyJobFinish.lua create mode 100644 website/content/docs/features/notifications.md diff --git a/.hilbishrc.lua b/.hilbishrc.lua index 5d6382b0..249f97ed 100644 --- a/.hilbishrc.lua +++ b/.hilbishrc.lua @@ -1,18 +1,39 @@ -- Default Hilbish config +local hilbish = require 'hilbish' local lunacolors = require 'lunacolors' local bait = require 'bait' local ansikit = require 'ansikit' +local unreadCount = 0 +local running = false local function doPrompt(fail) hilbish.prompt(lunacolors.format( '{blue}%u {cyan}%d ' .. (fail and '{red}' or '{green}') .. '∆ ' )) end +local function doNotifyPrompt() + if running or unreadCount == hilbish.messages.unreadCount() then return end + + local notifPrompt = string.format('• %s unread notification%s', hilbish.messages.unreadCount(), hilbish.messages.unreadCount() > 1 and 's' or '') + unreadCount = hilbish.messages.unreadCount() + hilbish.prompt(lunacolors.blue(notifPrompt), 'right') + + hilbish.timeout(function() + hilbish.prompt('', 'right') + end, 3000) +end + doPrompt() +bait.catch('command.preexec', function() + running = true +end) + bait.catch('command.exit', function(code) + running = false doPrompt(code ~= 0) + doNotifyPrompt() end) bait.catch('hilbish.vimMode', function(mode) @@ -22,3 +43,7 @@ bait.catch('hilbish.vimMode', function(mode) ansikit.cursorStyle(ansikit.lineCursor) end end) + +bait.catch('hilbish.notification', function(notif) + doNotifyPrompt() +end) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4742febf..36b82daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,12 @@ - `pipe` property to check if a sink with input is a pipe (like stdin) - Add fuzzy search to history search (enable via `hilbish.opts.fuzzy = true`) - Show indexes on cdr list +- `hilbish.messages` interface (details in [#219]) +- `hilbish.notification` signal when a message/notification is sent +- `notifyJobFinish` opt to send a notification when background jobs are +completed. +[#219]: https://github.com/Rosettea/Hilbish/issues/219 ### Fixed - Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils diff --git a/docs/hooks/command.md b/docs/hooks/command.md index cd1ae3ce..2d29f4bf 100644 --- a/docs/hooks/command.md +++ b/docs/hooks/command.md @@ -1,3 +1,8 @@ ++ `command.preexec` -> input, cmdStr > Thrown before a command +is executed. The `input` is the user written command, while `cmdStr` +is what will be executed (`input` will have aliases while `cmdStr` +will have alias resolved input). + + `command.exit` -> code, cmdStr > Thrown when a command exits. `code` is the exit code of the command, and `cmdStr` is the command that was run. diff --git a/docs/hooks/hilbish.md b/docs/hooks/hilbish.md index 3d6d2ea6..71189014 100644 --- a/docs/hooks/hilbish.md +++ b/docs/hooks/hilbish.md @@ -7,3 +7,6 @@ like yanking or pasting text. See `doc vim-mode actions` for more info. + `hilbish.cancel` > Sent when the user cancels their input with Ctrl-C. + ++ `hilbish.notification` -> message > Sent when a message is +sent. diff --git a/nature/hummingbird.lua b/nature/hummingbird.lua new file mode 100644 index 00000000..581e92c1 --- /dev/null +++ b/nature/hummingbird.lua @@ -0,0 +1,84 @@ +local bait = require 'bait' +local commander = require 'commander' +local lunacolors = require 'lunacolors' + +local M = {} +local counter = 0 +local unread = 0 +M._messages = {} +M.icons = { + INFO = '', + SUCCESS = '', + WARN = '', + ERROR = '' +} + +hilbish.messages = {} + +--- Represents a Hilbish message. +--- @class hilbish.message +--- @field icon string Unicode (preferably standard emoji) icon for the message notification. +--- @field title string Title of the message (like an email subject). +--- @field text string Contents of the message. +--- @field channel string Short identifier of the message. `hilbish` and `hilbish.*` is preserved for internal Hilbish messages. +--- @field summary string A short summary of the message. +--- @field read boolean Whether the full message has been read or not. + +function expect(tbl, field) + if not tbl[field] or tbl[field] == '' then + error(string.format('expected field %s in message')) + end +end + +--- Sends a message. +--- @param message hilbish.message +function hilbish.messages.send(message) + expect(message, 'text') + expect(message, 'title') + counter = counter + 1 + unread = unread + 1 + message.index = counter + message.read = false + + M._messages[message.index] = message + bait.throw('hilbish.notification', message) +end + +function hilbish.messages.read(idx) + local msg = M._messages[idx] + if msg then + M._messages[idx].read = true + unread = unread - 1 + end +end + +function hilbish.messages.readAll(idx) + for _, msg in ipairs(hilbish.messages.all()) do + hilbish.messages.read(msg.index) + end +end + +function hilbish.messages.unreadCount() + return unread +end + +function hilbish.messages.delete(idx) + local msg = M._messages[idx] + if not msg then + error(string.format('invalid message index %d', idx or -1)) + end + + M._messages[idx] = nil +end + +function hilbish.messages.clear() + for _, msg in ipairs(hilbish.messages.all()) do + hilbish.messages.delete(msg.index) + end +end + +function hilbish.messages.all() + return M._messages +end + +return M diff --git a/nature/init.lua b/nature/init.lua index d1f919cc..9e781352 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -11,6 +11,7 @@ require 'nature.completions' require 'nature.opts' require 'nature.vim' require 'nature.runner' +require 'nature.hummingbird' local shlvl = tonumber(os.getenv 'SHLVL') if shlvl ~= nil then diff --git a/nature/opts/init.lua b/nature/opts/init.lua index 10af1d69..56c34ba4 100644 --- a/nature/opts/init.lua +++ b/nature/opts/init.lua @@ -26,7 +26,8 @@ local defaultOpts = { The nice lil shell for {blue}Lua{reset} fanatics! ]], hilbish.user), motd = true, - fuzzy = false + fuzzy = false, + notifyJobFinish = true } for optsName, default in pairs(defaultOpts) do diff --git a/nature/opts/notifyJobFinish.lua b/nature/opts/notifyJobFinish.lua new file mode 100644 index 00000000..a8841a11 --- /dev/null +++ b/nature/opts/notifyJobFinish.lua @@ -0,0 +1,23 @@ +local bait = require 'bait' +local lunacolors = require 'lunacolors' + +bait.catch('job.done', function(job) + if not hilbish.opts.notifyJobFinish then return end + local notifText = string.format(lunacolors.format [[ +Background job with ID#%d has exited (PID %d). +Command string: {bold}{yellow}%s{reset}]], job.id, job.pid, job.cmd) + + if job.stdout ~= '' then + notifText = notifText .. '\n\nStandard output:\n' .. job.stdout + end + if job.stderr ~= '' then + notifText = notifText .. '\n\nStandard error:\n' .. job.stderr + end + + hilbish.messages.send { + channel = 'jobNotify', + title = string.format('Job ID#%d Exited', job.id), + summary = string.format(lunacolors.format 'Background job with command {bold}{yellow}%s{reset} has finished running!', job.cmd), + text = notifText + } +end) diff --git a/website/content/docs/features/notifications.md b/website/content/docs/features/notifications.md new file mode 100644 index 00000000..c3a9b53f --- /dev/null +++ b/website/content/docs/features/notifications.md @@ -0,0 +1,39 @@ +--- +title: Notification +description: Get notified of shell actions. +layout: doc +menu: + docs: + parent: "Features" +--- + +Hilbish features a simple notification system which can be +used by other plugins and parts of the shell to notify the user +of various actions. This is used via the `hilbish.message` interface. + +A `message` is defined as a table with the following properties: +- `icon`: A unicode/emoji icon for the notification. +- `title`: The title of the message +- `text`: Message text/body +- `channel`: The source of the message. This should be a +unique and easily readable text identifier. +- `summary`: A short summary of the notification and message. +If this is not present and you are using this to display messages, +you should take part of the `text` instead. + +The `hilbish.message` interface provides the following functions: +- `send(message)`: Sends a message and emits the `hilbish.notification` +signal. DO NOT emit the `hilbish.notification` signal directly, or +the message will not be stored by the message handler. +- `read(idx)`: Marks message at `idx` as read. +- `delete(idx)`: Removes message at `idx`. +- `readAll()`: Marks all messages as read. +- `clear()`: Deletes all messages. + +There are a few simple use cases of this notification/messaging system. +It could also be used as some "inter-shell" messaging system (???) but +is intended to display to users. + +An example is notifying users of completed jobs/commands ran in the background. +Any Hilbish-native command (think the upcoming Greenhouse pager) can display +it. From f540fc2c04f279d988a2a905ca35697f428a7926 Mon Sep 17 00:00:00 2001 From: sammyette Date: Mon, 10 Jul 2023 21:56:35 -0400 Subject: [PATCH 03/13] feat: show go version hilbish was compiled with --- api.go | 2 ++ main.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/api.go b/api.go index a4406930..61aac215 100644 --- a/api.go +++ b/api.go @@ -2,6 +2,7 @@ // The Hilbish module includes the core API, containing // interfaces and functions which directly relate to shell functionality. // #field ver The version of Hilbish +// #field goVersion The version of Go that Hilbish was compiled with // #field user Username of the user // #field host Hostname of the machine // #field dataDir Directory for Hilbish data files, including the docs and default modules @@ -110,6 +111,7 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { } util.SetFieldProtected(fakeMod, mod, "ver", rt.StringValue(getVersion())) + util.SetFieldProtected(fakeMod, mod, "goVersion", rt.StringValue(runtime.Version())) util.SetFieldProtected(fakeMod, mod, "user", rt.StringValue(username)) util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host)) util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir)) diff --git a/main.go b/main.go index 4fa321c7..300f333b 100644 --- a/main.go +++ b/main.go @@ -106,7 +106,7 @@ func main() { } if *verflag { - fmt.Printf("Hilbish %s\n", getVersion()) + fmt.Printf("Hilbish %s\nCompiled with %s\n", getVersion(), runtime.Version()) os.Exit(0) } From ab26b82a9f97048f7c727e83ca5ed6cf28df48ba Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Tue, 11 Jul 2023 01:57:00 +0000 Subject: [PATCH 04/13] docs: [ci] generate new docs --- docs/api/hilbish/_index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/hilbish/_index.md b/docs/api/hilbish/_index.md index 8fb587a4..4cf01806 100644 --- a/docs/api/hilbish/_index.md +++ b/docs/api/hilbish/_index.md @@ -13,6 +13,7 @@ interfaces and functions which directly relate to shell functionality. ## Interface fields - `ver`: The version of Hilbish +- `goVersion`: The version of Go that Hilbish was compiled with - `user`: Username of the user - `host`: Hostname of the machine - `dataDir`: Directory for Hilbish data files, including the docs and default modules From 00c967d7c1c72dccbaf9d1ece9b81659f4eb3dd8 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 17:06:29 -0400 Subject: [PATCH 05/13] ci: fix branch name --- .github/workflows/website.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 6ee43492..70f29529 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -21,7 +21,7 @@ jobs: - name: Set branch name id: branch - run: echo "::set-output name=BRANCH_NAME::${GITHUB_REF##*/}" + run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} >> "$GITHUB_ENV" - name: Fix base URL if: steps.branch.outputs.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' From 2b9059f7261334f5dd5e0ac8672a671cf889a5de Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 17:08:14 -0400 Subject: [PATCH 06/13] ci: add missing quote --- .github/workflows/website.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 70f29529..023138a9 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -21,7 +21,7 @@ jobs: - name: Set branch name id: branch - run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} >> "$GITHUB_ENV" + run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_ENV" - name: Fix base URL if: steps.branch.outputs.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' From caff604d953064c4678b0fbcdc18b808ff52cd43 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:48:51 -0400 Subject: [PATCH 07/13] ci: stop using deprecated method of setting branch name --- .github/workflows/website.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 023138a9..88a78ae1 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -24,24 +24,24 @@ jobs: run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_ENV" - name: Fix base URL - if: steps.branch.outputs.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' - run: sed -i "s%baseURL = 'https://rosettea.github.io/Hilbish/'%baseURL = 'https://rosettea.github.io/Hilbish/versions/${{ steps.branch.outputs.BRANCH_NAME }}'%" website/config.toml + if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' + run: sed -i "s%baseURL = 'https://rosettea.github.io/Hilbish/'%baseURL = 'https://rosettea.github.io/Hilbish/versions/${{ env.BRANCH_NAME }}'%" website/config.toml - name: Build run: 'cd website && hugo --minify' - name: Deploy - if: steps.branch.outputs.BRANCH_NAME == 'master' && github.repository_owner == 'Rosettea' + if: env.BRANCH_NAME == 'master' && github.repository_owner == 'Rosettea' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./website/public keep_files: true - name: Deploy - if: steps.branch.outputs.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' + if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./website/public - destination_dir: versions/${{ steps.branch.outputs.BRANCH_NAME }} + destination_dir: versions/${{ env.BRANCH_NAME }} keep_files: true From ba04fb2af75110c0e26ad6b36e959a5f4c3a05b8 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 9 Sep 2023 10:51:58 -0700 Subject: [PATCH 08/13] feat: allow numbered substitutions in aliases (#258) --- CHANGELOG.md | 3 +++ aliases.go | 22 +++++++++++++++++++++- main.go | 4 ++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b82daf..48722dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ - `hilbish.notification` signal when a message/notification is sent - `notifyJobFinish` opt to send a notification when background jobs are completed. +- Allow numbered arg substitutions in aliases. + - Example: `hilbish.alias('hello', 'echo %1 says hello')` allows the user to run `hello hilbish` + which will output `hilbish says hello`. [#219]: https://github.com/Rosettea/Hilbish/issues/219 ### Fixed diff --git a/aliases.go b/aliases.go index bfacc43d..fc5777ea 100644 --- a/aliases.go +++ b/aliases.go @@ -1,6 +1,8 @@ package main import ( + "regexp" + "strconv" "strings" "sync" @@ -46,9 +48,27 @@ func (a *aliasModule) Resolve(cmdstr string) string { a.mu.RLock() defer a.mu.RUnlock() - args := strings.Split(cmdstr, " ") + arg, _ := regexp.Compile(`[\\]?%\d+`) + + args, _ := splitInput(cmdstr) for a.aliases[args[0]] != "" { alias := a.aliases[args[0]] + alias = arg.ReplaceAllStringFunc(alias, func(a string) string { + idx, _ := strconv.Atoi(a[1:]) + if strings.HasPrefix(a, "\\") || idx == 0 { + return strings.TrimPrefix(a, "\\") + } + + if idx + 1 > len(args) { + return a + } + val := args[idx] + args = cut(args, idx) + cmdstr = strings.Join(args, " ") + + return val + }) + cmdstr = alias + strings.TrimPrefix(cmdstr, args[0]) cmdArgs, _ := splitInput(cmdstr) args = cmdArgs diff --git a/main.go b/main.go index 300f333b..52ba63dd 100644 --- a/main.go +++ b/main.go @@ -324,3 +324,7 @@ func getVersion() string { return v.String() } + +func cut(slice []string, idx int) []string { + return append(slice[:idx], slice[idx + 1:]...) +} From db8e87e5dd101a879da183030402feaf92d2994e Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 9 Sep 2023 13:53:02 -0400 Subject: [PATCH 09/13] fix: compare lower case strings in contains function this fixes file completion on windows. --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 300f333b..b75752eb 100644 --- a/main.go +++ b/main.go @@ -289,7 +289,7 @@ func removeDupes(slice []string) []string { func contains(s []string, e string) bool { for _, a := range s { - if a == e { + if strings.ToLower(a) == strings.ToLower(e) { return true } } From 83492e4e69249384854d49a7260306799b312f00 Mon Sep 17 00:00:00 2001 From: sammyette Date: Wed, 27 Sep 2023 20:31:27 -0400 Subject: [PATCH 10/13] docs: fix odd sentence in runner-mode docs --- website/content/docs/features/runner-mode.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/content/docs/features/runner-mode.md b/website/content/docs/features/runner-mode.md index 8774de96..58b55dd2 100644 --- a/website/content/docs/features/runner-mode.md +++ b/website/content/docs/features/runner-mode.md @@ -13,8 +13,8 @@ is that it runs Lua first and then falls back to shell script. In some cases, someone might want to switch to just shell script to avoid it while interactive but still have a Lua config, or go full Lua to use -Hilbish as a REPL. This also allows users to add alternative languages, -instead of either like Fennel. +Hilbish as a REPL. This also allows users to add alternative languages like +Fennel as the interactive script runner. Runner mode can also be used to handle specific kinds of input before evaluating like normal, which is how [Link.hsh](https://github.com/TorchedSammy/Link.hsh) From 483e5f6dbec7d32d7b75634732d82d056e0f1845 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 30 Sep 2023 19:52:33 -0400 Subject: [PATCH 11/13] fix(hilbish.completions): return prefix on the `call` function (from #263) --- CHANGELOG.md | 3 +++ complete.go | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48722dca..9cdcf11f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ completed. - Example: `hilbish.alias('hello', 'echo %1 says hello')` allows the user to run `hello hilbish` which will output `hilbish says hello`. +### Fixed +- Return the prefix when calling `hilbish.completions.call` + [#219]: https://github.com/Rosettea/Hilbish/issues/219 ### Fixed - Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils diff --git a/complete.go b/complete.go index 51b426fa..0c70e072 100644 --- a/complete.go +++ b/complete.go @@ -253,15 +253,16 @@ func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { } // we must keep the holy 80 cols - completerReturn, err := rt.Call1(l.MainThread(), - rt.FunctionValue(completecb), rt.StringValue(query), - rt.StringValue(ctx), rt.TableValue(fields)) + cont := c.Next() + err = rt.Call(l.MainThread(), rt.FunctionValue(completecb), + []rt.Value{rt.StringValue(query), rt.StringValue(ctx), rt.TableValue(fields)}, + cont) if err != nil { return nil, err } - return c.PushingNext1(t.Runtime, completerReturn), nil + return cont, nil } // #interface completions From 4421869b85d6c35f33f655f79ba622e75c863448 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 30 Sep 2023 23:21:00 -0400 Subject: [PATCH 12/13] fix: check length of args in aliases resolve this shouldnt be a problem.. but ... what --- aliases.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aliases.go b/aliases.go index fc5777ea..c2117299 100644 --- a/aliases.go +++ b/aliases.go @@ -51,6 +51,11 @@ func (a *aliasModule) Resolve(cmdstr string) string { arg, _ := regexp.Compile(`[\\]?%\d+`) args, _ := splitInput(cmdstr) + if len(args) == 0 { + // this shouldnt reach but...???? + return + } + for a.aliases[args[0]] != "" { alias := a.aliases[args[0]] alias = arg.ReplaceAllStringFunc(alias, func(a string) string { From a5b6fc8edaceb94a0852e62dd096da1b9733cf86 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 30 Sep 2023 23:25:03 -0400 Subject: [PATCH 13/13] fix: return cmdstr in alias resolve instead of nothing --- aliases.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aliases.go b/aliases.go index c2117299..8b815b32 100644 --- a/aliases.go +++ b/aliases.go @@ -53,7 +53,7 @@ func (a *aliasModule) Resolve(cmdstr string) string { args, _ := splitInput(cmdstr) if len(args) == 0 { // this shouldnt reach but...???? - return + return cmdstr } for a.aliases[args[0]] != "" {