u.nvim/examples/notify.lua
Jonathan Apodaca c760c495b7
All checks were successful
NeoVim tests / plenary-tests (push) Successful in 11s
update lua API to 1-based indices; add renderer
2025-05-04 15:44:09 -06:00

138 lines
3.7 KiB
Lua

local Buffer = require 'u.buffer'
local TreeBuilder = require('u.renderer').TreeBuilder
local tracker = require 'u.tracker'
local utils = require 'u.utils'
local Window = require 'my.window'
local TIMEOUT = 4000
local ICONS = {
[vim.log.levels.TRACE] = { text = '󰃤', group = 'DiagnosticSignOk' },
[vim.log.levels.DEBUG] = { text = '󰃤', group = 'DiagnosticSignOk' },
[vim.log.levels.INFO] = { text = '', group = 'DiagnosticSignInfo' },
[vim.log.levels.WARN] = { text = '', group = 'DiagnosticSignWarn' },
[vim.log.levels.ERROR] = { text = '', group = 'DiagnosticSignError' },
}
local DEFAULT_ICON = { text = '', group = 'DiagnosticSignOk' }
--- @alias Notification {
--- kind: number;
--- id: number;
--- text: string;
--- }
local M = {}
--- @type Window | nil
local notifs_w
local s_notifications_raw = tracker.create_signal {}
local s_notifications = s_notifications_raw:debounce(50)
-- Render effect:
tracker.create_effect(function()
--- @type Notification[]
local notifs = s_notifications:get()
if #notifs == 0 then
if notifs_w then
notifs_w:close(true)
notifs_w = nil
end
return
end
vim.schedule(function()
local editor_size = utils.get_editor_dimensions()
local avail_width = editor_size.width
local float_width = 40
local win_config = {
relative = 'editor',
anchor = 'NE',
row = 0,
col = avail_width,
width = float_width,
height = math.min(#notifs, editor_size.height - 3),
border = 'single',
focusable = false,
}
if not notifs_w or not vim.api.nvim_win_is_valid(notifs_w.win) then
notifs_w = Window.new(Buffer.create(false, true), win_config)
vim.wo[notifs_w.win].cursorline = false
vim.wo[notifs_w.win].list = false
vim.wo[notifs_w.win].listchars = ''
vim.wo[notifs_w.win].number = false
vim.wo[notifs_w.win].relativenumber = false
vim.wo[notifs_w.win].wrap = false
else
notifs_w:set_config(win_config)
end
notifs_w:render(TreeBuilder.new()
:nest(function(tb)
for idx, notif in ipairs(notifs) do
if idx > 1 then tb:put '\n' end
local notif_icon = ICONS[notif.kind] or DEFAULT_ICON
tb:put_h('text', { hl = notif_icon.group }, notif_icon.text)
tb:put { ' ', notif.text }
end
end)
:tree())
vim.api.nvim_win_call(notifs_w.win, function()
-- scroll to bottom:
vim.cmd.normal 'G'
-- scroll all the way to the left:
vim.cmd.normal '9999zh'
end)
end)
end)
local _orig_notify
--- @param msg string
--- @param level integer|nil
--- @param opts table|nil
local function my_notify(msg, level, opts)
vim.schedule(function() _orig_notify(msg, level, opts) end)
if level == nil then level = vim.log.levels.INFO end
if level < vim.log.levels.INFO then return end
local id = math.random(math.huge)
--- @param notifs Notification[]
s_notifications_raw:schedule_update(function(notifs)
table.insert(notifs, { kind = level, id = id, text = msg })
return notifs
end)
vim.defer_fn(function()
--- @param notifs Notification[]
s_notifications_raw:schedule_update(function(notifs)
for i, notif in ipairs(notifs) do
if notif.id == id then
table.remove(notifs, i)
break
end
end
return notifs
end)
end, TIMEOUT)
end
local _once_msgs = {}
local function my_notify_once(msg, level, opts)
if vim.tbl_contains(_once_msgs, msg) then return false end
table.insert(_once_msgs, msg)
vim.notify(msg, level, opts)
return true
end
function M.setup()
if _orig_notify == nil then _orig_notify = vim.notify end
vim.notify = my_notify
vim.notify_once = my_notify_once
end
return M