Neovim中Null-ls+Prettierd执行vim.lsp.buf.formatting()报nil值错误求助
问题与解决方案
问题详情
在Neovim中配置Null-ls + Prettierd格式化TSX文件时,执行命令:lua vim.lsp.buf.formatting()会触发以下错误:
E5108: Error executing lua [string ":lua"]:1: attempt to call field 'formatting' (a nil value) stack traceback: [string ":lua"]:1: in main chunk
推测问题由tsserver与Null-ls的配置冲突导致,相关配置文件如下:
Null-ls配置
local status, null_ls = pcall(require, "null-ls") if not status then return end null_ls.setup({ sources = { null_ls.builtins.diagnostics.eslint.with({ diagnostics_format = "[eslint] #{m} (#{c})" }), null_ls.builtins.diagnostics.fish, null_ls.builtins.formatting.prettierd.with({ filetypes = { "css", "javascript", "javascriptreact", "typescript", "typescriptreact", "json", "scss", "less", "tsx" } }), }, attach = function(client, bufnr) vim.api.nvim_command("autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync(nil, 1000)") end, autostart = true, -- Set autostart to true })
LSP配置
local status, nvim_lsp = pcall(require, "lspconfig") if (not status) then return end local protocol = require('vim.lsp.protocol') local on_attach = function(client, bufnr) -- format on save if client.name == "tsserver" then client.resolved_capabilities.document_formatting = false end if client.resolved_capabilities.document_formatting then vim.api.nvim_create_autocmd("BufWritePre", { group = vim.api.nvim_create_augroup("Format", { clear = true }), buffer = bufnr, callback = function() vim.lsp.buf.formatting_sync(nil, 1000) end }) end end -- TypeScript nvim_lsp.tsserver.setup { on_attach = on_attach, filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "typescript.tsx", "jsx" }, cmd = { "typescript-language-server", "--stdio" } } require'lspconfig'.lua_ls.setup { settings = { Lua = { runtime = { -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) version = 'LuaJIT', }, diagnostics = { -- Get the language server to recognize the `vim` global globals = { 'vim' }, }, workspace = { -- Make the server aware of Neovim runtime files library = vim.api.nvim_get_runtime_file("", true), }, -- Do not send telemetry data containing a randomized but unique identifier telemetry = { enable = false, }, }, }, }
核心原因
- API已废弃:
vim.lsp.buf.formatting()和vim.lsp.buf.formatting_sync()是旧版Neovim LSP API,新版已被移除,替换为vim.lsp.buf.format() - 能力识别错误:旧版的
resolved_capabilities字段已被废弃,改用server_capabilities,导致格式化能力判断失效 - 配置冗余:Null-ls的
attach选项并非标准配置,重复创建自动命令可能引发冲突
修复步骤
1. 替换过时API
- 手动格式化命令改为:
:lua vim.lsp.buf.format() - 自动保存回调中的
vim.lsp.buf.formatting_sync(nil, 1000)替换为vim.lsp.buf.format({ timeout_ms = 1000, bufnr = bufnr })
2. 修正Null-ls配置
删除attach字段,让通用on_attach处理自动格式化:
local status, null_ls = pcall(require, "null-ls") if not status then return end null_ls.setup({ sources = { null_ls.builtins.diagnostics.eslint.with({ diagnostics_format = "[eslint] #{m} (#{c})" }), null_ls.builtins.diagnostics.fish, null_ls.builtins.formatting.prettierd.with({ filetypes = { "css", "javascript", "javascriptreact", "typescript", "typescriptreact", "json", "scss", "less", "tsx" } }), }, autostart = true, })
3. 优化LSP的on_attach函数
更新能力判断字段,统一自动格式化逻辑:
local status, nvim_lsp = pcall(require, "lspconfig") if (not status) then return end local protocol = require('vim.lsp.protocol') local on_attach = function(client, bufnr) -- 禁用tsserver的格式化能力,交给Null-ls处理 if client.name == "tsserver" then client.server_capabilities.documentFormattingProvider = false client.server_capabilities.documentRangeFormattingProvider = false end -- 自动保存时格式化 if client.server_capabilities.documentFormattingProvider then vim.api.nvim_create_autocmd("BufWritePre", { group = vim.api.nvim_create_augroup("Format", { clear = true }), buffer = bufnr, callback = function() vim.lsp.buf.format({ timeout_ms = 1000, bufnr = bufnr }) end }) end end -- TypeScript nvim_lsp.tsserver.setup { on_attach = on_attach, filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "jsx", "tsx" }, cmd = { "typescript-language-server", "--stdio" } } require'lspconfig'.lua_ls.setup { on_attach = on_attach, settings = { Lua = { runtime = { version = 'LuaJIT', }, diagnostics = { globals = { 'vim' }, }, workspace = { library = vim.api.nvim_get_runtime_file("", true), }, telemetry = { enable = false, }, }, }, }
4. 验证
重启Neovim,打开TSX文件:
- 执行
:lua vim.lsp.buf.format()测试手动格式化 - 修改文件后保存,检查是否自动触发格式化
内容的提问来源于stack exchange,提问作者Arya Lanjewar
相关产品推荐
相关产品推荐

