return { { 'williamboman/mason.nvim', lazy = false, opts = {} }, -- Autocompletion { 'hrsh7th/nvim-cmp', event = 'InsertEnter', config = function() local cmp = require('cmp') cmp.setup({ sources = { { name = 'nvim_lsp' } }, mapping = cmp.mapping.preset.insert({ [''] = cmp.mapping.complete(), [''] = cmp.mapping.scroll_docs(-4), [''] = cmp.mapping.scroll_docs(4), -- Use enter to confirm completion [''] = cmp.mapping.confirm({ select = false }), -- Navigate completions with and [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), [''] = cmp.mapping(function(fallback) if cmp.visible() then cmp.confirm({ select = true }) elseif vim.snippet and vim.snippet.active() then vim.snippet.jump(1) else fallback() end end, { 'i', 's' }), }), snippet = { expand = function(args) vim.snippet.expand(args.body) end } }) end }, -- LSP { 'neovim/nvim-lspconfig', cmd = { 'LspInfo', 'LspInstall', 'LspStart' }, event = { 'BufReadPre', 'BufNewFile' }, dependencies = { { 'hrsh7th/cmp-nvim-lsp' }, { 'williamboman/mason.nvim' }, { 'williamboman/mason-lspconfig.nvim' } }, init = function() -- Reserve a space in the gutter -- This will avoid an annoying layout shift in the screen vim.opt.signcolumn = 'yes' end, config = function() -- Add cmp_nvim_lsp capabilities settings to lspconfig -- This should be executed before you configure any language server local capabilities = vim.lsp.protocol.make_client_capabilities() capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities) -- Define the autoformat function locally local buffer_autoformat = function(bufnr) local group = 'lsp_autoformat' vim.api.nvim_create_augroup(group, { clear = false }) vim.api.nvim_clear_autocmds({ group = group, buffer = bufnr }) vim.api.nvim_create_autocmd('BufWritePre', { buffer = bufnr, group = group, desc = 'LSP format on save', callback = function() -- note: do not enable async formatting vim.lsp.buf.format({ async = false, timeout_ms = 10000 }) end }) end -- LspAttach is where you enable features that only work -- if there is a language server active in the file vim.api.nvim_create_autocmd('LspAttach', { desc = 'LSP actions', callback = function(event) -- Autoformat on save local id = vim.tbl_get(event, 'data', 'client_id') local client = id and vim.lsp.get_client_by_id(id) if client == nil then return end if client.supports_method('textDocument/formatting') then buffer_autoformat(event.buf) end -- vim.keymap.set('n', 'K', 'lua vim.lsp.buf.hover()', -- { buffer = event.buf, desc = "Hover over selection" }) vim.keymap.set('n', 'gd', 'lua vim.lsp.buf.definition()', { buffer = event.buf, desc = "Go to definition" }) -- Go to definition in split window: Split window, move to left and open definition vim.keymap.set('n', 'gD', 'vsplit | wincmd L | lua vim.lsp.buf.declaration()', { noremap = true, silent = true, desc = "Go to definition in split window" }) vim.keymap.set('n', 'gi', 'lua vim.lsp.buf.implementation()', { buffer = event.buf, desc = "Go to implementation" }) vim.keymap.set('n', 'go', 'lua vim.lsp.buf.type_definition()', { buffer = event.buf, desc = "Go to type definition" }) vim.keymap.set('n', 'gr', 'lua vim.lsp.buf.references()', { buffer = event.buf, desc = "Show references" }) vim.keymap.set('n', 'gs', 'lua vim.lsp.buf.signature_help()', { buffer = event.buf, desc = "Show signature help" }) vim.keymap.set('n', 'gR', 'lua vim.lsp.buf.rename()', { buffer = event.buf, desc = "Rename" }) vim.keymap.set({ 'n', 'x' }, 'f', 'lua vim.lsp.buf.format({async = true})', { buffer = event.buf, desc = "Format selection" }) vim.keymap.set('n', '', 'lua vim.lsp.buf.code_action()', { buffer = event.buf, desc = "Code action" }) end }) vim.lsp.config('eslint', { capabilities = capabilities, settings = { eslint = { enable = true, packageManager = "yarn", configFiles = ".eslint.config.mjs", validate = "on" } } }) require('mason').setup() require('mason-lspconfig').setup({ ensure_installed = { "eslint", "clangd" }, handlers = { -- this first function is the "default handler" -- it applies to every language server without a "custom handler" function(server_name) vim.lsp.config(server_name, { capabilities = capabilities }) vim.lsp.enable(server_name) end, lua_ls = function() vim.lsp.config('lua_ls', { capabilities = capabilities, settings = { Lua = { diagnostics = { globals = { 'vim' }, }, }, }, }) vim.lsp.enable('lua_ls') end, tinymist = function() vim.lsp.config('tinymist', { capabilities = capabilities, settings = { formatterMode = "typstyle", exportPdf = "onSave", }, }) vim.lsp.enable('tinymist') end, } }) -- sourcekit is NOT managed by mason, set up separately local lspconfig = require('lspconfig') lspconfig["sourcekit"].setup({ capabilities = capabilities, cmd = { "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp", }, root_dir = function(filename, _) local util = require("lspconfig.util") return util.root_pattern("buildServer.json")(filename) or util.root_pattern("*.xcodeproj", "*.xcworkspace")(filename) or util.find_git_ancestor(filename) or util.root_pattern("Package.swift")(filename) end, }) end } }