Merge branch 'main' into dev

This commit is contained in:
chuyanlong 2025-09-22 08:34:00 +08:00
commit 239b8ee18b
17 changed files with 160 additions and 97 deletions

View file

@ -1,3 +1,3 @@
{ {
".": "15.1.1" ".": "15.2.0"
} }

View file

@ -1,5 +1,24 @@
# Changelog # 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) ## [15.1.1](https://github.com/LazyVim/LazyVim/compare/v15.1.0...v15.1.1) (2025-09-18)

View file

@ -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* Table of Contents *LazyVim-table-of-contents*

View file

@ -3,7 +3,7 @@ _G.LazyVim = require("lazyvim.util")
---@class LazyVimConfig: LazyVimOptions ---@class LazyVimConfig: LazyVimOptions
local M = {} local M = {}
M.version = "15.1.1" -- x-release-please-version M.version = "15.2.0" -- x-release-please-version
LazyVim.config = M LazyVim.config = M
---@class LazyVimOptions ---@class LazyVimOptions
@ -304,6 +304,8 @@ function M.load(name)
end end
M.did_init = false M.did_init = false
M._options = {} ---@type vim.wo|vim.bo
function M.init() function M.init()
if M.did_init then if M.did_init then
return return
@ -326,6 +328,12 @@ function M.init()
-- 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
M.load("options") 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 -- defer built-in clipboard handling: "xsel" and "pbcopy" can be slow
lazy_clipboard = vim.opt.clipboard lazy_clipboard = vim.opt.clipboard
vim.opt.clipboard = "" vim.opt.clipboard = ""

View file

@ -160,12 +160,12 @@ end
if vim.fn.executable("lazygit") == 1 then if vim.fn.executable("lazygit") == 1 then
map("n", "<leader>gg", function() Snacks.lazygit( { cwd = LazyVim.root.git() }) end, { desc = "Lazygit (Root Dir)" }) map("n", "<leader>gg", function() Snacks.lazygit( { cwd = LazyVim.root.git() }) end, { desc = "Lazygit (Root Dir)" })
map("n", "<leader>gG", function() Snacks.lazygit() end, { desc = "Lazygit (cwd)" }) map("n", "<leader>gG", function() Snacks.lazygit() end, { desc = "Lazygit (cwd)" })
map("n", "<leader>gf", function() Snacks.picker.git_log_file() end, { desc = "Git Current File History" })
map("n", "<leader>gl", function() Snacks.picker.git_log({ cwd = LazyVim.root.git() }) end, { desc = "Git Log" })
map("n", "<leader>gL", function() Snacks.picker.git_log() end, { desc = "Git Log (cwd)" })
end end
map("n", "<leader>gL", function() Snacks.picker.git_log() end, { desc = "Git Log (cwd)" })
map("n", "<leader>gb", function() Snacks.picker.git_log_line() end, { desc = "Git Blame Line" }) map("n", "<leader>gb", function() Snacks.picker.git_log_line() end, { desc = "Git Blame Line" })
map("n", "<leader>gf", function() Snacks.picker.git_log_file() end, { desc = "Git Current File History" })
map("n", "<leader>gl", function() Snacks.picker.git_log({ cwd = LazyVim.root.git() }) end, { desc = "Git Log" })
map({ "n", "x" }, "<leader>gB", function() Snacks.gitbrowse() end, { desc = "Git Browse (open)" }) map({ "n", "x" }, "<leader>gB", function() Snacks.gitbrowse() end, { desc = "Git Browse (open)" })
map({"n", "x" }, "<leader>gY", function() map({"n", "x" }, "<leader>gY", function()
Snacks.gitbrowse({ open = function(url) vim.fn.setreg("+", url) end, notify = false }) Snacks.gitbrowse({ open = function(url) vim.fn.setreg("+", url) end, notify = false })

View file

@ -98,15 +98,14 @@ return {
{ {
"saghen/blink.cmp", "saghen/blink.cmp",
optional = true, optional = true,
dependencies = { "giuxtaposition/blink-cmp-copilot" }, dependencies = { "fang2hou/blink-copilot" },
opts = { opts = {
sources = { sources = {
default = { "copilot" }, default = { "copilot" },
providers = { providers = {
copilot = { copilot = {
name = "copilot", name = "copilot",
module = "blink-cmp-copilot", module = "blink-copilot",
kind = "Copilot",
score_offset = 100, score_offset = 100,
async = true, async = true,
}, },

View file

@ -1,6 +1,6 @@
return { return {
-- disable builtin snippet support -- disable builtin snippet support
{ "garymjr/nvim-snippets", enabled = false }, { "garymjr/nvim-snippets", optional = true, enabled = false },
-- add luasnip -- add luasnip
{ {

View file

@ -13,6 +13,8 @@ return {
function() function()
if LazyVim.pick.picker.name == "telescope" then if LazyVim.pick.picker.name == "telescope" then
require("telescope").extensions.yank_history.yank_history({}) require("telescope").extensions.yank_history.yank_history({})
elseif LazyVim.pick.picker.name == "snacks" then
Snacks.picker.yanky()
else else
vim.cmd([[YankyRingHistory]]) vim.cmd([[YankyRingHistory]])
end end

View file

@ -120,7 +120,7 @@ return {
winopts = { winopts = {
layout = "vertical", layout = "vertical",
-- height is number of items minus 15 lines for the preview, with a max of 80% screen height -- 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, width = 0.5,
preview = not vim.tbl_isempty(vim.lsp.get_clients({ bufnr = 0, name = "vtsls" })) and { preview = not vim.tbl_isempty(vim.lsp.get_clients({ bufnr = 0, name = "vtsls" })) and {
layout = "vertical", layout = "vertical",
@ -135,7 +135,7 @@ return {
winopts = { winopts = {
width = 0.5, width = 0.5,
-- height is number of items, with a max of 80% screen height -- 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, end,

View file

@ -21,13 +21,13 @@ return {
}, },
opts = function(_, opts) opts = function(_, opts)
if type(opts.sources) == "table" then if type(opts.sources) == "table" then
vim.list_extend(opts.sources, { name = "clojure" }) vim.list_extend(opts.sources, { name = "conjure" })
end end
end, end,
}, },
-- Add s-exp mappings -- Add s-exp mappings
{ "PaterJason/nvim-treesitter-sexp", opts = {}, event = "LazyFile" }, { "julienvincent/nvim-paredit", opts = {}, event = "LazyFile" },
-- Colorize the output of the log buffer -- Colorize the output of the log buffer
{ {

View file

@ -136,6 +136,28 @@ return {
return true return true
end, end,
vtsls = function(_, opts) 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) LazyVim.lsp.on_attach(function(client, buffer)
client.commands["_typescript.moveToFileRefactoring"] = function(command, ctx) client.commands["_typescript.moveToFileRefactoring"] = function(command, ctx)
---@type string, string, lsp.Range ---@type string, string, lsp.Range

View file

@ -1,23 +1,20 @@
local fail = nil
if vim.fn.has("nvim-0.11.2") == 0 then if vim.fn.has("nvim-0.11.2") == 0 then
fail = { vim.api.nvim_echo({
{ "LazyVim requires Neovim >= 0.11.2\n", "ErrorMsg" }, { "LazyVim requires Neovim >= 0.11.2\n", "ErrorMsg" },
{ "For more info, see: https://github.com/LazyVim/LazyVim/issues/6421\n", "Comment" }, { "For more info, see: https://github.com/LazyVim/LazyVim/issues/6421\n", "Comment" },
{ "Press any key to exit", "MoreMsg" }, { "Press any key to exit", "MoreMsg" },
} }, true, {})
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, {})
vim.fn.getchar() vim.fn.getchar()
vim.cmd([[quit]]) vim.cmd([[quit]])
return {} 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 end
require("lazyvim.config").init() require("lazyvim.config").init()

View file

@ -68,7 +68,8 @@ return {
timeout_ms = nil, timeout_ms = nil,
}, },
-- LSP Server Settings -- LSP Server Settings
---@type table<string, vim.lsp.Config|{mason?:boolean, enabled?:boolean}|boolean> ---@alias lazyvim.lsp.Config vim.lsp.Config|{mason?:boolean, enabled?:boolean}
---@type table<string, lazyvim.lsp.Config|boolean>
servers = { servers = {
lua_ls = { lua_ls = {
-- mason = false, -- set to false if you don't want this server to be installed with mason -- 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) and vim.tbl_keys(require("mason-lspconfig.mappings").get_mason_map().lspconfig_to_package)
or {} --[[ @as string[] ]] or {} --[[ @as string[] ]]
local exclude_automatic_enable = {} ---@type string[] ---@return boolean? exclude automatic setup
local function configure(server) local function configure(server)
local server_opts = opts.servers[server] or {} local sopts = opts.servers[server]
sopts = sopts == true and {} or (not sopts) and { enabled = false } or sopts --[[@as lazyvim.lsp.Config]]
local setup = opts.setup[server] or opts.setup["*"] if sopts.enabled == false then
if setup and setup(server, server_opts) then return true
return true -- lsp will be setup by the setup function
end 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 -- 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) vim.lsp.enable(server)
return true return true
end 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 end
local servers = vim.tbl_keys(opts.servers)
local exclude = vim.tbl_filter(configure, servers)
if have_mason then if have_mason then
require("mason-lspconfig").setup({ require("mason-lspconfig").setup({
ensure_installed = vim.tbl_deep_extend( ensure_installed = vim.tbl_filter(function(server)
"force", return not vim.tbl_contains(exclude, server)
ensure_installed, end, vim.list_extend(servers, LazyVim.opts("mason-lspconfig.nvim").ensure_installed or {})),
LazyVim.opts("mason-lspconfig.nvim").ensure_installed or {} automatic_enable = { exclude = exclude },
),
automatic_enable = {
exclude = exclude_automatic_enable,
},
}) })
end 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), end),
}, },

View file

@ -58,6 +58,21 @@ return {
config = function(_, opts) config = function(_, opts)
local TS = require("nvim-treesitter") 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 -- some quick sanity checks
if not TS.get_installed then if not TS.get_installed then
return LazyVim.error("Please use `:Lazy` and update `nvim-treesitter`") return LazyVim.error("Please use `:Lazy` and update `nvim-treesitter`")
@ -94,12 +109,12 @@ return {
end end
-- indents -- 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()") LazyVim.set_default("indentexpr", "v:lua.LazyVim.treesitter.indentexpr()")
end end
-- folds -- 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 if LazyVim.set_default("foldmethod", "expr") then
LazyVim.set_default("foldexpr", "v:lua.LazyVim.treesitter.foldexpr()") LazyVim.set_default("foldexpr", "v:lua.LazyVim.treesitter.foldexpr()")
end end

View file

@ -317,11 +317,12 @@ local _defaults = {} ---@type table<string, boolean>
---@return boolean was_set ---@return boolean was_set
function M.set_default(option, value) function M.set_default(option, value)
local l = vim.api.nvim_get_option_value(option, { scope = "local" }) 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 _defaults[("%s=%s"):format(option, value)] = true
local key = ("%s=%s"):format(option, l) local key = ("%s=%s"):format(option, l)
local source = ""
if l ~= g and not _defaults[key] then if l ~= g and not _defaults[key] then
-- Option does not match global and is not a default value -- Option does not match global and is not a default value
-- Check if it was set by a script in $VIMRUNTIME -- 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) local scriptinfo = vim.tbl_filter(function(e)
return e.sid == info.last_set_sid return e.sid == info.last_set_sid
end, vim.fn.getscriptinfo()) 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")) local by_rtp = #scriptinfo == 1 and vim.startswith(scriptinfo[1].name, vim.fn.expand("$VIMRUNTIME"))
if not by_rtp then if not by_rtp then
if vim.g.lazyvim_debug_set_default then if vim.g.lazyvim_debug_set_default then
LazyVim.warn( 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 } { title = "LazyVim", once = true }
) )
end end
@ -343,7 +345,13 @@ function M.set_default(option, value)
end end
if vim.g.lazyvim_debug_set_default then 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 end
vim.api.nvim_set_option_value(option, value, { scope = "local" }) vim.api.nvim_set_option_value(option, value, { scope = "local" })

View file

@ -101,9 +101,20 @@ function M.pretty_path(opts)
local root = LazyVim.root.get({ normalize = true }) local root = LazyVim.root.get({ normalize = true })
local cwd = LazyVim.root.cwd() 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) 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) path = path:sub(#root + 2)
end end

View file

@ -1,36 +1,54 @@
---@class lazyvim.util.treesitter ---@class lazyvim.util.treesitter
local M = {} local M = {}
M._installed = nil ---@type table<string,string>? M._installed = nil ---@type table<string,boolean>?
M._queries = {} ---@type table<string,boolean>
---@param update boolean? ---@param update boolean?
function M.get_installed(update) function M.get_installed(update)
if update then if update then
M._installed = {} M._installed, M._queries = {}, {}
for _, lang in ipairs(require("nvim-treesitter").get_installed("parsers")) do for _, lang in ipairs(require("nvim-treesitter").get_installed("parsers")) do
M._installed[lang] = lang M._installed[lang] = true
end end
end end
return M._installed or {} return M._installed or {}
end 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 what string|number|nil
---@param query? string
---@overload fun(buf?:number):boolean ---@overload fun(buf?:number):boolean
---@overload fun(ft:string):boolean ---@overload fun(ft:string):boolean
---@return boolean ---@return boolean
function M.have(what) function M.have(what, query)
what = what or vim.api.nvim_get_current_buf() what = what or vim.api.nvim_get_current_buf()
what = type(what) == "number" and vim.bo[what].filetype or what --[[@as string]] what = type(what) == "number" and vim.bo[what].filetype or what --[[@as string]]
local lang = vim.treesitter.language.get_lang(what) 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 end
function M.foldexpr() function M.foldexpr()
return M.have() and vim.treesitter.foldexpr() or "0" return M.have(nil, "folds") and vim.treesitter.foldexpr() or "0"
end end
function M.indentexpr() 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 end
---@param cb fun() ---@param cb fun()