You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,
      },
    },
  },
}

核心原因

  1. API已废弃:vim.lsp.buf.formatting()和vim.lsp.buf.formatting_sync()是旧版Neovim LSP API,新版已被移除,替换为vim.lsp.buf.format()
  2. 能力识别错误:旧版的resolved_capabilities字段已被废弃,改用server_capabilities,导致格式化能力判断失效
  3. 配置冗余: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:45:03