You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
11 KiB

5 months ago
5 months ago
  1. return {
  2. "neovim/nvim-lspconfig",
  3. event = { "BufReadPre", "BufNewFile" },
  4. dependencies = {
  5. { "hrsh7th/cmp-nvim-lsp" },
  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", vim.diagnostic.goto_prev, opts)
  41. opts.desc = "Go to next diagnostic"
  42. keymap.set("n", "]d", vim.diagnostic.goto_next, opts)
  43. opts.desc = "Go to previous diagnostic (error only)"
  44. keymap.set("n", "[e", function()
  45. vim.diagnostic.goto_prev({ severity = vim.diagnostic.severity.ERROR })
  46. end, opts)
  47. opts.desc = "Go to next diagnostic (error only)"
  48. keymap.set("n", "]e", function()
  49. vim.diagnostic.goto_next({ severity = vim.diagnostic.severity.ERROR })
  50. end, opts)
  51. opts.desc = "Show documentation for what is under cursor"
  52. keymap.set("n", "<leader>ld", vim.diagnostic.setqflist, opts)
  53. opts.desc = "Show documentation for what is under cursor"
  54. keymap.set("n", "K", vim.lsp.buf.hover, opts)
  55. local client = vim.lsp.get_client_by_id(event.data.client_id)
  56. if client and client.server_capabilities.documentHighlightProvider then
  57. vim.api.nvim_create_autocmd("LspDetach", {
  58. group = vim.api.nvim_create_augroup("lsp-detach", { clear = true }),
  59. callback = function(event2)
  60. vim.lsp.buf.clear_references()
  61. end,
  62. })
  63. end
  64. -- The following autocommand is used to enable inlay hints in your
  65. -- code, if the language server you are using supports them
  66. --
  67. -- This may be unwanted, since they displace some of your code
  68. if client and client.server_capabilities.inlayHintProvider and vim.lsp.inlay_hint then
  69. opts.desc = "Toggle Inlay Hints"
  70. keymap.set("n", "<leader>th", function()
  71. vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({}))
  72. end, opts)
  73. end
  74. end,
  75. })
  76. local capabilities = vim.lsp.protocol.make_client_capabilities()
  77. capabilities = vim.tbl_deep_extend("force", capabilities, require("cmp_nvim_lsp").default_capabilities())
  78. -- Function to detect the operating system
  79. local function get_os()
  80. local handle = io.popen("uname")
  81. if not handle then
  82. return error("Failed to detect operating system")
  83. end
  84. local result = handle:read("*a")
  85. handle:close()
  86. return result:lower():gsub("%s+", "")
  87. end
  88. -- Set the base path based on the operating system
  89. local os = get_os()
  90. local base_path = ""
  91. if os == "darwin" then
  92. base_path = "/opt/homebrew/lib/node_modules"
  93. elseif os == "linux" then
  94. base_path = "/usr/lib/node_modules"
  95. end
  96. local function get_typescript_server_path(root_dir)
  97. local global_ts = base_path .. "/typescript/lib"
  98. local found_ts = ""
  99. local function check_dir(path)
  100. found_ts = util.path.join(path, "node_modules", "typescript", "lib")
  101. if util.path.exists(found_ts) then
  102. return path
  103. end
  104. end
  105. if util.search_ancestors(root_dir, check_dir) then
  106. return found_ts
  107. else
  108. return global_ts
  109. end
  110. end
  111. local path = util.path
  112. local function get_python_path(workspace)
  113. -- Use activated virtualenv.
  114. if vim.env.VIRTUAL_ENV then
  115. return path.join(vim.env.VIRTUAL_ENV, 'bin', 'python')
  116. end
  117. -- Find and use virtualenv in workspace directory.
  118. for _, pattern in ipairs({'*', '.*'}) do
  119. local match = vim.fn.glob(path.join(workspace, pattern, 'pyvenv.cfg'))
  120. if match ~= '' then
  121. return path.join(path.dirname(match), 'bin', 'python')
  122. end
  123. end
  124. -- Fallback to system Python.
  125. return exepath('python3') or exepath('python') or 'python'
  126. end
  127. local function organize_imports()
  128. local params = {
  129. command = "_typescript.organizeImports",
  130. arguments = {vim.api.nvim_buf_get_name(0)},
  131. title = ""
  132. }
  133. vim.lsp.buf.execute_command(params)
  134. end
  135. local servers = {
  136. ts_ls = {
  137. init_options = {
  138. plugins = {
  139. {
  140. name = "@vue/typescript-plugin",
  141. location = base_path .. "/@vue/typescript-plugin",
  142. languages = { "javascript", "typescript", "vue", "react" },
  143. },
  144. },
  145. },
  146. filetypes = {
  147. "javascript",
  148. "typescript",
  149. "vue",
  150. "typescriptreact",
  151. },
  152. commands = {
  153. OrganizeImports = {
  154. organize_imports,
  155. description = "Organize Imports"
  156. }
  157. }
  158. },
  159. volar = {
  160. filetypes = {
  161. "javascript",
  162. "typescript",
  163. "vue",
  164. },
  165. on_new_config = function(new_config, new_root_dir)
  166. new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir)
  167. end,
  168. },
  169. cssls = {},
  170. intelephense = {
  171. root_dir = function(pattern)
  172. ---@diagnostic disable-next-line: undefined-field
  173. local cwd = vim.loop.cwd()
  174. local root = util.root_pattern("composer.json")(pattern)
  175. -- prefer cwd if root is a descendant
  176. return util.path.is_descendant(cwd, root) and cwd or root
  177. end,
  178. init_options = {
  179. licenceKey = vim.fn.expand("$HOME/.local/share/nvim/intelephense-licence.txt"),
  180. },
  181. settings = {
  182. intelephense = {
  183. format = {
  184. enable = true,
  185. sortUseStatements = false,
  186. },
  187. },
  188. },
  189. },
  190. gopls = {
  191. cmd = { "gopls" },
  192. filetypes = { "go", "gomod", "gowork", "gotmpl" },
  193. root_dir = util.root_pattern("go.work", "go.mod", ".git"),
  194. settings = {
  195. gopls = {
  196. completeUnimported = true,
  197. usePlaceholders = true,
  198. analyses = {
  199. unusedparams = true,
  200. },
  201. },
  202. },
  203. },
  204. lua_ls = {
  205. settings = { -- custom settings for lua
  206. Lua = {
  207. -- make the language server recognize "vim" global
  208. diagnostics = {
  209. globals = { "vim" },
  210. },
  211. workspace = {
  212. -- make language server aware of runtime files
  213. library = {
  214. [vim.fn.expand("$VIMRUNTIME/lua")] = true,
  215. [vim.fn.stdpath("config") .. "/lua"] = true,
  216. },
  217. },
  218. },
  219. },
  220. },
  221. dartls = {
  222. cmd = { "dart", "language-server", "--protocol=lsp" },
  223. },
  224. rust_analyzer = {
  225. diagnostics = {
  226. enable = false,
  227. },
  228. },
  229. pyright = {
  230. before_init = function(_, config)
  231. config.settings.python.pythonpath = get_python_path(config.root_dir)
  232. end
  233. },
  234. yamlls = {
  235. settings = {
  236. yaml = {
  237. keyOrdering = false,
  238. },
  239. },
  240. },
  241. }
  242. require("mason").setup()
  243. local ensure_installed = vim.tbl_keys(servers or {})
  244. vim.list_extend(ensure_installed, {
  245. "stylua",
  246. "prettier",
  247. "prettierd",
  248. "eslint",
  249. "eslint_d",
  250. "jsonlint",
  251. "markdownlint",
  252. "phpcbf",
  253. "phpcs",
  254. "golangci-lint",
  255. "hadolint",
  256. "gofumpt",
  257. "goimports",
  258. })
  259. require("mason-tool-installer").setup({
  260. ensure_installed = ensure_installed,
  261. run_on_start = false,
  262. })
  263. require("mason-lspconfig").setup()
  264. for server_name, server in pairs(servers) do
  265. server.capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {})
  266. require("lspconfig")[server_name].setup(server)
  267. end
  268. end,
  269. }