mirror of https://github.com/Hilbis/Hilbish
Compare commits
21 Commits
554fb009f8
...
e288826be4
Author | SHA1 | Date |
---|---|---|
sammyette | e288826be4 | |
sammyette | ae356f6ffa | |
sammyette | d8a7a4332d | |
sammyette | 8fabdf4502 | |
sammyette | 003100d3c4 | |
sammyette | 7288f85e9a | |
sammyette | a5b6fc8eda | |
sammyette | 4421869b85 | |
sammyette | 6d07d8db53 | |
sammyette | 483e5f6dbe | |
sammyette | 83492e4e69 | |
sammyette | 4fcd310048 | |
sammyette | db8e87e5dd | |
sammyette | ba04fb2af7 | |
sammyette | caff604d95 | |
sammyette | 2b9059f726 | |
sammyette | 00c967d7c1 | |
TorchedSammy | ab26b82a9f | |
sammyette | f540fc2c04 | |
sammyette | c6c81ddece | |
sammyette | 3eae0f07be |
|
@ -1,18 +1,39 @@
|
||||||
-- Default Hilbish config
|
-- Default Hilbish config
|
||||||
|
local hilbish = require 'hilbish'
|
||||||
local lunacolors = require 'lunacolors'
|
local lunacolors = require 'lunacolors'
|
||||||
local bait = require 'bait'
|
local bait = require 'bait'
|
||||||
local ansikit = require 'ansikit'
|
local ansikit = require 'ansikit'
|
||||||
|
|
||||||
|
local unreadCount = 0
|
||||||
|
local running = false
|
||||||
local function doPrompt(fail)
|
local function doPrompt(fail)
|
||||||
hilbish.prompt(lunacolors.format(
|
hilbish.prompt(lunacolors.format(
|
||||||
'{blue}%u {cyan}%d ' .. (fail and '{red}' or '{green}') .. '∆ '
|
'{blue}%u {cyan}%d ' .. (fail and '{red}' or '{green}') .. '∆ '
|
||||||
))
|
))
|
||||||
end
|
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()
|
doPrompt()
|
||||||
|
|
||||||
|
bait.catch('command.preexec', function()
|
||||||
|
running = true
|
||||||
|
end)
|
||||||
|
|
||||||
bait.catch('command.exit', function(code)
|
bait.catch('command.exit', function(code)
|
||||||
|
running = false
|
||||||
doPrompt(code ~= 0)
|
doPrompt(code ~= 0)
|
||||||
|
doNotifyPrompt()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
bait.catch('hilbish.vimMode', function(mode)
|
bait.catch('hilbish.vimMode', function(mode)
|
||||||
|
@ -22,3 +43,7 @@ bait.catch('hilbish.vimMode', function(mode)
|
||||||
ansikit.cursorStyle(ansikit.lineCursor)
|
ansikit.cursorStyle(ansikit.lineCursor)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
bait.catch('hilbish.notification', function(notif)
|
||||||
|
doNotifyPrompt()
|
||||||
|
end)
|
||||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -6,9 +6,25 @@
|
||||||
- `read()` method for retrieving input (so now the `in` sink of commanders is useful)
|
- `read()` method for retrieving input (so now the `in` sink of commanders is useful)
|
||||||
- `flush()` and `autoFlush()` related to flushing outputs
|
- `flush()` and `autoFlush()` related to flushing outputs
|
||||||
- `pipe` property to check if a sink with input is a pipe (like stdin)
|
- `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
|
- Show indexes on cdr list
|
||||||
- Fix doc command not displaying correct subdocs when using shorthand api doc access (`doc api hilbish.jobs` as an example)
|
- Fix doc command not displaying correct subdocs when using shorthand api doc access (`doc api hilbish.jobs` as an example)
|
||||||
|
- `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.
|
||||||
|
- 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`.
|
||||||
|
- Greenhouse
|
||||||
|
- Greenhouse is a pager library and program. Basic usage is `greenhouse <file>`
|
||||||
|
- Using this also brings enhancements to the `doc` command like easy
|
||||||
|
navigation of neighboring doc files.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Return the prefix when calling `hilbish.completions.call`
|
||||||
|
|
||||||
|
[#219]: https://github.com/Rosettea/Hilbish/issues/219
|
||||||
### Fixed
|
### Fixed
|
||||||
- Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils
|
- Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils
|
||||||
|
|
||||||
|
|
27
aliases.go
27
aliases.go
|
@ -1,6 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -46,9 +48,32 @@ func (a *aliasModule) Resolve(cmdstr string) string {
|
||||||
a.mu.RLock()
|
a.mu.RLock()
|
||||||
defer a.mu.RUnlock()
|
defer a.mu.RUnlock()
|
||||||
|
|
||||||
args := strings.Split(cmdstr, " ")
|
arg, _ := regexp.Compile(`[\\]?%\d+`)
|
||||||
|
|
||||||
|
args, _ := splitInput(cmdstr)
|
||||||
|
if len(args) == 0 {
|
||||||
|
// this shouldnt reach but...????
|
||||||
|
return cmdstr
|
||||||
|
}
|
||||||
|
|
||||||
for a.aliases[args[0]] != "" {
|
for a.aliases[args[0]] != "" {
|
||||||
alias := 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])
|
cmdstr = alias + strings.TrimPrefix(cmdstr, args[0])
|
||||||
cmdArgs, _ := splitInput(cmdstr)
|
cmdArgs, _ := splitInput(cmdstr)
|
||||||
args = cmdArgs
|
args = cmdArgs
|
||||||
|
|
2
api.go
2
api.go
|
@ -2,6 +2,7 @@
|
||||||
// The Hilbish module includes the core API, containing
|
// The Hilbish module includes the core API, containing
|
||||||
// interfaces and functions which directly relate to shell functionality.
|
// interfaces and functions which directly relate to shell functionality.
|
||||||
// #field ver The version of Hilbish
|
// #field ver The version of Hilbish
|
||||||
|
// #field goVersion The version of Go that Hilbish was compiled with
|
||||||
// #field user Username of the user
|
// #field user Username of the user
|
||||||
// #field host Hostname of the machine
|
// #field host Hostname of the machine
|
||||||
// #field dataDir Directory for Hilbish data files, including the docs and default modules
|
// #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, "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, "user", rt.StringValue(username))
|
||||||
util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host))
|
util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host))
|
||||||
util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir))
|
util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir))
|
||||||
|
|
|
@ -253,15 +253,16 @@ func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// we must keep the holy 80 cols
|
// we must keep the holy 80 cols
|
||||||
completerReturn, err := rt.Call1(l.MainThread(),
|
cont := c.Next()
|
||||||
rt.FunctionValue(completecb), rt.StringValue(query),
|
err = rt.Call(l.MainThread(), rt.FunctionValue(completecb),
|
||||||
rt.StringValue(ctx), rt.TableValue(fields))
|
[]rt.Value{rt.StringValue(query), rt.StringValue(ctx), rt.TableValue(fields)},
|
||||||
|
cont)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.PushingNext1(t.Runtime, completerReturn), nil
|
return cont, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// #interface completions
|
// #interface completions
|
||||||
|
|
|
@ -13,6 +13,7 @@ interfaces and functions which directly relate to shell functionality.
|
||||||
|
|
||||||
## Interface fields
|
## Interface fields
|
||||||
- `ver`: The version of Hilbish
|
- `ver`: The version of Hilbish
|
||||||
|
- `goVersion`: The version of Go that Hilbish was compiled with
|
||||||
- `user`: Username of the user
|
- `user`: Username of the user
|
||||||
- `host`: Hostname of the machine
|
- `host`: Hostname of the machine
|
||||||
- `dataDir`: Directory for Hilbish data files, including the docs and default modules
|
- `dataDir`: Directory for Hilbish data files, including the docs and default modules
|
||||||
|
|
|
@ -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.
|
+ `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.
|
`code` is the exit code of the command, and `cmdStr` is the command that was run.
|
||||||
|
|
||||||
|
|
|
@ -7,3 +7,6 @@
|
||||||
like yanking or pasting text. See `doc vim-mode actions` for more info.
|
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.cancel` > Sent when the user cancels their input with Ctrl-C.
|
||||||
|
|
||||||
|
+ `hilbish.notification` -> message > Sent when a message is
|
||||||
|
sent.
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -8,6 +8,7 @@ require (
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
||||||
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
|
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
|
||||||
github.com/pborman/getopt v1.1.0
|
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/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171
|
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171
|
||||||
mvdan.cc/sh/v3 v3.5.1
|
mvdan.cc/sh/v3 v3.5.1
|
||||||
|
|
2
go.sum
2
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.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 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I=
|
||||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
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 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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
||||||
|
|
2
lua.go
2
lua.go
|
@ -68,7 +68,7 @@ func luaInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add more paths that Lua can require from
|
// 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 {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.")
|
fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.")
|
||||||
}
|
}
|
||||||
|
|
8
main.go
8
main.go
|
@ -106,7 +106,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *verflag {
|
if *verflag {
|
||||||
fmt.Printf("Hilbish %s\n", getVersion())
|
fmt.Printf("Hilbish %s\nCompiled with %s\n", getVersion(), runtime.Version())
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ func removeDupes(slice []string) []string {
|
||||||
|
|
||||||
func contains(s []string, e string) bool {
|
func contains(s []string, e string) bool {
|
||||||
for _, a := range s {
|
for _, a := range s {
|
||||||
if a == e {
|
if strings.ToLower(a) == strings.ToLower(e) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,3 +324,7 @@ func getVersion() string {
|
||||||
|
|
||||||
return v.String()
|
return v.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cut(slice []string, idx int) []string {
|
||||||
|
return append(slice[:idx], slice[idx + 1:]...)
|
||||||
|
}
|
||||||
|
|
|
@ -23,12 +23,36 @@ to Hilbish.
|
||||||
|
|
||||||
Usage: doc <section> [subdoc]
|
Usage: doc <section> [subdoc]
|
||||||
Available sections: ]] .. table.concat(modules, ', ')
|
Available sections: ]] .. table.concat(modules, ', ')
|
||||||
|
local f
|
||||||
|
local function handleYamlInfo(d)
|
||||||
local vals = {}
|
local vals = {}
|
||||||
|
local docs = d
|
||||||
|
|
||||||
|
local valsStr = docs:match '%-%-%-\n([^%-%-%-]+)\n'
|
||||||
|
print(valsStr)
|
||||||
|
if valsStr then
|
||||||
|
docs = docs:sub(valsStr:len() + 10, #docs)
|
||||||
|
|
||||||
|
-- parse vals
|
||||||
|
local lines = string.split(valsStr, '\n')
|
||||||
|
for _, line in ipairs(lines) do
|
||||||
|
local key = line:match '(%w+): '
|
||||||
|
local val = line:match '^%w+: (.-)$'
|
||||||
|
|
||||||
|
if key then
|
||||||
|
vals[key] = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--docs = docs:sub(1, #docs - 1)
|
||||||
|
return docs, vals
|
||||||
|
end
|
||||||
|
|
||||||
if #args > 0 then
|
if #args > 0 then
|
||||||
local mod = args[1]
|
local mod = args[1]
|
||||||
|
|
||||||
local f = io.open(moddocPath .. mod .. '.md', 'rb')
|
f = io.open(moddocPath .. mod .. '.md', 'rb')
|
||||||
local funcdocs = nil
|
local funcdocs = nil
|
||||||
local subdocName = args[2]
|
local subdocName = args[2]
|
||||||
if not f then
|
if not f then
|
||||||
|
@ -52,34 +76,13 @@ Available sections: ]] .. table.concat(modules, ', ')
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
funcdocs = f:read '*a':gsub('-([%d]+)', '%1')
|
|
||||||
|
end
|
||||||
|
|
||||||
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end)
|
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end)
|
||||||
local subdocs = table.map(moddocs, function(fname)
|
local subdocs = table.map(moddocs, function(fname)
|
||||||
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
|
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
|
||||||
end)
|
end)
|
||||||
if #moddocs ~= 0 then
|
|
||||||
funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n'
|
|
||||||
end
|
|
||||||
|
|
||||||
local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n'
|
|
||||||
if valsStr then
|
|
||||||
local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true)
|
|
||||||
funcdocs = funcdocs:sub(endpos + 1, #funcdocs)
|
|
||||||
|
|
||||||
-- parse vals
|
|
||||||
local lines = string.split(valsStr, '\n')
|
|
||||||
for _, line in ipairs(lines) do
|
|
||||||
local key = line:match '(%w+): '
|
|
||||||
local val = line:match '^%w+: (.-)$'
|
|
||||||
|
|
||||||
if key then
|
|
||||||
vals[key] = val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
doc = funcdocs:sub(1, #funcdocs - 1)
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local gh = Greenhouse(sinks.out)
|
local gh = Greenhouse(sinks.out)
|
||||||
function gh:resize()
|
function gh:resize()
|
||||||
|
@ -102,15 +105,16 @@ Available sections: ]] .. table.concat(modules, ', ')
|
||||||
self.sink:write(ansikit.getCSI(self.region.height + 2 .. ';1', 'H'))
|
self.sink:write(ansikit.getCSI(self.region.height + 2 .. ';1', 'H'))
|
||||||
if not self.isSpecial then
|
if not self.isSpecial then
|
||||||
if args[1] == 'api' then
|
if args[1] == 'api' then
|
||||||
self.sink:writeln(lunacolors.reset(string.format('%s', vals.title)))
|
self.sink:writeln(lunacolors.reset(string.format('%s', workingPage.title)))
|
||||||
self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', vals.description or 'No description.')))
|
self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', workingPage.description or 'No description.')))
|
||||||
else
|
else
|
||||||
self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath)))
|
self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local backtickOccurence = 0
|
local backtickOccurence = 0
|
||||||
local page = Page(nil, lunacolors.format(doc:gsub('`', function()
|
local function formatDocText(d)
|
||||||
|
return lunacolors.format(d:gsub('`', function()
|
||||||
backtickOccurence = backtickOccurence + 1
|
backtickOccurence = backtickOccurence + 1
|
||||||
if backtickOccurence % 2 == 0 then
|
if backtickOccurence % 2 == 0 then
|
||||||
return '{reset}'
|
return '{reset}'
|
||||||
|
@ -120,8 +124,33 @@ Available sections: ]] .. table.concat(modules, ', ')
|
||||||
end):gsub('\n#+.-\n', function(t)
|
end):gsub('\n#+.-\n', function(t)
|
||||||
local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
|
local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
|
||||||
return '{bold}{yellow}' .. signature .. '{reset}'
|
return '{bold}{yellow}' .. signature .. '{reset}'
|
||||||
end)))
|
end))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local doc, vals = handleYamlInfo(#args == 0 and doc or formatDocText(f:read '*a':gsub('-([%d]+)', '%1')))
|
||||||
|
if #moddocs ~= 0 and f then
|
||||||
|
doc = doc .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n'
|
||||||
|
end
|
||||||
|
if f then f:close() end
|
||||||
|
|
||||||
|
local page = Page(vals.title, doc)
|
||||||
|
page.description = vals.description
|
||||||
gh:addPage(page)
|
gh:addPage(page)
|
||||||
|
|
||||||
|
-- add subdoc pages
|
||||||
|
for _, sdName in ipairs(moddocs) do
|
||||||
|
local sdFile = fs.join(sdName, '_index.md')
|
||||||
|
if sdName:match '.md$' then
|
||||||
|
sdFile = sdName
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = io.open(moddocPath .. sdFile, 'rb')
|
||||||
|
local doc, vals = handleYamlInfo(f:read '*a':gsub('-([%d]+)', '%1'))
|
||||||
|
local page = Page(vals.title, formatDocText(doc))
|
||||||
|
page.description = vals.description
|
||||||
|
gh:addPage(page)
|
||||||
|
end
|
||||||
ansikit.hideCursor()
|
ansikit.hideCursor()
|
||||||
gh:initUi()
|
gh:initUi()
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -43,7 +43,7 @@ commander.register('greenhouse', function(args, sinks)
|
||||||
|
|
||||||
self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H'))
|
self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H'))
|
||||||
if not self.isSpecial then
|
if not self.isSpecial then
|
||||||
self.sink:writeln(lunacolors.format(string.format('{grayBg} ↳ Page %d %s{reset}', self.curPage, workingPage.title and ' — ' .. workingPage.title .. ' ' or '')))
|
self.sink:writeln(lunacolors.format(string.format('{grayBg} ↳ Page %d%s{reset}', self.curPage, workingPage.title and ' — ' .. workingPage.title .. ' ' or '')))
|
||||||
end
|
end
|
||||||
self.sink:write(buffer == '' and display or buffer)
|
self.sink:write(buffer == '' and display or buffer)
|
||||||
end
|
end
|
||||||
|
@ -98,27 +98,27 @@ commander.register('greenhouse', function(args, sinks)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if sinks['in'].pipe then
|
if sinks['in'].pipe then
|
||||||
local page = Page('', sinks['in']:readAll())
|
local page = Page('stdin', sinks['in']:readAll())
|
||||||
gh:addPage(page)
|
gh:addPage(page)
|
||||||
end
|
end
|
||||||
|
|
||||||
if #args ~= 0 then
|
|
||||||
for _, name in ipairs(args) do
|
for _, name in ipairs(args) do
|
||||||
local f <close> = io.open(name, 'r')
|
local f <close> = io.open(name, 'r')
|
||||||
if not f then
|
if not f then
|
||||||
sinks.err:writeln(string.format('could not open file %s', name))
|
sinks.err:writeln(string.format('could not open file %s', name))
|
||||||
end
|
end
|
||||||
|
|
||||||
local page = Page(name, f:read '*a')
|
local page = Page(name, f:read '*a')
|
||||||
gh:addPage(page)
|
gh:addPage(page)
|
||||||
end
|
end
|
||||||
ansikit.hideCursor()
|
|
||||||
gh:initUi()
|
if #gh.pages == 0 then
|
||||||
else
|
|
||||||
sinks.out:writeln [[greenhouse is the Hilbish pager library and command!
|
sinks.out:writeln [[greenhouse is the Hilbish pager library and command!
|
||||||
usage: greenhouse <file>...
|
usage: greenhouse <file>...
|
||||||
|
|
||||||
example: greenhouse hello.md]]
|
example: greenhouse hello.md]]
|
||||||
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ansikit.hideCursor()
|
||||||
|
gh:initUi()
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -74,6 +74,10 @@ function Greenhouse:draw()
|
||||||
workingPage = self.specialPage
|
workingPage = self.specialPage
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if workingPage.lazy and not workingPage.loaded then
|
||||||
|
workingPage.initialize()
|
||||||
|
end
|
||||||
|
|
||||||
local lines = workingPage.lines
|
local lines = workingPage.lines
|
||||||
self.sink:write(ansikit.getCSI(self.start .. ';1', 'H'))
|
self.sink:write(ansikit.getCSI(self.start .. ';1', 'H'))
|
||||||
self.sink:write(ansikit.getCSI(2, 'J'))
|
self.sink:write(ansikit.getCSI(2, 'J'))
|
||||||
|
|
|
@ -5,6 +5,9 @@ local Page = Object:extend()
|
||||||
function Page:new(title, text)
|
function Page:new(title, text)
|
||||||
self:setText(text)
|
self:setText(text)
|
||||||
self.title = title or 'Page'
|
self.title = title or 'Page'
|
||||||
|
self.lazy = false
|
||||||
|
self.loaded = true
|
||||||
|
self.children = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Page:setText(text)
|
function Page:setText(text)
|
||||||
|
@ -15,4 +18,15 @@ function Page:setTitle(title)
|
||||||
self.title = title
|
self.title = title
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Page:dynamic(initializer)
|
||||||
|
self.initializer = initializer
|
||||||
|
self.lazy = true
|
||||||
|
self.loaded = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Page:initialize()
|
||||||
|
self.initializer()
|
||||||
|
self.loaded = true
|
||||||
|
end
|
||||||
|
|
||||||
return Page
|
return Page
|
||||||
|
|
|
@ -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
|
|
@ -11,6 +11,7 @@ require 'nature.completions'
|
||||||
require 'nature.opts'
|
require 'nature.opts'
|
||||||
require 'nature.vim'
|
require 'nature.vim'
|
||||||
require 'nature.runner'
|
require 'nature.runner'
|
||||||
|
require 'nature.hummingbird'
|
||||||
|
|
||||||
local shlvl = tonumber(os.getenv 'SHLVL')
|
local shlvl = tonumber(os.getenv 'SHLVL')
|
||||||
if shlvl ~= nil then
|
if shlvl ~= nil then
|
||||||
|
|
|
@ -16,7 +16,7 @@ setmetatable(hilbish.opts, {
|
||||||
|
|
||||||
local function setupOpt(name, default)
|
local function setupOpt(name, default)
|
||||||
opts[name] = default
|
opts[name] = default
|
||||||
require('nature.opts.' .. name)
|
pcall(require, 'nature.opts.' .. name)
|
||||||
end
|
end
|
||||||
|
|
||||||
local defaultOpts = {
|
local defaultOpts = {
|
||||||
|
@ -25,7 +25,9 @@ local defaultOpts = {
|
||||||
greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}.
|
greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}.
|
||||||
The nice lil shell for {blue}Lua{reset} fanatics!
|
The nice lil shell for {blue}Lua{reset} fanatics!
|
||||||
]], hilbish.user),
|
]], hilbish.user),
|
||||||
motd = true
|
motd = true,
|
||||||
|
fuzzy = false,
|
||||||
|
notifyJobFinish = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for optsName, default in pairs(defaultOpts) do
|
for optsName, default in pairs(defaultOpts) do
|
||||||
|
|
|
@ -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)
|
|
@ -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.
|
// The rx parameter is passed, as the shell already checked that the search pattern is valid.
|
||||||
func (g *CompletionGroup) updateTabFind(rl *Instance) {
|
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.
|
// 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 == nil { continue }
|
||||||
if rl.regexSearch.MatchString(g.Suggestions[i]) {
|
if rl.regexSearch.MatchString(g.Suggestions[i]) {
|
||||||
suggs = append(suggs, 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
|
// this is a list so lets also check the descriptions
|
||||||
suggs = append(suggs, g.Suggestions[i])
|
suggs = append(suggs, g.Suggestions[i])
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// We overwrite the group's items, (will be refreshed as soon as something is typed in the search)
|
// We overwrite the group's items, (will be refreshed as soon as something is typed in the search)
|
||||||
g.Suggestions = suggs
|
g.Suggestions = suggs
|
||||||
|
|
|
@ -112,8 +112,10 @@ type Instance struct {
|
||||||
modeAutoFind bool // for when invoked via ^R or ^F outside of [tab]
|
modeAutoFind bool // for when invoked via ^R or ^F outside of [tab]
|
||||||
searchMode FindMode // Used for varying hints, and underlying functions called
|
searchMode FindMode // Used for varying hints, and underlying functions called
|
||||||
regexSearch *regexp.Regexp // Holds the current search regex match
|
regexSearch *regexp.Regexp // Holds the current search regex match
|
||||||
|
search string
|
||||||
mainHist bool // Which history stdin do we want
|
mainHist bool // Which history stdin do we want
|
||||||
histInfo []rune // We store a piece of hist info, for dual history sources
|
histInfo []rune // We store a piece of hist info, for dual history sources
|
||||||
|
Searcher func(string, []string) []string
|
||||||
|
|
||||||
//
|
//
|
||||||
// History -----------------------------------------------------------------------------------
|
// History -----------------------------------------------------------------------------------
|
||||||
|
@ -229,6 +231,25 @@ func NewInstance() *Instance {
|
||||||
rl.HintFormatting = "\x1b[2m"
|
rl.HintFormatting = "\x1b[2m"
|
||||||
rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn)
|
rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn)
|
||||||
rl.TempDirectory = os.TempDir()
|
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
|
// Registers
|
||||||
rl.initRegisters()
|
rl.initRegisters()
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (rl *Instance) getTabSearchCompletion() {
|
||||||
rl.getCurrentGroup()
|
rl.getCurrentGroup()
|
||||||
|
|
||||||
// Set the info for this completion mode
|
// 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 {
|
for _, g := range rl.tcGroups {
|
||||||
g.updateTabFind(rl)
|
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 total number of matches is zero, we directly change the info, and return
|
||||||
if comps, _, _ := rl.getCompletionCount(); comps == 0 {
|
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)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package readline
|
package readline
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FindMode defines how the autocomplete suggestions display
|
// FindMode defines how the autocomplete suggestions display
|
||||||
type FindMode int
|
type FindMode int
|
||||||
|
|
||||||
|
@ -30,12 +26,7 @@ func (rl *Instance) updateTabFind(r []rune) {
|
||||||
rl.tfLine = append(rl.tfLine, r...)
|
rl.tfLine = append(rl.tfLine, r...)
|
||||||
|
|
||||||
// The search regex is common to all search modes
|
// The search regex is common to all search modes
|
||||||
var err error
|
rl.search = string(rl.tfLine)
|
||||||
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"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// We update and print
|
// We update and print
|
||||||
rl.clearHelpers()
|
rl.clearHelpers()
|
||||||
|
|
|
@ -14,6 +14,7 @@ var (
|
||||||
// effects
|
// effects
|
||||||
BOLD = "\033[1m"
|
BOLD = "\033[1m"
|
||||||
DIM = "\033[2m"
|
DIM = "\033[2m"
|
||||||
|
UNDERLINE = "\033[4m"
|
||||||
RESET = "\033[0m"
|
RESET = "\033[0m"
|
||||||
// colors
|
// colors
|
||||||
RED = "\033[31m"
|
RED = "\033[31m"
|
||||||
|
|
21
rl.go
21
rl.go
|
@ -7,8 +7,9 @@ import (
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
"github.com/maxlandon/readline"
|
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/maxlandon/readline"
|
||||||
|
"github.com/sahilm/fuzzy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type lineReader struct {
|
type lineReader struct {
|
||||||
|
@ -24,6 +25,24 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
rl: rl,
|
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,
|
// we don't mind hilbish.read rl instances having completion,
|
||||||
// but it cant have shared history
|
// but it cant have shared history
|
||||||
if !noHist {
|
if !noHist {
|
||||||
|
|
|
@ -26,13 +26,14 @@ func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Valu
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoString runs the code string in the Lua runtime.
|
// 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("<string>", []byte(code), rt.TableValue(rtm.GlobalEnv()))
|
chunk, err := rtm.CompileAndLoadLuaChunk("<string>", []byte(code), rt.TableValue(rtm.GlobalEnv()))
|
||||||
|
var ret rt.Value
|
||||||
if chunk != nil {
|
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.
|
// DoFile runs the contents of the file in the Lua runtime.
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
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
|
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,
|
Hilbish as a REPL. This also allows users to add alternative languages like
|
||||||
instead of either like Fennel.
|
Fennel as the interactive script runner.
|
||||||
|
|
||||||
Runner mode can also be used to handle specific kinds of input before
|
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)
|
evaluating like normal, which is how [Link.hsh](https://github.com/TorchedSammy/Link.hsh)
|
||||||
|
|
Loading…
Reference in New Issue