From 808c7e045d50dcb2ad512ea7fa94baf411654a95 Mon Sep 17 00:00:00 2001 From: Steven Arcangeli Date: Wed, 13 Sep 2023 23:52:55 -0700 Subject: doc: add some recipes to the documentation --- README.md | 84 ++++------------------------ doc/conform.txt | 26 +++------ doc/recipes.md | 136 +++++++++++++++++++++++++++++++++++++++++++++ lua/conform/init.lua | 2 +- scripts/autoformat_doc.lua | 24 ++------ scripts/generate.py | 13 ++++- scripts/options_doc.lua | 2 + 7 files changed, 174 insertions(+), 113 deletions(-) create mode 100644 doc/recipes.md diff --git a/README.md b/README.md index b538e13..4a9fdfc 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ Lightweight yet powerful formatter plugin for Neovim - [Setup](#setup) - [Formatters](#formatters) - [Options](#options) -- [Customizing formatters](#customizing-formatters) -- [Autoformat on save](#autoformat-on-save) +- [Recipes](#recipes) - [API](#api) - [format(opts, callback)](#formatopts-callback) - [list_formatters(bufnr)](#list_formattersbufnr) @@ -229,6 +228,7 @@ require("conform").setup({ }, -- If this is set, Conform will run the formatter on save. -- It will pass the table to conform.format(). + -- This can also be a function that returns the table. format_on_save = { -- I recommend these options. See :help conform.format for details. lsp_fallback = true, @@ -236,6 +236,7 @@ require("conform").setup({ }, -- If this is set, Conform will run the formatter asynchronously after save. -- It will pass the table to conform.format(). + -- This can also be a function that returns the table. format_after_save = { lsp_fallback = true, }, @@ -292,81 +293,16 @@ require("conform").formatters.my_formatter = { -## Customizing formatters +## Recipes -If you want to customize how a formatter runs (for example, to pass in environment variables or -change the command arguments), you can either edit the formatter directly or create one yourself. + -```lua --- Directly change the values on the built-in configuration -require("conform.formatters.yamlfix").env = { - YAMLFIX_SEQUENCE_STYLE = "block_style", -} - --- Or create your own formatter that overrides certain values -require("conform").formatters.yamlfix = vim.tbl_deep_extend("force", require("conform.formatters.yamlfix"), { - env = { - YAMLFIX_SEQUENCE_STYLE = "block_style", - }, -}) -``` - -## Autoformat on save - -If you want more complex logic than the `format_on_save` option allows, you can write it yourself -using an autocmd. For example: - - - -```lua --- Format synchronously on save -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, bufnr = args.buf }) - end, -}) - --- To eliminate the boilerplate, you can pass a function to format_on_save --- and it will be called during the BufWritePre callback. -require("conform").setup({ - format_on_save = function(bufnr) - if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then - return - end - -- ...additional logic... - return { timeout_ms = 500, lsp_fallback = true } - end, -}) - --- There is a similar affordance for format_after_save, which uses BufWritePost. --- This is good for formatters that are too slow to run synchronously. -require("conform").setup({ - format_after_save = function(bufnr) - if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then - return - end - -- ...additional logic... - return { lsp_fallback = true } - end, -}) -``` +- [Format command](doc/recipes.md#format-command) +- [Customizing formatters](doc/recipes.md#customizing-formatters) +- [Autoformat with extra features](doc/recipes.md#autoformat-with-extra-features) +- [Command to toggle format-on-save](doc/recipes.md#command-to-toggle-format-on-save) - + ## API diff --git a/doc/conform.txt b/doc/conform.txt index 0052326..bcae22f 100644 --- a/doc/conform.txt +++ b/doc/conform.txt @@ -27,6 +27,7 @@ OPTIONS *conform-option }, -- If this is set, Conform will run the formatter on save. -- It will pass the table to conform.format(). + -- This can also be a function that returns the table. format_on_save = { -- I recommend these options. See :help conform.format for details. lsp_fallback = true, @@ -34,6 +35,7 @@ OPTIONS *conform-option }, -- If this is set, Conform will run the formatter asynchronously after save. -- It will pass the table to conform.format(). + -- This can also be a function that returns the table. format_after_save = { lsp_fallback = true, }, @@ -222,35 +224,23 @@ AUTOFORMAT *conform-autoforma 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 - -- Format synchronously on save - vim.api.nvim_create_autocmd("BufWritePre", { - pattern = "*", - callback = function(args) + -- if format_on_save is a function, it will be called during BufWritePre + require("conform").setup({ + format_on_save = function(bufnr) -- Disable autoformat on certain filetypes local ignore_filetypes = { "sql", "java" } - if vim.tbl_contains(ignore_filetypes, vim.bo[args.buf].filetype) then + if vim.tbl_contains(ignore_filetypes, vim.bo[bufnr].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 + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then return end -- Disable autoformat for files in a certain path - local bufname = vim.api.nvim_buf_get_name(args.buf) + local bufname = vim.api.nvim_buf_get_name(bufnr) if bufname:match("/node_modules/") then return end - require("conform").format({ timeout_ms = 500, lsp_fallback = true, bufnr = args.buf }) - end, - }) - - -- To eliminate the boilerplate, you can pass a function to format_on_save - -- and it will be called during the BufWritePre callback. - require("conform").setup({ - format_on_save = function(bufnr) - if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then - return - end -- ...additional logic... return { timeout_ms = 500, lsp_fallback = true } end, diff --git a/doc/recipes.md b/doc/recipes.md new file mode 100644 index 0000000..9fed51d --- /dev/null +++ b/doc/recipes.md @@ -0,0 +1,136 @@ +# Recipes + + + +- [Format command](#format-command) +- [Customizing formatters](#customizing-formatters) +- [Autoformat with extra features](#autoformat-with-extra-features) +- [Command to toggle format-on-save](#command-to-toggle-format-on-save) + + + +## Format command + +Define a command to run async formatting + +```lua +vim.api.nvim_create_user_command("Format", function(args) + local range = nil + if args.count ~= -1 then + local end_line = vim.api.nvim_buf_get_lines(0, args.line2 - 1, args.line2, true)[1] + range = { + start = { args.line1, 0 }, + ["end"] = { args.line2, end_line:len() }, + } + end + require("conform").format({ async = true, lsp_fallback = true, range = range }) +end, { range = true }) +``` + +## Customizing formatters + +If you want to customize how a formatter runs (for example, to pass in environment variables or +change the command arguments), you can either edit the formatter directly or create one yourself. + +```lua +-- Directly change the values on the built-in configuration +require("conform.formatters.yamlfix").env = { + YAMLFIX_SEQUENCE_STYLE = "block_style", +} + +-- Or create your own formatter that overrides certain values +require("conform").formatters.yamlfix = vim.tbl_deep_extend("force", require("conform.formatters.yamlfix"), { + env = { + YAMLFIX_SEQUENCE_STYLE = "block_style", + }, +}) + +-- Here is an example that modifies the command arguments for prettier to add +-- a custom config file, if it is present +require("conform.formatters.prettier").args = function(ctx) + local args = { "--stdin-filepath", "$FILENAME" } + local found = vim.fs.find(".custom-config.json", { upward = true, path = ctx.dirname })[1] + if found then + vim.list_extend(args, { "--config", found }) + end + return args +end +``` + +## Autoformat with extra features + +If you want more complex logic than the basic `format_on_save` option allows, you can use a function instead. + + + +```lua +-- if format_on_save is a function, it will be called during BufWritePre +require("conform").setup({ + format_on_save = function(bufnr) + -- Disable autoformat on certain filetypes + local ignore_filetypes = { "sql", "java" } + if vim.tbl_contains(ignore_filetypes, vim.bo[bufnr].filetype) then + return + end + -- Disable with a global or buffer-local variable + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + -- Disable autoformat for files in a certain path + local bufname = vim.api.nvim_buf_get_name(bufnr) + if bufname:match("/node_modules/") then + return + end + -- ...additional logic... + return { timeout_ms = 500, lsp_fallback = true } + end, +}) + +-- There is a similar affordance for format_after_save, which uses BufWritePost. +-- This is good for formatters that are too slow to run synchronously. +require("conform").setup({ + format_after_save = function(bufnr) + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + -- ...additional logic... + return { lsp_fallback = true } + end, +}) +``` + + + +## Command to toggle format-on-save + +Create user commands to quickly enable/disable autoformatting + +```lua +require("conform").setup({ + format_on_save = function(bufnr) + -- Disable with a global or buffer-local variable + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + return { timeout_ms = 500, lsp_fallback = true } + end, +}) + +vim.api.nvim_create_user_command("FormatDisable", function(args) + if args.bang then + -- FormatDisable! will disable formatting just for this buffer + vim.b.disable_autoformat = true + else + vim.g.disable_autoformat = true + end +end, { + desc = "Disable autoformat-on-save", + bang = true, +}) +vim.api.nvim_create_user_command("FormatEnable", function() + vim.b.disable_autoformat = false + vim.g.disable_autoformat = false +end, { + desc = "Re-enable autoformat-on-save", +}) +``` diff --git a/lua/conform/init.lua b/lua/conform/init.lua index 378822f..e2ba40a 100644 --- a/lua/conform/init.lua +++ b/lua/conform/init.lua @@ -66,7 +66,7 @@ M.setup = function(opts) 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', + 'The "format_on_save" option for filetype "%s" is deprecated. It is recommended to put this logic in the autocmd, see :help conform-autoformat', ft ), vim.log.levels.WARN diff --git a/scripts/autoformat_doc.lua b/scripts/autoformat_doc.lua index 4880310..f6476d4 100644 --- a/scripts/autoformat_doc.lua +++ b/scripts/autoformat_doc.lua @@ -1,32 +1,20 @@ --- Format synchronously on save -vim.api.nvim_create_autocmd("BufWritePre", { - pattern = "*", - callback = function(args) +-- if format_on_save is a function, it will be called during BufWritePre +require("conform").setup({ + format_on_save = function(bufnr) -- Disable autoformat on certain filetypes local ignore_filetypes = { "sql", "java" } - if vim.tbl_contains(ignore_filetypes, vim.bo[args.buf].filetype) then + if vim.tbl_contains(ignore_filetypes, vim.bo[bufnr].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 + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then return end -- Disable autoformat for files in a certain path - local bufname = vim.api.nvim_buf_get_name(args.buf) + local bufname = vim.api.nvim_buf_get_name(bufnr) if bufname:match("/node_modules/") then return end - require("conform").format({ timeout_ms = 500, lsp_fallback = true, bufnr = args.buf }) - end, -}) - --- To eliminate the boilerplate, you can pass a function to format_on_save --- and it will be called during the BufWritePre callback. -require("conform").setup({ - format_on_save = function(bufnr) - if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then - return - end -- ...additional logic... return { timeout_ms = 500, lsp_fallback = true } end, diff --git a/scripts/generate.py b/scripts/generate.py index 06fbdb0..1c794ae 100755 --- a/scripts/generate.py +++ b/scripts/generate.py @@ -3,7 +3,7 @@ import os.path import re from dataclasses import dataclass from functools import lru_cache -from typing import Dict, List +from typing import List from nvim_doc_tools import ( Vimdoc, @@ -22,6 +22,7 @@ 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") +RECIPES = os.path.join(DOC, "recipes.md") VIMDOC = os.path.join(DOC, "conform.txt") OPTIONS = os.path.join(ROOT, "scripts", "options_doc.lua") AUTOFORMAT = os.path.join(ROOT, "scripts", "autoformat_doc.lua") @@ -82,7 +83,7 @@ def update_autocmd_md(): example_lines.extend(f.readlines()) example_lines.extend(["```\n", "\n"]) replace_section( - README, + RECIPES, r"^$", r"^$", example_lines, @@ -117,6 +118,13 @@ def update_readme_toc(): ) +def update_recipes_toc(): + toc = ["\n"] + generate_md_toc(RECIPES) + ["\n"] + replace_section(RECIPES, r"^$", r"^$", toc) + subtoc = add_md_link_path("doc/recipes.md", toc) + replace_section(README, r"^$", r"^$", subtoc) + + def gen_options_vimdoc() -> VimdocSection: section = VimdocSection("Options", "conform-options", ["\n", ">lua\n"]) with open(OPTIONS, "r", encoding="utf-8") as f: @@ -169,5 +177,6 @@ def main() -> None: update_options() update_autocmd_md() update_md_api() + update_recipes_toc() update_readme_toc() generate_vimdoc() diff --git a/scripts/options_doc.lua b/scripts/options_doc.lua index 5dab627..9073369 100644 --- a/scripts/options_doc.lua +++ b/scripts/options_doc.lua @@ -13,6 +13,7 @@ require("conform").setup({ }, -- If this is set, Conform will run the formatter on save. -- It will pass the table to conform.format(). + -- This can also be a function that returns the table. format_on_save = { -- I recommend these options. See :help conform.format for details. lsp_fallback = true, @@ -20,6 +21,7 @@ require("conform").setup({ }, -- If this is set, Conform will run the formatter asynchronously after save. -- It will pass the table to conform.format(). + -- This can also be a function that returns the table. format_after_save = { lsp_fallback = true, }, -- cgit v1.2.3-70-g09d2