feat: add notification/message interface (#239)

details in #219
comp-cache
sammyette 2023-07-10 19:03:30 -04:00 committed by GitHub
parent 3eae0f07be
commit c6c81ddece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 187 additions and 1 deletions

View File

@ -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)

View File

@ -8,7 +8,12 @@
- `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`) - Add fuzzy search to history search (enable via `hilbish.opts.fuzzy = true`)
- Show indexes on cdr list - 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 ### 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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -26,7 +26,8 @@ local defaultOpts = {
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 fuzzy = false,
notifyJobFinish = true
} }
for optsName, default in pairs(defaultOpts) do for optsName, default in pairs(defaultOpts) do

View File

@ -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)

View File

@ -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.