conform.nvim
conform.nvim copied to clipboard
Mason support
I'm wondering if there is any plan to integrate with mason, such integration would allow auto-downloading of formatters depending on which ones the user has registered. Unsure how much work this would entail or if such feature is better of in a separate plugin.
Edit:
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
My interest in this is pretty low, as I don't use mason. I'm not sure exactly what this would entail, but from skimming the docs it seems like you would just need a list of mason packages. If someone wants to do this, I think the way would be to add a new optional mason_package
field to the metadata of formatters, and then plumb that through to the FormatterInfo
object. Then it would be pretty easy to get your list of mason packages from the list_all_formatters()
API.
auto-downloading of formatters depending on which ones the user has registered
I'm using WhoIsSethDaniel/mason-tool-installer.nvim to do that.
auto-downloading of formatters depending on which ones the user has registered
I'm using WhoIsSethDaniel/mason-tool-installer.nvim to do that.
Have you manually specified the formatters to download, or is there a convenient way to fetch the ones that have been registered with the plugin?
Have you manually specified the formatters to download or is there a convenient way to fetch the ones that have been registered with the plugin?
Yes, I set them manually in ensure_installed
(mason-tool-installer
) and also in formatters_by_ft
(conform
). I don't think there's another way to specify the formatters only once for both plug-ins (hence your original request).
I mentioned mason-tool-installer
because you talked about auto-downloading formatters. Very useful plug-in in my opinion.
I don't mind setting all my tools in both plug-ins personally, it's pretty much "set-and-forget", unless you often add/remove LSP/linters/formatters (which isn't my case).
@xfzv @zapling I have written a small function that takes the formatters_by_ft
from conform.nvim and turns them into a list that mason-tool-installer
can use. That way, I only have to specify any formatter in one location.
https://github.com/chrisgrieser/.config/blob/7dc36c350976010b32ece078edd581687634811a/nvim/lua/plugins/linter-formatter.lua#L27-L82 https://github.com/chrisgrieser/.config/blob/7dc36c350976010b32ece078edd581687634811a/nvim/lua/plugins/linter-formatter.lua#L214-L234
This would be really amazing, manually installing these tools is really annoying and errorprone
I have thus far used this snippet, although it might not be the most compatible with each formatter:
local mason_reg = require "mason-registry"
local formatters = {}
local formatters_by_ft = {}
for _, pkg in pairs(mason_reg.get_installed_packages()) do
for _, type in pairs(pkg.spec.categories) do
-- only act upon a formatter
if type == "Formatter" then
-- if formatter doesn't have a builtin config, create our own from a generic template
if not require "conform".get_formatter_config(pkg.spec.name) then
-- the key of the entry to this table
-- is the name of the bare executable
-- the actual value may not be the absolute path
-- in some cases
local bin = next(pkg.spec.bin)
-- this should be replaced by a function
-- that quieries the configured mason install path
local prefix = vim.fn.stdpath("data") .. "/mason/bin/"
formatters[pkg.spec.name] = {
command = prefix .. bin,
args = { "$FILENAME" },
stdin = true,
require_cwd = false
}
end
-- finally add the formatter to it's compatible filetype(s)
for _, ft in pairs(pkg.spec.languages) do
local ftl = string.lower(ft)
formatters_by_ft[ftl] = formatters_by_ft[ftl] or {}
table.insert(formatters_by_ft[ftl], pkg.spec.name)
end
end
end
end
return {
format_on_save = {
lsp_fallback = true,
timeout_ms = 500
},
formatters = formatters,
formatters_by_ft = formatters_by_ft
}
Although in some cases, some formatters tend to overwrite recent changes, like commenting something out for example. This mostly happens with formatters that didn't have a builtin configuration, as such I would assume that there is some issue with the configuration that I am providing.
Another thing to point out is the fact that using the prefix
variable before bin
might not be necessary, if mason.nvim is configured to append/prepend the formatter to the PATH
I think a solution that is simple to implement on conform.nvim's side, yet still useful for users, would be to expose a function that simply returns a list of all CLIs that conform.nvim requires. Basically everything listed in formatters_by_ft
, minus the special formatters like trim_whitespace
.
If conform.nvim had such a function, users like us could feed the list to a mason-tools-installer. Would also solve the "only need to list a CLI once" problem, and also make the config of everyone using mason + conform.nvim much cleaner.
Mason already has ensure_installed
. Whenever I want to add a new formatter, I add it to that table first.
ensure_installed
This is part of the mason-lspconfig
package and is not able to install formatters to my knowledge.
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
This is awesome! Takes a few steps away instead of using mason-tool-installer. Thank you.
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
Very nice, works like a charm 👏
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
Awesome, works perfectly!
I do the inverse. I created a table that is the source of truth of everything that needs an installed package. Everything else on my config relies on this table. This allows me to just use mason.nvim, mason-tools-installer.nvim and nothing else, not even mason-lspconfig.nvim.
tools.lua
tools_by_filetype = {
javascript = {
formatters = { "prettierd" },
linters = { "eslint_d" },
dap = { "js-debug-adapter" },
lsp = { "typescript-language-server" }
},
python = { ... }
}
Then I can easily use this on plugins:
---On nvim-lint
config = function()
...linters_by_ft = {
javascript = tools_by_filetype.javascript.linters, -- is { "eslint_d" }
python = { tools_by_filetype.python.linters }, -- is { { "mypy", "pylint" } }
}
---On conform.nvim
config = function()
...formatters_by_ft = {
javascript = tools_by_filetype.javascript.formatters, -- is { "prettierd", "eslint_d" }
typescript = { tools_by_filetype.javascript.formatters }, -- is { { "prettierd", "eslint_d" } }
---On mason-tools-installer.nvim
config = function()
....ensure_installed = some_utility_function(tools_by_filetype)
---On nvim-lspconfig
config = function()
....for _, server in ipairs(some_utility_function(tools_by_filetype, "LSP")) do
lspconfig[server].setup({
...
This has been working fine for me. I just needed to create 2 utility functions and copy the nvim-lspconfig mappings from here: mason-lspconfig mappings
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
This is awesome, thank you. And yes I was very wrong.
What if there's a formatter that is already installed system-wide? for example, what if I installed prettier not using Mason? In that case I'll add it to the conform config, but this does not need to be downloaded. Will mason-conform.nvim still try to download it?
I have created a mason-conform.nvim plugin that detects the formatters registered with conform and automatically downloads them via mason. I added a conform to mason mapping for all the formatters I could find in the mason registry, I might have missed something but feel free to create a PR if that's the case.
This is awesome, thank you. And yes I was very wrong.
What if there's a formatter that is already installed system-wide? for example, what if I installed prettier not using Mason? In that case I'll add it to the conform config, but this does not need to be downloaded. Will mason-conform.nvim still try to download it?
Right now there is no such functionality implemented. Feel free to open a ticket for it and I'll get to it when I have time.
this is my mapping config just do MasonInstall, ready to use
return {
"stevearc/conform.nvim",
event = { "BufReadPre", "BufNewFile" },
opts = function()
local mason_reg = require("mason-registry")
local formatters = {}
local formatters_by_ft = {}
-- add diff langue vs filetype
local keymap = {
["c++"] = "cpp",
["c#"] = "cs",
}
-- add dif conform vs mason
local name_map = {
["cmakelang"] = "cmake_format",
["deno"] = "deno_fmt",
["elm-format"] = "elm_format",
["gdtoolkit"] = "gdformat",
["nixpkgs-fmt"] = "nixpkgs_fmt",
["opa"] = "opa_fmt",
["php-cs-fixer"] = "php_cs_fixer",
["ruff"] = "ruff_format",
["sql-formatter"] = "sql_formatter",
["xmlformatter"] = "xmlformat",
}
for _, pkg in pairs(mason_reg.get_installed_packages()) do
for _, type in pairs(pkg.spec.categories) do
-- only act upon a formatter
if type == "Formatter" then
-- if formatter doesn't have a builtin config, create our own from a generic template
if not require("conform").get_formatter_config(pkg.spec.name) then
-- the key of the entry to this table
-- is the name of the bare executable
-- the actual value may not be the absolute path
-- in some cases
local bin = next(pkg.spec.bin)
-- this should be replaced by a function
-- that quieries the configured mason install path
local prefix = vim.fn.stdpath("data") .. "/mason/bin/"
formatters[pkg.spec.name] = {
command = prefix .. bin,
args = { "$FILENAME" },
stdin = true,
require_cwd = false,
}
end
-- finally add the formatter to it's compatible filetype(s)
for _, ft in pairs(pkg.spec.languages) do
local ftl = string.lower(ft)
local ready = mason_reg.get_package(pkg.spec.name):is_installed()
if ready then
if keymap[ftl] ~= nil then
ftl = keymap[ftl]
end
if name_map[pkg.spec.name] ~= nil then
pkg.spec.name = name_map[pkg.spec.name]
end
formatters_by_ft[ftl] = formatters_by_ft[ftl] or {}
table.insert(formatters_by_ft[ftl], pkg.spec.name)
end
end
end
end
end
return {
format_on_save = {
lsp_fallback = true,
timeout_ms = 500,
},
formatters = formatters,
formatters_by_ft = formatters_by_ft,
}
end,
config = function(_, opts)
local conform = require("conform")
conform.setup(opts)
vim.keymap.set({ "n", "v" }, "<leader>lF", function()
conform.format({
lsp_fallback = true,
async = false,
timeout_ms = 500,
})
end, { desc = "Format file or range (in visual mode)" })
end,
}