Skip to content

Commit

Permalink
refactor!: remove ability for formatter list to disable autoformat
Browse files Browse the repository at this point in the history
I realized that there are so, so many possible features people would
want when configuring the autoformatter, but it's better to just code it
up yourself rather than try to create a config language that can
describe all possible logic. Also adding new docs to provide examples of
more advanced autoformat logic.
  • Loading branch information
stevearc committed Aug 29, 2023
1 parent e09ef2a commit d508ae8
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 14 deletions.
37 changes: 34 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# conform.nvim

Formatter plugin for Neovim
Lightweight yet powerful formatter plugin for Neovim

<!-- TOC -->

Expand All @@ -9,6 +9,7 @@ Formatter plugin for Neovim
- [Setup](#setup)
- [Formatters](#formatters)
- [Options](#options)
- [Autoformat on save](#autoformat-on-save)
- [API](#api)
- [format(opts)](#formatopts)
- [list_formatters(bufnr)](#list_formattersbufnr)
Expand Down Expand Up @@ -114,8 +115,6 @@ require("conform").setup({
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
},
},
})
Expand Down Expand Up @@ -266,6 +265,38 @@ require("conform").formatters.my_formatter = {

<!-- /OPTIONS -->

## Autoformat on save

If you want more complex logic than the `format_on_save` option allows, you can write it yourself
using your own autocmd. For example:

<!-- AUTOFORMAT -->

```lua
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*",
callback = function(args)
-- Disable autoformat on certain filetypes
local ignore_filetypes = { "sql", "java" }
if vim.tbl_contains(ignore_filetypes, vim.bo[args.buf].filetype) then
return
end
-- Disable with a global or buffer-local variable
if vim.g.disable_autoformat or vim.b[args.buf].disable_autoformat then
return
end
-- Disable autoformat for files in a certain path
local bufname = vim.api.nvim_buf_get_name(args.buf)
if bufname:match("/node_modules/") then
return
end
require("conform").format({ timeout_ms = 500, lsp_fallback = true, buf = args.buf })
end,
})
```

<!-- /AUTOFORMAT -->

## API

<!-- API -->
Expand Down
29 changes: 29 additions & 0 deletions doc/conform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CONTENTS *conform-content
1. Options |conform-options|
2. Api |conform-api|
3. Formatters |conform-formatters|
4. Autoformat |conform-autoformat|

--------------------------------------------------------------------------------
OPTIONS *conform-options*
Expand Down Expand Up @@ -172,5 +173,33 @@ FORMATTERS *conform-formatter
`yapf` - Yet Another Python Formatter.
`zigfmt` - Reformat Zig source into canonical form.

--------------------------------------------------------------------------------
AUTOFORMAT *conform-autoformat*

If you want more complex logic than the `format_on_save` option allows, you can
write it yourself using your own autocmd. For example:
>lua
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*",
callback = function(args)
-- Disable autoformat on certain filetypes
local ignore_filetypes = { "sql", "java" }
if vim.tbl_contains(ignore_filetypes, vim.bo[args.buf].filetype) then
return
end
-- Disable with a global or buffer-local variable
if vim.g.disable_autoformat or vim.b[args.buf].disable_autoformat then
return
end
-- Disable autoformat for files in a certain path
local bufname = vim.api.nvim_buf_get_name(args.buf)
if bufname:match("/node_modules/") then
return
end
require("conform").format({ timeout_ms = 500, lsp_fallback = true, buf = args.buf })
end,
})
<

================================================================================
vim:tw=80:ts=2:ft=help:norl:syntax=help:
22 changes: 14 additions & 8 deletions lua/conform/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ local M = {}

---@class (exact) conform.RunOptions
---@field run_all_formatters nil|boolean Run all listed formatters instead of stopping at the first one.
---@field format_on_save nil|boolean Run these formatters in the built-in format_on_save autocmd.

---@class (exact) conform.FormatterList : conform.RunOptions
---@field formatters string[]
Expand All @@ -51,6 +50,20 @@ M.setup = function(opts)
require("conform.log").level = opts.log_level
end

for ft, formatters in pairs(M.formatters_by_ft) do
---@diagnostic disable-next-line: undefined-field
if formatters.format_on_save ~= nil then
vim.notify(
string.format(
'The "format_on_save" option for filetype "%s" is deprecated. It is recommended to create your own autocmd for fine grained control, see :help conform-autoformat',
ft
),
vim.log.levels.WARN
)
break
end
end

if opts.format_on_save then
if type(opts.format_on_save) == "boolean" then
opts.format_on_save = {}
Expand All @@ -63,13 +76,6 @@ M.setup = function(opts)
local format_opts = vim.tbl_deep_extend("keep", opts.format_on_save, {
buf = args.buf,
})
local filetypes = vim.split(vim.bo[args.buf].filetype, ".", { plain = true })
for _, ft in ipairs(filetypes) do
local ft_formatters = M.formatters_by_ft[ft]
if ft_formatters and ft_formatters.format_on_save == false then
return
end
end
M.format(format_opts)
end,
})
Expand Down
45 changes: 42 additions & 3 deletions scripts/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@
from functools import lru_cache
from typing import Dict, List

from nvim_doc_tools import (Vimdoc, VimdocSection, generate_md_toc, indent,
parse_functions, read_nvim_json, render_md_api,
render_vimdoc_api, replace_section, wrap)
from nvim_doc_tools import (
Vimdoc,
VimdocSection,
generate_md_toc,
indent,
parse_functions,
read_nvim_json,
render_md_api,
render_vimdoc_api,
replace_section,
wrap,
)

HERE = os.path.dirname(__file__)
ROOT = os.path.abspath(os.path.join(HERE, os.path.pardir))
README = os.path.join(ROOT, "README.md")
DOC = os.path.join(ROOT, "doc")
VIMDOC = os.path.join(DOC, "conform.txt")
OPTIONS = os.path.join(ROOT, "tests", "options_doc.lua")
AUTOFORMAT = os.path.join(ROOT, "tests", "autoformat_doc.lua")


@dataclass
Expand Down Expand Up @@ -66,6 +76,19 @@ def update_options():
)


def update_autocmd_md():
example_lines = ["\n", "```lua\n"]
with open(AUTOFORMAT, "r", encoding="utf-8") as f:
example_lines.extend(f.readlines())
example_lines.extend(["```\n", "\n"])
replace_section(
README,
r"^<!-- AUTOFORMAT -->$",
r"^<!-- /AUTOFORMAT -->$",
example_lines,
)


def add_md_link_path(path: str, lines: List[str]) -> List[str]:
ret = []
for line in lines:
Expand Down Expand Up @@ -102,6 +125,20 @@ def gen_options_vimdoc() -> VimdocSection:
return section


def gen_autocmd_vimdoc() -> VimdocSection:
section = VimdocSection("Autoformat", "conform-autoformat", ["\n"])
section.body.extend(
wrap(
"If you want more complex logic than the `format_on_save` option allows, you can write it yourself using your own autocmd. For example:"
)
)
section.body.append(">lua\n")
with open(AUTOFORMAT, "r", encoding="utf-8") as f:
section.body.extend(indent(f.readlines(), 4))
section.body.append("<\n")
return section


def gen_formatter_vimdoc() -> VimdocSection:
section = VimdocSection("Formatters", "conform-formatters", ["\n"])
for formatter in get_all_formatters():
Expand All @@ -118,6 +155,7 @@ def generate_vimdoc():
gen_options_vimdoc(),
VimdocSection("API", "conform-api", render_vimdoc_api("conform", funcs)),
gen_formatter_vimdoc(),
gen_autocmd_vimdoc(),
]
)

Expand All @@ -129,6 +167,7 @@ def main() -> None:
"""Update the README"""
update_formatter_list()
update_options()
update_autocmd_md()
update_md_api()
update_readme_toc()
generate_vimdoc()
20 changes: 20 additions & 0 deletions tests/autoformat_doc.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*",
callback = function(args)
-- Disable autoformat on certain filetypes
local ignore_filetypes = { "sql", "java" }
if vim.tbl_contains(ignore_filetypes, vim.bo[args.buf].filetype) then
return
end
-- Disable with a global or buffer-local variable
if vim.g.disable_autoformat or vim.b[args.buf].disable_autoformat then
return
end
-- Disable autoformat for files in a certain path
local bufname = vim.api.nvim_buf_get_name(args.buf)
if bufname:match("/node_modules/") then
return
end
require("conform").format({ timeout_ms = 500, lsp_fallback = true, buf = args.buf })
end,
})

0 comments on commit d508ae8

Please sign in to comment.