diff --git a/.github/.release-please-manifest.json b/.github/.release-please-manifest.json index 8e00e87c..b25a6511 100644 --- a/.github/.release-please-manifest.json +++ b/.github/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "15.1.1" + ".": "15.2.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b5e9ac..21249147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [15.2.0](https://github.com/LazyVim/LazyVim/compare/v15.1.1...v15.2.0) (2025-09-20) + + +### Features + +* **clojure:** use 'nvim-paredit' instead 'nvim-treesitter-sexp' as clojure S-exp Plugin ([#5876](https://github.com/LazyVim/LazyVim/issues/5876)) ([2659028](https://github.com/LazyVim/LazyVim/commit/26590285ead7a89bb45f309714f7f40136c89267)) +* **core:** relax hard requirement for `vim.lsp.is_enabled`. Show warning instead ([3ca7b47](https://github.com/LazyVim/LazyVim/commit/3ca7b47365c85a07047e48cad450feff66c8bdd6)) +* **options:** don't overwrite indentexpr/foldexpr/foldmethod when set by plugins. Fixes [#6464](https://github.com/LazyVim/LazyVim/issues/6464) ([ccbaf55](https://github.com/LazyVim/LazyVim/commit/ccbaf55c2f8bc691f8f64fe40ce00a1abda4fbac)) +* **yanky:** use snacks picker for improved yank history navigation ([#5802](https://github.com/LazyVim/LazyVim/issues/5802)) ([55e762a](https://github.com/LazyVim/LazyVim/commit/55e762a8888cd5f336e4e2d4b2cc6b8b1b950663)) + + +### Bug Fixes + +* **editor:** calculate the height passed to the prompt of fzf-lua properly ([#6481](https://github.com/LazyVim/LazyVim/issues/6481)) ([65e38d3](https://github.com/LazyVim/LazyVim/commit/65e38d3b34cab653a05318c1a9014df3c89fdb53)) +* **lang.clojure:** correct cmp-conjure source name ([#6208](https://github.com/LazyVim/LazyVim/issues/6208)) ([55b5c1f](https://github.com/LazyVim/LazyVim/commit/55b5c1fecb0b7e71c5eb40555b17d1e4820690f0)) +* **options:** set_default option ([2401d5f](https://github.com/LazyVim/LazyVim/commit/2401d5fca6f2a2fcaca4f9c4c84c4b713c602352)) +* **options:** track some initial options right after loading `options.lua`. See [#6463](https://github.com/LazyVim/LazyVim/issues/6463) ([9c611b0](https://github.com/LazyVim/LazyVim/commit/9c611b0c5758d0d659e7fdb29119b7083a56f989)) +* **treesitter:** check if queries for indent/fold exists before enabling it. Fixes [#6474](https://github.com/LazyVim/LazyVim/issues/6474) ([5ce7cd6](https://github.com/LazyVim/LazyVim/commit/5ce7cd650a5fffc257e0312b82fffd26abe2a1fa)) + ## [15.1.1](https://github.com/LazyVim/LazyVim/compare/v15.1.0...v15.1.1) (2025-09-18) diff --git a/doc/LazyVim.txt b/doc/LazyVim.txt index 5c3e670d..054756aa 100644 --- a/doc/LazyVim.txt +++ b/doc/LazyVim.txt @@ -1,4 +1,4 @@ -*LazyVim.txt* For Neovim Last change: 2025 September 18 +*LazyVim.txt* For Neovim Last change: 2025 September 21 ============================================================================== Table of Contents *LazyVim-table-of-contents* diff --git a/lua/lazyvim/config/init.lua b/lua/lazyvim/config/init.lua index 0df3885b..e85dbd63 100644 --- a/lua/lazyvim/config/init.lua +++ b/lua/lazyvim/config/init.lua @@ -3,7 +3,7 @@ _G.LazyVim = require("lazyvim.util") ---@class LazyVimConfig: LazyVimOptions local M = {} -M.version = "15.1.1" -- x-release-please-version +M.version = "15.2.0" -- x-release-please-version LazyVim.config = M ---@class LazyVimOptions @@ -304,6 +304,8 @@ function M.load(name) end M.did_init = false +M._options = {} ---@type vim.wo|vim.bo + function M.init() if M.did_init then return @@ -326,6 +328,12 @@ function M.init() -- this is needed to make sure options will be correctly applied -- after installing missing plugins M.load("options") + + -- save some options to track defaults + M._options.indentexpr = vim.o.indentexpr + M._options.foldmethod = vim.o.foldmethod + M._options.foldexpr = vim.o.foldexpr + -- defer built-in clipboard handling: "xsel" and "pbcopy" can be slow lazy_clipboard = vim.opt.clipboard vim.opt.clipboard = "" diff --git a/lua/lazyvim/config/keymaps.lua b/lua/lazyvim/config/keymaps.lua index ea925448..946fee30 100644 --- a/lua/lazyvim/config/keymaps.lua +++ b/lua/lazyvim/config/keymaps.lua @@ -160,12 +160,12 @@ end if vim.fn.executable("lazygit") == 1 then map("n", "gg", function() Snacks.lazygit( { cwd = LazyVim.root.git() }) end, { desc = "Lazygit (Root Dir)" }) map("n", "gG", function() Snacks.lazygit() end, { desc = "Lazygit (cwd)" }) - map("n", "gf", function() Snacks.picker.git_log_file() end, { desc = "Git Current File History" }) - map("n", "gl", function() Snacks.picker.git_log({ cwd = LazyVim.root.git() }) end, { desc = "Git Log" }) - map("n", "gL", function() Snacks.picker.git_log() end, { desc = "Git Log (cwd)" }) end +map("n", "gL", function() Snacks.picker.git_log() end, { desc = "Git Log (cwd)" }) map("n", "gb", function() Snacks.picker.git_log_line() end, { desc = "Git Blame Line" }) +map("n", "gf", function() Snacks.picker.git_log_file() end, { desc = "Git Current File History" }) +map("n", "gl", function() Snacks.picker.git_log({ cwd = LazyVim.root.git() }) end, { desc = "Git Log" }) map({ "n", "x" }, "gB", function() Snacks.gitbrowse() end, { desc = "Git Browse (open)" }) map({"n", "x" }, "gY", function() Snacks.gitbrowse({ open = function(url) vim.fn.setreg("+", url) end, notify = false }) diff --git a/lua/lazyvim/plugins/extras/ai/copilot.lua b/lua/lazyvim/plugins/extras/ai/copilot.lua index 48870743..7c326499 100644 --- a/lua/lazyvim/plugins/extras/ai/copilot.lua +++ b/lua/lazyvim/plugins/extras/ai/copilot.lua @@ -98,15 +98,14 @@ return { { "saghen/blink.cmp", optional = true, - dependencies = { "giuxtaposition/blink-cmp-copilot" }, + dependencies = { "fang2hou/blink-copilot" }, opts = { sources = { default = { "copilot" }, providers = { copilot = { name = "copilot", - module = "blink-cmp-copilot", - kind = "Copilot", + module = "blink-copilot", score_offset = 100, async = true, }, diff --git a/lua/lazyvim/plugins/extras/coding/luasnip.lua b/lua/lazyvim/plugins/extras/coding/luasnip.lua index 85ed2fd5..5b62113e 100644 --- a/lua/lazyvim/plugins/extras/coding/luasnip.lua +++ b/lua/lazyvim/plugins/extras/coding/luasnip.lua @@ -1,6 +1,6 @@ return { -- disable builtin snippet support - { "garymjr/nvim-snippets", enabled = false }, + { "garymjr/nvim-snippets", optional = true, enabled = false }, -- add luasnip { diff --git a/lua/lazyvim/plugins/extras/coding/yanky.lua b/lua/lazyvim/plugins/extras/coding/yanky.lua index c880aceb..6285796d 100644 --- a/lua/lazyvim/plugins/extras/coding/yanky.lua +++ b/lua/lazyvim/plugins/extras/coding/yanky.lua @@ -13,6 +13,8 @@ return { function() if LazyVim.pick.picker.name == "telescope" then require("telescope").extensions.yank_history.yank_history({}) + elseif LazyVim.pick.picker.name == "snacks" then + Snacks.picker.yanky() else vim.cmd([[YankyRingHistory]]) end diff --git a/lua/lazyvim/plugins/extras/editor/fzf.lua b/lua/lazyvim/plugins/extras/editor/fzf.lua index 31297b94..9e7ef671 100644 --- a/lua/lazyvim/plugins/extras/editor/fzf.lua +++ b/lua/lazyvim/plugins/extras/editor/fzf.lua @@ -120,7 +120,7 @@ return { winopts = { layout = "vertical", -- height is number of items minus 15 lines for the preview, with a max of 80% screen height - height = math.floor(math.min(vim.o.lines * 0.8 - 16, #items + 2) + 0.5) + 16, + height = math.floor(math.min(vim.o.lines * 0.8 - 16, #items + 4) + 0.5) + 16, width = 0.5, preview = not vim.tbl_isempty(vim.lsp.get_clients({ bufnr = 0, name = "vtsls" })) and { layout = "vertical", @@ -135,7 +135,7 @@ return { winopts = { width = 0.5, -- height is number of items, with a max of 80% screen height - height = math.floor(math.min(vim.o.lines * 0.8, #items + 2) + 0.5), + height = math.floor(math.min(vim.o.lines * 0.8, #items + 4) + 0.5), }, }) end, diff --git a/lua/lazyvim/plugins/extras/lang/clojure.lua b/lua/lazyvim/plugins/extras/lang/clojure.lua index 7197aabd..c7af0b55 100644 --- a/lua/lazyvim/plugins/extras/lang/clojure.lua +++ b/lua/lazyvim/plugins/extras/lang/clojure.lua @@ -21,13 +21,13 @@ return { }, opts = function(_, opts) if type(opts.sources) == "table" then - vim.list_extend(opts.sources, { name = "clojure" }) + vim.list_extend(opts.sources, { name = "conjure" }) end end, }, -- Add s-exp mappings - { "PaterJason/nvim-treesitter-sexp", opts = {}, event = "LazyFile" }, + { "julienvincent/nvim-paredit", opts = {}, event = "LazyFile" }, -- Colorize the output of the log buffer { diff --git a/lua/lazyvim/plugins/extras/lang/typescript.lua b/lua/lazyvim/plugins/extras/lang/typescript.lua index 2307b04e..1db7cfc7 100644 --- a/lua/lazyvim/plugins/extras/lang/typescript.lua +++ b/lua/lazyvim/plugins/extras/lang/typescript.lua @@ -136,6 +136,28 @@ return { return true end, vtsls = function(_, opts) + if vim.lsp.config.denols and vim.lsp.config.vtsls then + ---@param server string + local resolve = function(server) + local markers, root_dir = vim.lsp.config[server].root_markers, vim.lsp.config[server].root_dir + vim.lsp.config(server, { + root_dir = function(bufnr, on_dir) + local is_deno = vim.fs.root(bufnr, { "deno.json", "deno.jsonc" }) ~= nil + if is_deno == (server == "denols") then + if root_dir then + return root_dir(bufnr, on_dir) + elseif type(markers) == "table" then + local root = vim.fs.root(bufnr, markers) + return root and on_dir(root) + end + end + end, + }) + end + resolve("denols") + resolve("vtsls") + end + LazyVim.lsp.on_attach(function(client, buffer) client.commands["_typescript.moveToFileRefactoring"] = function(command, ctx) ---@type string, string, lsp.Range diff --git a/lua/lazyvim/plugins/init.lua b/lua/lazyvim/plugins/init.lua index 4ba9b36d..80394371 100644 --- a/lua/lazyvim/plugins/init.lua +++ b/lua/lazyvim/plugins/init.lua @@ -1,23 +1,20 @@ -local fail = nil if vim.fn.has("nvim-0.11.2") == 0 then - fail = { + vim.api.nvim_echo({ { "LazyVim requires Neovim >= 0.11.2\n", "ErrorMsg" }, { "For more info, see: https://github.com/LazyVim/LazyVim/issues/6421\n", "Comment" }, { "Press any key to exit", "MoreMsg" }, - } -elseif vim.fn.has("nvim-0.12") == 1 and not vim.lsp.is_enabled then - fail = { - { "LazyVim requires Neovim >= 0.11.2 or a recent Nightly\n", "ErrorMsg" }, - { "Your nightly is too old, please update to a more recent version.\n", "Comment" }, - { "Press any key to exit", "MoreMsg" }, - } -end - -if fail then - vim.api.nvim_echo(fail, true, {}) + }, true, {}) vim.fn.getchar() vim.cmd([[quit]]) return {} +elseif not vim.lsp.is_enabled then + vim.schedule(function() + LazyVim.warn({ + "You're using an **old** `nightly` version of **Neovim**", + "Please update to a recent `nightly`,", + "or a stable version (`>= 0.11.2`).", + }) + end) end require("lazyvim.config").init() diff --git a/lua/lazyvim/plugins/lsp/init.lua b/lua/lazyvim/plugins/lsp/init.lua index bc6a7f46..4be74c82 100644 --- a/lua/lazyvim/plugins/lsp/init.lua +++ b/lua/lazyvim/plugins/lsp/init.lua @@ -68,7 +68,8 @@ return { timeout_ms = nil, }, -- LSP Server Settings - ---@type table + ---@alias lazyvim.lsp.Config vim.lsp.Config|{mason?:boolean, enabled?:boolean} + ---@type table servers = { lua_ls = { -- mason = false, -- set to false if you don't want this server to be installed with mason @@ -187,75 +188,38 @@ return { and vim.tbl_keys(require("mason-lspconfig.mappings").get_mason_map().lspconfig_to_package) or {} --[[ @as string[] ]] - local exclude_automatic_enable = {} ---@type string[] - + ---@return boolean? exclude automatic setup local function configure(server) - local server_opts = opts.servers[server] or {} - - local setup = opts.setup[server] or opts.setup["*"] - if setup and setup(server, server_opts) then - return true -- lsp will be setup by the setup function + local sopts = opts.servers[server] + sopts = sopts == true and {} or (not sopts) and { enabled = false } or sopts --[[@as lazyvim.lsp.Config]] + if sopts.enabled == false then + return true end - vim.lsp.config(server, server_opts) + local setup = opts.setup[server] or opts.setup["*"] + if setup and setup(server, sopts) then + return true -- lsp will be configured and enabled by the setup function + end + + vim.lsp.config(server, sopts) -- configure the server -- manually enable if mason=false or if this is a server that cannot be installed with mason-lspconfig - if server_opts.mason == false or not vim.tbl_contains(mason_all, server) then + if sopts.mason == false or not vim.tbl_contains(mason_all, server) then vim.lsp.enable(server) return true end - return false - end - - local ensure_installed = {} ---@type string[] - for server, server_opts in pairs(opts.servers) do - server_opts = server_opts == true and {} or server_opts or false - if server_opts and server_opts.enabled ~= false then - -- run manual setup if mason=false or if this is a server that cannot be installed with mason-lspconfig - if configure(server) then - exclude_automatic_enable[#exclude_automatic_enable + 1] = server - else - ensure_installed[#ensure_installed + 1] = server - end - else - exclude_automatic_enable[#exclude_automatic_enable + 1] = server - end end + local servers = vim.tbl_keys(opts.servers) + local exclude = vim.tbl_filter(configure, servers) if have_mason then require("mason-lspconfig").setup({ - ensure_installed = vim.tbl_deep_extend( - "force", - ensure_installed, - LazyVim.opts("mason-lspconfig.nvim").ensure_installed or {} - ), - automatic_enable = { - exclude = exclude_automatic_enable, - }, + ensure_installed = vim.tbl_filter(function(server) + return not vim.tbl_contains(exclude, server) + end, vim.list_extend(servers, LazyVim.opts("mason-lspconfig.nvim").ensure_installed or {})), + automatic_enable = { exclude = exclude }, }) end - - if vim.lsp.is_enabled("denols") and vim.lsp.is_enabled("vtsls") then - ---@param server string - local resolve = function(server) - local markers, root_dir = vim.lsp.config[server].root_markers, vim.lsp.config[server].root_dir - vim.lsp.config(server, { - root_dir = function(bufnr, on_dir) - local is_deno = vim.fs.root(bufnr, { "deno.json", "deno.jsonc" }) ~= nil - if is_deno == (server == "denols") then - if root_dir then - return root_dir(bufnr, on_dir) - elseif type(markers) == "table" then - local root = vim.fs.root(bufnr, markers) - return root and on_dir(root) - end - end - end, - }) - end - resolve("denols") - resolve("vtsls") - end end), }, diff --git a/lua/lazyvim/plugins/treesitter.lua b/lua/lazyvim/plugins/treesitter.lua index 751a72f3..8ad15924 100644 --- a/lua/lazyvim/plugins/treesitter.lua +++ b/lua/lazyvim/plugins/treesitter.lua @@ -58,6 +58,21 @@ return { config = function(_, opts) local TS = require("nvim-treesitter") + setmetatable(require("nvim-treesitter.install"), { + __newindex = function(_, k) + if k == "compilers" then + vim.schedule(function() + LazyVim.error({ + "Setting custom compilers for `nvim-treesitter` is no longer supported.", + "", + "For more info, see:", + "- [compilers](https://docs.rs/cc/latest/cc/#compile-time-requirements)", + }) + end) + end + end, + }) + -- some quick sanity checks if not TS.get_installed then return LazyVim.error("Please use `:Lazy` and update `nvim-treesitter`") @@ -94,12 +109,12 @@ return { end -- indents - if vim.tbl_get(opts, "indent", "enable") ~= false then + if vim.tbl_get(opts, "indent", "enable") ~= false and LazyVim.treesitter.have(ev.match, "indents") then LazyVim.set_default("indentexpr", "v:lua.LazyVim.treesitter.indentexpr()") end -- folds - if vim.tbl_get(opts, "folds", "enable") ~= false then + if vim.tbl_get(opts, "folds", "enable") ~= false and LazyVim.treesitter.have(ev.match, "folds") then if LazyVim.set_default("foldmethod", "expr") then LazyVim.set_default("foldexpr", "v:lua.LazyVim.treesitter.foldexpr()") end diff --git a/lua/lazyvim/util/init.lua b/lua/lazyvim/util/init.lua index ac3ffcec..812e6f22 100644 --- a/lua/lazyvim/util/init.lua +++ b/lua/lazyvim/util/init.lua @@ -317,11 +317,12 @@ local _defaults = {} ---@type table ---@return boolean was_set function M.set_default(option, value) local l = vim.api.nvim_get_option_value(option, { scope = "local" }) - local g = vim.api.nvim_get_option_value(option, { scope = "global" }) + local g = LazyVim.config._options[option] or vim.api.nvim_get_option_value(option, { scope = "global" }) _defaults[("%s=%s"):format(option, value)] = true local key = ("%s=%s"):format(option, l) + local source = "" if l ~= g and not _defaults[key] then -- Option does not match global and is not a default value -- Check if it was set by a script in $VIMRUNTIME @@ -330,11 +331,12 @@ function M.set_default(option, value) local scriptinfo = vim.tbl_filter(function(e) return e.sid == info.last_set_sid end, vim.fn.getscriptinfo()) + source = scriptinfo[1] and scriptinfo[1].name or "" local by_rtp = #scriptinfo == 1 and vim.startswith(scriptinfo[1].name, vim.fn.expand("$VIMRUNTIME")) if not by_rtp then if vim.g.lazyvim_debug_set_default then LazyVim.warn( - ("Not setting option `%s` to `%s` because it was changed by a filetype plugin."):format(option, value), + ("Not setting option `%s` to `%q` because it was changed by a plugin."):format(option, value), { title = "LazyVim", once = true } ) end @@ -343,7 +345,13 @@ function M.set_default(option, value) end if vim.g.lazyvim_debug_set_default then - LazyVim.info(("Setting option `%s` to `%s`"):format(option, value), { title = "LazyVim", once = true }) + LazyVim.info({ + ("Setting option `%s` to `%q`"):format(option, value), + ("Was: %q"):format(l), + ("Global: %q"):format(g), + source ~= "" and ("Last set by: %s"):format(source) or "", + "buf: " .. vim.api.nvim_buf_get_name(0), + }, { title = "LazyVim", once = true }) end vim.api.nvim_set_option_value(option, value, { scope = "local" }) diff --git a/lua/lazyvim/util/lualine.lua b/lua/lazyvim/util/lualine.lua index 5f4f1885..a6aa24f3 100644 --- a/lua/lazyvim/util/lualine.lua +++ b/lua/lazyvim/util/lualine.lua @@ -101,9 +101,20 @@ function M.pretty_path(opts) local root = LazyVim.root.get({ normalize = true }) local cwd = LazyVim.root.cwd() - if opts.relative == "cwd" and path:find(cwd, 1, true) == 1 then + -- original path is preserved to provide user with expected result of pretty_path, not a normalized one, + -- which might be confusing + local norm_path = path + + if LazyVim.is_win() then + -- in case any of the provided paths involved mixed case, an additional normalization step for windows + norm_path = norm_path:lower() + root = root:lower() + cwd = cwd:lower() + end + + if opts.relative == "cwd" and norm_path:find(cwd, 1, true) == 1 then path = path:sub(#cwd + 2) - elseif path:find(root, 1, true) == 1 then + elseif norm_path:find(root, 1, true) == 1 then path = path:sub(#root + 2) end diff --git a/lua/lazyvim/util/treesitter.lua b/lua/lazyvim/util/treesitter.lua index 5df6aa53..b1d647e8 100644 --- a/lua/lazyvim/util/treesitter.lua +++ b/lua/lazyvim/util/treesitter.lua @@ -1,36 +1,54 @@ ---@class lazyvim.util.treesitter local M = {} -M._installed = nil ---@type table? +M._installed = nil ---@type table? +M._queries = {} ---@type table ---@param update boolean? function M.get_installed(update) if update then - M._installed = {} + M._installed, M._queries = {}, {} for _, lang in ipairs(require("nvim-treesitter").get_installed("parsers")) do - M._installed[lang] = lang + M._installed[lang] = true end end return M._installed or {} end +---@param lang string +---@param query string +function M.have_query(lang, query) + local key = lang .. ":" .. query + if M._queries[key] == nil then + M._queries[key] = vim.treesitter.query.get(lang, query) ~= nil + end + return M._queries[key] +end + ---@param what string|number|nil +---@param query? string ---@overload fun(buf?:number):boolean ---@overload fun(ft:string):boolean ---@return boolean -function M.have(what) +function M.have(what, query) what = what or vim.api.nvim_get_current_buf() what = type(what) == "number" and vim.bo[what].filetype or what --[[@as string]] local lang = vim.treesitter.language.get_lang(what) - return lang ~= nil and M.get_installed()[lang] ~= nil + if lang == nil or M.get_installed()[lang] == nil then + return false + end + if query and not M.have_query(lang, query) then + return false + end + return true end function M.foldexpr() - return M.have() and vim.treesitter.foldexpr() or "0" + return M.have(nil, "folds") and vim.treesitter.foldexpr() or "0" end function M.indentexpr() - return M.have() and require("nvim-treesitter").indentexpr() or -1 + return M.have(nil, "indents") and require("nvim-treesitter").indentexpr() or -1 end ---@param cb fun()