Neovim中LSP virtual_text异常:命令模式退出后符号重置
Neovim LSP虚拟文本符号重置问题修复
问题描述
在Neovim中配置LSP虚拟文本(virtual_text)后出现异常:进入命令模式再退出,自定义的虚拟文本前缀符号会恢复为默认样式。
系统环境
- LSB Version: n/a
- Distributor ID: Fedora
- Description: Fedora Linux 39 (Workstation Edition)
- Release: 39
- Codename: n/a
用户配置代码
---@diagnosticjdisable: undefined-global return { { "VonHeikemen/lsp-zero.nvim", branch = "v3.x", lazy = true, config = false, init = function() -- Disable automatic setup, we are doing it manually vim.g.lsp_zero_extend_cmp = 0 vim.g.lsp_zero_extend_lspconfig = 0 end, }, -- Autocompletion { "hrsh7th/nvim-cmp", event = "InsertEnter", dependencies = { { "L3MON4D3/LuaSnip", "rafamadriz/friendly-snippets", }, }, config = function() -- Herk is where you configure the autocompletion settings. local lsp_zero = require("lsp-zero") lsp_zero.extend_cmp() -- And you can configure cmp even more, if you want to. local cmp = require("cmp") local cmp_action = lsp_zero.cmp_action() -- for vscode snippets require('luasnip.loaders.from_vscode').lazy_load() cmp.setup({ formatting = lsp_zero.cmp_format({ details = true }), mapping = cmp.mapping.preset.insert({ ["<C-b>"] = cmp.mapping.scroll_docs(-4), ["<C-f>"] = cmp.mapping.scroll_docs(4), ["<C-Space>"] = cmp.mapping.complete(), ["<C-e>"] = cmp.mapping.abort(), ["<CR>"] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true, }), }), snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end, }, sources = cmp.config.sources({ { name = "copilot" }, { name = "nvim_lsp" }, { name = "luasnip" }, }, { { name = "buffer" }, }), }) end, }, -- LSP { "neovim/nvim-lspconfig", cmd = "LspInfo", event = { "BufReadPre", "BufNewFile" }, dependencies = { { "hrsh7th/cmp-nvim-lsp" }, }, config = function() -- This is where all the LSP shenanigans will live local lsp_zero = require("lsp-zero") lsp_zero.extend_lspconfig() lsp_zero.on_attach(function(client, bufnr) -- see :help lsp-zero-keybindings -- to learn the available actions lsp_zero.default_keymaps({ buffer = bufnr }) end) lsp_zero.on_attach(function(client, bufnr) lsp_zero.default_keymaps({ buffer = bufnr }) end) require("mason").setup({}) require("mason-lspconfig").setup({ -- Replace the language servers listed here -- with the ones you want to install ensure_installed = { "clangd", "rust_analyzer", "pyright", "tsserver", "html", "lua_ls", "ast_grep", "cssls", "gopls", }, handlers = { lsp_zero.default_setup, }, vim.diagnostic.config({ virtual_text = { prefix = "--", -- Could be '■', '▎', 'x' }, }), }) -- (Optional) Configure lua language server for neovim local lua_opts = lsp_zero.nvim_lua_ls() require("lspconfig").lua_ls.setup(lua_opts) lsp_zero.on_attach(function(client, bufnr) lsp_zero.default_keymaps({ buffer = bufnr }) end) lsp_zero.set_sign_icons({ error = "", warn = "", hint = "", info = "", }) end, }, }
问题原因
- 诊断配置位置错误:
vim.diagnostic.config被错误嵌套在mason-lspconfig.setup的参数表中,该位置的配置无法被正确执行,且LSP启动时会被默认配置覆盖。 - 重复绑定回调:多次调用
lsp_zero.on_attach导致回调重复注册,可能触发不必要的配置重置逻辑。
修复方案
- 将
vim.diagnostic.config从mason-lspconfig.setup中移出,单独调用以确保全局生效。 - 移除重复的
lsp_zero.on_attach绑定,仅保留一次即可。 - 确保诊断配置在LSP服务启动前完成设置,避免被后续操作覆盖。
修改后的配置代码
---@diagnostic disable: undefined-global return { { "VonHeikemen/lsp-zero.nvim", branch = "v3.x", lazy = true, config = false, init = function() -- Disable automatic setup, we are doing it manually vim.g.lsp_zero_extend_cmp = 0 vim.g.lsp_zero_extend_lspconfig = 0 end, }, -- Autocompletion { "hrsh7th/nvim-cmp", event = "InsertEnter", dependencies = { "L3MON4D3/LuaSnip", "rafamadriz/friendly-snippets", }, config = function() local lsp_zero = require("lsp-zero") lsp_zero.extend_cmp() local cmp = require("cmp") local cmp_action = lsp_zero.cmp_action() -- 加载vscode风格代码片段 require('luasnip.loaders.from_vscode').lazy_load() cmp.setup({ formatting = lsp_zero.cmp_format({ details = true }), mapping = cmp.mapping.preset.insert({ ["<C-b>"] = cmp.mapping.scroll_docs(-4), ["<C-f>"] = cmp.mapping.scroll_docs(4), ["<C-Space>"] = cmp.mapping.complete(), ["<C-e>"] = cmp.mapping.abort(), ["<CR>"] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true, }), }), snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end, }, sources = cmp.config.sources({ { name = "copilot" }, { name = "nvim_lsp" }, { name = "luasnip" }, }, { { name = "buffer" }, }), }) end, }, -- LSP { "neovim/nvim-lspconfig", cmd = "LspInfo", event = { "BufReadPre", "BufNewFile" }, dependencies = { "hrsh7th/cmp-nvim-lsp", }, config = function() local lsp_zero = require("lsp-zero") lsp_zero.extend_lspconfig() -- 仅绑定一次on_attach回调 lsp_zero.on_attach(function(client, bufnr) lsp_zero.default_keymaps({ buffer = bufnr }) end) require("mason").setup({}) require("mason-lspconfig").setup({ ensure_installed = { "clangd", "rust_analyzer", "pyright", "tsserver", "html", "lua_ls", "ast_grep", "cssls", "gopls", }, handlers = { lsp_zero.default_setup, }, }) -- 单独设置诊断配置,确保全局生效 vim.diagnostic.config({ virtual_text = { prefix = "--", -- 可替换为'■', '▎', 'x'等符号 }, }) -- 配置lua语言服务器 local lua_opts = lsp_zero.nvim_lua_ls() require("lspconfig").lua_ls.setup(lua_opts) lsp_zero.set_sign_icons({ error = "", warn = "", hint = "", info = "", }) end, }, }
额外优化
如果修改后问题仍存在,可在诊断配置中添加update_in_insert = false,避免插入模式下的配置干扰:
vim.diagnostic.config({ virtual_text = { prefix = "--", }, update_in_insert = false, })
内容的提问来源于stack exchange,提问作者Yossef Sabry
相关产品推荐
相关产品推荐

