diff options
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | doc/conform.txt | 18 | ||||
-rw-r--r-- | doc/recipes.md | 4 | ||||
-rw-r--r-- | lua/conform/health.lua | 10 | ||||
-rw-r--r-- | lua/conform/init.lua | 61 | ||||
-rw-r--r-- | lua/conform/types.lua | 9 | ||||
-rw-r--r-- | scripts/options_doc.lua | 2 |
7 files changed, 73 insertions, 38 deletions
@@ -459,6 +459,8 @@ require("conform").setup({ go = { "goimports", "gofmt" }, -- Use a sub-list to run only the first available formatter javascript = { { "prettierd", "prettier" } }, + -- You can also customize some of the format options for the filetype + rust = { "rustfmt", lsp_format = "fallback" }, -- You can use a function here to determine the formatters dynamically python = function(bufnr) if require("conform").get_formatter_info("ruff_format", bufnr).available then @@ -602,6 +604,11 @@ Format a buffer | | undojoin | `nil\|boolean` | Use undojoin to merge formatting changes with previous edit (default false) | | | formatters | `nil\|string[]` | List of formatters to run. Defaults to all formatters for the buffer filetype. | | | lsp_format | `nil\|conform.LspFormatOpts` | Configure if and when LSP should be used for formatting. Defaults to "never". | +| | | > `"never"` | never use the LSP for formatting (default) | +| | | > `"fallback"` | LSP formatting is used when no other formatters are available | +| | | > `"prefer"` | use only LSP formatting when available | +| | | > `"first"` | LSP formatting is used when available and then other formatters | +| | | > `"last"` | other formatters are used then LSP formatting when available | | | quiet | `nil\|boolean` | Don't show any notifications for warnings or failures. Defaults to false. | | | range | `nil\|conform.Range` | Range to format. Table must contain `start` and `end` keys with {row, col} tuples using (1,0) indexing. Defaults to current selection in visual mode | | | id | `nil\|integer` | Passed to vim.lsp.buf.format when using LSP formatting | diff --git a/doc/conform.txt b/doc/conform.txt index 32baf86..002e46c 100644 --- a/doc/conform.txt +++ b/doc/conform.txt @@ -19,6 +19,8 @@ OPTIONS *conform-option go = { "goimports", "gofmt" }, -- Use a sub-list to run only the first available formatter javascript = { { "prettierd", "prettier" } }, + -- You can also customize some of the format options for the filetype + rust = { "rustfmt", lsp_format = "fallback" }, -- You can use a function here to determine the formatters dynamically python = function(bufnr) if require("conform").get_formatter_info("ruff_format", bufnr).available then @@ -135,6 +137,14 @@ setup({opts}) *conform.setu true. {lsp_format} `nil|conform.LspFormatOpts` Configure if and when LSP should be used for formatting. Defaults to "never". + `"never"` never use the LSP for formatting (default) + `"fallback"` LSP formatting is used when no other formatters + are available + `"prefer"` use only LSP formatting when available + `"first"` LSP formatting is used when available and then + other formatters + `"last"` other formatters are used then LSP formatting + when available {quiet} `nil|boolean` Don't show any notifications for warnings or failures. Defaults to false. {format_after_save} `nil|conform.FormatOpts|fun(bufnr: integer): nil|conform.FormatOpts` @@ -170,6 +180,14 @@ format({opts}, {callback}): boolean *conform.forma formatters for the buffer filetype. {lsp_format} `nil|conform.LspFormatOpts` Configure if and when LSP should be used for formatting. Defaults to "never". + `"never"` never use the LSP for formatting (default) + `"fallback"` LSP formatting is used when no other formatters are + available + `"prefer"` use only LSP formatting when available + `"first"` LSP formatting is used when available and then other + formatters + `"last"` other formatters are used then LSP formatting when + available {quiet} `nil|boolean` Don't show any notifications for warnings or failures. Defaults to false. {range} `nil|conform.Range` Range to format. Table must contain diff --git a/doc/recipes.md b/doc/recipes.md index f5d6f99..45c1e07 100644 --- a/doc/recipes.md +++ b/doc/recipes.md @@ -155,7 +155,9 @@ return { desc = "Format buffer", }, }, - -- Everything in opts will be passed to setup() + -- This will provide type hinting with LuaLS + ---@module "conform" + ---@type conform.setupOpts opts = { -- Define your formatters formatters_by_ft = { diff --git a/lua/conform/health.lua b/lua/conform/health.lua index 3ee7567..d0bfca1 100644 --- a/lua/conform/health.lua +++ b/lua/conform/health.lua @@ -16,14 +16,6 @@ local function get_formatter_filetypes(name) for filetype, formatters in pairs(conform.formatters_by_ft) do if type(formatters) == "function" then formatters = formatters(0) - -- support the old structure where formatters could be a subkey - elseif not islist(formatters) then - vim.notify_once( - "Using deprecated structure for formatters_by_ft. See :help conform-options for details.", - vim.log.levels.ERROR - ) - ---@diagnostic disable-next-line: undefined-field - formatters = formatters.formatters end for _, ft_name in ipairs(formatters) do @@ -61,7 +53,7 @@ M.check = function() end end ----@param formatters conform.FormatterUnit[] +---@param formatters conform.FiletypeFormatterInternal ---@return string[] local function flatten_formatters(formatters) local flat = {} diff --git a/lua/conform/init.lua b/lua/conform/init.lua index 91ec1bd..acd8c8c 100644 --- a/lua/conform/init.lua +++ b/lua/conform/init.lua @@ -198,7 +198,7 @@ end ---@private ---@param bufnr? integer ----@return conform.FormatterUnit[] +---@return conform.FiletypeFormatterInternal[] M.list_formatters_for_buffer = function(bufnr) if not bufnr or bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() @@ -233,16 +233,6 @@ M.list_formatters_for_buffer = function(bufnr) if type(ft_formatters) == "function" then dedupe_formatters(ft_formatters(bufnr), formatters) else - -- support the old structure where formatters could be a subkey - if not islist(ft_formatters) then - vim.notify_once( - "Using deprecated structure for formatters_by_ft. See :help conform-options for details.", - vim.log.levels.ERROR - ) - ---@diagnostic disable-next-line: undefined-field - ft_formatters = ft_formatters.formatters - end - dedupe_formatters(ft_formatters, formatters) end end @@ -251,6 +241,31 @@ M.list_formatters_for_buffer = function(bufnr) return formatters end +---@param bufnr? integer +---@return nil|conform.DefaultFormatOpts +local function get_opts_from_filetype(bufnr) + if not bufnr or bufnr == 0 then + bufnr = vim.api.nvim_get_current_buf() + end + local matching_filetype = get_matching_filetype(bufnr) + if not matching_filetype then + return nil + end + + local ft_formatters = M.formatters_by_ft[matching_filetype] + assert(ft_formatters ~= nil, "get_matching_filetype ensures formatters_by_ft has key") + if type(ft_formatters) == "function" then + ft_formatters = ft_formatters(bufnr) + end + local ret = {} + for k, v in pairs(ft_formatters) do + if type(k) == "string" then + ret[k] = v + end + end + return ret +end + ---@param bufnr integer ---@param mode "v"|"V" ---@return table {start={row,col}, end={row,col}} using (1, 0) indexing @@ -283,7 +298,7 @@ local function range_from_selection(bufnr, mode) end ---@private ----@param names conform.FormatterUnit[] +---@param names conform.FiletypeFormatterInternal ---@param bufnr integer ---@param warn_on_missing boolean ---@return conform.FormatterInfo[] @@ -339,7 +354,13 @@ end ---@return boolean True if any formatters were attempted M.format = function(opts, callback) ---@type {timeout_ms: integer, bufnr: integer, async: boolean, dry_run: boolean, lsp_format: "never"|"first"|"last"|"prefer"|"fallback", quiet: boolean, formatters?: string[], range?: conform.Range, undojoin: boolean} - opts = vim.tbl_extend("keep", opts or {}, M.default_format_opts) + opts = opts or {} + local has_explicit_formatters = opts ~= nil and opts.formatters ~= nil + if not has_explicit_formatters then + opts = vim.tbl_extend("keep", opts, get_opts_from_filetype(opts.bufnr)) + end + + opts = vim.tbl_extend("keep", opts, M.default_format_opts) opts = vim.tbl_extend("keep", opts, { timeout_ms = 1000, bufnr = 0, @@ -372,10 +393,9 @@ M.format = function(opts, callback) local lsp_format = require("conform.lsp_format") local runner = require("conform.runner") - local explicit_formatters = opts.formatters ~= nil local formatter_names = opts.formatters or M.list_formatters_for_buffer(opts.bufnr) local formatters = - M.resolve_formatters(formatter_names, opts.bufnr, not opts.quiet and explicit_formatters) + M.resolve_formatters(formatter_names, opts.bufnr, not opts.quiet and has_explicit_formatters) local has_lsp = has_lsp_formatter(opts) ---@param err? conform.Error @@ -456,7 +476,7 @@ M.format = function(opts, callback) run_cli_formatters(handle_result) return true else - local level = explicit_formatters and "warn" or "debug" + local level = has_explicit_formatters and "warn" or "debug" log[level]("No formatters found for %s", vim.api.nvim_buf_get_name(opts.bufnr)) callback("No formatters found for buffer") return false @@ -536,15 +556,6 @@ M.list_all_formatters = function() if type(ft_formatters) == "function" then ft_formatters = ft_formatters(0) end - -- support the old structure where formatters could be a subkey - if not islist(ft_formatters) then - vim.notify_once( - "Using deprecated structure for formatters_by_ft. See :help conform-options for details.", - vim.log.levels.ERROR - ) - ---@diagnostic disable-next-line: undefined-field - ft_formatters = ft_formatters.formatters - end for _, formatter in ipairs(ft_formatters) do if type(formatter) == "table" then diff --git a/lua/conform/types.lua b/lua/conform/types.lua index 1f1beee..2f051ca 100644 --- a/lua/conform/types.lua +++ b/lua/conform/types.lua @@ -58,9 +58,12 @@ ---@field start integer[] ---@field end integer[] ----@alias conform.FormatterUnit string|string[] ----@alias conform.FiletypeFormatter conform.FormatterUnit[]|fun(bufnr: integer): string[] ---- +---@alias conform.FiletypeFormatter conform.FiletypeFormatterInternal|fun(bufnr: integer): conform.FiletypeFormatterInternal + +---This list of formatters to run for a filetype, an any associated format options. +---@class conform.FiletypeFormatterInternal : conform.DefaultFormatOpts +---@field [integer] string|string[] + ---@alias conform.LspFormatOpts ---| '"never"' # never use the LSP for formatting (default) ---| '"fallback"' # LSP formatting is used when no other formatters are available diff --git a/scripts/options_doc.lua b/scripts/options_doc.lua index d47c832..c6d8457 100644 --- a/scripts/options_doc.lua +++ b/scripts/options_doc.lua @@ -6,6 +6,8 @@ require("conform").setup({ go = { "goimports", "gofmt" }, -- Use a sub-list to run only the first available formatter javascript = { { "prettierd", "prettier" } }, + -- You can also customize some of the format options for the filetype + rust = { "rustfmt", lsp_format = "fallback" }, -- You can use a function here to determine the formatters dynamically python = function(bufnr) if require("conform").get_formatter_info("ruff_format", bufnr).available then |