local add_disable_cmp_filetypes = require('plugin_utils').add_disable_cmp_filetypes local base_colors = require('color').base_colors local lsp_icons = require('font').lsp_icons local codicons = require('font').codicons local diagnostic_icons = require('font').diagnostic_icons local enable_lsp_lines = require('plugin_utils').enable_lsp_lines local get_lsp_lines_status = require('plugin_utils').get_lsp_lines_status local cycle_lsp_lines = require('plugin_utils').cycle_lsp_lines local plugins = { { 'neovim/nvim-lspconfig', event = { 'BufReadPre', 'BufWrite' }, -- Use onetime deno file ft = { 'typescript', 'typescriptreact' }, dependencies = { { 'williamboman/mason.nvim' }, { 'jose-elias-alvarez/null-ls.nvim' }, { 'hrsh7th/cmp-nvim-lsp' }, { 'b0o/SchemaStore.nvim' }, { 'SmiteshP/nvim-navic' }, { 'jose-elias-alvarez/typescript.nvim' }, { 'yioneko/nvim-vtsls' }, }, config = function() vim.diagnostic.config({ virtual_text = false, signs = { priority = 100, }, severity_sort = true, }) local signs = { Error = diagnostic_icons.error, Warn = diagnostic_icons.warn, Info = diagnostic_icons.info, Hint = diagnostic_icons.hint, } for type, icon in pairs(signs) do local hl = 'DiagnosticSign' .. type vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl }) end local lspconfig = require('lspconfig') local mason_lspconfig = require('mason-lspconfig') local cmp_nvim_lsp = require('cmp_nvim_lsp') local null_ls = require('null-ls') local opts = { capabilities = cmp_nvim_lsp.default_capabilities(), on_attach = function(client, bufnr) if client.server_capabilities.documentHighlightProvider then vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { buffer = bufnr, callback = function() vim.lsp.buf.document_highlight() end, }) vim.api.nvim_create_autocmd('CursorMoved', { buffer = bufnr, callback = function() vim.lsp.buf.clear_references() end, }) end client.server_capabilities.semanticTokensProvider = nil if client.server_capabilities.documentSymbolProvider then require('nvim-navic').attach(client, bufnr) end end, } local node_root_dir = lspconfig.util.root_pattern('package.json') local is_node_repo = node_root_dir(vim.api.nvim_buf_get_name(0)) ~= nil mason_lspconfig.setup_handlers({ function(server_name) -- NOTE: vtsls added to mason and lspconfig -- Try to always enable vtsls if server_name == 'vtsls' then if not is_node_repo then return end -- Load nvim-vtsls require('vtsls') opts.settings = { typescript = { suggest = { completeFunctionCalls = true, }, }, } end if server_name == 'eslint' then if not is_node_repo then return end end if server_name == 'denols' then if is_node_repo then return end opts.root_dir = lspconfig.util.root_pattern('deno.json') opts.init_options = { lint = true, unstable = true, suggest = { imports = { hosts = { ['https://deno.land'] = true, }, }, }, } end if server_name == 'sumneko_lua' then opts.settings = { Lua = { diagnostics = { globals = { 'vim' } }, completion = { callSnippet = 'Replace' }, format = { enable = false }, hint = { enable = true }, telemetry = { enable = false }, workspace = { checkThirdParty = false }, -- semantic = { enable = false }, }, } end if server_name == 'jsonls' then opts.settings = { json = { schemas = require('schemastore').json.schemas(), validate = { enable = true }, }, } end if server_name == 'yamlls' then opts.settings = { yaml = { schemas = { require('schemastore').json.schemas() }, validate = { enable = true }, }, } end lspconfig[server_name].setup(opts) end, }) null_ls.setup({ diagnostics_format = '#{m} (#{s}: #{c})', sources = { null_ls.builtins.code_actions.gitsigns, null_ls.builtins.formatting.prettierd.with({ prefer_local = 'node_modules/.bin', }), null_ls.builtins.formatting.stylua, null_ls.builtins.diagnostics.cspell.with({ diagnostics_postprocess = function(diagnostic) diagnostic.severity = vim.diagnostic.severity['HINT'] end, }), null_ls.builtins.code_actions.cspell, }, }) vim.keymap.set({ 'n' }, '(lsp)q', 'FzfPreviewNvimLspCurrentDiagnosticsRpc') vim.keymap.set({ 'n' }, '(lsp)Q', 'FzfPreviewNvimLspDiagnosticsRpc') vim.keymap.set({ 'n' }, '(lsp)f', vim.lsp.buf.format) vim.keymap.set({ 'n' }, '(lsp)d', 'FzfPreviewNvimLspDefinitionRpc') vim.keymap.set({ 'n' }, '(lsp)i', 'FzfPreviewNvimLspImplementationRpc') vim.keymap.set({ 'n' }, '(lsp)I', vim.lsp.buf.implementation) vim.keymap.set({ 'n' }, '(lsp)t', 'FzfPreviewNvimLspTypeDefinitionRpc') vim.keymap.set({ 'n' }, '(lsp)T', vim.lsp.buf.type_definition) vim.keymap.set({ 'n' }, '(lsp)rf', 'FzfPreviewNvimLspReferencesRpc') -- tagjump does not work with Deno vim.keymap.set({ 'n' }, '', vim.lsp.buf.definition) vim.api.nvim_create_autocmd({ 'FileType' }, { pattern = { 'typescript', 'typescriptreact' }, callback = function() if is_node_repo then vim.keymap.set({ 'n' }, '(lsp)f', function() vim.cmd([[EslintFixAll]]) vim.lsp.buf.format({ name = 'null-ls' }) end) else vim.keymap.set({ 'n' }, '(lsp)f', function() vim.lsp.buf.format({ name = 'denols' }) end) end end, }) vim.api.nvim_create_autocmd({ 'FileType' }, { pattern = { 'lua' }, callback = function() vim.keymap.set({ 'n' }, '(lsp)f', function() vim.lsp.buf.format({ name = 'null-ls' }) end) end, }) end, }, { 'williamboman/mason.nvim', dependencies = { { 'williamboman/mason-lspconfig' }, { 'jayp0521/mason-null-ls.nvim' }, }, cmd = { 'Mason', 'MasonInstall', 'MasonUninstall', 'MasonUninstallAll', 'MasonLog' }, config = function() require('mason').setup() require('mason-lspconfig').setup({ ensure_installed = { -- 'tsserver', 'vtsls', 'eslint', 'denols', 'sumneko_lua', 'vimls', 'jsonls', 'yamlls', }, automatic_installation = true, }) require('mason-null-ls').setup({ ensure_installed = { 'prettierd', 'stylua', 'cspell', }, automatic_installation = true, }) end, }, { 'glepnir/lspsaga.nvim', -- NOTE: Use versions earlier than 0.2.3 commit = 'b7b477', -- dir = '~/repos/github.com/yuki-yano/lspsaga.nvim', event = { 'LspAttach' }, init = function() add_disable_cmp_filetypes({ 'sagarename' }) end, config = function() require('lspsaga').init_lsp_saga({ border_style = 'rounded', -- saga_winblend = 10, diagnostic_header = { diagnostic_icons.error .. ' ', diagnostic_icons.warn .. ' ', diagnostic_icons.info .. ' ', diagnostic_icons.hint .. ' ', }, code_action_lightbulb = { enable = false, }, }) -- TODO: new version settings -- require('lspsaga').setup({ -- ui = { -- theme = 'round', -- border = 'rounded', -- title = true, -- code_action = lsp_icons.code_action, -- diagnostic = lsp_icons.diagnostics, -- incoming = lsp_icons.incoming, -- outgoing = lsp_icons.outgoing, -- colors = { -- normal_bg = base_colors.black, -- title_bg = base_colors.green, -- red = base_colors.red, -- magenta = base_colors.magenta, -- orange = base_colors.orange, -- yellow = base_colors.yellow, -- green = base_colors.green, -- cyan = base_colors.cyan, -- blue = base_colors.blue, -- purple = base_colors.purple, -- white = base_colors.white, -- black = base_colors.black, -- }, -- }, -- diagnostic = { -- show_code_action = false, -- }, -- lightbulb = { -- enable = false, -- }, -- symbol_in_winbar = { -- enable = false, -- }, -- }) -- TODO: Integrate with nvim-ufo vim.keymap.set({ 'n' }, 'K', function() local ft = vim.o.filetype if ft == 'vim' or ft == 'help' then vim.cmd([[execute 'h ' . expand('') ]]) else vim.cmd([[Lspsaga hover_doc]]) end end) vim.keymap.set({ 'n' }, '(lsp)h', 'Lspsaga lsp_finder') vim.keymap.set({ 'n' }, '(lsp)D', 'Lspsaga peek_definition') -- Use actions-preview.nvim -- vim.keymap.set({ 'n', 'x' }, '(lsp)a', 'Lspsaga code_action') vim.keymap.set({ 'n' }, '(lsp)rn', 'Lspsaga rename') vim.keymap.set({ 'n' }, '(lsp)n', 'Lspsaga diagnostic_jump_next') vim.keymap.set({ 'n' }, '(lsp)p', 'Lspsaga diagnostic_jump_prev') vim.keymap.set({ 'n' }, '(lsp)m', 'Lspsaga show_cursor_diagnostics') end, }, { 'zbirenbaum/neodim', dependencies = { { 'nvim-treesitter/nvim-treesitter' }, }, event = { 'LspAttach' }, init = function() -- FIX: Workaround, highlighted group does not exist error -- TSPunctuation{Xxx} where it should be defined as TSPunct{Xxx}. vim.api.nvim_set_hl(0, 'TSPunctuationBracket', { link = '@punctuation.bracket' }) vim.api.nvim_set_hl(0, 'TSPunctuationDelimiter', { link = '@punctuation.delimiter' }) vim.api.nvim_set_hl(0, 'TSPunctuationSpecial', { link = '@punctuation.special' }) vim.api.nvim_set_hl(0, 'TSSpell', { link = '@spell' }) end, config = function() require('neodim').setup({ update_in_insert = { enable = false, }, hide = { signs = false, underline = true, }, }) end, }, { 'folke/trouble.nvim', cmd = { 'Trouble', 'TroubleToggle' }, config = function() require('trouble').setup({ use_diagnostic_signs = true, fold_open = 'v', fold_closed = '>', indent_lines = false, }) end, }, { 'j-hui/fidget.nvim', event = { 'LspAttach' }, config = function() require('fidget').setup() end, }, { 'ray-x/lsp_signature.nvim', event = { 'LspAttach' }, config = function() require('lsp_signature').setup({ hint_enable = false, }) end, }, { 'aznhe21/actions-preview.nvim', dependencies = { { 'MunifTanjim/nui.nvim' }, { 'nvim-telescope/telescope.nvim' }, }, event = { 'LspAttach' }, config = function() require('actions-preview').setup({ diff = { algorithm = 'histogram', }, }) vim.keymap.set({ 'n', 'x' }, '(lsp)a', require('actions-preview').code_actions) end, }, { -- Load from lspconfig 'SmiteshP/nvim-navic', config = function() require('nvim-navic').setup({ icons = codicons, }) end, }, { 'yioneko/nvim-vtsls', config = function() vim.api.nvim_create_autocmd({ 'FileType' }, { pattern = { 'typescript', 'typescriptreact' }, callback = function() vim.keymap.set({ 'n' }, '(lsp)s', 'VtsExec goto_source_definition') end, }) vim.api.nvim_create_user_command('OrganizeImport', function() vim.cmd([[VtsExec organize_imports]]) end, {}) end, }, { -- NOTE: Use my fork 'yuki-yano/lsp_lines.nvim', enabled = enable_lsp_lines, event = { 'LspAttach' }, init = function() vim.api.nvim_create_autocmd({ 'ColorScheme' }, { pattern = { 'gruvbox-material' }, callback = function() vim.api.nvim_set_hl(0, 'DiagnosticVirtualTextError', { link = 'DiagnosticSignError' }) vim.api.nvim_set_hl(0, 'DiagnosticVirtualTextWarn', { link = 'DiagnosticSignWarn' }) end, }) end, config = function() local virtual_lines = get_lsp_lines_status() require('lsp_lines').setup() vim.diagnostic.config({ virtual_lines = virtual_lines.value }) vim.keymap.set({ 'n' }, '(lsp)l', cycle_lsp_lines) end, }, } for _, plugin in ipairs(plugins) do plugin.enabled = vim.env.LSP == 'nvim' end return plugins