local util = require('user.util') vim.diagnostic.config({ -- only show virtual text for WARN and higher virtual_text = { severity = { min = vim.diagnostic.severity.WARN } }, }) vim.lsp.config('*', { flags = { debounce_text_changes = 250, } }) vim.lsp.enable('bashls'); vim.lsp.enable('eslint'); if vim.fn.executable('dprint') == 1 then local version = vim.version.parse(vim.fn.system('dprint --version')) if vim.version.cmp(version, { 0, 45, 0 }) >= 0 then vim.lsp.enable('dprint') end end if vim.fn.executable('deno') == 1 then vim.lsp.enable('deno'); else local preferences = { importModuleSpecifierPreference = 'non-relative', -- this prevents renames from aliasing when destructuring providePrefixAndSuffixTextForRename = false, } local helix_preferences = vim.tbl_get( util.read_helix_config(), 'language-server', 'typescript-language-server', 'config', 'preferences' ) if helix_preferences ~= nil then preferences = vim.tbl_deep_extend('force', preferences, helix_preferences) end local function make_settings() -- we disable formatting but these are still used when performing some code -- actions local format = { indentSize = vim.bo.shiftwidth, convertTabsToSpaces = vim.o.expandtab, } return { javascript = { format = format }, typescript = { format = format }, } end vim.lsp.config('ts_ls', { init_options = { completionDisableFilterText = true, preferences = preferences, }, settings = make_settings(), handlers = { ['$/typescriptVersion'] = function(err, result, ctx, config) vim.notify(string.format('Typescript %s', result.version)) end, }, on_init = function(client) -- mark tsserver as not having formatting available as we rely on -- eslint and dprint for that client.server_capabilities.documentFormattingProvider = false client.server_capabilities.documentRangeFormattingProvider = false -- we only really know our settings once we've opened a file so report -- the new formatting settings client:notify(vim.lsp.protocol.Methods.workspace_didChangeConfiguration, { settings = make_settings(), }) end, }) vim.lsp.enable('ts_ls') end vim.lsp.enable('gopls') vim.lsp.config('ruby_lsp', { init_options = { enabledFeatures = { formatting = false, }, } }) vim.lsp.enable('ruby_lsp') vim.lsp.enable('nil_ls') vim.lsp.config('jdtls', { handlers = { ['$/progress'] = function() -- this is quite noisy so just disable it end }, }) vim.lsp.enable('jdtls') vim.lsp.enable('lua_ls') -- custom LSP servers vim.lsp.config('elvish', { cmd = { 'elvish', '--lsp' }, filetypes = { 'elvish' }, settings = {}, }) vim.lsp.enable('elvish') -- diagnostics vim.keymap.set('n', 'e', function() vim.diagnostic.open_float() end) vim.keymap.set('n', '[d', function() vim.diagnostic.jump({ count = -1, float = true, severity = vim.diagnostic.severity.ERROR }) end) vim.keymap.set('n', ']d', function() vim.diagnostic.jump({ count = 1, float = true, severity = vim.diagnostic.severity.ERROR }) end) vim.keymap.set('n', '[D', function() vim.diagnostic.jump({ count = -1, float = true }) end) vim.keymap.set('n', ']D', function() vim.diagnostic.jump({ count = 1, float = true }) end) vim.keymap.set('n', 'qe', function() vim.diagnostic.setqflist({ severity = vim.diagnostic.severity.ERROR }) end) vim.keymap.set('n', 'qw', function() vim.diagnostic.setqflist({ severity = { min = vim.diagnostic.severity.WARN } }) end) vim.keymap.set('n', 'qd', function() vim.diagnostic.setqflist({}) end) vim.keymap.set('n', 'qc', 'cclose') -- LSP-specific vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) if client.name == 'dprint' or client.name == 'eslint' then -- mappings should have been attached by typescript and re-attaching can -- overwrite the typescript specific overrides return end local opts = { buffer = args.buf } vim.keymap.set('n', 'gD', 'lua vim.lsp.buf.declaration()', opts) vim.keymap.set('n', 'gd', 'Telescope lsp_definitions', opts) vim.keymap.set('n', 'D', 'Telescope lsp_type_definitions', opts) -- as much as possible we try to use the default bindings, replacing them -- with Telescope if appropriate vim.keymap.set('n', 'gri', 'Telescope lsp_implementations', opts) vim.keymap.set('n', 'grr', 'Telescope lsp_references', opts) vim.keymap.set('n', 'gO', 'Telescope lsp_document_symbols', opts) if client.name == 'ts_ls' then -- exclude import statements from reference search (may have false positives) vim.keymap.set('n', 'grr', 'Telescope lsp_references default_text=!import\\ ', opts) vim.keymap.set('n', 'grA', 'LspTypescriptSourceAction', opts) end end, }) -- handle file renames vim.api.nvim_create_autocmd('User', { pattern = 'MiniFilesActionRename', callback = function(opts) local params = { files = { { oldUri = vim.uri_from_fname(opts.data.from), newUri = vim.uri_from_fname(opts.data.to), } } } local bufnr = vim.fn.bufadd(opts.data.to) local clients = vim.lsp.get_clients({ bufnr = bufnr }) for _, client in ipairs(clients) do if client:supports_method('workspace/willRenameFiles') then local resp = client:request_sync('workspace/willRenameFiles', params, 5000, bufnr) if resp and resp.result ~= nil then vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding) end end end for _, client in ipairs(clients) do if client:supports_method('workspace/didRenameFiles') then client:notify('workspace/didRenameFiles', params) end end end, nested = true, })