mirror of
https://github.com/LazyVim/LazyVim.git
synced 2025-06-24 17:58:51 +02:00
feat(core)!: move a bunch of LazyVim features to snacks.nvim (#4706)
## Description LazyVim comes with a bunch of smaller QoL plugin like features, but it's not easy for non LazyVim users to use them. That's why I started working on [snacks.nvim](https://github.com/folke/snacks.nvim), a collection of small QoL plugins for Neovim. Snacks also includes a bunch of new improvements to these features. This PR fully integrates with snacks. ## Todo - [ ] add proper deprecations where needed - [ ] create snacks docs - [ ] document all the new improvements relevant to LazyVim users ## Closes - [ ] #4492 - [ ] #4333 - [ ] #4687 ## Screenshots <!-- Add screenshots of the changes if applicable. --> ## Checklist - [ ] I've read the [CONTRIBUTING](https://github.com/LazyVim/LazyVim/blob/main/CONTRIBUTING.md) guidelines.
This commit is contained in:
parent
75750be1c0
commit
2f4697443c
29 changed files with 277 additions and 1066 deletions
|
@ -1,77 +1,6 @@
|
|||
---@class lazyvim.util.ui
|
||||
local M = {}
|
||||
|
||||
---@alias Sign {name:string, text:string, texthl:string, priority:number}
|
||||
|
||||
-- Returns a list of regular and extmark signs sorted by priority (low to high)
|
||||
---@return Sign[]
|
||||
---@param buf number
|
||||
---@param lnum number
|
||||
function M.get_signs(buf, lnum)
|
||||
-- Get regular signs
|
||||
---@type Sign[]
|
||||
local signs = {}
|
||||
|
||||
if vim.fn.has("nvim-0.10") == 0 then
|
||||
-- Only needed for Neovim <0.10
|
||||
-- Newer versions include legacy signs in nvim_buf_get_extmarks
|
||||
for _, sign in ipairs(vim.fn.sign_getplaced(buf, { group = "*", lnum = lnum })[1].signs) do
|
||||
local ret = vim.fn.sign_getdefined(sign.name)[1] --[[@as Sign]]
|
||||
if ret then
|
||||
ret.priority = sign.priority
|
||||
signs[#signs + 1] = ret
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Get extmark signs
|
||||
local extmarks = vim.api.nvim_buf_get_extmarks(
|
||||
buf,
|
||||
-1,
|
||||
{ lnum - 1, 0 },
|
||||
{ lnum - 1, -1 },
|
||||
{ details = true, type = "sign" }
|
||||
)
|
||||
for _, extmark in pairs(extmarks) do
|
||||
signs[#signs + 1] = {
|
||||
name = extmark[4].sign_hl_group or extmark[4].sign_name or "",
|
||||
text = extmark[4].sign_text,
|
||||
texthl = extmark[4].sign_hl_group,
|
||||
priority = extmark[4].priority,
|
||||
}
|
||||
end
|
||||
|
||||
-- Sort by priority
|
||||
table.sort(signs, function(a, b)
|
||||
return (a.priority or 0) < (b.priority or 0)
|
||||
end)
|
||||
|
||||
return signs
|
||||
end
|
||||
|
||||
---@return Sign?
|
||||
---@param buf number
|
||||
---@param lnum number
|
||||
function M.get_mark(buf, lnum)
|
||||
local marks = vim.fn.getmarklist(buf)
|
||||
vim.list_extend(marks, vim.fn.getmarklist())
|
||||
for _, mark in ipairs(marks) do
|
||||
if mark.pos[1] == buf and mark.pos[2] == lnum and mark.mark:match("[a-zA-Z]") then
|
||||
return { text = mark.mark:sub(2), texthl = "DiagnosticHint" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param sign? Sign
|
||||
---@param len? number
|
||||
function M.icon(sign, len)
|
||||
sign = sign or {}
|
||||
len = len or 2
|
||||
local text = vim.fn.strcharpart(sign.text or "", 0, len) ---@type string
|
||||
text = text .. string.rep(" ", len - vim.fn.strchars(text))
|
||||
return sign.texthl and ("%#" .. sign.texthl .. "#" .. text .. "%*") or text
|
||||
end
|
||||
|
||||
function M.foldtext()
|
||||
local ok = pcall(vim.treesitter.get_parser, vim.api.nvim_get_current_buf())
|
||||
local ret = ok and vim.treesitter.foldtext and vim.treesitter.foldtext()
|
||||
|
@ -91,74 +20,6 @@ function M.foldtext()
|
|||
return ret
|
||||
end
|
||||
|
||||
function M.statuscolumn()
|
||||
local win = vim.g.statusline_winid
|
||||
local buf = vim.api.nvim_win_get_buf(win)
|
||||
local is_file = vim.bo[buf].buftype == ""
|
||||
local show_signs = vim.wo[win].signcolumn ~= "no"
|
||||
|
||||
local components = { "", "", "" } -- left, middle, right
|
||||
|
||||
local show_open_folds = vim.g.lazyvim_statuscolumn and vim.g.lazyvim_statuscolumn.folds_open
|
||||
local use_githl = vim.g.lazyvim_statuscolumn and vim.g.lazyvim_statuscolumn.folds_githl
|
||||
|
||||
if show_signs then
|
||||
local signs = M.get_signs(buf, vim.v.lnum)
|
||||
|
||||
---@type Sign?,Sign?,Sign?
|
||||
local left, right, fold, githl
|
||||
for _, s in ipairs(signs) do
|
||||
if s.name and (s.name:find("GitSign") or s.name:find("MiniDiffSign")) then
|
||||
right = s
|
||||
if use_githl then
|
||||
githl = s["texthl"]
|
||||
end
|
||||
else
|
||||
left = s
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_win_call(win, function()
|
||||
if vim.fn.foldclosed(vim.v.lnum) >= 0 then
|
||||
fold = { text = vim.opt.fillchars:get().foldclose or "", texthl = githl or "Folded" }
|
||||
elseif
|
||||
show_open_folds
|
||||
and not LazyVim.ui.skip_foldexpr[buf]
|
||||
and tostring(vim.treesitter.foldexpr(vim.v.lnum)):sub(1, 1) == ">"
|
||||
then -- fold start
|
||||
fold = { text = vim.opt.fillchars:get().foldopen or "", texthl = githl }
|
||||
end
|
||||
end)
|
||||
-- Left: mark or non-git sign
|
||||
components[1] = M.icon(M.get_mark(buf, vim.v.lnum) or left)
|
||||
-- Right: fold icon or git sign (only if file)
|
||||
components[3] = is_file and M.icon(fold or right) or ""
|
||||
end
|
||||
|
||||
-- Numbers in Neovim are weird
|
||||
-- They show when either number or relativenumber is true
|
||||
local is_num = vim.wo[win].number
|
||||
local is_relnum = vim.wo[win].relativenumber
|
||||
if (is_num or is_relnum) and vim.v.virtnum == 0 then
|
||||
if vim.fn.has("nvim-0.11") == 1 then
|
||||
components[2] = "%l" -- 0.11 handles both the current and other lines with %l
|
||||
else
|
||||
if vim.v.relnum == 0 then
|
||||
components[2] = is_num and "%l" or "%r" -- the current line
|
||||
else
|
||||
components[2] = is_relnum and "%r" or "%l" -- other lines
|
||||
end
|
||||
end
|
||||
components[2] = "%=" .. components[2] .. " " -- right align
|
||||
end
|
||||
|
||||
if vim.v.virtnum ~= 0 then
|
||||
components[2] = "%= "
|
||||
end
|
||||
|
||||
return table.concat(components, "")
|
||||
end
|
||||
|
||||
---@return {fg?:string}?
|
||||
function M.fg(name)
|
||||
local color = M.color(name)
|
||||
|
@ -224,47 +85,45 @@ function M.foldexpr()
|
|||
return "0"
|
||||
end
|
||||
|
||||
---@param buf number?
|
||||
function M.bufremove(buf)
|
||||
buf = buf or 0
|
||||
buf = buf == 0 and vim.api.nvim_get_current_buf() or buf
|
||||
|
||||
if vim.bo.modified then
|
||||
local choice = vim.fn.confirm(("Save changes to %q?"):format(vim.fn.bufname()), "&Yes\n&No\n&Cancel")
|
||||
if choice == 0 or choice == 3 then -- 0 for <Esc>/<C-c> and 3 for Cancel
|
||||
return
|
||||
end
|
||||
if choice == 1 then -- Yes
|
||||
vim.cmd.write()
|
||||
end
|
||||
end
|
||||
|
||||
for _, win in ipairs(vim.fn.win_findbuf(buf)) do
|
||||
vim.api.nvim_win_call(win, function()
|
||||
if not vim.api.nvim_win_is_valid(win) or vim.api.nvim_win_get_buf(win) ~= buf then
|
||||
return
|
||||
function M.maximize()
|
||||
---@type {k:string, v:any}[]?
|
||||
local maximized = nil
|
||||
return Snacks.toggle({
|
||||
name = "Maximize",
|
||||
get = function()
|
||||
return maximized ~= nil
|
||||
end,
|
||||
set = function(state)
|
||||
if state then
|
||||
maximized = {}
|
||||
local function set(k, v)
|
||||
table.insert(maximized, 1, { k = k, v = vim.o[k] })
|
||||
vim.o[k] = v
|
||||
end
|
||||
set("winwidth", 999)
|
||||
set("winheight", 999)
|
||||
set("winminwidth", 10)
|
||||
set("winminheight", 4)
|
||||
vim.cmd("wincmd =")
|
||||
-- `QuitPre` seems to be executed even if we quit a normal window, so we don't want that
|
||||
-- `VimLeavePre` might be another consideration? Not sure about differences between the 2
|
||||
vim.api.nvim_create_autocmd("ExitPre", {
|
||||
once = true,
|
||||
group = vim.api.nvim_create_augroup("lazyvim_restore_max_exit_pre", { clear = true }),
|
||||
desc = "Restore width/height when close Neovim while maximized",
|
||||
callback = function()
|
||||
M.maximize.set(false)
|
||||
end,
|
||||
})
|
||||
else
|
||||
for _, opt in ipairs(maximized) do
|
||||
vim.o[opt.k] = opt.v
|
||||
end
|
||||
maximized = nil
|
||||
vim.cmd("wincmd =")
|
||||
end
|
||||
-- Try using alternate buffer
|
||||
local alt = vim.fn.bufnr("#")
|
||||
if alt ~= buf and vim.fn.buflisted(alt) == 1 then
|
||||
vim.api.nvim_win_set_buf(win, alt)
|
||||
return
|
||||
end
|
||||
|
||||
-- Try using previous buffer
|
||||
local has_previous = pcall(vim.cmd, "bprevious")
|
||||
if has_previous and buf ~= vim.api.nvim_win_get_buf(win) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Create new listed buffer
|
||||
local new_buf = vim.api.nvim_create_buf(true, false)
|
||||
vim.api.nvim_win_set_buf(win, new_buf)
|
||||
end)
|
||||
end
|
||||
if vim.api.nvim_buf_is_valid(buf) then
|
||||
pcall(vim.cmd, "bdelete! " .. buf)
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue