diff --git a/docs/release-notes/rl-0.8.md b/docs/release-notes/rl-0.8.md index e0c06fc8..6581a277 100644 --- a/docs/release-notes/rl-0.8.md +++ b/docs/release-notes/rl-0.8.md @@ -109,6 +109,7 @@ - Add tsx support in conform and lint - Moved code setting `additionalRuntimePaths` and `enableLuaLoader` out of `luaConfigPre`'s default to prevent being overridden +- Use conform over custom autocmds for LSP format on save [diniamo](https://github.com/diniamo): @@ -312,6 +313,8 @@ - Fix fzf-lua having a hard dependency on fzf. - Enable inlay hints support - `config.vim.lsp.inlayHints`. - Add `neo-tree`, `snacks.picker` extensions to `lualine`. +- Add support for `vim.lsp.formatOnSave` and + `vim.lsp.mappings.toggleFormatOnSave` [tebuevd](https://github.com/tebuevd): @@ -361,7 +364,8 @@ [Hardtime.nvim]: https://github.com/m4xshen/hardtime.nvim -- Add Plugin [Hardtime.nvim] under `vim.binds.hardtime-nvim` with `enable` and `setupOpts` options +- Add Plugin [Hardtime.nvim] under `vim.binds.hardtime-nvim` with `enable` and + `setupOpts` options [taylrfnt](https://github.com/taylrfnt): diff --git a/modules/plugins/formatter/conform-nvim/conform-nvim.nix b/modules/plugins/formatter/conform-nvim/conform-nvim.nix index 727985a3..cfe89bf3 100644 --- a/modules/plugins/formatter/conform-nvim/conform-nvim.nix +++ b/modules/plugins/formatter/conform-nvim/conform-nvim.nix @@ -1,12 +1,9 @@ -{ - pkgs, - lib, - ... -}: let - inherit (lib.options) mkOption mkEnableOption literalExpression; - inherit (lib.types) attrs enum nullOr; - inherit (lib.nvim.types) mkPluginSetupOption; - inherit (lib.nvim.lua) mkLuaInline; +{lib, ...}: let + inherit (lib.generators) mkLuaInline; + inherit (lib.options) mkOption mkEnableOption literalMD; + inherit (lib.types) attrs either nullOr; + inherit (lib.nvim.lua) toLuaObject; + inherit (lib.nvim.types) luaInline mkPluginSetupOption; in { options.vim.formatter.conform-nvim = { enable = mkEnableOption "lightweight yet powerful formatter plugin for Neovim [conform-nvim]"; @@ -31,26 +28,46 @@ in { }; format_on_save = mkOption { - type = nullOr attrs; - default = { - lsp_format = "fallback"; - timeout_ms = 500; - }; + type = nullOr (either attrs luaInline); + default = mkLuaInline '' + function() + if not vim.g.formatsave or vim.b.disableFormatSave then + return + else + return {lsp_format = "fallback", timeout_ms = 500} + end + end + ''; + defaultText = literalMD '' + enabled by default, and respects {option}`vim.lsp.formatOnSave` and + {option}`vim.lsp.mappings.toggleFormatSave` + ''; description = '' - Table that will be passed to `conform.format()`. If this - is set, Conform will run the formatter on save. + Attribute set or Lua function that will be passed to + `conform.format()`. If this is set, Conform will run the formatter + on save. ''; }; - format_after_save = mkOption { - type = nullOr attrs; - default = {lsp_format = "fallback";}; - description = '' - Table that will be passed to `conform.format()`. If this - is set, Conform will run the formatter asynchronously after - save. - ''; - }; + format_after_save = let + defaultFormatAfterSaveOpts = {lsp_format = "fallback";}; + in + mkOption { + type = nullOr (either attrs luaInline); + default = mkLuaInline '' + function() + if not vim.g.formatsave or vim.b.disableFormatSave then + return + else + return ${toLuaObject defaultFormatAfterSaveOpts} + end + end + ''; + description = '' + Table or function(luainline) that will be passed to `conform.format()`. If this + is set, Conform will run the formatter asynchronously after save. + ''; + }; }; }; } diff --git a/modules/plugins/lsp/config.nix b/modules/plugins/lsp/config.nix index c2320aaf..e7b67c8e 100644 --- a/modules/plugins/lsp/config.nix +++ b/modules/plugins/lsp/config.nix @@ -6,6 +6,7 @@ }: let inherit (lib.generators) mkLuaInline; inherit (lib.modules) mkIf; + inherit (lib.lists) optional; inherit (lib.strings) optionalString; inherit (lib.trivial) boolToString; inherit (lib.nvim.binds) addDescriptionsToMappings; @@ -14,7 +15,10 @@ usingNvimCmp = config.vim.autocomplete.nvim-cmp.enable; usingBlinkCmp = config.vim.autocomplete.blink-cmp.enable; self = import ./module.nix {inherit config lib pkgs;}; + conformCfg = config.vim.formatter.conform-nvim; + conformFormatOnSave = conformCfg.enable && conformCfg.setupOpts.format_on_save != null; + augroup = "nvf_lsp"; mappingDefinitions = self.options.vim.lsp.mappings; mappings = addDescriptionsToMappings cfg.mappings mappingDefinitions; mkBinding = binding: action: @@ -29,24 +33,59 @@ in { sourcePlugins = ["cmp-nvim-lsp"]; }; + augroups = [{name = augroup;}]; autocmds = - if cfg.inlayHints.enable - then [ - { - callback = mkLuaInline '' - function(event) - local bufnr = event.buf - local client = vim.lsp.get_client_by_id(event.data.client_id) - if client and client.supports_method(vim.lsp.protocol.Methods.textDocument_inlayHint) then - vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr }) + (optional cfg.inlayHints.enable { + group = augroup; + event = ["LspAttach"]; + desc = "LSP on-attach enable inlay hints autocmd"; + callback = mkLuaInline '' + function(event) + local bufnr = event.buf + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client and client.supports_method(vim.lsp.protocol.Methods.textDocument_inlayHint) then + vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr }) + end + end + ''; + }) + ++ (optional (!conformFormatOnSave) { + group = augroup; + event = ["BufWritePre"]; + desc = "LSP on-attach create format on save autocmd"; + callback = mkLuaInline '' + function(ev) + if vim.b.disableFormatSave or not vim.g.formatsave then + return + end + + local bufnr = ev.buf + + ${optionalString cfg.null-ls.enable '' + -- prefer null_ls formatter + do + local clients = vim.lsp.get_clients({ + bufnr = bufnr, + name = "null-ls", + method = "textDocument/formatting", + }) + if clients[1] then + vim.lsp.buf.format({ bufnr = bufnr, id = clients[1].id }) + return end end - ''; - desc = "LSP on-attach enable inlay hints autocmd"; - event = ["LspAttach"]; - } - ] - else []; + ''} + + local clients = vim.lsp.get_clients({ + bufnr = bufnr, + method = "textDocument/formatting", + }) + if clients[1] then + vim.lsp.buf.format({ bufnr = bufnr, id = clients[1].id }) + end + end + ''; + }); pluginRC.lsp-setup = '' vim.g.formatsave = ${boolToString cfg.formatOnSave}; @@ -74,60 +113,9 @@ in { ${mkBinding mappings.toggleFormatOnSave "function() vim.b.disableFormatSave = not vim.b.disableFormatSave end"} end - -- Enable formatting - local augroup = vim.api.nvim_create_augroup("LspFormatting", {}) - - format_callback = function(client, bufnr) - if vim.g.formatsave then - vim.api.nvim_clear_autocmds({ group = augroup, buffer = bufnr }) - vim.api.nvim_create_autocmd("BufWritePre", { - group = augroup, - buffer = bufnr, - callback = function() - if vim.b.disableFormatSave then - return - end - - ${ - if config.vim.lsp.null-ls.enable - then '' - local function is_null_ls_formatting_enabled(bufnr) - local file_type = vim.api.nvim_buf_get_option(bufnr, "filetype") - local generators = require("null-ls.generators").get_available( - file_type, - require("null-ls.methods").internal.FORMATTING - ) - return #generators > 0 - end - - if is_null_ls_formatting_enabled(bufnr) then - vim.lsp.buf.format({ - bufnr = bufnr, - filter = function(client) - return client.name == "null-ls" - end - }) - else - vim.lsp.buf.format({ - bufnr = bufnr, - }) - end - '' - else " - vim.lsp.buf.format({ - bufnr = bufnr, - }) - " - } - end, - }) - end - end - ${optionalString config.vim.ui.breadcrumbs.enable ''local navic = require("nvim-navic")''} default_on_attach = function(client, bufnr) attach_keymaps(client, bufnr) - format_callback(client, bufnr) ${optionalString config.vim.ui.breadcrumbs.enable '' -- let navic attach to buffers if client.server_capabilities.documentSymbolProvider then @@ -138,6 +126,7 @@ in { local capabilities = vim.lsp.protocol.make_client_capabilities() ${optionalString usingNvimCmp '' + -- TODO(horriblename): migrate to vim.lsp.config['*'] -- HACK: copied from cmp-nvim-lsp. If we ever lazy load lspconfig we -- should re-evaluate whether we can just use `default_capabilities` capabilities = {