From b51f1ae28924a752258e7607fbc3210f9b18eaac Mon Sep 17 00:00:00 2001 From: Gustaf Rydholm Date: Thu, 22 Jul 2021 00:08:36 +0200 Subject: Updates based on Chris's lunarvim --- .config/nvim/lua/lsp/emmet-ls.lua | 23 +++ .config/nvim/lua/lsp/init.lua | 264 ++++++++++++++++++++++++++++++++ .config/nvim/lua/lsp/tailwindcss-ls.lua | 13 ++ .config/nvim/lua/lsp/ts-fmt-lint.lua | 72 +++++++++ .config/nvim/lua/lsp/tsserver-ls.lua | 83 ++++++++++ 5 files changed, 455 insertions(+) create mode 100644 .config/nvim/lua/lsp/emmet-ls.lua create mode 100644 .config/nvim/lua/lsp/init.lua create mode 100644 .config/nvim/lua/lsp/tailwindcss-ls.lua create mode 100644 .config/nvim/lua/lsp/ts-fmt-lint.lua create mode 100644 .config/nvim/lua/lsp/tsserver-ls.lua (limited to '.config/nvim/lua/lsp') diff --git a/.config/nvim/lua/lsp/emmet-ls.lua b/.config/nvim/lua/lsp/emmet-ls.lua new file mode 100644 index 0000000..e38747a --- /dev/null +++ b/.config/nvim/lua/lsp/emmet-ls.lua @@ -0,0 +1,23 @@ +-- if not package.loaded['lspconfig'] then +-- return +-- end + +local nvim_lsp = require "lspconfig" +local configs = require "lspconfig/configs" +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +configs.emmet_ls = { + default_config = { + cmd = { "emmet-ls", "--stdio" }, + filetypes = { "html", "css", "javascript", "typescript", "vue" }, + root_dir = function() + return vim.loop.cwd() + end, + settings = {}, + }, +} + +nvim_lsp.emmet_ls.setup { + -- on_attach = on_attach; +} diff --git a/.config/nvim/lua/lsp/init.lua b/.config/nvim/lua/lsp/init.lua new file mode 100644 index 0000000..6a52b9d --- /dev/null +++ b/.config/nvim/lua/lsp/init.lua @@ -0,0 +1,264 @@ +-- TODO: figure out why this don't work +vim.fn.sign_define( + "LspDiagnosticsSignError", + { texthl = "LspDiagnosticsSignError", text = "", numhl = "LspDiagnosticsSignError" } +) +vim.fn.sign_define( + "LspDiagnosticsSignWarning", + { texthl = "LspDiagnosticsSignWarning", text = "", numhl = "LspDiagnosticsSignWarning" } +) +vim.fn.sign_define( + "LspDiagnosticsSignHint", + { texthl = "LspDiagnosticsSignHint", text = "", numhl = "LspDiagnosticsSignHint" } +) +vim.fn.sign_define( + "LspDiagnosticsSignInformation", + { texthl = "LspDiagnosticsSignInformation", text = "", numhl = "LspDiagnosticsSignInformation" } +) + +-- local opts = { border = "single" } +-- TODO revisit this +-- local border = { +-- { "🭽", "FloatBorder" }, +-- { "▔", "FloatBorder" }, +-- { "🭾", "FloatBorder" }, +-- { "▕", "FloatBorder" }, +-- { "🭿", "FloatBorder" }, +-- { "▁", "FloatBorder" }, +-- { "🭼", "FloatBorder" }, +-- { "▏", "FloatBorder" }, +-- } + +-- My font didn't like this :/ +-- vim.api.nvim_set_keymap( +-- "n", +-- "gl", +-- 'lua vim.lsp.diagnostic.show_line_diagnostics({ show_header = false, border = { { "🭽", "FloatBorder" }, { "▔", "FloatBorder" }, { "🭾", "FloatBorder" }, { "▕", "FloatBorder" }, { "🭿", "FloatBorder" }, { "▁", "FloatBorder" }, { "🭼", "FloatBorder" }, { "▏", "FloatBorder" }, } })', +-- { noremap = true, silent = true } +-- ) + +if O.lsp.default_keybinds then + vim.cmd "nnoremap gd lua vim.lsp.buf.definition()" + vim.cmd "nnoremap gD lua vim.lsp.buf.declaration()" + vim.cmd "nnoremap gr lua vim.lsp.buf.references()" + vim.cmd "nnoremap gi lua vim.lsp.buf.implementation()" + vim.api.nvim_set_keymap( + "n", + "gl", + 'lua vim.lsp.diagnostic.show_line_diagnostics({ show_header = false, border = "single" })', + { noremap = true, silent = true } + ) + + vim.cmd "nnoremap gp lua require'lsp'.PeekDefinition()" + vim.cmd "nnoremap K :lua vim.lsp.buf.hover()" + vim.cmd "nnoremap :lua vim.lsp.diagnostic.goto_prev({popup_opts = {border = O.lsp.popup_border}})" + vim.cmd "nnoremap :lua vim.lsp.diagnostic.goto_next({popup_opts = {border = O.lsp.popup_border}})" + vim.cmd "nnoremap lua vim.lsp.buf.signature_help()" + -- scroll down hover doc or scroll in definition preview + -- scroll up hover doc + vim.cmd 'command! -nargs=0 LspVirtualTextToggle lua require("lsp/virtual_text").toggle()' +end + +-- Set Default Prefix. +-- Note: You can set a prefix per lsp server in the lv-globals.lua file +vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + virtual_text = O.lsp.diagnostics.virtual_text, + signs = O.lsp.diagnostics.signs, + underline = O.lsp.document_highlight, +}) + +vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { + border = O.lsp.popup_border, +}) + +vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { + border = O.lsp.popup_border, +}) + +-- symbols for autocomplete +vim.lsp.protocol.CompletionItemKind = { + "  (Text) ", + "  (Method)", + "  (Function)", + "  (Constructor)", + " ﴲ (Field)", + "[] (Variable)", + "  (Class)", + " ﰮ (Interface)", + "  (Module)", + " 襁 (Property)", + "  (Unit)", + "  (Value)", + " 練 (Enum)", + "  (Keyword)", + "  (Snippet)", + "  (Color)", + "  (File)", + "  (Reference)", + "  (Folder)", + "  (EnumMember)", + " ﲀ (Constant)", + " ﳤ (Struct)", + "  (Event)", + "  (Operator)", + "  (TypeParameter)", +} + +--[[ " autoformat +autocmd BufWritePre *.js lua vim.lsp.buf.formatting_sync(nil, 100) +autocmd BufWritePre *.jsx lua vim.lsp.buf.formatting_sync(nil, 100) +autocmd BufWritePre *.lua lua vim.lsp.buf.formatting_sync(nil, 100) ]] +-- Java +-- autocmd FileType java nnoremap ca lua require('jdtls').code_action() + +local function lsp_highlight_document(client) + if O.lsp.document_highlight == false then + return -- we don't need further + end + -- Set autocommands conditional on server_capabilities + if client.resolved_capabilities.document_highlight then + vim.api.nvim_exec( + [[ + hi LspReferenceRead cterm=bold ctermbg=red guibg=#464646 + hi LspReferenceText cterm=bold ctermbg=red guibg=#464646 + hi LspReferenceWrite cterm=bold ctermbg=red guibg=#464646 + augroup lsp_document_highlight + autocmd! * + autocmd CursorHold lua vim.lsp.buf.document_highlight() + autocmd CursorMoved lua vim.lsp.buf.clear_references() + augroup END + ]], + false + ) + end +end +local lsp_config = {} + +-- Taken from https://www.reddit.com/r/neovim/comments/gyb077/nvimlsp_peek_defination_javascript_ttserver/ +function lsp_config.preview_location(location, context, before_context) + -- location may be LocationLink or Location (more useful for the former) + context = context or 15 + before_context = before_context or 0 + local uri = location.targetUri or location.uri + if uri == nil then + return + end + local bufnr = vim.uri_to_bufnr(uri) + if not vim.api.nvim_buf_is_loaded(bufnr) then + vim.fn.bufload(bufnr) + end + + local range = location.targetRange or location.range + local contents = vim.api.nvim_buf_get_lines( + bufnr, + range.start.line - before_context, + range["end"].line + 1 + context, + false + ) + local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") + return vim.lsp.util.open_floating_preview(contents, filetype, { border = O.lsp.popup_border }) +end + +function lsp_config.preview_location_callback(_, method, result) + local context = 15 + if result == nil or vim.tbl_isempty(result) then + print("No location found: " .. method) + return nil + end + if vim.tbl_islist(result) then + lsp_config.floating_buf, lsp_config.floating_win = lsp_config.preview_location(result[1], context) + else + lsp_config.floating_buf, lsp_config.floating_win = lsp_config.preview_location(result, context) + end +end + +function lsp_config.PeekDefinition() + if vim.tbl_contains(vim.api.nvim_list_wins(), lsp_config.floating_win) then + vim.api.nvim_set_current_win(lsp_config.floating_win) + else + local params = vim.lsp.util.make_position_params() + return vim.lsp.buf_request(0, "textDocument/definition", params, lsp_config.preview_location_callback) + end +end + +function lsp_config.PeekTypeDefinition() + if vim.tbl_contains(vim.api.nvim_list_wins(), lsp_config.floating_win) then + vim.api.nvim_set_current_win(lsp_config.floating_win) + else + local params = vim.lsp.util.make_position_params() + return vim.lsp.buf_request(0, "textDocument/typeDefinition", params, lsp_config.preview_location_callback) + end +end + +function lsp_config.PeekImplementation() + if vim.tbl_contains(vim.api.nvim_list_wins(), lsp_config.floating_win) then + vim.api.nvim_set_current_win(lsp_config.floating_win) + else + local params = vim.lsp.util.make_position_params() + return vim.lsp.buf_request(0, "textDocument/implementation", params, lsp_config.preview_location_callback) + end +end + +function lsp_config.common_on_attach(client, bufnr) + if O.lsp.on_attach_callback then + O.lsp.on_attach_callback(client, bufnr) + end + lsp_highlight_document(client) +end + +function lsp_config.tsserver_on_attach(client, _) + -- lsp_config.common_on_attach(client, bufnr) + client.resolved_capabilities.document_formatting = false + + local ts_utils = require "nvim-lsp-ts-utils" + + -- defaults + ts_utils.setup { + debug = false, + disable_commands = false, + enable_import_on_completion = false, + import_all_timeout = 5000, -- ms + + -- eslint + eslint_enable_code_actions = true, + eslint_enable_disable_comments = true, + -- eslint_bin = O.lang.tsserver.linter, + eslint_config_fallback = nil, + eslint_enable_diagnostics = true, + + -- formatting + enable_formatting = O.lang.tsserver.autoformat, + formatter = O.lang.tsserver.formatter.exe, + formatter_config_fallback = nil, + + -- parentheses completion + complete_parens = false, + signature_help_in_parens = false, + + -- update imports on file move + update_imports_on_move = false, + require_confirmation_on_move = false, + watch_dir = nil, + } + + -- required to fix code action ranges + ts_utils.setup_client(client) + + -- TODO: keymap these? + -- vim.api.nvim_buf_set_keymap(bufnr, "n", "gs", ":TSLspOrganize", {silent = true}) + -- vim.api.nvim_buf_set_keymap(bufnr, "n", "qq", ":TSLspFixCurrent", {silent = true}) + -- vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", ":TSLspRenameFile", {silent = true}) + -- vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", ":TSLspImportAll", {silent = true}) +end + +require("utils").define_augroups { + _general_lsp = { + { "FileType", "lspinfo", "nnoremap q :q" }, + }, +} + +-- Use a loop to conveniently both setup defined servers +-- and map buffer local keybindings when the language server attaches +-- local servers = {"pyright", "tsserver"} +-- for _, lsp in ipairs(servers) do nvim_lsp[lsp].setup {on_attach = on_attach} end +return lsp_config diff --git a/.config/nvim/lua/lsp/tailwindcss-ls.lua b/.config/nvim/lua/lsp/tailwindcss-ls.lua new file mode 100644 index 0000000..38c1e7c --- /dev/null +++ b/.config/nvim/lua/lsp/tailwindcss-ls.lua @@ -0,0 +1,13 @@ +-- TODO: what is a tailwindcss filetype +local lspconfig = require "lspconfig" + +lspconfig.tailwindcss.setup { + cmd = { + "node", + DATA_PATH .. "/lspinstall/tailwindcss/tailwindcss-intellisense/extension/dist/server/tailwindServer.js", + "--stdio", + }, + filetypes = O.lang.tailwindcss.filetypes, + root_dir = require("lspconfig/util").root_pattern("tailwind.config.js", "postcss.config.ts", ".postcssrc"), + on_attach = require("lsp").common_on_attach, +} diff --git a/.config/nvim/lua/lsp/ts-fmt-lint.lua b/.config/nvim/lua/lsp/ts-fmt-lint.lua new file mode 100644 index 0000000..7cebfd8 --- /dev/null +++ b/.config/nvim/lua/lsp/ts-fmt-lint.lua @@ -0,0 +1,72 @@ +-- Example configuations here: https://github.com/mattn/efm-langserver +local M = {} + +M.setup = function() + vim.cmd "let proj = FindRootDirectory()" + local root_dir = vim.api.nvim_get_var "proj" + + local get_linter_instance = function() + -- prioritize local instance over global + local local_instance = root_dir .. "/node_modules/.bin/" .. O.lang.tsserver.linter + if vim.fn.executable(local_instance) == 1 then + return local_instance + end + return O.lang.tsserver.linter + end + + local tsserver_args = {} + local formattingSupported = false + + if O.lang.tsserver.linter == "eslint" or O.lang.tsserver.linter == "eslint_d" then + local eslint = { + lintCommand = get_linter_instance() .. " -f visualstudio --stdin --stdin-filename ${INPUT}", + lintStdin = true, + lintFormats = { + "%f(%l,%c): %tarning %m", + "%f(%l,%c): %trror %m", + }, + lintSource = O.lang.tsserver.linter, + lintIgnoreExitCode = true, + } + table.insert(tsserver_args, eslint) + -- Only eslint_d supports --fix-to-stdout + if string.find(get_linter_instance(), "eslint_d") then + formattingSupported = true + local eslint_fix = { + formatCommand = get_linter_instance() .. " --fix-to-stdout --stdin --stdin-filename ${INPUT}", + formatStdin = true, + } + table.insert(tsserver_args, eslint_fix) + end + end + + require("lspconfig").efm.setup { + -- init_options = {initializationOptions}, + cmd = { DATA_PATH .. "/lspinstall/efm/efm-langserver" }, + init_options = { documentFormatting = formattingSupported, codeAction = false }, + root_dir = require("lspconfig").util.root_pattern(".git/", "package.json"), + filetypes = { + "vue", + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "javascript.jsx", + "typescript.tsx", + }, + settings = { + rootMarkers = { ".git/", "package.json" }, + languages = { + vue = tsserver_args, + javascript = tsserver_args, + javascriptreact = tsserver_args, + ["javascript.jsx"] = tsserver_args, + typescript = tsserver_args, + ["typescript.tsx"] = tsserver_args, + typescriptreact = tsserver_args, + }, + }, + } +end + +return M diff --git a/.config/nvim/lua/lsp/tsserver-ls.lua b/.config/nvim/lua/lsp/tsserver-ls.lua new file mode 100644 index 0000000..c687dfc --- /dev/null +++ b/.config/nvim/lua/lsp/tsserver-ls.lua @@ -0,0 +1,83 @@ +vim.cmd "let proj = FindRootDirectory()" +local root_dir = vim.api.nvim_get_var "proj" + +-- use the global prettier if you didn't find the local one +local prettier_instance = root_dir .. "/node_modules/.bin/prettier" +if vim.fn.executable(prettier_instance) ~= 1 then + prettier_instance = O.lang.tsserver.formatter.exe +end + +O.formatters.filetype["javascriptreact"] = { + function() + local args = { "--stdin-filepath", vim.fn.fnameescape(vim.api.nvim_buf_get_name(0)) } + local extend_args = O.lang.tsserver.formatter.args + + if extend_args then + for i = 1, #extend_args do + table.insert(args, extend_args[i]) + end + end + + return { + exe = prettier_instance, + args = args, + stdin = true, + } + end, +} +O.formatters.filetype["javascript"] = O.formatters.filetype["javascriptreact"] +O.formatters.filetype["typescript"] = O.formatters.filetype["javascriptreact"] +O.formatters.filetype["typescriptreact"] = O.formatters.filetype["javascriptreact"] + +require("formatter.config").set_defaults { + logging = false, + filetype = O.formatters.filetype, +} + +if require("utils").check_lsp_client_active "tsserver" then + return +end + +-- npm install -g typescript typescript-language-server +-- require'snippets'.use_suggested_mappings() +-- local capabilities = vim.lsp.protocol.make_client_capabilities() +-- capabilities.textDocument.completion.completionItem.snippetSupport = true; +-- local on_attach_common = function(client) +-- print("LSP Initialized") +-- require'completion'.on_attach(client) +-- require'illuminate'.on_attach(client) +-- end + +local on_attach = function(client, bufnr) + local lsp = require "lsp" + lsp.common_on_attach(client, bufnr) + lsp.tsserver_on_attach(client, bufnr) +end + +require("lspconfig").tsserver.setup { + cmd = { + DATA_PATH .. "/lspinstall/typescript/node_modules/.bin/typescript-language-server", + "--stdio", + }, + filetypes = { + "javascript", + "javascriptreact", + "javascript.jsx", + "typescript", + "typescriptreact", + "typescript.tsx", + }, + on_attach = on_attach, + -- This makes sure tsserver is not used for formatting (I prefer prettier) + settings = { documentFormatting = false }, + handlers = { + -- ["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + -- virtual_text = O.lang.tsserver.diagnostics.virtual_text, + -- signs = O.lang.tsserver.diagnostics.signs, + -- underline = O.lang.tsserver.diagnostics.underline, + -- update_in_insert = true, + -- }), + }, +} + +require("lsp.ts-fmt-lint").setup() -- cgit v1.2.3-70-g09d2