diff --git a/lua/lazyvim/config/init.lua b/lua/lazyvim/config/init.lua index c0319dcf..23ca90d4 100644 --- a/lua/lazyvim/config/init.lua +++ b/lua/lazyvim/config/init.lua @@ -1,4 +1,4 @@ -local Util = require("lazy.core.util") +local Util = require("lazyvim.util") ---@class LazyVimConfig: LazyVimOptions local M = {} @@ -155,6 +155,7 @@ function M.setup(opts) M.load("autocmds") end M.load("keymaps") + Util.format.setup() end, }) @@ -240,18 +241,11 @@ end ---@param name "autocmds" | "options" | "keymaps" function M.load(name) local function _load(mod) - Util.try(function() - require(mod) - end, { - msg = "Failed loading " .. mod, - on_error = function(msg) - 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, - }) + if require("lazy.core.cache").find(mod)[1] then + Util.try(function() + require(mod) + end, { msg = "Failed loading " .. mod }) + end end -- always load lazyvim, then user file if M.defaults[name] or name == "options" then @@ -275,6 +269,11 @@ function M.init() vim.opt.rtp:append(plugin.dir) 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 ---@diagnostic disable-next-line: undefined-field 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 -- this is needed to make sure options will be correctly applied -- after installing missing plugins - require("lazyvim.config").load("options") + M.load("options") local Plugin = require("lazy.core.plugin") local add = Plugin.Spec.add ---@diagnostic disable-next-line: duplicate-set-field diff --git a/lua/lazyvim/config/keymaps.lua b/lua/lazyvim/config/keymaps.lua index e8307f45..b60aa43e 100644 --- a/lua/lazyvim/config/keymaps.lua +++ b/lua/lazyvim/config/keymaps.lua @@ -105,8 +105,8 @@ map("n", "uf", require("lazyvim.plugins.lsp.format").toggle, { desc = "T map("n", "us", function() Util.toggle("spell") end, { desc = "Toggle Spelling" }) map("n", "uw", function() Util.toggle("wrap") end, { desc = "Toggle Word Wrap" }) map("n", "uL", function() Util.toggle("relativenumber") end, { desc = "Toggle Relative Line Numbers" }) -map("n", "ul", function() Util.toggle_number() end, { desc = "Toggle Line Numbers" }) -map("n", "ud", Util.toggle_diagnostics, { desc = "Toggle Diagnostics" }) +map("n", "ul", function() Util.toggle.number() end, { desc = "Toggle Line Numbers" }) +map("n", "ud", function() Util.toggle.diagnostics() end, { desc = "Toggle Diagnostics" }) local conceallevel = vim.o.conceallevel > 0 and vim.o.conceallevel or 3 map("n", "uc", function() Util.toggle("conceallevel", false, {0, conceallevel}) end, { desc = "Toggle Conceal" }) if vim.lsp.inlay_hint then @@ -114,8 +114,8 @@ if vim.lsp.inlay_hint then end -- lazygit -map("n", "gg", function() Util.float_term({ "lazygit" }, { cwd = Util.get_root(), esc_esc = false, ctrl_hjkl = false }) end, { desc = "Lazygit (root dir)" }) -map("n", "gG", function() Util.float_term({ "lazygit" }, {esc_esc = false, ctrl_hjkl = false}) end, { desc = "Lazygit (cwd)" }) +map("n", "gg", function() Util.terminal({ "lazygit" }, { cwd = Util.root.get(), esc_esc = false, ctrl_hjkl = false }) end, { desc = "Lazygit (root dir)" }) +map("n", "gG", function() Util.terminal({ "lazygit" }, {esc_esc = false, ctrl_hjkl = false}) end, { desc = "Lazygit (cwd)" }) -- quit map("n", "qq", "qa", { desc = "Quit all" }) @@ -127,9 +127,9 @@ map("n", "ui", vim.show_pos, { desc = "Inspect Pos" }) map("n", "L", Util.changelog, {desc = "LazyVim Changelog"}) -- 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", "ft", lazyterm, { desc = "Terminal (root dir)" }) -map("n", "fT", function() Util.float_term() end, { desc = "Terminal (cwd)" }) +map("n", "fT", function() Util.terminal() end, { desc = "Terminal (cwd)" }) map("n", "", lazyterm, { desc = "Terminal (root dir)" }) map("n", "", lazyterm, { desc = "which_key_ignore" }) diff --git a/lua/lazyvim/config/options.lua b/lua/lazyvim/config/options.lua index f110f7fb..e2ae9485 100644 --- a/lua/lazyvim/config/options.lua +++ b/lua/lazyvim/config/options.lua @@ -63,10 +63,10 @@ end -- Folding 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 - vim.opt.statuscolumn = [[%!v:lua.require'lazyvim.util.ui'.statuscolumn()]] + vim.opt.statuscolumn = [[%!v:lua.require'lazyvim.util'.ui.statuscolumn()]] end -- HACK: causes freezes on <= 0.9, so only enable on >= 0.10 for now diff --git a/lua/lazyvim/plugins/editor.lua b/lua/lazyvim/plugins/editor.lua index e8df2e0b..0fb63944 100644 --- a/lua/lazyvim/plugins/editor.lua +++ b/lua/lazyvim/plugins/editor.lua @@ -11,7 +11,7 @@ return { { "fe", 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, desc = "Explorer NeoTree (root dir)", }, @@ -60,7 +60,7 @@ return { }, config = function(_, opts) local function on_move(data) - Util.on_rename(data.source, data.destination) + Util.lsp.on_rename(data.source, data.destination) end local events = require("neo-tree.events") @@ -270,7 +270,7 @@ return { "nvim-telescope/telescope.nvim", optional = true, opts = function(_, opts) - if not require("lazyvim.util").has("flash.nvim") then + if not Util.has("flash.nvim") then return end local function flash(prompt_bufnr) diff --git a/lua/lazyvim/plugins/extras/coding/codeium.lua b/lua/lazyvim/plugins/extras/coding/codeium.lua index f8d4c671..457535cd 100644 --- a/lua/lazyvim/plugins/extras/coding/codeium.lua +++ b/lua/lazyvim/plugins/extras/coding/codeium.lua @@ -49,9 +49,9 @@ return { local Util = require("lazyvim.util") local colors = { - ok = Util.fg("Special"), - error = Util.fg("DiagnosticError"), - pending = Util.fg("DiagnosticWarn"), + ok = Util.ui.fg("Special"), + error = Util.ui.fg("DiagnosticError"), + pending = Util.ui.fg("DiagnosticWarn"), } table.insert(opts.sections.lualine_x, 2, { function() diff --git a/lua/lazyvim/plugins/extras/coding/copilot.lua b/lua/lazyvim/plugins/extras/coding/copilot.lua index 38630917..279a974f 100644 --- a/lua/lazyvim/plugins/extras/coding/copilot.lua +++ b/lua/lazyvim/plugins/extras/coding/copilot.lua @@ -21,10 +21,10 @@ return { opts = function(_, opts) local Util = require("lazyvim.util") local colors = { - [""] = Util.fg("Special"), - ["Normal"] = Util.fg("Special"), - ["Warning"] = Util.fg("DiagnosticError"), - ["InProgress"] = Util.fg("DiagnosticWarn"), + [""] = Util.ui.fg("Special"), + ["Normal"] = Util.ui.fg("Special"), + ["Warning"] = Util.ui.fg("DiagnosticError"), + ["InProgress"] = Util.ui.fg("DiagnosticWarn"), } table.insert(opts.sections.lualine_x, 2, { function() @@ -36,7 +36,7 @@ return { if not package.loaded["copilot"] then return 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 return false end @@ -66,7 +66,7 @@ return { copilot_cmp.setup(opts) -- attach cmp source whenever copilot attaches -- 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 copilot_cmp._on_insert_enter({}) end diff --git a/lua/lazyvim/plugins/extras/editor/mini-files.lua b/lua/lazyvim/plugins/extras/editor/mini-files.lua index c3ddd273..55fc768c 100644 --- a/lua/lazyvim/plugins/extras/editor/mini-files.lua +++ b/lua/lazyvim/plugins/extras/editor/mini-files.lua @@ -57,7 +57,7 @@ return { vim.api.nvim_create_autocmd("User", { pattern = "MiniFilesActionRename", 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, diff --git a/lua/lazyvim/plugins/extras/lang/go.lua b/lua/lazyvim/plugins/extras/lang/go.lua index b9966b7e..39410353 100644 --- a/lua/lazyvim/plugins/extras/lang/go.lua +++ b/lua/lazyvim/plugins/extras/lang/go.lua @@ -61,7 +61,7 @@ return { gopls = function(_, opts) -- workaround for gopls not supporting semanticTokensProvider -- 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 not client.server_capabilities.semanticTokensProvider then local semantic = client.config.capabilities.textDocument.semanticTokens diff --git a/lua/lazyvim/plugins/extras/lang/python.lua b/lua/lazyvim/plugins/extras/lang/python.lua index ff4267fb..835c9da8 100644 --- a/lua/lazyvim/plugins/extras/lang/python.lua +++ b/lua/lazyvim/plugins/extras/lang/python.lua @@ -16,7 +16,7 @@ return { }, setup = { ruff_lsp = function() - require("lazyvim.util").on_attach(function(client, _) + require("lazyvim.util").lsp.on_attach(function(client, _) if client.name == "ruff_lsp" then -- Disable hover in favor of Pyright client.server_capabilities.hoverProvider = false diff --git a/lua/lazyvim/plugins/extras/lang/yaml.lua b/lua/lazyvim/plugins/extras/lang/yaml.lua index fdfba404..5afe1b83 100644 --- a/lua/lazyvim/plugins/extras/lang/yaml.lua +++ b/lua/lazyvim/plugins/extras/lang/yaml.lua @@ -64,7 +64,7 @@ return { yamlls = function() -- Neovim < 0.10 does not have dynamic registration for formatting 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 client.server_capabilities.documentFormattingProvider = true end diff --git a/lua/lazyvim/plugins/lsp/init.lua b/lua/lazyvim/plugins/lsp/init.lua index bdef1a74..f18eed4f 100644 --- a/lua/lazyvim/plugins/lsp/init.lua +++ b/lua/lazyvim/plugins/lsp/init.lua @@ -1,3 +1,5 @@ +local Util = require("lazyvim.util") + return { -- lspconfig { @@ -88,6 +90,8 @@ return { require("lazyvim.plugins.lsp.format").setup(opts) -- setup formatting and keymaps Util.on_attach(function(client, buffer) + -- setup keymaps + Util.lsp.on_attach(function(client, buffer) require("lazyvim.plugins.lsp.keymaps").on_attach(client, buffer) end) @@ -112,7 +116,7 @@ return { local inlay_hint = vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint 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 inlay_hint(buffer, true) end @@ -184,10 +188,10 @@ return { mlsp.setup({ ensure_installed = ensure_installed, handlers = { setup } }) 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") - Util.lsp_disable("tsserver", is_deno) - Util.lsp_disable("denols", function(root_dir) + Util.lsp.disable("tsserver", is_deno) + Util.lsp.disable("denols", function(root_dir) return not is_deno(root_dir) end) end @@ -208,7 +212,6 @@ return { nls.builtins.diagnostics.fish, nls.builtins.formatting.stylua, nls.builtins.formatting.shfmt, - -- nls.builtins.diagnostics.flake8, }, } end, diff --git a/lua/lazyvim/plugins/lsp/keymaps.lua b/lua/lazyvim/plugins/lsp/keymaps.lua index ad05b334..7b9c2189 100644 --- a/lua/lazyvim/plugins/lsp/keymaps.lua +++ b/lua/lazyvim/plugins/lsp/keymaps.lua @@ -66,7 +66,7 @@ end ---@param method string function M.has(buffer, 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 if client.supports_method(method) then return true @@ -83,7 +83,7 @@ function M.resolve(buffer) end local spec = M.get() 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 local maps = opts.servers[client.name] and opts.servers[client.name].keys or {} vim.list_extend(spec, maps) diff --git a/lua/lazyvim/plugins/ui.lua b/lua/lazyvim/plugins/ui.lua index d4e8859b..f1bac031 100644 --- a/lua/lazyvim/plugins/ui.lua +++ b/lua/lazyvim/plugins/ui.lua @@ -141,21 +141,21 @@ return { { function() return require("noice").api.status.command.get() 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 { function() return require("noice").api.status.mode.get() 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 { function() return " " .. 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", symbols = { @@ -374,8 +374,8 @@ return { lazy = true, init = function() vim.g.navic_silence = true - require("lazyvim.util").on_attach(function(client, buffer) - if client.server_capabilities.documentSymbolProvider then + require("lazyvim.util").lsp.on_attach(function(client, buffer) + if client.supports_method("textDocument/documentSymbol") then require("nvim-navic").attach(client, buffer) end end) diff --git a/lua/lazyvim/util/init.lua b/lua/lazyvim/util/init.lua index 05bc8154..146e73e2 100644 --- a/lua/lazyvim/util/init.lua +++ b/lua/lazyvim/util/init.lua @@ -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 = {} -M.root_patterns = { ".git", "lua" } -function M.get_clients(...) - local fn = vim.lsp.get_clients or vim.lsp.get_active_clients - return fn(...) -end +---@type table +local deprecated = { + get_clients = "lsp", + on_attach = "lsp", + 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) -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 +setmetatable(M, { + __index = function(t, k) + if LazyUtil[k] then + return LazyUtil[k] + end + local dep = deprecated[k] + if dep then + local mod = type(dep) == "table" and dep[1] or dep + local key = type(dep) == "table" and dep[2] or k + 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 function M.has(plugin) return require("lazy.core.config").spec.plugins[plugin] ~= nil 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() function M.on_very_lazy(fn) vim.api.nvim_create_autocmd("User", { @@ -53,173 +69,13 @@ function M.opts(name) return Plugin.values(plugin, "opts", false) 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", "", 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 -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", "", "", { buffer = buf, nowait = true }) - end - if opts.ctrl_hjkl == false then - vim.keymap.set("t", "", "", { buffer = buf, nowait = true }) - vim.keymap.set("t", "", "", { buffer = buf, nowait = true }) - vim.keymap.set("t", "", "", { buffer = buf, nowait = true }) - vim.keymap.set("t", "", "", { 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) - 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 -- delay notifications till vim.notify was replaced or after 500ms @@ -259,25 +115,6 @@ function M.lazy_notify() timer:start(500, 0, replay) 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 fn fun(name:string) function M.on_load(name, fn) @@ -305,28 +142,6 @@ function M.changelog() vim.diagnostic.disable(float.buf) 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 -- not create a keymap if a lazy key handler exists. -- 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.silent = opts.silent ~= false if opts.remap and not vim.g.vscode then + ---@diagnostic disable-next-line: no-unknown opts.remap = nil end vim.keymap.set(modes, lhs, rhs, opts) diff --git a/lua/lazyvim/util/lsp.lua b/lua/lazyvim/util/lsp.lua new file mode 100644 index 00000000..d5903cd8 --- /dev/null +++ b/lua/lazyvim/util/lsp.lua @@ -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 diff --git a/lua/lazyvim/util/root.lua b/lua/lazyvim/util/root.lua new file mode 100644 index 00000000..296e045b --- /dev/null +++ b/lua/lazyvim/util/root.lua @@ -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 diff --git a/lua/lazyvim/util/telescope.lua b/lua/lazyvim/util/telescope.lua new file mode 100644 index 00000000..2aae403d --- /dev/null +++ b/lua/lazyvim/util/telescope.lua @@ -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", "", 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 diff --git a/lua/lazyvim/util/terminal.lua b/lua/lazyvim/util/terminal.lua new file mode 100644 index 00000000..7787615b --- /dev/null +++ b/lua/lazyvim/util/terminal.lua @@ -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 +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", "", "", { buffer = buf, nowait = true }) + end + if opts.ctrl_hjkl == false then + vim.keymap.set("t", "", "", { buffer = buf, nowait = true }) + vim.keymap.set("t", "", "", { buffer = buf, nowait = true }) + vim.keymap.set("t", "", "", { buffer = buf, nowait = true }) + vim.keymap.set("t", "", "", { 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 diff --git a/lua/lazyvim/util/toggle.lua b/lua/lazyvim/util/toggle.lua new file mode 100644 index 00000000..b520070b --- /dev/null +++ b/lua/lazyvim/util/toggle.lua @@ -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 diff --git a/lua/lazyvim/util/ui.lua b/lua/lazyvim/util/ui.lua index 66ec4bca..22b70e4b 100644 --- a/lua/lazyvim/util/ui.lua +++ b/lua/lazyvim/util/ui.lua @@ -1,3 +1,4 @@ +---@class lazyvim.util.ui local M = {} ---@alias Sign {name:string, text:string, texthl:string, priority:number} @@ -119,4 +120,13 @@ function M.statuscolumn() }, "") 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