vim.diagnostic.config({ -- only show virtual text for WARN and higher virtual_text = { severity = { min = vim.diagnostic.severity.WARN } }, }) 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 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 = { importModuleSpecifierPreference = 'non-relative', -- this prevents renames from aliasing when destructuring providePrefixAndSuffixTextForRename = false, }, }, settings = make_settings(), handlers = { ['$/typescriptVersion'] = function(err, result, ctx, config) vim.notify(string.format('Typescript %s', result.version)) end, -- handler used with extract type to interface, etc which asks to rename -- the newly created type ['_typescript.rename'] = function(err, result, ctx) local client = vim.lsp.get_client_by_id(ctx.client_id) vim.lsp.util.show_document({ uri = result.textDocument.uri, range = { start = result.position, ['end'] = result.position, } }, client.offset_encoding) vim.lsp.buf.rename() return result end, }, flags = { debounce_text_changes = 150, }, 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, on_attach = function(client) -- add custom commands, we follow upstream's Lsp* prefix convention -- setup custom source actions, unlike code actions these apply to the -- whole file rather than a particular line. local function source_action(usercmd_name, command_name) vim.api.nvim_buf_create_user_command(0, usercmd_name, function() vim.lsp.buf.code_action({ context = { only = { command_name } }, apply = true, }) end, {}) end source_action("LspAddMissingImports", "source.addMissingImports.ts") source_action("LspOrganizeImports", "source.organizeImports.ts") source_action("LspRemoveUnusedImports", "source.removeUnusedImports.ts") -- rename file with import renaming, this does no error checking vim.api.nvim_buf_create_user_command(0, "LspRenameFile", function() local source = vim.api.nvim_buf_get_name(0) local function do_rename(target) if target == nil then return end -- rename the buffer vim.lsp.util.rename(source, target) -- ask LSP to rename imports client:exec_cmd({ command = "_typescript.applyRenameFile", arguments = { { sourceUri = vim.uri_from_fname(source), targetUri = vim.uri_from_fname(target), } } }) end vim.ui.input({ prompt = "New Filename: ", completion = "file", default = source, }, do_rename) end, {}) end, }) vim.lsp.enable("ts_ls") end if vim.fn.executable("gopls") == 1 then vim.lsp.enable("gopls") end if vim.fn.executable("ruby-lsp") == 1 then vim.lsp.config("ruby_lsp", { init_options = { enabledFeatures = { formatting = false, }, } }) vim.lsp.enable("ruby_lsp") end if vim.fn.executable("nil") == 1 then vim.lsp.enable("nil_ls") end if vim.fn.executable("jdtls") == 1 then vim.lsp.config("jdtls", { handlers = { ["$/progress"] = function() -- this is quite noisy so just disable it end }, }) vim.lsp.enable("jdtls") end -- custom LSP servers vim.lsp.config("elvish", { cmd = {'elvish', '--lsp'}, filetypes = {'elvish'}, settings = {}, }) vim.lsp.enable("elvish")