conform.nvim icon indicating copy to clipboard operation
conform.nvim copied to clipboard

bug: Assigning formatters to `*` breaks formatexpr fallback

Open fredrikfoss opened this issue 5 months ago • 1 comments

Setting a formatter for * breaks the formatexpr fallback. For example, if I set formatexpr to v:lua.require'conform'.formatexpr(), have no formatter set for LANG, and * set to use injected, only the injected formatter will run when formatting with gq. It will not fall back to use the LSP formatter or integrated formatter, as it otherwise would had I not allocated a formatter to *.

Example:

vim.o.formatexpr = "v:lua.require'conform'.formatexpr()"

require("conform").setup({
  formatters_by_ft = {
    ["*"] = { "injected" },
  },
})

vim.lsp.enable("lua_ls")

In the above example, the Lua language server will no longer format with gq. Only the injected formatter will run.

Somewhat related, when setting ["_"] = { "FORMATTER", lsp_format = "prefer" }, the lsp_format option seems to have no effect when using formatexpr. Only FORMATTER is run, and the running language server is ignored.

Reproduce

local root = vim.fn.fnamemodify("./.repro", ":p")

for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "--single-branch",
    "https://github.com/folke/lazy.nvim.git",
    lazypath,
  })
end
vim.opt.runtimepath:prepend(lazypath)

local plugins = {
  "folke/tokyonight.nvim",
  {
    "stevearc/conform.nvim",
    config = function()
      require("conform").setup({
        log_level = vim.log.levels.DEBUG,

        -- Use injected for all files
        formatters_by_ft = {
          ["*"] = { "injected" },
        },
      })
    end,
  },

  -- mason and mason-tool-installer for installing the Lua language server
  {
    "mason-org/mason.nvim",
    config = function()
      require("mason").setup()
    end,
  },
  {
    "WhoIsSethDaniel/mason-tool-installer.nvim",
    config = function()
      require("mason-tool-installer").setup({
        ensure_installed = {
          "lua-language-server",
        },
      })
    end,
  },

  -- nvim-lspconfig for the Lua language server config
  "neovim/nvim-lspconfig",
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")

-- Set formatexpr to use Conform
vim.o.formatexpr = "v:lua.require'conform'.formatexpr()"

-- Enable Lua language server
vim.lsp.enable("lua_ls")

Open a Lua file, type gggqG in normal mode to format the file. Notice how the file isn't being formatted. What I expected was for the Lua file to be formatted by the running language server.

fredrikfoss avatar Jul 16 '25 16:07 fredrikfoss

I think I'm running into the same issue, where I have a fallback in my config of ['_'] = { 'trim_whitespace' } and at some point after f9ef25a7ef00267b7d13bfc00b0dea22d78702d5 (this commit doesn't have the issue) the lsp_format = 'fallback' option stopped triggering the lsp formatter (lsp_format = 'last' does trigger it though)

rynoV avatar Sep 01 '25 04:09 rynoV