288 lines
10 KiB

9 months ago
9 months ago
  1. return {
  2. "neovim/nvim-lspconfig",
  3. event = { "BufReadPre", "BufNewFile" },
  4. dependencies = {
  5. { "saghen/blink.cmp" },
  6. { "antosha417/nvim-lsp-file-operations", config = true },
  7. { "williamboman/mason.nvim", config = true },
  8. { "williamboman/mason-lspconfig.nvim" },
  9. { "WhoIsSethDaniel/mason-tool-installer.nvim" },
  10. { "j-hui/fidget.nvim", opts = {} },
  11. { "folke/neodev.nvim", opts = {} },
  12. },
  13. config = function()
  14. local lspconfig = require("lspconfig")
  15. local util = require("lspconfig.util")
  16. local keymap = vim.keymap
  17. vim.api.nvim_create_autocmd("LspAttach", {
  18. group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }),
  19. callback = function(event)
  20. local opts = { noremap = true, silent = true }
  21. opts.desc = "Show LSP references"
  22. keymap.set("n", "gr", "<cmd>Telescope lsp_references<CR>", opts)
  23. opts.desc = "Go to declaration"
  24. keymap.set("n", "gD", vim.lsp.buf.declaration, opts)
  25. opts.desc = "Show LSP definitions"
  26. keymap.set("n", "gd", "<cmd>Telescope lsp_definitions<CR>", opts)
  27. opts.desc = "Show LSP implementations"
  28. keymap.set("n", "gi", "<cmd>Telescope lsp_implementations<CR>", opts)
  29. opts.desc = "Show LSP type definitions"
  30. keymap.set("n", "gt", "<cmd>Telescope lsp_type_definitions<CR>", opts)
  31. opts.desc = "See available code actions"
  32. keymap.set({ "n", "v" }, "<leader>ca", vim.lsp.buf.code_action, opts)
  33. opts.desc = "Smart rename"
  34. keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
  35. opts.desc = "Show buffer diagnostics"
  36. keymap.set("n", "<leader>D", "<cmd>Telescope diagnostics bufnr=0<CR>", opts)
  37. opts.desc = "Show line diagnostics"
  38. keymap.set("n", "<leader>d", vim.diagnostic.open_float, opts)
  39. opts.desc = "Go to previous diagnostic"
  40. keymap.set("n", "[d", function()
  41. vim.diagnostic.jump({ count=-1, float=true })
  42. end, opts)
  43. opts.desc = "Go to next diagnostic"
  44. keymap.set("n", "]d", function()
  45. vim.diagnostic.jump({ count=1, float=true })
  46. end, opts)
  47. opts.desc = "Go to previous diagnostic (error only)"
  48. keymap.set("n", "[e", function()
  49. vim.diagnostic.jump({ count=-1, float=true, severity = vim.diagnostic.severity.ERROR })
  50. end, opts)
  51. opts.desc = "Go to next diagnostic (error only)"
  52. keymap.set("n", "]e", function()
  53. vim.diagnostic.jump({ count=1, float=true, severity = vim.diagnostic.severity.ERROR })
  54. end, opts)
  55. opts.desc = "Show documentation for what is under cursor"
  56. keymap.set("n", "K", vim.lsp.buf.hover, opts)
  57. local client = vim.lsp.get_client_by_id(event.data.client_id)
  58. if client and client.server_capabilities.documentHighlightProvider then
  59. vim.api.nvim_create_autocmd("LspDetach", {
  60. group = vim.api.nvim_create_augroup("lsp-detach", { clear = true }),
  61. callback = function()
  62. vim.lsp.buf.clear_references()
  63. end,
  64. })
  65. end
  66. end,
  67. })
  68. local capabilities = vim.lsp.protocol.make_client_capabilities()
  69. capabilities = vim.tbl_deep_extend(
  70. "force",
  71. capabilities,
  72. require('blink.cmp').get_lsp_capabilities()
  73. )
  74. local base_path = ""
  75. if (vim.loop.fs_stat("/usr/lib/node_modules")) then
  76. base_path = "/usr/lib/node_modules"
  77. elseif (vim.loop.fs_stat("/usr/local/lib/node_modules")) then
  78. base_path = "/usr/local/lib/node_modules"
  79. elseif (vim.loop.fs_stat("/opt/homebrew/lib/node_modules")) then
  80. base_path = "/opt/homebrew/lib/node_modules"
  81. end
  82. local function get_typescript_server_path(root_dir)
  83. local global_ts = base_path .. "/typescript/lib"
  84. local found_ts = ""
  85. local function check_dir(path)
  86. found_ts = table.concat({path, "node_modules", "typescript", "lib"}, "/")
  87. if vim.loop.fs_stat(found_ts) then
  88. return path
  89. end
  90. end
  91. if util.search_ancestors(root_dir .. '/frontend/node_modules', check_dir) then
  92. return found_ts
  93. end
  94. if util.search_ancestors(root_dir .. '/node_modules', check_dir) then
  95. return found_ts
  96. end
  97. return global_ts
  98. end
  99. local function organize_imports()
  100. local params = {
  101. command = "_typescript.organizeImports",
  102. arguments = { vim.api.nvim_buf_get_name(0) },
  103. title = ""
  104. }
  105. vim.lsp.buf.execute_command(params)
  106. end
  107. local servers = {
  108. ts_ls = {
  109. init_options = {
  110. plugins = {
  111. {
  112. name = "@vue/typescript-plugin",
  113. location = base_path .. "/@vue/typescript-plugin",
  114. languages = { "javascript", "typescript", "vue", "react" },
  115. },
  116. },
  117. },
  118. filetypes = {
  119. "javascript",
  120. "typescript",
  121. "vue",
  122. "typescriptreact",
  123. },
  124. commands = {
  125. OrganizeImports = {
  126. organize_imports,
  127. description = "Organize Imports"
  128. }
  129. },
  130. on_new_config = function(new_config, new_root_dir)
  131. if get_typescript_server_path then
  132. new_config.init_options.typescript = new_config.init_options.typescript or {}
  133. new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir)
  134. else
  135. vim.notify("get_typescript_server_path is not defined", vim.log.levels.ERROR)
  136. end
  137. end,
  138. },
  139. -- volar = {
  140. -- filetypes = {
  141. -- "javascript",
  142. -- "typescript",
  143. -- "vue",
  144. -- },
  145. -- on_new_config = function(new_config, new_root_dir)
  146. -- new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir)
  147. -- end,
  148. -- },
  149. cssls = {},
  150. intelephense = {
  151. root_dir = function(pattern)
  152. ---@diagnostic disable-next-line: undefined-field
  153. local cwd = vim.loop.cwd()
  154. local root = util.root_pattern("composer.json")(pattern)
  155. -- prefer cwd if root is a descendant
  156. return util.path.is_descendant(cwd, root) and cwd or root
  157. end,
  158. init_options = {
  159. licenceKey = vim.fn.expand("$HOME/.local/share/nvim/intelephense-licence.txt"),
  160. },
  161. settings = {
  162. intelephense = {
  163. format = {
  164. enable = true,
  165. sortUseStatements = false,
  166. },
  167. },
  168. },
  169. },
  170. gopls = {
  171. cmd = { "gopls" },
  172. filetypes = { "go", "gomod", "gowork", "gotmpl" },
  173. root_dir = util.root_pattern("go.work", "go.mod", ".git"),
  174. settings = {
  175. gopls = {
  176. completeUnimported = true,
  177. usePlaceholders = true,
  178. analyses = {
  179. unusedparams = true,
  180. },
  181. },
  182. },
  183. },
  184. lua_ls = {
  185. settings = { -- custom settings for lua
  186. Lua = {
  187. -- make the language server recognize "vim" global
  188. diagnostics = {
  189. globals = { "vim" },
  190. },
  191. workspace = {
  192. -- make language server aware of runtime files
  193. library = {
  194. [vim.fn.expand("$VIMRUNTIME/lua")] = true,
  195. [vim.fn.stdpath("config") .. "/lua"] = true,
  196. },
  197. },
  198. },
  199. },
  200. },
  201. dartls = {
  202. cmd = { "dart", "language-server", "--protocol=lsp" },
  203. },
  204. rust_analyzer = {
  205. diagnostics = {
  206. enable = false,
  207. },
  208. },
  209. pyright = {
  210. -- before_init = function(_, config)
  211. -- config.settings.python.pythonpath = get_python_path(config.root_dir)
  212. -- end
  213. },
  214. yamlls = {
  215. settings = {
  216. yaml = {
  217. keyOrdering = false,
  218. },
  219. },
  220. },
  221. }
  222. require("mason").setup()
  223. local ensure_installed = vim.tbl_keys(servers or {})
  224. vim.list_extend(ensure_installed, {
  225. "stylua",
  226. "prettier",
  227. "prettierd",
  228. "eslint",
  229. "eslint_d",
  230. "jsonlint",
  231. "markdownlint",
  232. "phpcbf",
  233. "phpcs",
  234. "golangci-lint",
  235. "hadolint",
  236. "gofumpt",
  237. "goimports",
  238. })
  239. require("mason-tool-installer").setup({
  240. ensure_installed = ensure_installed,
  241. run_on_start = false,
  242. })
  243. require("mason-lspconfig").setup()
  244. for server_name, server in pairs(servers) do
  245. server.capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {})
  246. lspconfig[server_name].setup(server)
  247. end
  248. end,
  249. }