diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | doc/conform.txt | 73 | ||||
-rw-r--r-- | lua/conform/formatters/injected.lua | 20 | ||||
-rw-r--r-- | lua/conform/init.lua | 34 | ||||
-rw-r--r-- | lua/conform/types.lua | 9 |
5 files changed, 85 insertions, 52 deletions
@@ -609,6 +609,7 @@ Format a buffer | | | > `"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 | +| | stop_after_first | `nil\|boolean` | Only run the first available formatter in the list. Defaults to false. | | | 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 002e46c..589289b 100644 --- a/doc/conform.txt +++ b/doc/conform.txt @@ -132,11 +132,12 @@ setup({opts}) *conform.setu This can also be a function that returns the table. {default_format_opts} `nil|conform.DefaultFormatOpts` The default options to use when calling conform.format() - {timeout_ms} `nil|integer` Time in milliseconds to block for - formatting. Defaults to 1000. No effect if async = - true. - {lsp_format} `nil|conform.LspFormatOpts` Configure if and when LSP - should be used for formatting. Defaults to "never". + {timeout_ms} `nil|integer` Time in milliseconds to block for + formatting. Defaults to 1000. No effect if + async = 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 @@ -145,8 +146,10 @@ setup({opts}) *conform.setu 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. + {quiet} `nil|boolean` Don't show any notifications for + warnings or failures. Defaults to false. + {stop_after_first} `nil|boolean` Only run the first available + formatter in the list. Defaults to false. {format_after_save} `nil|conform.FormatOpts|fun(bufnr: integer): nil|conform.FormatOpts` If this is set, Conform will run the formatter asynchronously after save. It will pass the table @@ -166,20 +169,23 @@ format({opts}, {callback}): boolean *conform.forma Parameters: {opts} `nil|conform.FormatOpts` - {timeout_ms} `nil|integer` Time in milliseconds to block for - formatting. Defaults to 1000. No effect if async = true. - {bufnr} `nil|integer` Format this buffer (default 0) - {async} `nil|boolean` If true the method won't block. Defaults to - false. If the buffer is modified before the formatter - completes, the formatting will be discarded. - {dry_run} `nil|boolean` If true don't apply formatting changes to - the 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". + {timeout_ms} `nil|integer` Time in milliseconds to block for + formatting. Defaults to 1000. No effect if async = + true. + {bufnr} `nil|integer` Format this buffer (default 0) + {async} `nil|boolean` If true the method won't block. + Defaults to false. If the buffer is modified before + the formatter completes, the formatting will be + discarded. + {dry_run} `nil|boolean` If true don't apply formatting + changes to the 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 @@ -188,19 +194,22 @@ format({opts}, {callback}): boolean *conform.forma 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 + {stop_after_first} `nil|boolean` Only run the first available + formatter in the list. Defaults to false. + {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 {start} `integer[]` {end} `integer[]` - {id} `nil|integer` Passed to |vim.lsp.buf.format| when using - LSP formatting - {name} `nil|string` Passed to |vim.lsp.buf.format| when using - LSP formatting - {filter} `nil|fun(client: table): boolean` Passed to - |vim.lsp.buf.format| when using LSP formatting + {id} `nil|integer` Passed to |vim.lsp.buf.format| when + using LSP formatting + {name} `nil|string` Passed to |vim.lsp.buf.format| when + using LSP formatting + {filter} `nil|fun(client: table): boolean` Passed to |vim.ls + p.buf.format| when using LSP formatting {callback} `nil|fun(err: nil|string, did_edit: nil|boolean)` Called once formatting has completed Returns: diff --git a/lua/conform/formatters/injected.lua b/lua/conform/formatters/injected.lua index 4dbf1eb..6cfd387 100644 --- a/lua/conform/formatters/injected.lua +++ b/lua/conform/formatters/injected.lua @@ -284,13 +284,21 @@ return { ---@type string[] local formatter_names if type(ft_formatters) == "function" then - formatter_names = ft_formatters(ctx.buf) - else - local formatters = require("conform").resolve_formatters(ft_formatters, ctx.buf, false) - formatter_names = vim.tbl_map(function(f) - return f.name - end, formatters) + ft_formatters = ft_formatters(ctx.buf) end + local stop_after_first = ft_formatters.stop_after_first + if stop_after_first == nil then + stop_after_first = conform.default_format_opts.stop_after_first + end + if stop_after_first == nil then + stop_after_first = false + end + + local formatters = + conform.resolve_formatters(ft_formatters, ctx.buf, false, stop_after_first) + formatter_names = vim.tbl_map(function(f) + return f.name + end, formatters) local idx = num_format log.debug("Injected format %s:%d:%d: %s", lang, start_lnum, end_lnum, formatter_names) log.trace("Injected format lines %s", input_lines) diff --git a/lua/conform/init.lua b/lua/conform/init.lua index acd8c8c..208edc7 100644 --- a/lua/conform/init.lua +++ b/lua/conform/init.lua @@ -198,7 +198,7 @@ end ---@private ---@param bufnr? integer ----@return conform.FiletypeFormatterInternal[] +---@return string[] M.list_formatters_for_buffer = function(bufnr) if not bufnr or bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() @@ -301,8 +301,9 @@ end ---@param names conform.FiletypeFormatterInternal ---@param bufnr integer ---@param warn_on_missing boolean +---@param stop_after_first boolean ---@return conform.FormatterInfo[] -M.resolve_formatters = function(names, bufnr, warn_on_missing) +M.resolve_formatters = function(names, bufnr, warn_on_missing, stop_after_first) local all_info = {} local function add_info(info, warn) if info.available then @@ -329,6 +330,10 @@ M.resolve_formatters = function(names, bufnr, warn_on_missing) end end end + + if stop_after_first and #all_info > 0 then + break + end end return all_info end @@ -353,7 +358,6 @@ end ---@param callback? fun(err: nil|string, did_edit: nil|boolean) Called once formatting has completed ---@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 = opts or {} local has_explicit_formatters = opts ~= nil and opts.formatters ~= nil if not has_explicit_formatters then @@ -361,6 +365,7 @@ M.format = function(opts, callback) end opts = vim.tbl_extend("keep", opts, M.default_format_opts) + ---@type {timeout_ms: integer, bufnr: integer, async: boolean, dry_run: boolean, lsp_format: "never"|"first"|"last"|"prefer"|"fallback", quiet: boolean, stop_after_first: boolean, formatters?: string[], range?: conform.Range, undojoin: boolean} opts = vim.tbl_extend("keep", opts, { timeout_ms = 1000, bufnr = 0, @@ -369,6 +374,7 @@ M.format = function(opts, callback) lsp_format = "never", quiet = false, undojoin = false, + stop_after_first = false, }) -- For backwards compatibility @@ -394,8 +400,12 @@ M.format = function(opts, callback) local runner = require("conform.runner") 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 has_explicit_formatters) + local formatters = M.resolve_formatters( + formatter_names, + opts.bufnr, + not opts.quiet and has_explicit_formatters, + opts.stop_after_first + ) local has_lsp = has_lsp_formatter(opts) ---@param err? conform.Error @@ -483,12 +493,6 @@ M.format = function(opts, callback) end end ----@class conform.FormatLinesOpts ----@field timeout_ms nil|integer Time in milliseconds to block for formatting. Defaults to 1000. No effect if async = true. ----@field bufnr nil|integer use this as the working buffer (default 0) ----@field async nil|boolean If true the method won't block. Defaults to false. If the buffer is modified before the formatter completes, the formatting will be discarded. ----@field quiet nil|boolean Don't show any notifications for warnings or failures. Defaults to false. - ---Process lines with formatters ---@private ---@param formatter_names string[] @@ -498,18 +502,20 @@ end ---@return nil|conform.Error error Only present if async = false ---@return nil|string[] new_lines Only present if async = false M.format_lines = function(formatter_names, lines, opts, callback) - ---@type {timeout_ms: integer, bufnr: integer, async: boolean, quiet: boolean} + ---@type {timeout_ms: integer, bufnr: integer, async: boolean, quiet: boolean, stop_after_first: boolean} opts = vim.tbl_extend("keep", opts or {}, { timeout_ms = 1000, bufnr = 0, async = false, quiet = false, + stop_after_first = false, }) callback = callback or function(_err, _lines) end local errors = require("conform.errors") local log = require("conform.log") local runner = require("conform.runner") - local formatters = M.resolve_formatters(formatter_names, opts.bufnr, not opts.quiet) + local formatters = + M.resolve_formatters(formatter_names, opts.bufnr, not opts.quiet, opts.stop_after_first) if vim.tbl_isempty(formatters) then callback(nil, lines) return @@ -545,7 +551,7 @@ M.list_formatters = function(bufnr) bufnr = vim.api.nvim_get_current_buf() end local formatters = M.list_formatters_for_buffer(bufnr) - return M.resolve_formatters(formatters, bufnr, false) + return M.resolve_formatters(formatters, bufnr, false, false) end ---List information about all filetype-configured formatters diff --git a/lua/conform/types.lua b/lua/conform/types.lua index 2f051ca..9b775a9 100644 --- a/lua/conform/types.lua +++ b/lua/conform/types.lua @@ -79,6 +79,7 @@ ---@field undojoin? boolean Use undojoin to merge formatting changes with previous edit (default false) ---@field formatters? string[] List of formatters to run. Defaults to all formatters for the buffer filetype. ---@field lsp_format? conform.LspFormatOpts Configure if and when LSP should be used for formatting. Defaults to "never". +---@field stop_after_first? boolean Only run the first available formatter in the list. Defaults to false. ---@field quiet? boolean Don't show any notifications for warnings or failures. Defaults to false. ---@field range? 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 ---@field id? integer Passed to |vim.lsp.buf.format| when using LSP formatting @@ -89,6 +90,14 @@ ---@field timeout_ms? integer Time in milliseconds to block for formatting. Defaults to 1000. No effect if async = true. ---@field lsp_format? conform.LspFormatOpts Configure if and when LSP should be used for formatting. Defaults to "never". ---@field quiet? boolean Don't show any notifications for warnings or failures. Defaults to false. +---@field stop_after_first? boolean Only run the first available formatter in the list. Defaults to false. + +---@class conform.FormatLinesOpts +---@field timeout_ms? integer Time in milliseconds to block for formatting. Defaults to 1000. No effect if async = true. +---@field bufnr? integer use this as the working buffer (default 0) +---@field async? boolean If true the method won't block. Defaults to false. If the buffer is modified before the formatter completes, the formatting will be discarded. +---@field quiet? boolean Don't show any notifications for warnings or failures. Defaults to false. +---@field stop_after_first? boolean Only run the first available formatter in the list. Defaults to false. ---@class (exact) conform.setupOpts ---@field formatters_by_ft? table<string, conform.FiletypeFormatter> Map of filetype to formatters |