Skip to content

Commit

Permalink
feat(nvim): Switch from efm-ls to conform.nvim and nvim-lint
Browse files Browse the repository at this point in the history
Fixes #126
  • Loading branch information
mrjones2014 committed May 29, 2024
1 parent b0d19e8 commit c300f6a
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 171 deletions.
1 change: 0 additions & 1 deletion home-manager/modules/nvim.nix
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@
prettierd

# LSP servers
efm-langserver
nil
rust-analyzer
taplo
Expand Down
41 changes: 27 additions & 14 deletions nvim/lua/my/configure/lspconfig.lua
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
local nvim_navbuddy_telescope
local formatters_by_ft = require('my.lsp.filetypes').formatters_by_ft
return {
'neovim/nvim-lspconfig',
dependencies = {
'hrsh7th/cmp-nvim-lsp',
{ 'folke/neodev.nvim', event = 'BufReadPre' },
{ 'folke/neodev.nvim' },
{ 'folke/neoconf.nvim' },
{
'creativenull/efmls-configs-nvim',
dev = true,
-- neoconf must be loaded before any LSP
dependencies = { 'folke/neoconf.nvim' },
'stevearc/conform.nvim',
opts = {
formatters_by_ft = formatters_by_ft,
format_after_save = function()
if not require('my.utils.lsp').is_formatting_enabled() then
return
end
return { lsp_fallback = true }
end,
},
},
{
'mfussenegger/nvim-lint',
init = function()
vim.api.nvim_create_autocmd('BufWritePost', {
callback = function()
require('lint').try_lint()
end,
})
end,
config = function()
require('lint').linters_by_ft = require('my.lsp.filetypes').linters_by_ft
end,
},
{
'folke/neoconf.nvim',
Expand Down Expand Up @@ -109,19 +130,11 @@ return {
require('my.utils.lsp').on_attach(require('my.utils.lsp').on_attach_default)
end,
config = function()
local efm_setup_done = false

local function setup_lsp_for_filetype(filetype, server_name)
local has_config, config = pcall(require, 'my.lsp.' .. filetype)
config = has_config and config or {}
config.capabilities = require('cmp_nvim_lsp').default_capabilities(vim.lsp.protocol.make_client_capabilities())

-- setup efmls if not done already
if not efm_setup_done and require('my.lsp.filetypes').uses_efm(filetype) then
efm_setup_done = true
require('lspconfig').efm.setup(require('my.lsp.filetypes').efmls_config(config.capabilities))
end

require('lspconfig')[server_name].setup(config)
local snippets = require('my.lsp.snippets')[filetype]
if snippets then
Expand All @@ -137,7 +150,7 @@ return {
end
end

return require('my.lsp.filetypes').uses_efm(vim.bo.ft)
return false
end

local function setup_server(filetype, file_patterns, server_name)
Expand Down
2 changes: 1 addition & 1 deletion nvim/lua/my/configure/treesitter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ return {
-- highlight mdx with markdown -- it's close enough. We also do JSX injection via ./after/queries/markdown/injections.scm
vim.treesitter.language.register('markdown', 'mdx')
require('nvim-treesitter.configs').setup({ ---@diagnostic disable-line:missing-fields
ensure_installed = require('my.lsp.filetypes').treesitter_parsers(),
ensure_installed = require('my.lsp.filetypes').treesitter_parsers,
highlight = {
enable = true,
},
Expand Down
14 changes: 1 addition & 13 deletions nvim/lua/my/legendary/autocmds.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function M.default_autocmds()
}
end

function M.lsp_autocmds(bufnr, server_name)
function M.lsp_autocmds(bufnr)
local _, autocmds = pcall(vim.api.nvim_get_autocmds, { group = 'LspOnAttachAutocmds' })
autocmds = (type(autocmds) == 'table' and autocmds) or {}
local augroup = {
Expand All @@ -71,18 +71,6 @@ function M.lsp_autocmds(bufnr, server_name)
})
end

if
not vim.iter(autocmds):find(function(autocmd)
return autocmd.buflocal == true and autocmd.buffer == bufnr and autocmd.event == 'BufWritePost'
end)
then
table.insert(augroup, {
'BufWritePost',
require('my.utils.lsp').format_document,
opts = { buffer = bufnr },
})
end

if #augroup == 0 then
return {}
end
Expand Down
4 changes: 3 additions & 1 deletion nvim/lua/my/legendary/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ function M.lsp_commands(bufnr)
vim.list_extend(commands, {
{
':Format',
require('my.utils.lsp').format_document,
function()
require('conform').format({ async = true, lsp_fallback = true })
end,
description = 'Format the current document with LSP',
opts = { buffer = bufnr },
},
Expand Down
79 changes: 11 additions & 68 deletions nvim/lua/my/lsp/filetypes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ M.config = {
lspconfig = 'marksman',
formatter = {
'prettier_d',
'cbfmt',
'injected', -- see :h conform-formatters, formats injected code blocks
},
treesitter = { 'markdown', 'markdown_inline' },
},
Expand Down Expand Up @@ -89,77 +89,20 @@ M.config['javascript'] = M.config['typescript']
M.config['typescriptreact'] = M.config['typescript']
M.config['javascriptreact'] = M.config['typescript']

local efm_customizations = {
['cbfmt'] = function()
local cbfmt = require('efmls-configs.formatters.cbfmt')
cbfmt.formatCommand =
string.format('%s --config %s', cbfmt.formatCommand, string.format('%s/.config/cbfmt.toml', vim.env.HOME))
return cbfmt
end,
}

local function load_efm_modules(mods, mod_type)
if not mods then
return nil
end

-- normalize type to string[]
mods = type(mods) == 'string' and { mods } or mods
return vim
.iter(mods)
:map(function(mod)
if efm_customizations[mod] then
return efm_customizations[mod]()
end

local ok, module = pcall(require, string.format('efmls-configs.%s.%s', mod_type, mod))
if not ok then
vim.notify(string.format('Module efmls-configs.%s.%s not found', mod_type, mod))
return nil
end
return module
end)
:totable()
end

local function load_linters(linters)
return load_efm_modules(linters, 'linters') or {}
end

local function load_formatters(formatters)
return load_efm_modules(formatters, 'formatters') or {}
end

function M.efmls_config(capabilities)
local languages = {}
for filetype, config in pairs(M.config) do
if config.linter or config.formatter then
languages[filetype] = vim.list_extend(load_formatters(config.formatter), load_linters(config.linter))
local function cfg_by_ft(cfg)
local result = {}
for ft, ft_cfg in pairs(M.config) do
if ft_cfg[cfg] then
result[ft] = type(ft_cfg[cfg]) == 'table' and ft_cfg[cfg] or { ft_cfg[cfg] }
end
end

return {
filetypes = vim.tbl_keys(languages),
settings = { languages = languages },
init_options = {
documentFormatting = true,
documentRangeFormatting = true,
},
capabilities = capabilities,
}
end

function M.uses_efm(ft)
ft = ft or vim.bo.ft
return vim.tbl_get(M.config, ft, 'formatter') ~= nil or vim.tbl_get(M.config, ft, 'linter') ~= nil
return result
end

function M.formats_with_efm(ft)
ft = ft or vim.bo.ft
return vim.tbl_get(M.config, ft, 'formatter') ~= nil
end
M.formatters_by_ft = cfg_by_ft('formatter')
M.linters_by_ft = cfg_by_ft('linter')

function M.treesitter_parsers()
M.treesitter_parsers = (function()
local result = {}
for ft, config in pairs(M.config) do
if config.treesitter ~= false then
Expand All @@ -173,6 +116,6 @@ function M.treesitter_parsers()
table.insert(result, 'regex')

return result
end
end)()

return M
81 changes: 8 additions & 73 deletions nvim/lua/my/utils/lsp.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ local Methods = vim.lsp.protocol.Methods

local M = {}

local init_done = false

local formatting_enabled = true

---Set up a callback to run on LSP attach
Expand All @@ -21,11 +19,6 @@ function M.on_attach(callback)
end

function M.on_attach_default(client, bufnr)
if not init_done then
init_done = true
M.setup_async_formatting()
end

-- if current nvim version supports inlay hints, enable them
if vim.lsp['inlay_hint'] ~= nil and client.supports_method(Methods.textDocument_inlayHint) then
vim.lsp.inlay_hint.enable(true)
Expand All @@ -40,43 +33,6 @@ function M.on_attach_default(client, bufnr)
end
end

function M.setup_async_formatting()
-- format on save asynchronously, see M.format_document
vim.lsp.handlers[Methods.textDocument_formatting] = function(err, result, ctx)
if err ~= nil then
-- efm uses table messages
if type(err) == 'table' then
if err.message then
err = err.message
else
err = vim.inspect(err)
end
end
vim.api.nvim_err_write(err --[[@as string]])
return
end

if result == nil then
return
end

if
vim.api.nvim_buf_get_var(ctx.bufnr, 'format_changedtick') == vim.api.nvim_buf_get_var(ctx.bufnr, 'changedtick')
then
local view = vim.fn.winsaveview()
vim.lsp.util.apply_text_edits(result, ctx.bufnr, 'utf-16')
if view then
vim.fn.winrestview(view)
end
if ctx.bufnr == vim.api.nvim_get_current_buf() then
vim.b.format_saving = true
vim.cmd.update()
vim.b.format_saving = false
end
end
end
end

function M.apply_ui_tweaks()
-- customize LSP icons
local icons = {
Expand Down Expand Up @@ -132,19 +88,19 @@ function M.toggle_formatting_enabled(enable)
end
end

function M.is_formatting_enabled()
return formatting_enabled
end

---@param buf number|nil defaults to 0 (current buffer)
---@return string|nil
function M.get_formatter_name(buf)
buf = buf or tonumber(vim.g.actual_curbuf or vim.api.nvim_get_current_buf())

-- if it uses efm-langserver, grab the formatter name
local ft_efm_cfg = require('my.lsp.filetypes').config[vim.bo[buf].filetype]
if ft_efm_cfg and ft_efm_cfg.formatter then
if type(ft_efm_cfg.formatter) == 'table' then
return ft_efm_cfg.formatter[1]
else
return tostring(ft_efm_cfg.formatter)
end
-- if it uses conform.nvim, grab the formatter name
local formatter = require('my.lsp.filetypes').formatters_by_ft[vim.bo[buf].ft]
if formatter then
return type(formatter) == 'table' and table.concat(formatter, ', ') or formatter
end

-- otherwise just return the LSP server name
Expand All @@ -168,25 +124,4 @@ function M.is_formatting_supported(buf)
return #clients > 0
end

function M.format_document()
if not M.is_formatting_supported() then
return
end

if not vim.b.format_saving then
vim.b.format_changedtick = vim.b.changedtick
local formats_with_efm = require('my.lsp.filetypes').formats_with_efm()
vim.lsp.buf.format({
async = true,
filter = function(client)
if formats_with_efm then
return client.name == 'efm'
else
return client.name ~= 'efm'
end
end,
})
end
end

return M

0 comments on commit c300f6a

Please sign in to comment.