fix(ui): special handling for floats closed before VimEnter. Seems that WinClosed events dont execute before that. Fixes #1390

This commit is contained in:
Folke Lemaitre 2024-03-27 08:48:55 +01:00
parent d37a76b871
commit eefb8974d6
No known key found for this signature in database
GPG Key ID: 41F8B1FBACAE2040
3 changed files with 89 additions and 26 deletions

View File

@ -98,6 +98,36 @@ function M.throttle(ms, fn)
end end
end end
--- Creates a weak reference to an object.
--- Calling the returned function will return the object if it has not been garbage collected.
---@generic T: table
---@param obj T
---@return T|fun():T?
function M.weak(obj)
local weak = { _obj = obj }
---@return table<any, any>
local function get()
local ret = rawget(weak, "_obj")
return ret == nil and error("Object has been garbage collected", 2) or ret
end
local mt = {
__mode = "v",
__call = function(t)
return rawget(t, "_obj")
end,
__index = function(_, k)
return get()[k]
end,
__newindex = function(_, k, v)
get()[k] = v
end,
__pairs = function()
return pairs(get())
end,
}
return setmetatable(weak, mt)
end
---@class LazyCmdOptions: LazyFloatOptions ---@class LazyCmdOptions: LazyFloatOptions
---@field cwd? string ---@field cwd? string
---@field env? table<string,string> ---@field env? table<string,string>

View File

@ -24,6 +24,7 @@ local ViewConfig = require("lazy.view.config")
---@field win_opts LazyWinOpts ---@field win_opts LazyWinOpts
---@field backdrop_buf number ---@field backdrop_buf number
---@field backdrop_win number ---@field backdrop_win number
---@field id number
---@overload fun(opts?:LazyFloatOptions):LazyFloat ---@overload fun(opts?:LazyFloatOptions):LazyFloat
local M = {} local M = {}
@ -33,6 +34,12 @@ setmetatable(M, {
end, end,
}) })
local _id = 0
local function next_id()
_id = _id + 1
return _id
end
---@param opts? LazyFloatOptions ---@param opts? LazyFloatOptions
function M.new(opts) function M.new(opts)
local self = setmetatable({}, { __index = M }) local self = setmetatable({}, { __index = M })
@ -42,6 +49,7 @@ end
---@param opts? LazyFloatOptions ---@param opts? LazyFloatOptions
function M:init(opts) function M:init(opts)
require("lazy.view.colors").setup() require("lazy.view.colors").setup()
self.id = next_id()
self.opts = vim.tbl_deep_extend("force", { self.opts = vim.tbl_deep_extend("force", {
size = Config.options.ui.size, size = Config.options.ui.size,
style = "minimal", style = "minimal",
@ -65,8 +73,13 @@ function M:init(opts)
title_pos = self.opts.title and self.opts.title_pos or nil, title_pos = self.opts.title and self.opts.title_pos or nil,
} }
self:mount() self:mount()
self:on_key(ViewConfig.keys.close, self.close) self:on("VimEnter", function()
self:on({ "WinLeave", "BufDelete", "BufHidden" }, self.close, { once = false }) vim.schedule(function()
if not self:win_valid() then
self:close()
end
end)
end, { buffer = false })
return self return self
end end
@ -138,7 +151,13 @@ function M:mount()
self:layout() self:layout()
self.win = vim.api.nvim_open_win(self.buf, true, self.win_opts) self.win = vim.api.nvim_open_win(self.buf, true, self.win_opts)
self:on("WinClosed", function()
self:close()
self:augroup(true)
end, { win = true })
self:focus() self:focus()
self:on_key(ViewConfig.keys.close, self.close)
self:on({ "BufDelete", "BufHidden" }, self.close)
if vim.bo[self.buf].buftype == "" then if vim.bo[self.buf].buftype == "" then
vim.bo[self.buf].buftype = "nofile" vim.bo[self.buf].buftype = "nofile"
@ -185,27 +204,38 @@ function M:mount()
}) })
end end
---@param clear? boolean
function M:augroup(clear)
return vim.api.nvim_create_augroup("trouble.window." .. self.id, { clear = clear == true })
end
---@param events string|string[] ---@param events string|string[]
---@param fn fun(self?):boolean? ---@param fn fun(self:LazyFloat, event:{buf:number}):boolean?
---@param opts? table ---@param opts? vim.api.keyset.create_autocmd | {buffer: false, win?:boolean}
function M:on(events, fn, opts) function M:on(events, fn, opts)
if type(events) == "string" then opts = opts or {}
events = { events } if opts.win then
opts.pattern = self.win .. ""
opts.win = nil
elseif opts.buffer == nil then
opts.buffer = self.buf
elseif opts.buffer == false then
opts.buffer = nil
end end
for _, e in ipairs(events) do if opts.pattern then
local event, pattern = e:match("(%w+) (%w+)") opts.buffer = nil
event = event or e
vim.api.nvim_create_autocmd(
event,
vim.tbl_extend("force", {
pattern = pattern,
buffer = (not pattern) and self.buf or nil,
callback = function()
return fn(self)
end,
}, opts or {})
)
end end
local _self = Util.weak(self)
opts.callback = function(e)
local this = _self()
if not this then
-- delete the autocmd
return true
end
return fn(this, e)
end
opts.group = self:augroup()
vim.api.nvim_create_autocmd(events, opts)
end end
---@param key string ---@param key string
@ -223,6 +253,7 @@ end
---@param opts? {wipe:boolean} ---@param opts? {wipe:boolean}
function M:close(opts) function M:close(opts)
self:augroup(true)
local buf = self.buf local buf = self.buf
local win = self.win local win = self.win
local wipe = opts and opts.wipe local wipe = opts and opts.wipe

View File

@ -53,7 +53,7 @@ function M.create()
Float.init(self, { Float.init(self, {
title = Config.options.ui.title, title = Config.options.ui.title,
title_pos = Config.options.ui.title_pos, title_pos = Config.options.ui.title_pos,
noautocmd = true, noautocmd = false,
}) })
if Config.options.ui.wrap then if Config.options.ui.wrap then
@ -69,12 +69,14 @@ function M.create()
self.render = Render.new(self) self.render = Render.new(self)
self.update = Util.throttle(Config.options.ui.throttle, self.update) self.update = Util.throttle(Config.options.ui.throttle, self.update)
self:on({ "User LazyRender", "User LazyFloatResized" }, function() for _, pattern in ipairs({ "LazyRender", "LazyFloatResized" }) do
self:on({ "User" }, function()
if not (self.buf and vim.api.nvim_buf_is_valid(self.buf)) then if not (self.buf and vim.api.nvim_buf_is_valid(self.buf)) then
return true return true
end end
self:update() self:update()
end) end, { pattern = pattern })
end
vim.keymap.set("n", ViewConfig.keys.abort, function() vim.keymap.set("n", ViewConfig.keys.abort, function()
require("lazy.manage.process").abort() require("lazy.manage.process").abort()