Compare commits

..

7 Commits

Author SHA1 Message Date
fc29454c55 refactor extmark to its own file
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m24s
2025-09-21 22:08:08 -06:00
c6b0076630 (shell.nix) upgrade to latest Neovim
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m18s
2025-09-13 08:54:17 -06:00
eefcbb7bbe (stylua) sort_requires.enabled = true
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m16s
2025-09-13 08:51:29 -06:00
f1e225cba9 do not check sub-modes in get_tags_at
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m20s
cull test-dependency
2025-09-13 08:36:33 -06:00
6785398c96 (u.pos) add more utility functions
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m18s
2025-09-08 22:16:24 -06:00
2ea6c02c69 (renderer) add more tests; fix bugs in text-change
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m21s
2025-09-07 18:05:38 -06:00
06e6b88391 range: extmarks/tsquery; renderer: text-change
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
NeoVim tests / code-quality (push) Successful in 1m19s
2025-08-30 15:03:56 -06:00

View File

@ -1,5 +1,6 @@
local Renderer = require('u.renderer').Renderer local Buffer = require 'u.buffer'
local TreeBuilder = require('u.renderer').TreeBuilder local TreeBuilder = require('u.renderer').TreeBuilder
local Window = require 'my.window'
local tracker = require 'u.tracker' local tracker = require 'u.tracker'
local utils = require 'u.utils' local utils = require 'u.utils'
@ -13,25 +14,15 @@ local ICONS = {
} }
local DEFAULT_ICON = { text = '', group = 'DiagnosticSignOk' } local DEFAULT_ICON = { text = '', group = 'DiagnosticSignOk' }
local S_EDITOR_DIMENSIONS =
tracker.create_signal(utils.get_editor_dimensions(), 's:editor_dimensions')
vim.api.nvim_create_autocmd('VimResized', {
callback = function()
local new_dim = utils.get_editor_dimensions()
S_EDITOR_DIMENSIONS:set(new_dim)
end,
})
--- @alias u.examples.Notification { --- @alias u.examples.Notification {
--- kind: number; --- kind: number;
--- id: number; --- id: number;
--- text: string; --- text: string;
--- timer: uv.uv_timer_t;
--- } --- }
local M = {} local M = {}
--- @type { win: integer, buf: integer, renderer: u.renderer.Renderer } | nil --- @type Window | nil
local notifs_w local notifs_w
local s_notifications_raw = tracker.create_signal {} local s_notifications_raw = tracker.create_signal {}
@ -41,47 +32,42 @@ local s_notifications = s_notifications_raw:debounce(50)
tracker.create_effect(function() tracker.create_effect(function()
--- @type u.examples.Notification[] --- @type u.examples.Notification[]
local notifs = s_notifications:get() local notifs = s_notifications:get()
--- @type { width: integer, height: integer }
local editor_size = S_EDITOR_DIMENSIONS:get()
if #notifs == 0 then if #notifs == 0 then
if notifs_w then if notifs_w then
if vim.api.nvim_win_is_valid(notifs_w.win) then vim.api.nvim_win_close(notifs_w.win, true) end notifs_w:close(true)
notifs_w = nil notifs_w = nil
end end
return return
end end
vim.schedule(function()
local editor_size = utils.get_editor_dimensions()
local avail_width = editor_size.width local avail_width = editor_size.width
local float_width = 40 local float_width = 40
local float_height = math.min(#notifs, editor_size.height - 3)
local win_config = { local win_config = {
relative = 'editor', relative = 'editor',
anchor = 'NE', anchor = 'NE',
row = 0, row = 0,
col = avail_width, col = avail_width,
width = float_width, width = float_width,
height = float_height, height = math.min(#notifs, editor_size.height - 3),
border = 'single', border = 'single',
focusable = false, focusable = false,
zindex = 900,
} }
vim.schedule(function()
if not notifs_w or not vim.api.nvim_win_is_valid(notifs_w.win) then if not notifs_w or not vim.api.nvim_win_is_valid(notifs_w.win) then
local b = vim.api.nvim_create_buf(false, true) notifs_w = Window.new(Buffer.create(false, true), win_config)
local w = vim.api.nvim_open_win(b, false, win_config) vim.wo[notifs_w.win].cursorline = false
vim.wo[w].cursorline = false vim.wo[notifs_w.win].list = false
vim.wo[w].list = false vim.wo[notifs_w.win].listchars = ''
vim.wo[w].listchars = '' vim.wo[notifs_w.win].number = false
vim.wo[w].number = false vim.wo[notifs_w.win].relativenumber = false
vim.wo[w].relativenumber = false vim.wo[notifs_w.win].wrap = false
vim.wo[w].wrap = false
notifs_w = { win = w, buf = b, renderer = Renderer.new(b) }
else else
vim.api.nvim_win_set_config(notifs_w.win, win_config) notifs_w:set_config(win_config)
end end
notifs_w.renderer:render(TreeBuilder.new() notifs_w:render(TreeBuilder.new()
:nest(function(tb) :nest(function(tb)
for idx, notif in ipairs(notifs) do for idx, notif in ipairs(notifs) do
if idx > 1 then tb:put '\n' end if idx > 1 then tb:put '\n' end
@ -93,81 +79,48 @@ tracker.create_effect(function()
end) end)
:tree()) :tree())
vim.api.nvim_win_call(notifs_w.win, function() vim.api.nvim_win_call(notifs_w.win, function()
vim.fn.winrestview { -- scroll to bottom:
-- scroll all the way left: vim.cmd.normal 'G'
leftcol = 0, -- scroll all the way to the left:
-- set the bottom line to be at the bottom of the window: vim.cmd.normal '9999zh'
topline = vim.api.nvim_buf_line_count(notifs_w.buf) - win_config.height + 1,
}
end) end)
end) end)
end) end)
--- @param id number local _orig_notify
local function _delete_notif(id)
--- @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 u.examples.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 u.examples.Notification[] --- @param notifs u.examples.Notification[]
s_notifications_raw:schedule_update(function(notifs) s_notifications_raw:schedule_update(function(notifs)
for i, notif in ipairs(notifs) do for i, notif in ipairs(notifs) do
if notif.id == id then if notif.id == id then
notif.timer:stop()
notif.timer:close()
table.remove(notifs, i) table.remove(notifs, i)
break break
end end
end end
return notifs return notifs
end) end)
end end, TIMEOUT)
local _orig_notify
--- @param msg string
--- @param level integer|nil
--- @param opts? { id: number }
function M.notify(msg, level, opts)
if level == nil then level = vim.log.levels.INFO end
opts = opts or {}
local id = opts.id or math.random(999999999)
--- @type u.examples.Notification?
local notif = vim.iter(s_notifications_raw:get()):find(function(n) return n.id == id end)
if not notif then
-- Create a new notification (maybe):
if vim.trim(msg) == '' then return id end
if level < vim.log.levels.INFO then return id end
local timer = assert((vim.uv or vim.loop).new_timer(), 'could not create timer')
timer:start(TIMEOUT, 0, function() _delete_notif(id) end)
notif = {
id = id,
kind = level,
text = msg,
timer = timer,
}
--- @param notifs u.examples.Notification[]
s_notifications_raw:schedule_update(function(notifs)
table.insert(notifs, notif)
return notifs
end)
else
-- Update an existing notification:
s_notifications_raw:schedule_update(function(notifs)
-- We already have a copy-by-reference of the notif we want to modify:
notif.timer:stop()
notif.text = msg
notif.kind = level
notif.timer:start(TIMEOUT, 0, function() _delete_notif(id) end)
return notifs
end)
end
return id
end end
local _once_msgs = {} local _once_msgs = {}
function M.notify_once(msg, level, opts) local function my_notify_once(msg, level, opts)
if vim.tbl_contains(_once_msgs, msg) then return false end if vim.tbl_contains(_once_msgs, msg) then return false end
table.insert(_once_msgs, msg) table.insert(_once_msgs, msg)
vim.notify(msg, level, opts) vim.notify(msg, level, opts)
@ -177,8 +130,8 @@ end
function M.setup() function M.setup()
if _orig_notify == nil then _orig_notify = vim.notify end if _orig_notify == nil then _orig_notify = vim.notify end
vim.notify = M.notify vim.notify = my_notify
vim.notify_once = M.notify_once vim.notify_once = my_notify_once
end end
return M return M