From d508ae8f46b5b41e2806b412311719a941167c1a Mon Sep 17 00:00:00 2001 From: Steven Arcangeli Date: Mon, 28 Aug 2023 18:27:46 -0700 Subject: refactor!: remove ability for formatter list to disable autoformat 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. --- README.md | 37 ++++++++++++++++++++++++++++++++++--- doc/conform.txt | 29 +++++++++++++++++++++++++++++ lua/conform/init.lua | 22 ++++++++++++++-------- scripts/generate.py | 45 ++++++++++++++++++++++++++++++++++++++++++--- tests/autoformat_doc.lua | 20 ++++++++++++++++++++ 5 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 tests/autoformat_doc.lua diff --git a/README.md b/README.md index 88730a1..0999d60 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # conform.nvim -Formatter plugin for Neovim +Lightweight yet powerful formatter plugin for Neovim @@ -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) @@ -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 }, }, }) @@ -266,6 +265,38 @@ require("conform").formatters.my_formatter = { +## 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: + + + +```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, +}) +``` + + + ## API diff --git a/doc/conform.txt b/doc/conform.txt index 77266cf..f602580 100644 --- a/doc/conform.txt +++ b/doc/conform.txt @@ -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* @@ -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: diff --git a/lua/conform/init.lua b/lua/conform/init.lua index 1c8b333..3197b35 100644 --- a/lua/conform/init.lua +++ b/lua/conform/init.lua @@ -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[] @@ -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 = {} @@ -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, }) diff --git a/scripts/generate.py b/scripts/generate.py index f317534..e8b0dad 100755 --- a/scripts/generate.py +++ b/scripts/generate.py @@ -5,9 +5,18 @@ from dataclasses import dataclass 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)) @@ -15,6 +24,7 @@ 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 @@ -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"^$", + r"^$", + example_lines, + ) + + def add_md_link_path(path: str, lines: List[str]) -> List[str]: ret = [] for line in lines: @@ -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(): @@ -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(), ] ) @@ -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() diff --git a/tests/autoformat_doc.lua b/tests/autoformat_doc.lua new file mode 100644 index 0000000..8c0761e --- /dev/null +++ b/tests/autoformat_doc.lua @@ -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, +}) -- cgit v1.2.3-70-g09d2