aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Arcangeli <506791+stevearc@users.noreply.github.com>2023-09-08 11:57:05 -0700
committerGitHub <noreply@github.com>2023-09-08 11:57:05 -0700
commita72f0fe173ea1506cf0d2bf97007876cb07f3ae4 (patch)
tree2ce7ba9fb405a42e0d7138cf32d2fde69b703eed
parent1bd3c1bffc6b5cdba83264f3be5bb1d282c13707 (diff)
parent2178a4fe3f16ef4780cc0a6bc45da07cd0f92798 (diff)
Merge pull request #33 from stevearc/stevearc-refactor
New config syntax for "run first" vs "run all"
-rw-r--r--README.md63
-rw-r--r--doc/conform.txt33
-rw-r--r--lua/conform/health.lua92
-rw-r--r--lua/conform/init.lua178
-rw-r--r--scripts/options_doc.lua18
-rw-r--r--tests/api_spec.lua98
6 files changed, 323 insertions, 159 deletions
diff --git a/README.md b/README.md
index fa3c907..86cef63 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ Lightweight yet powerful formatter plugin for Neovim
- [format(opts, callback)](#formatopts-callback)
- [list_formatters(bufnr)](#list_formattersbufnr)
- [list_all_formatters()](#list_all_formatters)
+ - [get_formatter_info(formatter, bufnr)](#get_formatter_infoformatter-bufnr)
- [Acknowledgements](#acknowledgements)
<!-- /TOC -->
@@ -109,14 +110,10 @@ At a minimum, you will need to set up some formatters by filetype
require("conform").setup({
formatters_by_ft = {
lua = { "stylua" },
- -- Conform will use the first available formatter in the list
- javascript = { "prettier_d", "prettier" },
- -- Formatters can also be specified with additional options
- python = {
- formatters = { "isort", "black" },
- -- Run formatters one after another instead of stopping at the first success
- run_all_formatters = true,
- },
+ -- Conform will run multiple formatters sequentially
+ python = { "isort", "black" },
+ -- Use a sub-list to run only the first available formatter
+ javascript = { { "prettierd", "prettier" } },
},
})
```
@@ -213,16 +210,14 @@ require("conform").setup({
-- Map of filetype to formatters
formatters_by_ft = {
lua = { "stylua" },
- -- Conform will use the first available formatter in the list
- javascript = { "prettierd", "prettier" },
- -- Formatters can also be specified with additional options
- python = {
- formatters = { "isort", "black" },
- -- Run formatters one after another instead of stopping at the first success
- run_all_formatters = true,
- -- Don't run these formatters as part of the format_on_save autocmd (see below)
- format_on_save = false,
- },
+ -- Conform will run multiple formatters sequentially
+ python = { "isort", "black" },
+ -- Use a sub-list to run only the first available formatter
+ javascript = { { "prettierd", "prettier" } },
+ -- Use the "*" filetype to run formatters on all files.
+ -- Note that if you use this, you may want to set lsp_fallback = "always"
+ -- (see :help conform.format)
+ ["*"] = { "trim_whitespace" },
},
-- If this is set, Conform will run the formatter on save.
-- It will pass the table to conform.format().
@@ -359,17 +354,17 @@ vim.api.nvim_create_autocmd("BufWritePost", {
`format(opts, callback): boolean` \
Format a buffer
-| Param | Type | Desc | |
-| -------- | ---------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
-| opts | `nil\|table` | | |
-| | 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. |
-| | formatters | `nil\|string[]` | List of formatters to run. Defaults to all formatters for the buffer filetype. |
-| | lsp_fallback | `nil\|boolean` | Attempt LSP formatting if no formatters are available. Defaults to false. |
-| | quiet | `nil\|boolean` | Don't show any notifications for warnings or failures. Defaults to false. |
-| | range | `nil\|table` | 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 |
-| callback | `nil\|fun(err: nil\|string)` | Called once formatting has completed | |
+| Param | Type | Desc | |
+| -------- | ---------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| opts | `nil\|table` | | |
+| | 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. |
+| | formatters | `nil\|string[]` | List of formatters to run. Defaults to all formatters for the buffer filetype. |
+| | lsp_fallback | `nil\|boolean\|"always"` | Attempt LSP formatting if no formatters are available. Defaults to false. If "always", will attempt LSP formatting even if formatters are available (useful if you set formatters for the "*" filetype) |
+| | quiet | `nil\|boolean` | Don't show any notifications for warnings or failures. Defaults to false. |
+| | range | `nil\|table` | 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 |
+| callback | `nil\|fun(err: nil\|string)` | Called once formatting has completed | |
Returns:
@@ -391,6 +386,16 @@ Retrieve the available formatters for a buffer
`list_all_formatters(): conform.FormatterInfo[]` \
List information about all filetype-configured formatters
+
+### get_formatter_info(formatter, bufnr)
+
+`get_formatter_info(formatter, bufnr): conform.FormatterInfo` \
+Get information about a formatter (including availability)
+
+| Param | Type | Desc |
+| --------- | -------------- | ------------------------- |
+| formatter | `string` | The name of the formatter |
+| bufnr | `nil\|integer` | |
<!-- /API -->
## Acknowledgements
diff --git a/doc/conform.txt b/doc/conform.txt
index 46c971f..149db88 100644
--- a/doc/conform.txt
+++ b/doc/conform.txt
@@ -16,16 +16,14 @@ OPTIONS *conform-option
-- Map of filetype to formatters
formatters_by_ft = {
lua = { "stylua" },
- -- Conform will use the first available formatter in the list
- javascript = { "prettierd", "prettier" },
- -- Formatters can also be specified with additional options
- python = {
- formatters = { "isort", "black" },
- -- Run formatters one after another instead of stopping at the first success
- run_all_formatters = true,
- -- Don't run these formatters as part of the format_on_save autocmd (see below)
- format_on_save = false,
- },
+ -- Conform will run multiple formatters sequentially
+ python = { "isort", "black" },
+ -- Use a sub-list to run only the first available formatter
+ javascript = { { "prettierd", "prettier" } },
+ -- Use the "*" filetype to run formatters on all files.
+ -- Note that if you use this, you may want to set lsp_fallback = "always"
+ -- (see :help conform.format)
+ ["*"] = { "trim_whitespace" },
},
-- If this is set, Conform will run the formatter on save.
-- It will pass the table to conform.format().
@@ -101,8 +99,11 @@ format({opts}, {callback}): boolean *conform.forma
to false.
{formatters} `nil|string[]` List of formatters to run. Defaults to
all formatters for the buffer filetype.
- {lsp_fallback} `nil|boolean` Attempt LSP formatting if no formatters
- are available. Defaults to false.
+ {lsp_fallback} `nil|boolean|"always"` Attempt LSP formatting if no
+ formatters are available. Defaults to false. If
+ "always", will attempt LSP formatting even if
+ formatters are available (useful if you set formatters
+ for the "*" filetype)
{quiet} `nil|boolean` Don't show any notifications for warnings
or failures. Defaults to false.
{range} `nil|table` Range to format. Table must contain `start`
@@ -121,6 +122,14 @@ list_formatters({bufnr}): conform.FormatterInfo[] *conform.list_formatter
list_all_formatters(): conform.FormatterInfo[] *conform.list_all_formatters*
List information about all filetype-configured formatters
+
+get_formatter_info({formatter}, {bufnr}): conform.FormatterInfo *conform.get_formatter_info*
+ Get information about a formatter (including availability)
+
+ Parameters:
+ {formatter} `string` The name of the formatter
+ {bufnr} `nil|integer`
+
--------------------------------------------------------------------------------
FORMATTERS *conform-formatters*
diff --git a/lua/conform/health.lua b/lua/conform/health.lua
index d36ef03..18085bf 100644
--- a/lua/conform/health.lua
+++ b/lua/conform/health.lua
@@ -6,11 +6,24 @@ local function get_formatter_filetypes(name)
local conform = require("conform")
local filetypes = {}
for filetype, formatters in pairs(conform.formatters_by_ft) do
+ -- support the old structure where formatters could be a subkey
if not vim.tbl_islist(formatters) then
+ ---@diagnostic disable-next-line: undefined-field
formatters = formatters.formatters
end
- if vim.tbl_contains(formatters, name) then
- table.insert(filetypes, filetype)
+
+ for _, ft_name in ipairs(formatters) do
+ if type(ft_name) == "string" then
+ if ft_name == name then
+ table.insert(filetypes, filetype)
+ break
+ end
+ else
+ if vim.tbl_contains(ft_name, name) then
+ table.insert(filetypes, filetype)
+ break
+ end
+ end
end
end
return filetypes
@@ -38,6 +51,22 @@ M.check = function()
end
end
+---@param formatters conform.FormatterUnit[]
+---@return string[]
+local function flatten_formatters(formatters)
+ local flat = {}
+ for _, name in ipairs(formatters) do
+ if type(name) == "string" then
+ table.insert(flat, name)
+ else
+ for _, f in ipairs(flatten_formatters(name)) do
+ table.insert(flat, f)
+ end
+ end
+ end
+ return flat
+end
+
M.show_window = function()
local conform = require("conform")
local lines = {}
@@ -60,35 +89,43 @@ M.show_window = function()
end
table.insert(lines, "")
- ---@param formatters conform.FormatterInfo[]
+ ---@param formatter conform.FormatterInfo
+ local function append_formatter_info(formatter)
+ if not formatter.available then
+ local line = string.format("%s unavailable: %s", formatter.name, formatter.available_msg)
+ table.insert(lines, line)
+ table.insert(
+ highlights,
+ { "DiagnosticWarn", #lines, formatter.name:len(), formatter.name:len() + 12 }
+ )
+ else
+ local filetypes = get_formatter_filetypes(formatter.name)
+ local line = string.format("%s ready (%s)", formatter.name, table.concat(filetypes, ", "))
+ table.insert(lines, line)
+ table.insert(
+ highlights,
+ { "DiagnosticInfo", #lines, formatter.name:len(), formatter.name:len() + 6 }
+ )
+ end
+ end
+
+ local seen = {}
+ ---@param formatters string[]
local function append_formatters(formatters)
- for _, formatter in ipairs(formatters) do
- if not formatter.available then
- local line = string.format("%s unavailable: %s", formatter.name, formatter.available_msg)
- table.insert(lines, line)
- table.insert(
- highlights,
- { "DiagnosticWarn", #lines, formatter.name:len(), formatter.name:len() + 12 }
- )
+ for _, name in ipairs(formatters) do
+ if type(name) == "table" then
+ append_formatters(name)
else
- local filetypes = get_formatter_filetypes(formatter.name)
- local line = string.format("%s ready (%s)", formatter.name, table.concat(filetypes, ", "))
- table.insert(lines, line)
- table.insert(
- highlights,
- { "DiagnosticInfo", #lines, formatter.name:len(), formatter.name:len() + 6 }
- )
+ seen[name] = true
+ local formatter = conform.get_formatter_info(name)
+ append_formatter_info(formatter)
end
end
end
table.insert(lines, "Formatters for this buffer:")
table.insert(highlights, { "Title", #lines, 0, -1 })
- local seen = {}
- local buf_formatters = conform.list_formatters_for_buffer()
- for _, formatter in ipairs(buf_formatters) do
- seen[formatter.name] = true
- end
+ local buf_formatters = flatten_formatters(conform.list_formatters_for_buffer())
append_formatters(buf_formatters)
if vim.tbl_isempty(buf_formatters) then
table.insert(lines, "<none>")
@@ -97,10 +134,11 @@ M.show_window = function()
table.insert(lines, "")
table.insert(lines, "Other formatters:")
table.insert(highlights, { "Title", #lines, 0, -1 })
- local all_formatters = vim.tbl_filter(function(f)
- return not seen[f.name]
- end, conform.list_all_formatters())
- append_formatters(all_formatters)
+ for _, formatter in ipairs(conform.list_all_formatters()) do
+ if not seen[formatter.name] then
+ append_formatter_info(formatter)
+ end
+ end
local bufnr = vim.api.nvim_create_buf(false, true)
local winid = vim.api.nvim_open_win(bufnr, true, {
diff --git a/lua/conform/init.lua b/lua/conform/init.lua
index b0222e8..9f844b1 100644
--- a/lua/conform/init.lua
+++ b/lua/conform/init.lua
@@ -38,13 +38,9 @@ local M = {}
---@field start integer[]
---@field end integer[]
----@class (exact) conform.RunOptions
----@field run_all_formatters nil|boolean Run all listed formatters instead of stopping at the first one.
+---@alias conform.FormatterUnit string|string[]
----@class (exact) conform.FormatterList : conform.RunOptions
----@field formatters string[]
-
----@type table<string, string[]|conform.FormatterList>
+---@type table<string, conform.FormatterUnit[]>
M.formatters_by_ft = {}
---@type table<string, conform.FormatterConfig|fun(bufnr: integer): nil|conform.FormatterConfig>
@@ -103,64 +99,46 @@ end
---@private
---@param bufnr? integer
----@return conform.FormatterInfo[]
----@return conform.RunOptions
+---@return conform.FormatterUnit[]
M.list_formatters_for_buffer = function(bufnr)
if not bufnr or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
end
local formatters = {}
local seen = {}
- local run_options = {
- run_all_formatters = false,
- format_on_save = true,
- }
local filetypes = vim.split(vim.bo[bufnr].filetype, ".", { plain = true })
+
+ local function dedupe_formatters(names, collect)
+ for _, name in ipairs(names) do
+ if type(name) == "table" then
+ local alternation = {}
+ dedupe_formatters(name, alternation)
+ if not vim.tbl_isempty(alternation) then
+ table.insert(collect, alternation)
+ end
+ elseif not seen[name] then
+ table.insert(collect, name)
+ seen[name] = true
+ end
+ end
+ end
+
table.insert(filetypes, "*")
for _, filetype in ipairs(filetypes) do
+ ---@type conform.FormatterUnit[]
local ft_formatters = M.formatters_by_ft[filetype]
if ft_formatters then
+ -- support the old structure where formatters could be a subkey
if not vim.tbl_islist(ft_formatters) then
- for k, v in pairs(ft_formatters) do
- if k ~= "formatters" then
- run_options[k] = v
- end
- end
+ ---@diagnostic disable-next-line: undefined-field
ft_formatters = ft_formatters.formatters
end
- for _, formatter in ipairs(ft_formatters) do
- if not seen[formatter] then
- table.insert(formatters, formatter)
- seen[formatter] = true
- end
- end
- end
- end
-
- ---@type conform.FormatterInfo[]
- local all_info = vim.tbl_map(function(f)
- return M.get_formatter_info(f, bufnr)
- end, formatters)
- return all_info, run_options
-end
-
----@param formatters conform.FormatterInfo[]
----@param run_options conform.RunOptions
----@return conform.FormatterInfo[]
-local function filter_formatters(formatters, run_options)
- ---@type conform.FormatterInfo[]
- local all_info = {}
- for _, info in ipairs(formatters) do
- if info.available then
- table.insert(all_info, info)
- if not run_options.run_all_formatters then
- break
- end
+ dedupe_formatters(ft_formatters, formatters)
end
end
- return all_info
+ return formatters
end
---@param bufnr integer
@@ -194,19 +172,54 @@ local function range_from_selection(bufnr, mode)
}
end
+---@param names conform.FormatterUnit[]
+---@param bufnr integer
+---@param warn_on_missing boolean
+---@return conform.FormatterInfo[]
+local function resolve_formatters(names, bufnr, warn_on_missing)
+ local all_info = {}
+ local function add_info(info, warn)
+ if info.available then
+ table.insert(all_info, info)
+ elseif warn then
+ vim.notify(
+ string.format("Formatter '%s' unavailable: %s", info.name, info.available_msg),
+ vim.log.levels.WARN
+ )
+ end
+ return info.available
+ end
+
+ for _, name in ipairs(names) do
+ if type(name) == "string" then
+ local info = M.get_formatter_info(name, bufnr)
+ add_info(info, warn_on_missing)
+ else
+ -- If this is an alternation, take the first one that's available
+ for i, v in ipairs(name) do
+ local info = M.get_formatter_info(v, bufnr)
+ if add_info(info, i == #name) then
+ break
+ end
+ end
+ end
+ end
+ return all_info
+end
+
---Format a buffer
---@param opts? table
--- 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.
--- formatters nil|string[] List of formatters to run. Defaults to all formatters for the buffer filetype.
---- lsp_fallback nil|boolean Attempt LSP formatting if no formatters are available. Defaults to false.
+--- lsp_fallback nil|boolean|"always" Attempt LSP formatting if no formatters are available. Defaults to false. If "always", will attempt LSP formatting even if formatters are available (useful if you set formatters for the "*" filetype)
--- quiet nil|boolean Don't show any notifications for warnings or failures. Defaults to false.
--- range nil|table 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
---@param callback? fun(err: nil|string) 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, lsp_fallback: boolean, quiet: boolean, formatters?: string[], range?: conform.Range}
+ ---@type {timeout_ms: integer, bufnr: integer, async: boolean, lsp_fallback: boolean|"always", quiet: boolean, formatters?: string[], range?: conform.Range}
opts = vim.tbl_extend("keep", opts or {}, {
timeout_ms = 1000,
bufnr = 0,
@@ -219,35 +232,15 @@ M.format = function(opts, callback)
local lsp_format = require("conform.lsp_format")
local runner = require("conform.runner")
- local formatters = {}
- local any_formatters_configured
- if opts.formatters then
- any_formatters_configured = true
- for _, formatter in ipairs(opts.formatters) do
- local info = M.get_formatter_info(formatter)
- if info.available then
- table.insert(formatters, info)
- else
- if opts.quiet then
- log.warn("Formatter '%s' unavailable: %s", info.name, info.available_msg)
- else
- vim.notify(
- string.format("Formatter '%s' unavailable: %s", info.name, info.available_msg),
- vim.log.levels.WARN
- )
- end
- end
- end
- else
- local run_info
- formatters, run_info = M.list_formatters_for_buffer(opts.bufnr)
- any_formatters_configured = not vim.tbl_isempty(formatters)
- formatters = filter_formatters(formatters, run_info)
- end
- local formatter_names = vim.tbl_map(function(f)
+ local formatter_names = opts.formatters or M.list_formatters_for_buffer(opts.bufnr)
+ local any_formatters_configured = formatter_names ~= nil and not vim.tbl_isempty(formatter_names)
+ local formatters =
+ resolve_formatters(formatter_names, opts.bufnr, not opts.quiet and opts.formatters ~= nil)
+
+ local resolved_names = vim.tbl_map(function(f)
return f.name
end, formatters)
- log.debug("Running formatters on %s: %s", vim.api.nvim_buf_get_name(opts.bufnr), formatter_names)
+ log.debug("Running formatters on %s: %s", vim.api.nvim_buf_get_name(opts.bufnr), resolved_names)
local any_formatters = not vim.tbl_isempty(formatters)
if any_formatters then
@@ -276,7 +269,18 @@ M.format = function(opts, callback)
if not err_message and not vim.api.nvim_buf_is_valid(opts.bufnr) then
err_message = "buffer was deleted"
end
- callback(err_message)
+ if err_message then
+ return callback(err_message)
+ end
+
+ if
+ opts.lsp_fallback == "always" and not vim.tbl_isempty(lsp_format.get_format_clients(opts))
+ then
+ log.debug("Running LSP formatter on %s", vim.api.nvim_buf_get_name(opts.bufnr))
+ lsp_format.format(opts, callback)
+ else
+ callback()
+ end
end
if opts.async then
@@ -303,8 +307,11 @@ end
---@param bufnr? integer
---@return conform.FormatterInfo[]
M.list_formatters = function(bufnr)
- local formatters, run_options = M.list_formatters_for_buffer(bufnr)
- return filter_formatters(formatters, run_options)
+ if not bufnr or bufnr == 0 then
+ bufnr = vim.api.nvim_get_current_buf()
+ end
+ local formatters = M.list_formatters_for_buffer(bufnr)
+ return resolve_formatters(formatters, bufnr, false)
end
---List information about all filetype-configured formatters
@@ -312,11 +319,20 @@ end
M.list_all_formatters = function()
local formatters = {}
for _, ft_formatters in pairs(M.formatters_by_ft) do
+ -- support the old structure where formatters could be a subkey
if not vim.tbl_islist(ft_formatters) then
+ ---@diagnostic disable-next-line: undefined-field
ft_formatters = ft_formatters.formatters
end
+
for _, formatter in ipairs(ft_formatters) do
- formatters[formatter] = true
+ if type(formatter) == "table" then
+ for _, v in ipairs(formatter) do
+ formatters[v] = true
+ end
+ else
+ formatters[formatter] = true
+ end
end
end
@@ -360,8 +376,8 @@ M.get_formatter_config = function(formatter, bufnr)
return config
end
----@private
----@param formatter string
+---Get information about a formatter (including availability)
+---@param formatter string The name of the formatter
---@param bufnr? integer
---@return conform.FormatterInfo
M.get_formatter_info = function(formatter, bufnr)
diff --git a/scripts/options_doc.lua b/scripts/options_doc.lua
index a501e38..1a6921c 100644
--- a/scripts/options_doc.lua
+++ b/scripts/options_doc.lua
@@ -2,16 +2,14 @@ require("conform").setup({
-- Map of filetype to formatters
formatters_by_ft = {
lua = { "stylua" },
- -- Conform will use the first available formatter in the list
- javascript = { "prettierd", "prettier" },
- -- Formatters can also be specified with additional options
- python = {
- formatters = { "isort", "black" },
- -- Run formatters one after another instead of stopping at the first success
- run_all_formatters = true,
- -- Don't run these formatters as part of the format_on_save autocmd (see below)
- format_on_save = false,
- },
+ -- Conform will run multiple formatters sequentially
+ python = { "isort", "black" },
+ -- Use a sub-list to run only the first available formatter
+ javascript = { { "prettierd", "prettier" } },
+ -- Use the "*" filetype to run formatters on all files.
+ -- Note that if you use this, you may want to set lsp_fallback = "always"
+ -- (see :help conform.format)
+ ["*"] = { "trim_whitespace" },
},
-- If this is set, Conform will run the formatter on save.
-- It will pass the table to conform.format().
diff --git a/tests/api_spec.lua b/tests/api_spec.lua
new file mode 100644
index 0000000..b59f367
--- /dev/null
+++ b/tests/api_spec.lua
@@ -0,0 +1,98 @@
+require("plenary.async").tests.add_to_env()
+local test_util = require("tests.test_util")
+local conform = require("conform")
+
+describe("api", function()
+ after_each(function()
+ test_util.reset_editor()
+ end)
+
+ it("retrieves info about a formatter", function()
+ local info = conform.get_formatter_info("stylua")
+ assert.equal("stylua", info.name)
+ assert.equal("stylua", info.command)
+ assert.equal("boolean", type(info.available))
+ end)
+
+ it("retrieves unavailable info if formatter does not exist", function()
+ local info = conform.get_formatter_info("asdf")
+ assert.equal("asdf", info.name)
+ assert.equal("asdf", info.command)
+ assert.falsy(info.available)
+ end)
+
+ describe("list_formatters", function()
+ local get_formatter_info = conform.get_formatter_info
+ before_each(function()
+ conform.get_formatter_info = function(...)
+ local info = get_formatter_info(...)
+ info.available = true
+ return info
+ end
+ end)
+ after_each(function()
+ conform.get_formatter_info = get_formatter_info
+ end)
+
+ it("lists all formatters configured for buffer", function()
+ conform.formatters_by_ft.lua = { "stylua", "lua-format" }
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.bo[bufnr].filetype = "lua"
+ local formatters = conform.list_formatters()
+ local formatter_names = vim.tbl_map(function(f)
+ return f.name
+ end, formatters)
+ assert.are.same({ "stylua", "lua-format" }, formatter_names)
+ end)
+
+ it("merges formatters from mixed filetypes", function()
+ conform.formatters_by_ft.lua = { "stylua", "lua-format" }
+ conform.formatters_by_ft["*"] = { "trim_whitespace" }
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.bo[bufnr].filetype = "lua"
+ local formatters = conform.list_formatters()
+ local formatter_names = vim.tbl_map(function(f)
+ return f.name
+ end, formatters)
+ assert.are.same({ "stylua", "lua-format", "trim_whitespace" }, formatter_names)
+ end)
+
+ it("flattens formatters in alternation groups", function()
+ conform.formatters_by_ft.lua = { { "stylua", "lua-format" }, "trim_whitespace" }
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.bo[bufnr].filetype = "lua"
+ local formatters = conform.list_formatters()
+ local formatter_names = vim.tbl_map(function(f)
+ return f.name
+ end, formatters)
+ assert.are.same({ "stylua", "trim_whitespace" }, formatter_names)
+ end)
+ end)
+
+ describe("list_all_formatters", function()
+ it("lists all formatters configured for all buffers", function()
+ conform.formatters_by_ft.lua = { "stylua", "lua-format" }
+ conform.formatters_by_ft["*"] = { "trim_whitespace" }
+ local formatters = conform.list_all_formatters()
+ local formatter_names = vim.tbl_map(function(f)
+ return f.name
+ end, formatters)
+ table.sort(formatter_names)
+ assert.are.same({ "lua-format", "stylua", "trim_whitespace" }, formatter_names)
+ end)
+
+ it("flattens formatters in alternation groups", function()
+ conform.formatters_by_ft.lua = { { "stylua", "lua-format" } }
+ conform.formatters_by_ft["*"] = { "trim_whitespace" }
+ local formatters = conform.list_all_formatters()
+ local formatter_names = vim.tbl_map(function(f)
+ return f.name
+ end, formatters)
+ table.sort(formatter_names)
+ assert.are.same({ "lua-format", "stylua", "trim_whitespace" }, formatter_names)
+ end)
+ end)
+end)