init.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. return {
  2. "neovim/nvim-lspconfig",
  3. dependencies = {
  4. require("plugins.lsp.extras.lazydev"),
  5. require("plugins.lsp.extras.gopher"),
  6. "mason-org/mason-lspconfig.nvim",
  7. "mason-org/mason.nvim",
  8. "j-hui/fidget.nvim",
  9. "ibhagwan/fzf-lua",
  10. "WhoIsSethDaniel/mason-tool-installer.nvim",
  11. },
  12. config = function()
  13. -- Mason setup
  14. require("mason").setup({ max_concurrent_installers = 4 })
  15. require("fidget").setup({})
  16. -- Enhance floating preview windows
  17. local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview
  18. function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)
  19. opts = opts or {}
  20. opts.border = opts.border or "rounded"
  21. opts.max_width = opts.max_width or 80
  22. opts.max_height = opts.max_height or 20
  23. return orig_util_open_floating_preview(contents, syntax, opts, ...)
  24. end
  25. -- Diagnostics configuration
  26. vim.diagnostic.config({
  27. virtual_text = { spacing = 2, source = "if_many" },
  28. float = { border = "rounded", source = "if_many" },
  29. signs = vim.g.have_nerd_font and {
  30. text = {
  31. [vim.diagnostic.severity.ERROR] = "󰅚",
  32. [vim.diagnostic.severity.WARN] = "󰀪",
  33. [vim.diagnostic.severity.INFO] = "󰋽",
  34. [vim.diagnostic.severity.HINT] = "󰌶",
  35. },
  36. } or true,
  37. underline = true,
  38. update_in_insert = true,
  39. severity_sort = true,
  40. })
  41. -- Global floating options
  42. _G.floating_options = {
  43. focusable = true,
  44. focus = false,
  45. max_height = 50,
  46. max_width = 100,
  47. }
  48. -- Auto-format on save
  49. vim.api.nvim_create_autocmd("BufWritePre", {
  50. callback = function()
  51. if vim.lsp.buf_is_attached() then
  52. vim.lsp.buf.format()
  53. end
  54. end,
  55. })
  56. -- Filter out unwanted code actions
  57. vim.lsp.buf.code_action = (function(orig)
  58. return function(opts)
  59. opts = opts or {}
  60. opts.filter = function(action)
  61. if not action then
  62. return false
  63. end
  64. -- Ignore gopls "Browse" actions
  65. if action.title and action.title:match("Browse gopls") then
  66. return false
  67. end
  68. return true
  69. end
  70. return orig(opts)
  71. end
  72. end)(vim.lsp.buf.code_action)
  73. -- Keymaps setup function
  74. local function setup_keymaps(bufnr)
  75. local fzf = require("fzf-lua")
  76. local opts = { buffer = bufnr }
  77. -- Helper function for mapping
  78. local function nmap(key, func, desc_opts)
  79. vim.keymap.set("n", key, func, desc_opts)
  80. end
  81. -- Basic LSP
  82. nmap("K", vim.lsp.buf.hover, vim.tbl_extend("force", opts, { desc = "Hover Doc" }))
  83. nmap("<C-h>", vim.lsp.buf.signature_help, vim.tbl_extend("force", opts, { desc = "Signature Help" }))
  84. nmap("<leader>r", vim.lsp.buf.rename, vim.tbl_extend("force", opts, { desc = "Rename" }))
  85. nmap("<leader>ca", vim.lsp.buf.code_action, vim.tbl_extend("force", opts, { desc = "Code Action" }))
  86. -- Navigation
  87. nmap("gd", fzf.lsp_definitions, vim.tbl_extend("force", opts, { desc = "Go to Definition" }))
  88. nmap("gr", fzf.lsp_references, vim.tbl_extend("force", opts, { desc = "Go to References" }))
  89. nmap("gD", vim.lsp.buf.declaration, vim.tbl_extend("force", opts, { desc = "Go to Declaration" }))
  90. nmap("gi", fzf.lsp_implementations, vim.tbl_extend("force", opts, { desc = "Go to Implementation" }))
  91. nmap("gt", fzf.lsp_typedefs, vim.tbl_extend("force", opts, { desc = "Go to Type Definition" }))
  92. -- Diagnostics
  93. nmap("vd", vim.diagnostic.open_float, vim.tbl_extend("force", opts, { desc = "View Diagnostics" }))
  94. nmap("<leader>dl", fzf.diagnostics_document, vim.tbl_extend("force", opts, { desc = "Document Diagnostics" }))
  95. nmap("<leader>dw", fzf.diagnostics_workspace, vim.tbl_extend("force", opts, { desc = "Workspace Diagnostics" }))
  96. nmap("<leader>ds", fzf.lsp_document_symbols, vim.tbl_extend("force", opts, { desc = "Document Symbols" }))
  97. nmap("<leader>ws", fzf.lsp_workspace_symbols, vim.tbl_extend("force", opts, { desc = "Workspace Symbols" }))
  98. -- LSP management
  99. nmap("<leader>lr", function()
  100. local clients = vim.lsp.get_clients({ bufnr = bufnr })
  101. if #clients == 0 then
  102. vim.notify("No LSP clients attached to buffer", vim.log.levels.WARN)
  103. return
  104. end
  105. local client_names = {}
  106. for _, client in ipairs(clients) do
  107. table.insert(client_names, client.name)
  108. vim.cmd("LspRestart " .. client.name)
  109. end
  110. vim.notify("Restarted LSP clients: " .. table.concat(client_names, ", "), vim.log.levels.INFO)
  111. end, vim.tbl_extend("force", opts, { desc = "Restart LSP" }))
  112. nmap("<leader>li", ":LspInfo<CR>", vim.tbl_extend("force", opts, { desc = "LSP Info" }))
  113. end
  114. -- LSP servers configuration
  115. local servers = {
  116. "gopls",
  117. "jsonls",
  118. "lua_ls",
  119. "yamlls",
  120. "graphql",
  121. "html",
  122. "omnisharp",
  123. "svelte",
  124. "vtsls",
  125. "ccls",
  126. "templ",
  127. "tinymist",
  128. }
  129. -- Tools for mason-tool-installer
  130. local tools = {
  131. "prettierd",
  132. "shfmt",
  133. "stylua",
  134. "latexindent",
  135. "clang-format",
  136. "csharpier",
  137. "quick-lint-js",
  138. }
  139. -- Servers not supported by mason
  140. local mason_unsupported = { "ccls" }
  141. local mason_servers = vim.tbl_filter(function(server)
  142. return not vim.tbl_contains(mason_unsupported, server)
  143. end, servers)
  144. -- Mason setup
  145. require("mason-lspconfig").setup({
  146. ensure_installed = mason_servers,
  147. automatic_installation = true,
  148. automatic_enable = false,
  149. })
  150. require("mason-tool-installer").setup({ ensure_installed = tools })
  151. -- Enable LSP servers
  152. vim.lsp.enable(servers)
  153. -- LSP Attach autocmd
  154. vim.api.nvim_create_autocmd("LspAttach", {
  155. group = vim.api.nvim_create_augroup("UserLspConfig", { clear = true }),
  156. callback = function(args)
  157. local client = vim.lsp.get_client_by_id(args.data.client_id)
  158. if not client then
  159. return
  160. end
  161. -- Setup keymaps
  162. setup_keymaps(args.buf)
  163. -- Inlay hints
  164. if client:supports_method(vim.lsp.protocol.Methods.textDocument_inlayHint, args.buf) then
  165. vim.keymap.set("n", "<leader>th", function()
  166. vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = args.buf }), { bufnr = args.buf })
  167. end, { buffer = args.buf, desc = "Toggle Inlay Hints" })
  168. end
  169. -- Document highlights
  170. if client.server_capabilities.documentHighlightProvider then
  171. vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
  172. buffer = args.buf,
  173. callback = vim.lsp.buf.document_highlight,
  174. })
  175. vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, {
  176. buffer = args.buf,
  177. callback = vim.lsp.buf.clear_references,
  178. })
  179. end
  180. end,
  181. })
  182. end,
  183. }