-- LSP: Auto-format on save -- https://github.com/plex/vim-config -- This is part of LazyVim's code, with my modifications. -- See: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/plugins/lsp/format.lua local M = {} ---@type PluginLspOpts M.opts = nil function M.enabled() return M.opts.autoformat end function M.toggle() if vim.b.autoformat == false then vim.b.autoformat = nil M.opts.autoformat = true else M.opts.autoformat = not M.opts.autoformat end local msg = M.opts.autoformat and 'Enabled' or 'Disabled' vim.notify( msg .. ' format on save', vim.log.levels.INFO, { title = 'Format' } ) end ---@param opts? {force?:boolean} function M.format(opts) local buf = vim.api.nvim_get_current_buf() if vim.b.autoformat == false and not (opts and opts.force) then return end local formatters = M.get_formatters(buf) local client_ids = vim.tbl_map(function(client) return client.id end, formatters.active) if #client_ids == 0 then return end if M.opts.format_notify then M.notify(formatters) end vim.lsp.buf.format(vim.tbl_deep_extend('force', { bufnr = buf, filter = function(client) return vim.tbl_contains(client_ids, client.id) end, }, require('plex.lib.utils').opts('nvim-lspconfig').format or {})) end ---@param formatters LazyVimFormatters function M.notify(formatters) local lines = { '# Active:' } for _, client in ipairs(formatters.active) do local line = '- **' .. client.name .. '**' if client.name == 'null-ls' then line = line .. ' (' .. table.concat( vim.tbl_map(function(f) return '`' .. f.name .. '`' end, formatters.null_ls), ', ' ) .. ')' end table.insert(lines, line) end if #formatters.available > 0 then table.insert(lines, '') table.insert(lines, '# Disabled:') for _, client in ipairs(formatters.available) do table.insert(lines, '- **' .. client.name .. '**') end end vim.notify(table.concat(lines, '\n'), vim.log.levels.INFO, { title = 'Formatting', on_open = function(win) local scope = { scope = 'local', win = win } vim.api.nvim_set_option_value('conceallevel', 3, scope) vim.api.nvim_set_option_value('spell', false, scope) local buf = vim.api.nvim_win_get_buf(win) vim.treesitter.start(buf, 'markdown') end, }) end -- Gets all lsp clients that support formatting. -- When a null-ls formatter is available for the current filetype, -- only null-ls formatters are returned. function M.get_formatters(bufnr) local ft = vim.bo[bufnr].filetype -- check if we have any null-ls formatters for the current filetype local null_ls = package.loaded['null-ls'] and require('null-ls.sources').get_available(ft, 'NULL_LS_FORMATTING') or {} ---@class LazyVimFormatters local ret = { ---@type lsp.Client[] active = {}, ---@type lsp.Client[] available = {}, null_ls = null_ls, } local clients if vim.lsp.get_clients ~= nil then clients = vim.lsp.get_clients({ bufnr = bufnr }) else ---@diagnostic disable-next-line: deprecated clients = vim.lsp.get_active_clients({ bufnr = bufnr }) end for _, client in ipairs(clients) do if M.supports_format(client) then if (#null_ls > 0 and client.name == 'null-ls') or #null_ls == 0 then table.insert(ret.active, client) else table.insert(ret.available, client) end end end return ret end -- Gets all lsp clients that support formatting -- and have not disabled it in their client config ---@param client lsp.Client function M.supports_format(client) if client.config and client.config.capabilities and client.config.capabilities['documentFormattingProvider'] == false then return false end return client.supports_method('textDocument/formatting') or client.supports_method('textDocument/rangeFormatting') end ---@param opts PluginLspOpts function M.setup(opts) M.opts = opts vim.api.nvim_create_autocmd('BufWritePre', { group = vim.api.nvim_create_augroup('plex_format', {}), callback = function() if M.opts.autoformat then M.format() end end, }) end return M