perf(util): split lazyvim.util in smaller separate modules

This commit is contained in:
Folke Lemaitre 2023-10-10 19:29:24 +02:00
parent 5f5acb5b88
commit c8c929c9fd
20 changed files with 442 additions and 283 deletions

View file

@ -1,4 +1,4 @@
local Util = require("lazy.core.util") local Util = require("lazyvim.util")
---@class LazyVimConfig: LazyVimOptions ---@class LazyVimConfig: LazyVimOptions
local M = {} local M = {}
@ -155,6 +155,7 @@ function M.setup(opts)
M.load("autocmds") M.load("autocmds")
end end
M.load("keymaps") M.load("keymaps")
Util.format.setup()
end, end,
}) })
@ -240,18 +241,11 @@ end
---@param name "autocmds" | "options" | "keymaps" ---@param name "autocmds" | "options" | "keymaps"
function M.load(name) function M.load(name)
local function _load(mod) local function _load(mod)
Util.try(function() if require("lazy.core.cache").find(mod)[1] then
require(mod) Util.try(function()
end, { require(mod)
msg = "Failed loading " .. mod, end, { msg = "Failed loading " .. mod })
on_error = function(msg) end
local info = require("lazy.core.cache").find(mod)
if info == nil or (type(info) == "table" and #info == 0) then
return
end
Util.error(msg)
end,
})
end end
-- always load lazyvim, then user file -- always load lazyvim, then user file
if M.defaults[name] or name == "options" then if M.defaults[name] or name == "options" then
@ -275,6 +269,11 @@ function M.init()
vim.opt.rtp:append(plugin.dir) vim.opt.rtp:append(plugin.dir)
end end
package.preload["lazyvim.plugins.lsp.format"] = function()
Util.deprecate([[require("lazyvim.plugins.lsp.format")]], [[require("lazyvim.util").format]])
return Util.format
end
M.use_lazy_file = M.use_lazy_file and vim.fn.argc(-1) > 0 M.use_lazy_file = M.use_lazy_file and vim.fn.argc(-1) > 0
---@diagnostic disable-next-line: undefined-field ---@diagnostic disable-next-line: undefined-field
M.use_lazy_file = M.use_lazy_file and require("lazy.core.handler.event").trigger_events == nil M.use_lazy_file = M.use_lazy_file and require("lazy.core.handler.event").trigger_events == nil
@ -285,7 +284,7 @@ function M.init()
-- load options here, before lazy init while sourcing plugin modules -- load options here, before lazy init while sourcing plugin modules
-- this is needed to make sure options will be correctly applied -- this is needed to make sure options will be correctly applied
-- after installing missing plugins -- after installing missing plugins
require("lazyvim.config").load("options") M.load("options")
local Plugin = require("lazy.core.plugin") local Plugin = require("lazy.core.plugin")
local add = Plugin.Spec.add local add = Plugin.Spec.add
---@diagnostic disable-next-line: duplicate-set-field ---@diagnostic disable-next-line: duplicate-set-field

View file

@ -105,8 +105,8 @@ map("n", "<leader>uf", require("lazyvim.plugins.lsp.format").toggle, { desc = "T
map("n", "<leader>us", function() Util.toggle("spell") end, { desc = "Toggle Spelling" }) map("n", "<leader>us", function() Util.toggle("spell") end, { desc = "Toggle Spelling" })
map("n", "<leader>uw", function() Util.toggle("wrap") end, { desc = "Toggle Word Wrap" }) map("n", "<leader>uw", function() Util.toggle("wrap") end, { desc = "Toggle Word Wrap" })
map("n", "<leader>uL", function() Util.toggle("relativenumber") end, { desc = "Toggle Relative Line Numbers" }) map("n", "<leader>uL", function() Util.toggle("relativenumber") end, { desc = "Toggle Relative Line Numbers" })
map("n", "<leader>ul", function() Util.toggle_number() end, { desc = "Toggle Line Numbers" }) map("n", "<leader>ul", function() Util.toggle.number() end, { desc = "Toggle Line Numbers" })
map("n", "<leader>ud", Util.toggle_diagnostics, { desc = "Toggle Diagnostics" }) map("n", "<leader>ud", function() Util.toggle.diagnostics() end, { desc = "Toggle Diagnostics" })
local conceallevel = vim.o.conceallevel > 0 and vim.o.conceallevel or 3 local conceallevel = vim.o.conceallevel > 0 and vim.o.conceallevel or 3
map("n", "<leader>uc", function() Util.toggle("conceallevel", false, {0, conceallevel}) end, { desc = "Toggle Conceal" }) map("n", "<leader>uc", function() Util.toggle("conceallevel", false, {0, conceallevel}) end, { desc = "Toggle Conceal" })
if vim.lsp.inlay_hint then if vim.lsp.inlay_hint then
@ -114,8 +114,8 @@ if vim.lsp.inlay_hint then
end end
-- lazygit -- lazygit
map("n", "<leader>gg", function() Util.float_term({ "lazygit" }, { cwd = Util.get_root(), esc_esc = false, ctrl_hjkl = false }) end, { desc = "Lazygit (root dir)" }) map("n", "<leader>gg", function() Util.terminal({ "lazygit" }, { cwd = Util.root.get(), esc_esc = false, ctrl_hjkl = false }) end, { desc = "Lazygit (root dir)" })
map("n", "<leader>gG", function() Util.float_term({ "lazygit" }, {esc_esc = false, ctrl_hjkl = false}) end, { desc = "Lazygit (cwd)" }) map("n", "<leader>gG", function() Util.terminal({ "lazygit" }, {esc_esc = false, ctrl_hjkl = false}) end, { desc = "Lazygit (cwd)" })
-- quit -- quit
map("n", "<leader>qq", "<cmd>qa<cr>", { desc = "Quit all" }) map("n", "<leader>qq", "<cmd>qa<cr>", { desc = "Quit all" })
@ -127,9 +127,9 @@ map("n", "<leader>ui", vim.show_pos, { desc = "Inspect Pos" })
map("n", "<leader>L", Util.changelog, {desc = "LazyVim Changelog"}) map("n", "<leader>L", Util.changelog, {desc = "LazyVim Changelog"})
-- floating terminal -- floating terminal
local lazyterm = function() Util.float_term(nil, { cwd = Util.get_root() }) end local lazyterm = function() Util.terminal(nil, { cwd = Util.root.get() }) end
map("n", "<leader>ft", lazyterm, { desc = "Terminal (root dir)" }) map("n", "<leader>ft", lazyterm, { desc = "Terminal (root dir)" })
map("n", "<leader>fT", function() Util.float_term() end, { desc = "Terminal (cwd)" }) map("n", "<leader>fT", function() Util.terminal() end, { desc = "Terminal (cwd)" })
map("n", "<c-/>", lazyterm, { desc = "Terminal (root dir)" }) map("n", "<c-/>", lazyterm, { desc = "Terminal (root dir)" })
map("n", "<c-_>", lazyterm, { desc = "which_key_ignore" }) map("n", "<c-_>", lazyterm, { desc = "which_key_ignore" })

View file

@ -63,10 +63,10 @@ end
-- Folding -- Folding
vim.opt.foldlevel = 99 vim.opt.foldlevel = 99
vim.opt.foldtext = "v:lua.require'lazyvim.util.ui'.foldtext()" vim.opt.foldtext = "v:lua.require'lazyvim.util'.ui.foldtext()"
if vim.fn.has("nvim-0.9.0") == 1 then if vim.fn.has("nvim-0.9.0") == 1 then
vim.opt.statuscolumn = [[%!v:lua.require'lazyvim.util.ui'.statuscolumn()]] vim.opt.statuscolumn = [[%!v:lua.require'lazyvim.util'.ui.statuscolumn()]]
end end
-- HACK: causes freezes on <= 0.9, so only enable on >= 0.10 for now -- HACK: causes freezes on <= 0.9, so only enable on >= 0.10 for now

View file

@ -11,7 +11,7 @@ return {
{ {
"<leader>fe", "<leader>fe",
function() function()
require("neo-tree.command").execute({ toggle = true, dir = require("lazyvim.util").get_root() }) require("neo-tree.command").execute({ toggle = true, dir = Util.root.get() })
end, end,
desc = "Explorer NeoTree (root dir)", desc = "Explorer NeoTree (root dir)",
}, },
@ -60,7 +60,7 @@ return {
}, },
config = function(_, opts) config = function(_, opts)
local function on_move(data) local function on_move(data)
Util.on_rename(data.source, data.destination) Util.lsp.on_rename(data.source, data.destination)
end end
local events = require("neo-tree.events") local events = require("neo-tree.events")
@ -270,7 +270,7 @@ return {
"nvim-telescope/telescope.nvim", "nvim-telescope/telescope.nvim",
optional = true, optional = true,
opts = function(_, opts) opts = function(_, opts)
if not require("lazyvim.util").has("flash.nvim") then if not Util.has("flash.nvim") then
return return
end end
local function flash(prompt_bufnr) local function flash(prompt_bufnr)

View file

@ -49,9 +49,9 @@ return {
local Util = require("lazyvim.util") local Util = require("lazyvim.util")
local colors = { local colors = {
ok = Util.fg("Special"), ok = Util.ui.fg("Special"),
error = Util.fg("DiagnosticError"), error = Util.ui.fg("DiagnosticError"),
pending = Util.fg("DiagnosticWarn"), pending = Util.ui.fg("DiagnosticWarn"),
} }
table.insert(opts.sections.lualine_x, 2, { table.insert(opts.sections.lualine_x, 2, {
function() function()

View file

@ -21,10 +21,10 @@ return {
opts = function(_, opts) opts = function(_, opts)
local Util = require("lazyvim.util") local Util = require("lazyvim.util")
local colors = { local colors = {
[""] = Util.fg("Special"), [""] = Util.ui.fg("Special"),
["Normal"] = Util.fg("Special"), ["Normal"] = Util.ui.fg("Special"),
["Warning"] = Util.fg("DiagnosticError"), ["Warning"] = Util.ui.fg("DiagnosticError"),
["InProgress"] = Util.fg("DiagnosticWarn"), ["InProgress"] = Util.ui.fg("DiagnosticWarn"),
} }
table.insert(opts.sections.lualine_x, 2, { table.insert(opts.sections.lualine_x, 2, {
function() function()
@ -36,7 +36,7 @@ return {
if not package.loaded["copilot"] then if not package.loaded["copilot"] then
return return
end end
local ok, clients = pcall(require("lazyvim.util").get_clients, { name = "copilot", bufnr = 0 }) local ok, clients = pcall(require("lazyvim.util").lsp.get_clients, { name = "copilot", bufnr = 0 })
if not ok then if not ok then
return false return false
end end
@ -66,7 +66,7 @@ return {
copilot_cmp.setup(opts) copilot_cmp.setup(opts)
-- attach cmp source whenever copilot attaches -- attach cmp source whenever copilot attaches
-- fixes lazy-loading issues with the copilot cmp source -- fixes lazy-loading issues with the copilot cmp source
require("lazyvim.util").on_attach(function(client) require("lazyvim.util").lsp.on_attach(function(client)
if client.name == "copilot" then if client.name == "copilot" then
copilot_cmp._on_insert_enter({}) copilot_cmp._on_insert_enter({})
end end

View file

@ -57,7 +57,7 @@ return {
vim.api.nvim_create_autocmd("User", { vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesActionRename", pattern = "MiniFilesActionRename",
callback = function(event) callback = function(event)
require("lazyvim.util").on_rename(event.data.from, event.data.to) require("lazyvim.util").lsp.on_rename(event.data.from, event.data.to)
end, end,
}) })
end, end,

View file

@ -61,7 +61,7 @@ return {
gopls = function(_, opts) gopls = function(_, opts)
-- workaround for gopls not supporting semanticTokensProvider -- workaround for gopls not supporting semanticTokensProvider
-- https://github.com/golang/go/issues/54531#issuecomment-1464982242 -- https://github.com/golang/go/issues/54531#issuecomment-1464982242
require("lazyvim.util").on_attach(function(client, _) require("lazyvim.util").lsp.on_attach(function(client, _)
if client.name == "gopls" then if client.name == "gopls" then
if not client.server_capabilities.semanticTokensProvider then if not client.server_capabilities.semanticTokensProvider then
local semantic = client.config.capabilities.textDocument.semanticTokens local semantic = client.config.capabilities.textDocument.semanticTokens

View file

@ -16,7 +16,7 @@ return {
}, },
setup = { setup = {
ruff_lsp = function() ruff_lsp = function()
require("lazyvim.util").on_attach(function(client, _) require("lazyvim.util").lsp.on_attach(function(client, _)
if client.name == "ruff_lsp" then if client.name == "ruff_lsp" then
-- Disable hover in favor of Pyright -- Disable hover in favor of Pyright
client.server_capabilities.hoverProvider = false client.server_capabilities.hoverProvider = false

View file

@ -64,7 +64,7 @@ return {
yamlls = function() yamlls = function()
-- Neovim < 0.10 does not have dynamic registration for formatting -- Neovim < 0.10 does not have dynamic registration for formatting
if vim.fn.has("nvim-0.10") == 0 then if vim.fn.has("nvim-0.10") == 0 then
require("lazyvim.util").on_attach(function(client, _) require("lazyvim.util").lsp.on_attach(function(client, _)
if client.name == "yamlls" then if client.name == "yamlls" then
client.server_capabilities.documentFormattingProvider = true client.server_capabilities.documentFormattingProvider = true
end end

View file

@ -1,3 +1,5 @@
local Util = require("lazyvim.util")
return { return {
-- lspconfig -- lspconfig
{ {
@ -88,6 +90,8 @@ return {
require("lazyvim.plugins.lsp.format").setup(opts) require("lazyvim.plugins.lsp.format").setup(opts)
-- setup formatting and keymaps -- setup formatting and keymaps
Util.on_attach(function(client, buffer) Util.on_attach(function(client, buffer)
-- setup keymaps
Util.lsp.on_attach(function(client, buffer)
require("lazyvim.plugins.lsp.keymaps").on_attach(client, buffer) require("lazyvim.plugins.lsp.keymaps").on_attach(client, buffer)
end) end)
@ -112,7 +116,7 @@ return {
local inlay_hint = vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint local inlay_hint = vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint
if opts.inlay_hints.enabled and inlay_hint then if opts.inlay_hints.enabled and inlay_hint then
Util.on_attach(function(client, buffer) Util.lsp.on_attach(function(client, buffer)
if client.supports_method("textDocument/inlayHint") then if client.supports_method("textDocument/inlayHint") then
inlay_hint(buffer, true) inlay_hint(buffer, true)
end end
@ -184,10 +188,10 @@ return {
mlsp.setup({ ensure_installed = ensure_installed, handlers = { setup } }) mlsp.setup({ ensure_installed = ensure_installed, handlers = { setup } })
end end
if Util.lsp_get_config("denols") and Util.lsp_get_config("tsserver") then if Util.lsp.get_config("denols") and Util.lsp.get_config("tsserver") then
local is_deno = require("lspconfig.util").root_pattern("deno.json", "deno.jsonc") local is_deno = require("lspconfig.util").root_pattern("deno.json", "deno.jsonc")
Util.lsp_disable("tsserver", is_deno) Util.lsp.disable("tsserver", is_deno)
Util.lsp_disable("denols", function(root_dir) Util.lsp.disable("denols", function(root_dir)
return not is_deno(root_dir) return not is_deno(root_dir)
end) end)
end end
@ -208,7 +212,6 @@ return {
nls.builtins.diagnostics.fish, nls.builtins.diagnostics.fish,
nls.builtins.formatting.stylua, nls.builtins.formatting.stylua,
nls.builtins.formatting.shfmt, nls.builtins.formatting.shfmt,
-- nls.builtins.diagnostics.flake8,
}, },
} }
end, end,

View file

@ -66,7 +66,7 @@ end
---@param method string ---@param method string
function M.has(buffer, method) function M.has(buffer, method)
method = method:find("/") and method or "textDocument/" .. method method = method:find("/") and method or "textDocument/" .. method
local clients = require("lazyvim.util").get_clients({ bufnr = buffer }) local clients = require("lazyvim.util").lsp.get_clients({ bufnr = buffer })
for _, client in ipairs(clients) do for _, client in ipairs(clients) do
if client.supports_method(method) then if client.supports_method(method) then
return true return true
@ -83,7 +83,7 @@ function M.resolve(buffer)
end end
local spec = M.get() local spec = M.get()
local opts = require("lazyvim.util").opts("nvim-lspconfig") local opts = require("lazyvim.util").opts("nvim-lspconfig")
local clients = require("lazyvim.util").get_clients({ bufnr = buffer }) local clients = require("lazyvim.util").lsp.get_clients({ bufnr = buffer })
for _, client in ipairs(clients) do for _, client in ipairs(clients) do
local maps = opts.servers[client.name] and opts.servers[client.name].keys or {} local maps = opts.servers[client.name] and opts.servers[client.name].keys or {}
vim.list_extend(spec, maps) vim.list_extend(spec, maps)

View file

@ -141,21 +141,21 @@ return {
{ {
function() return require("noice").api.status.command.get() end, function() return require("noice").api.status.command.get() end,
cond = function() return package.loaded["noice"] and require("noice").api.status.command.has() end, cond = function() return package.loaded["noice"] and require("noice").api.status.command.has() end,
color = Util.fg("Statement"), color = Util.ui.fg("Statement"),
}, },
-- stylua: ignore -- stylua: ignore
{ {
function() return require("noice").api.status.mode.get() end, function() return require("noice").api.status.mode.get() end,
cond = function() return package.loaded["noice"] and require("noice").api.status.mode.has() end, cond = function() return package.loaded["noice"] and require("noice").api.status.mode.has() end,
color = Util.fg("Constant"), color = Util.ui.fg("Constant"),
}, },
-- stylua: ignore -- stylua: ignore
{ {
function() return "" .. require("dap").status() end, function() return "" .. require("dap").status() end,
cond = function () return package.loaded["dap"] and require("dap").status() ~= "" end, cond = function () return package.loaded["dap"] and require("dap").status() ~= "" end,
color = Util.fg("Debug"), color = Util.ui.fg("Debug"),
}, },
{ require("lazy.status").updates, cond = require("lazy.status").has_updates, color = Util.fg("Special") }, { require("lazy.status").updates, cond = require("lazy.status").has_updates, color = Util.ui.fg("Special") },
{ {
"diff", "diff",
symbols = { symbols = {
@ -374,8 +374,8 @@ return {
lazy = true, lazy = true,
init = function() init = function()
vim.g.navic_silence = true vim.g.navic_silence = true
require("lazyvim.util").on_attach(function(client, buffer) require("lazyvim.util").lsp.on_attach(function(client, buffer)
if client.server_capabilities.documentSymbolProvider then if client.supports_method("textDocument/documentSymbol") then
require("nvim-navic").attach(client, buffer) require("nvim-navic").attach(client, buffer)
end end
end) end)

View file

@ -1,38 +1,54 @@
local Util = require("lazy.core.util") local LazyUtil = require("lazy.core.util")
---@class lazyvim.util: LazyUtilCore
---@field ui lazyvim.util.ui
---@field lsp lazyvim.util.lsp
---@field root lazyvim.util.root
---@field telescope lazyvim.util.telescope
---@field terminal lazyvim.util.terminal
---@field toggle lazyvim.util.toggle
---@field format lazyvim.util.format
local M = {} local M = {}
M.root_patterns = { ".git", "lua" } ---@type table<string, string|string[]>
function M.get_clients(...) local deprecated = {
local fn = vim.lsp.get_clients or vim.lsp.get_active_clients get_clients = "lsp",
return fn(...) on_attach = "lsp",
end on_rename = "lsp",
root_patterns = { "root", "patterns" },
get_root = { "root", "get" },
float_term = { "terminal", "open" },
toggle = { "toggle", "option" },
toggle_diagnostics = { "toggle", "diagnostics" },
toggle_number = { "toggle", "number" },
fg = "ui",
}
---@param on_attach fun(client, buffer) setmetatable(M, {
function M.on_attach(on_attach) __index = function(t, k)
vim.api.nvim_create_autocmd("LspAttach", { if LazyUtil[k] then
callback = function(args) return LazyUtil[k]
local buffer = args.buf ---@type number end
local client = vim.lsp.get_client_by_id(args.data.client_id) local dep = deprecated[k]
on_attach(client, buffer) if dep then
end, local mod = type(dep) == "table" and dep[1] or dep
}) local key = type(dep) == "table" and dep[2] or k
end M.deprecate([[require("lazyvim.util").]] .. k, [[require("lazyvim.util").]] .. mod .. "." .. key)
---@diagnostic disable-next-line: no-unknown
t[mod] = require("lazyvim.util." .. mod) -- load here to prevent loops
return t[mod][key]
end
---@diagnostic disable-next-line: no-unknown
t[k] = require("lazyvim.util." .. k)
return t[k]
end,
})
---@param plugin string ---@param plugin string
function M.has(plugin) function M.has(plugin)
return require("lazy.core.config").spec.plugins[plugin] ~= nil return require("lazy.core.config").spec.plugins[plugin] ~= nil
end end
function M.fg(name)
---@type {foreground?:number}?
---@diagnostic disable-next-line: deprecated
local hl = vim.api.nvim_get_hl and vim.api.nvim_get_hl(0, { name = name }) or vim.api.nvim_get_hl_by_name(name, true)
---@diagnostic disable-next-line: undefined-field
local fg = hl and (hl.fg or hl.foreground)
return fg and { fg = string.format("#%06x", fg) } or nil
end
---@param fn fun() ---@param fn fun()
function M.on_very_lazy(fn) function M.on_very_lazy(fn)
vim.api.nvim_create_autocmd("User", { vim.api.nvim_create_autocmd("User", {
@ -53,173 +69,13 @@ function M.opts(name)
return Plugin.values(plugin, "opts", false) return Plugin.values(plugin, "opts", false)
end end
-- returns the root directory based on:
-- * lsp workspace folders
-- * lsp root_dir
-- * root pattern of filename of the current buffer
-- * root pattern of cwd
---@return string
function M.get_root()
---@type string?
local path = vim.api.nvim_buf_get_name(0)
path = path ~= "" and vim.loop.fs_realpath(path) or nil
---@type string[]
local roots = {}
if path then
for _, client in pairs(M.get_clients({ bufnr = 0 })) do
local workspace = client.config.workspace_folders
local paths = workspace and vim.tbl_map(function(ws)
return vim.uri_to_fname(ws.uri)
end, workspace) or client.config.root_dir and { client.config.root_dir } or {}
for _, p in ipairs(paths) do
local r = vim.loop.fs_realpath(p)
if path:find(r, 1, true) then
roots[#roots + 1] = r
end
end
end
end
table.sort(roots, function(a, b)
return #a > #b
end)
---@type string?
local root = roots[1]
if not root then
path = path and vim.fs.dirname(path) or vim.loop.cwd()
---@type string?
root = vim.fs.find(M.root_patterns, { path = path, upward = true })[1]
root = root and vim.fs.dirname(root) or vim.loop.cwd()
end
---@cast root string
return root
end
-- this will return a function that calls telescope.
-- cwd will default to lazyvim.util.get_root
-- for `files`, git_files or find_files will be chosen depending on .git
function M.telescope(builtin, opts)
local params = { builtin = builtin, opts = opts }
return function()
builtin = params.builtin
opts = params.opts
opts = vim.tbl_deep_extend("force", { cwd = M.get_root() }, opts or {})
if builtin == "files" then
if vim.loop.fs_stat((opts.cwd or vim.loop.cwd()) .. "/.git") then
opts.show_untracked = true
builtin = "git_files"
else
builtin = "find_files"
end
end
if opts.cwd and opts.cwd ~= vim.loop.cwd() then
opts.attach_mappings = function(_, map)
map("i", "<a-c>", function()
local action_state = require("telescope.actions.state")
local line = action_state.get_current_line()
M.telescope(
params.builtin,
vim.tbl_deep_extend("force", {}, params.opts or {}, { cwd = false, default_text = line })
)()
end)
return true
end
end
require("telescope.builtin")[builtin](opts)
end
end
---@type table<string,LazyFloat>
local terminals = {}
-- Opens a floating terminal (interactive by default)
---@param cmd? string[]|string
---@param opts? LazyCmdOptions|{interactive?:boolean, esc_esc?:false, ctrl_hjkl?:false}
function M.float_term(cmd, opts)
opts = vim.tbl_deep_extend("force", {
ft = "lazyterm",
size = { width = 0.9, height = 0.9 },
}, opts or {}, { persistent = true })
---@cast opts LazyCmdOptions|{interactive?:boolean, esc_esc?:false}
local termkey = vim.inspect({ cmd = cmd or "shell", cwd = opts.cwd, env = opts.env, count = vim.v.count1 })
if terminals[termkey] and terminals[termkey]:buf_valid() then
terminals[termkey]:toggle()
else
terminals[termkey] = require("lazy.util").float_term(cmd, opts)
local buf = terminals[termkey].buf
vim.b[buf].lazyterm_cmd = cmd
if opts.esc_esc == false then
vim.keymap.set("t", "<esc>", "<esc>", { buffer = buf, nowait = true })
end
if opts.ctrl_hjkl == false then
vim.keymap.set("t", "<c-h>", "<c-h>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-j>", "<c-j>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-k>", "<c-k>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-l>", "<c-l>", { buffer = buf, nowait = true })
end
vim.api.nvim_create_autocmd("BufEnter", {
buffer = buf,
callback = function()
vim.cmd.startinsert()
end,
})
end
return terminals[termkey]
end
---@param silent boolean?
---@param values? {[1]:any, [2]:any}
function M.toggle(option, silent, values)
if values then
if vim.opt_local[option]:get() == values[1] then
vim.opt_local[option] = values[2]
else
vim.opt_local[option] = values[1]
end
return Util.info("Set " .. option .. " to " .. vim.opt_local[option]:get(), { title = "Option" })
end
vim.opt_local[option] = not vim.opt_local[option]:get()
if not silent then
if vim.opt_local[option]:get() then
Util.info("Enabled " .. option, { title = "Option" })
else
Util.warn("Disabled " .. option, { title = "Option" })
end
end
end
local nu = { number = true, relativenumber = true }
function M.toggle_number()
if vim.opt_local.number:get() or vim.opt_local.relativenumber:get() then
nu = { number = vim.opt_local.number:get(), relativenumber = vim.opt_local.relativenumber:get() }
vim.opt_local.number = false
vim.opt_local.relativenumber = false
Util.warn("Disabled line numbers", { title = "Option" })
else
vim.opt_local.number = nu.number
vim.opt_local.relativenumber = nu.relativenumber
Util.info("Enabled line numbers", { title = "Option" })
end
end
local enabled = true
function M.toggle_diagnostics()
enabled = not enabled
if enabled then
vim.diagnostic.enable()
Util.info("Enabled diagnostics", { title = "Diagnostics" })
else
vim.diagnostic.disable()
Util.warn("Disabled diagnostics", { title = "Diagnostics" })
end
end
function M.deprecate(old, new) function M.deprecate(old, new)
Util.warn(("`%s` is deprecated. Please use `%s` instead"):format(old, new), { title = "LazyVim" }) M.warn(("`%s` is deprecated. Please use `%s` instead"):format(old, new), {
title = "LazyVim",
once = true,
stacktrace = true,
stacklevel = 6,
})
end end
-- delay notifications till vim.notify was replaced or after 500ms -- delay notifications till vim.notify was replaced or after 500ms
@ -259,25 +115,6 @@ function M.lazy_notify()
timer:start(500, 0, replay) timer:start(500, 0, replay)
end end
---@return _.lspconfig.options
function M.lsp_get_config(server)
local configs = require("lspconfig.configs")
return rawget(configs, server)
end
---@param server string
---@param cond fun( root_dir, config): boolean
function M.lsp_disable(server, cond)
local util = require("lspconfig.util")
local def = M.lsp_get_config(server)
---@diagnostic disable-next-line: undefined-field
def.document_config.on_new_config = util.add_hook_before(def.document_config.on_new_config, function(config, root_dir)
if cond(root_dir, config) then
config.enabled = false
end
end)
end
---@param name string ---@param name string
---@param fn fun(name:string) ---@param fn fun(name:string)
function M.on_load(name, fn) function M.on_load(name, fn)
@ -305,28 +142,6 @@ function M.changelog()
vim.diagnostic.disable(float.buf) vim.diagnostic.disable(float.buf)
end end
---@param from string
---@param to string
function M.on_rename(from, to)
local clients = M.get_clients()
for _, client in ipairs(clients) do
if client.supports_method("workspace/willRenameFiles") then
---@diagnostic disable-next-line: invisible
local resp = client.request_sync("workspace/willRenameFiles", {
files = {
{
oldUri = vim.uri_from_fname(from),
newUri = vim.uri_from_fname(to),
},
},
}, 1000, 0)
if resp and resp.result ~= nil then
vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding)
end
end
end
end
-- Wrapper around vim.keymap.set that will -- Wrapper around vim.keymap.set that will
-- not create a keymap if a lazy key handler exists. -- not create a keymap if a lazy key handler exists.
-- It will also set `silent` to true by default. -- It will also set `silent` to true by default.
@ -345,6 +160,7 @@ function M.safe_keymap_set(mode, lhs, rhs, opts)
opts = opts or {} opts = opts or {}
opts.silent = opts.silent ~= false opts.silent = opts.silent ~= false
if opts.remap and not vim.g.vscode then if opts.remap and not vim.g.vscode then
---@diagnostic disable-next-line: no-unknown
opts.remap = nil opts.remap = nil
end end
vim.keymap.set(modes, lhs, rhs, opts) vim.keymap.set(modes, lhs, rhs, opts)

112
lua/lazyvim/util/lsp.lua Normal file
View file

@ -0,0 +1,112 @@
---@class lazyvim.util.lsp
local M = {}
function M.get_clients(...)
---@diagnostic disable-next-line: deprecated
local fn = vim.lsp.get_clients or vim.lsp.get_active_clients
return fn(...)
end
---@param on_attach fun(client, buffer)
function M.on_attach(on_attach)
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local buffer = args.buf ---@type number
local client = vim.lsp.get_client_by_id(args.data.client_id)
on_attach(client, buffer)
end,
})
end
---@param from string
---@param to string
function M.on_rename(from, to)
local clients = M.get_clients()
for _, client in ipairs(clients) do
if client.supports_method("workspace/willRenameFiles") then
---@diagnostic disable-next-line: invisible
local resp = client.request_sync("workspace/willRenameFiles", {
files = {
{
oldUri = vim.uri_from_fname(from),
newUri = vim.uri_from_fname(to),
},
},
}, 1000, 0)
if resp and resp.result ~= nil then
vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding)
end
end
end
end
---@return _.lspconfig.options
function M.get_config(server)
local configs = require("lspconfig.configs")
return rawget(configs, server)
end
---@param server string
---@param cond fun( root_dir, config): boolean
function M.disable(server, cond)
local util = require("lspconfig.util")
local def = M.get_config(server)
---@diagnostic disable-next-line: undefined-field
def.document_config.on_new_config = util.add_hook_before(def.document_config.on_new_config, function(config, root_dir)
if cond(root_dir, config) then
config.enabled = false
end
end)
end
---@alias lsp.Client.filter fun(client: lsp.Client): boolean
---@param name string
---@return lsp.Client.filter
function M.filter(name)
return function(client)
return client.name == name
end
end
---@param opts? LazyFormatter| {filter?: (string|lsp.Client.filter), bufnr?: number}
function M.formatter(opts)
opts = opts or {}
local filter = opts.filter
filter = type(filter) == "string" and M.filter(filter) or filter
---@cast filter lsp.Client.filter?
---@type LazyFormatter
local ret = {
name = "LSP",
primary = true,
priority = 1,
format = function(buf)
M.format({ bufnr = buf, filter = filter })
end,
sources = function(buf)
local clients = M.get_clients({ bufnr = buf })
---@param client lsp.Client
local ret = vim.tbl_filter(function(client)
return (not filter or filter(client))
and (
client.supports_method("textDocument/formatting")
or client.supports_method("textDocument/rangeFormatting")
)
end, clients)
---@param client lsp.Client
return vim.tbl_map(function(client)
return client.name
end, ret)
end,
}
return vim.tbl_deep_extend("force", ret, opts) --[[@as LazyFormatter]]
end
---@param opts? {filter?: lsp.Client.filter, bufnr?: number}
function M.format(opts)
vim.lsp.buf.format(
vim.tbl_deep_extend("force", opts or {}, require("lazyvim.util").opts("nvim-lspconfig").format or {})
)
end
return M

49
lua/lazyvim/util/root.lua Normal file
View file

@ -0,0 +1,49 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.root
local M = {}
M.patterns = { ".git", "lua" }
-- returns the root directory based on:
-- * lsp workspace folders
-- * lsp root_dir
-- * root pattern of filename of the current buffer
-- * root pattern of cwd
---@return string
function M.get()
---@type string?
local path = vim.api.nvim_buf_get_name(0)
path = path ~= "" and vim.loop.fs_realpath(path) or nil
---@type string[]
local roots = {}
if path then
for _, client in pairs(Util.lsp.get_clients({ bufnr = 0 })) do
local workspace = client.config.workspace_folders
local paths = workspace and vim.tbl_map(function(ws)
return vim.uri_to_fname(ws.uri)
end, workspace) or client.config.root_dir and { client.config.root_dir } or {}
for _, p in ipairs(paths) do
local r = vim.loop.fs_realpath(p)
if path:find(r, 1, true) then
roots[#roots + 1] = r
end
end
end
end
table.sort(roots, function(a, b)
return #a > #b
end)
---@type string?
local root = roots[1]
if not root then
path = path and vim.fs.dirname(path) or vim.loop.cwd()
---@type string?
root = vim.fs.find(M.patterns, { path = path, upward = true })[1]
root = root and vim.fs.dirname(root) or vim.loop.cwd()
end
---@cast root string
return root
end
return M

View file

@ -0,0 +1,53 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.telescope.opts
---@field cwd? string|boolean
---@field show_untracked? boolean
---@class lazyvim.util.telescope
---@overload fun(builtin:string, opts?:lazyvim.util.telescope.opts)
local M = setmetatable({}, {
__call = function(m, ...)
return m.telescope(...)
end,
})
-- this will return a function that calls telescope.
-- cwd will default to lazyvim.util.get_root
-- for `files`, git_files or find_files will be chosen depending on .git
---@param builtin string
---@param opts? lazyvim.util.telescope.opts
function M.telescope(builtin, opts)
local params = { builtin = builtin, opts = opts }
return function()
builtin = params.builtin
opts = params.opts
opts = vim.tbl_deep_extend("force", { cwd = Util.root.get() }, opts or {}) --[[@as lazyvim.util.telescope.opts]]
if builtin == "files" then
if vim.loop.fs_stat((opts.cwd or vim.loop.cwd()) .. "/.git") then
opts.show_untracked = true
builtin = "git_files"
else
builtin = "find_files"
end
end
if opts.cwd and opts.cwd ~= vim.loop.cwd() then
---@diagnostic disable-next-line: inject-field
opts.attach_mappings = function(_, map)
map("i", "<a-c>", function()
local action_state = require("telescope.actions.state")
local line = action_state.get_current_line()
M.telescope(
params.builtin,
vim.tbl_deep_extend("force", {}, params.opts or {}, { cwd = false, default_text = line })
)()
end)
return true
end
end
require("telescope.builtin")[builtin](opts)
end
end
return M

View file

@ -0,0 +1,55 @@
---@class lazyvim.util.terminal
---@overload fun(cmd: string|string[], opts: LazyTermOpts): LazyFloat
local M = setmetatable({}, {
__call = function(m, ...)
return m.open(...)
end,
})
---@type table<string,LazyFloat>
local terminals = {}
---@class LazyTermOpts: LazyCmdOptions
---@field interactive? boolean
---@field esc_esc? boolean
---@field ctrl_hjkl? boolean
-- Opens a floating terminal (interactive by default)
---@param cmd? string[]|string
---@param opts? LazyTermOpts
function M.open(cmd, opts)
opts = vim.tbl_deep_extend("force", {
ft = "lazyterm",
size = { width = 0.9, height = 0.9 },
}, opts or {}, { persistent = true }) --[[@as LazyTermOpts]]
local termkey = vim.inspect({ cmd = cmd or "shell", cwd = opts.cwd, env = opts.env, count = vim.v.count1 })
if terminals[termkey] and terminals[termkey]:buf_valid() then
terminals[termkey]:toggle()
else
terminals[termkey] = require("lazy.util").float_term(cmd, opts)
local buf = terminals[termkey].buf
vim.b[buf].lazyterm_cmd = cmd
if opts.esc_esc == false then
vim.keymap.set("t", "<esc>", "<esc>", { buffer = buf, nowait = true })
end
if opts.ctrl_hjkl == false then
vim.keymap.set("t", "<c-h>", "<c-h>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-j>", "<c-j>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-k>", "<c-k>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-l>", "<c-l>", { buffer = buf, nowait = true })
end
vim.api.nvim_create_autocmd("BufEnter", {
buffer = buf,
callback = function()
vim.cmd.startinsert()
end,
})
end
return terminals[termkey]
end
return M

View file

@ -0,0 +1,62 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.toggle
local M = {}
---@param silent boolean?
---@param values? {[1]:any, [2]:any}
function M.option(option, silent, values)
if values then
if vim.opt_local[option]:get() == values[1] then
---@diagnostic disable-next-line: no-unknown
vim.opt_local[option] = values[2]
else
---@diagnostic disable-next-line: no-unknown
vim.opt_local[option] = values[1]
end
return Util.info("Set " .. option .. " to " .. vim.opt_local[option]:get(), { title = "Option" })
end
---@diagnostic disable-next-line: no-unknown
vim.opt_local[option] = not vim.opt_local[option]:get()
if not silent then
if vim.opt_local[option]:get() then
Util.info("Enabled " .. option, { title = "Option" })
else
Util.warn("Disabled " .. option, { title = "Option" })
end
end
end
local nu = { number = true, relativenumber = true }
function M.number()
if vim.opt_local.number:get() or vim.opt_local.relativenumber:get() then
nu = { number = vim.opt_local.number:get(), relativenumber = vim.opt_local.relativenumber:get() }
vim.opt_local.number = false
vim.opt_local.relativenumber = false
Util.warn("Disabled line numbers", { title = "Option" })
else
vim.opt_local.number = nu.number
vim.opt_local.relativenumber = nu.relativenumber
Util.info("Enabled line numbers", { title = "Option" })
end
end
local enabled = true
function M.diagnostics()
enabled = not enabled
if enabled then
vim.diagnostic.enable()
Util.info("Enabled diagnostics", { title = "Diagnostics" })
else
vim.diagnostic.disable()
Util.warn("Disabled diagnostics", { title = "Diagnostics" })
end
end
setmetatable(M, {
__call = function(m, ...)
return m.option(...)
end,
})
return M

View file

@ -1,3 +1,4 @@
---@class lazyvim.util.ui
local M = {} local M = {}
---@alias Sign {name:string, text:string, texthl:string, priority:number} ---@alias Sign {name:string, text:string, texthl:string, priority:number}
@ -119,4 +120,13 @@ function M.statuscolumn()
}, "") }, "")
end end
function M.fg(name)
---@type {foreground?:number}?
---@diagnostic disable-next-line: deprecated
local hl = vim.api.nvim_get_hl and vim.api.nvim_get_hl(0, { name = name }) or vim.api.nvim_get_hl_by_name(name, true)
---@diagnostic disable-next-line: undefined-field
local fg = hl and (hl.fg or hl.foreground)
return fg and { fg = string.format("#%06x", fg) } or nil
end
return M return M