lsp.lua 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. local util = require('user.util')
  2. vim.diagnostic.config({
  3. -- only show virtual text for WARN and higher
  4. virtual_text = { severity = { min = vim.diagnostic.severity.WARN } },
  5. })
  6. vim.lsp.config('*', {
  7. flags = {
  8. debounce_text_changes = 250,
  9. }
  10. })
  11. vim.lsp.enable('bashls');
  12. vim.lsp.enable('eslint');
  13. if vim.fn.executable('dprint') == 1 then
  14. local version = vim.version.parse(vim.fn.system('dprint --version'))
  15. if vim.version.cmp(version, { 0, 45, 0 }) >= 0 then
  16. vim.lsp.enable('dprint')
  17. end
  18. end
  19. if vim.fn.executable('deno') == 1 then
  20. vim.lsp.enable('deno');
  21. else
  22. local preferences = {
  23. importModuleSpecifierPreference = 'non-relative',
  24. -- this prevents renames from aliasing when destructuring
  25. providePrefixAndSuffixTextForRename = false,
  26. }
  27. local helix_preferences = vim.tbl_get(
  28. util.read_helix_config(),
  29. 'language-server',
  30. 'typescript-language-server',
  31. 'config',
  32. 'preferences'
  33. )
  34. if helix_preferences ~= nil then
  35. preferences = vim.tbl_deep_extend('force', preferences, helix_preferences)
  36. end
  37. local function make_settings()
  38. -- we disable formatting but these are still used when performing some code
  39. -- actions
  40. local format = {
  41. indentSize = vim.bo.shiftwidth,
  42. convertTabsToSpaces = vim.o.expandtab,
  43. }
  44. return {
  45. javascript = { format = format },
  46. typescript = { format = format },
  47. }
  48. end
  49. vim.lsp.config('ts_ls', {
  50. init_options = {
  51. completionDisableFilterText = true,
  52. preferences = preferences,
  53. },
  54. settings = make_settings(),
  55. handlers = {
  56. ['$/typescriptVersion'] = function(err, result, ctx, config)
  57. vim.notify(string.format('Typescript %s', result.version))
  58. end,
  59. },
  60. on_init = function(client)
  61. -- mark tsserver as not having formatting available as we rely on
  62. -- eslint and dprint for that
  63. client.server_capabilities.documentFormattingProvider = false
  64. client.server_capabilities.documentRangeFormattingProvider = false
  65. -- we only really know our settings once we've opened a file so report
  66. -- the new formatting settings
  67. client:notify(vim.lsp.protocol.Methods.workspace_didChangeConfiguration, {
  68. settings = make_settings(),
  69. })
  70. end,
  71. })
  72. vim.lsp.enable('ts_ls')
  73. end
  74. vim.lsp.enable('svelte')
  75. vim.lsp.enable('gopls')
  76. vim.lsp.config('ruby_lsp', {
  77. init_options = {
  78. enabledFeatures = {
  79. formatting = false,
  80. },
  81. }
  82. })
  83. vim.lsp.enable('ruby_lsp')
  84. vim.lsp.config('pyright', {
  85. handlers = {
  86. ['$/progress'] = function()
  87. -- this is quite noisy so just disable it
  88. end
  89. },
  90. })
  91. vim.lsp.enable('pyright')
  92. vim.lsp.config('nil_ls', {
  93. on_init = function(client)
  94. -- disable formatting
  95. client.server_capabilities.documentFormattingProvider = false
  96. client.server_capabilities.documentRangeFormattingProvider = false
  97. end,
  98. })
  99. vim.lsp.enable('nil_ls')
  100. vim.lsp.config('jdtls', {
  101. handlers = {
  102. ['$/progress'] = function()
  103. -- this is quite noisy so just disable it
  104. end
  105. },
  106. })
  107. vim.lsp.enable('jdtls')
  108. vim.lsp.enable('lua_ls')
  109. -- custom LSP servers
  110. vim.lsp.config('elvish', {
  111. cmd = { 'elvish', '--lsp' },
  112. filetypes = { 'elvish' },
  113. settings = {},
  114. })
  115. vim.lsp.enable('elvish')
  116. -- diagnostics
  117. vim.keymap.set('n', '<space>e', function() vim.diagnostic.open_float() end)
  118. vim.keymap.set('n', '[d',
  119. function() vim.diagnostic.jump({ count = -1, float = true, severity = vim.diagnostic.severity.ERROR }) end)
  120. vim.keymap.set('n', ']d',
  121. function() vim.diagnostic.jump({ count = 1, float = true, severity = vim.diagnostic.severity.ERROR }) end)
  122. vim.keymap.set('n', '[D', function() vim.diagnostic.jump({ count = -1, float = true }) end)
  123. vim.keymap.set('n', ']D', function() vim.diagnostic.jump({ count = 1, float = true }) end)
  124. vim.keymap.set('n', '<space>qe', function() vim.diagnostic.setqflist({ severity = vim.diagnostic.severity.ERROR }) end)
  125. vim.keymap.set('n', '<space>qw',
  126. function() vim.diagnostic.setqflist({ severity = { min = vim.diagnostic.severity.WARN } }) end)
  127. vim.keymap.set('n', '<space>qd', function() vim.diagnostic.setqflist({}) end)
  128. vim.keymap.set('n', '<space>qc', '<cmd>cclose<CR>')
  129. -- LSP-specific
  130. vim.api.nvim_create_autocmd('LspAttach', {
  131. callback = function(args)
  132. local client = vim.lsp.get_client_by_id(args.data.client_id)
  133. if client.name == 'dprint' or client.name == 'eslint' then
  134. -- mappings should have been attached by typescript and re-attaching can
  135. -- overwrite the typescript specific overrides
  136. return
  137. end
  138. local opts = { buffer = args.buf }
  139. vim.keymap.set('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
  140. vim.keymap.set('n', 'gd', '<cmd>Telescope lsp_definitions<CR>', opts)
  141. vim.keymap.set('n', '<space>D', '<cmd>Telescope lsp_type_definitions<CR>', opts)
  142. -- as much as possible we try to use the default bindings, replacing them
  143. -- with Telescope if appropriate
  144. vim.keymap.set('n', 'gri', '<cmd>Telescope lsp_implementations<CR>', opts)
  145. vim.keymap.set('n', 'grr', '<cmd>Telescope lsp_references<CR>', opts)
  146. vim.keymap.set('n', 'gO', '<cmd>Telescope lsp_document_symbols<CR>', opts)
  147. if client.name == 'ts_ls' then
  148. -- exclude import statements from reference search (may have false positives)
  149. vim.keymap.set('n', 'grr', '<cmd>Telescope lsp_references default_text=!import\\ <CR>', opts)
  150. vim.keymap.set('n', 'grA', '<cmd>LspTypescriptSourceAction<CR>', opts)
  151. end
  152. end,
  153. })
  154. -- handle file renames
  155. vim.api.nvim_create_autocmd('User', {
  156. pattern = 'MiniFilesActionRename',
  157. callback = function(opts)
  158. local params = {
  159. files = { {
  160. oldUri = vim.uri_from_fname(opts.data.from),
  161. newUri = vim.uri_from_fname(opts.data.to),
  162. } }
  163. }
  164. local bufnr = vim.fn.bufadd(opts.data.to)
  165. -- delay a bit to allow LSP clients to attach
  166. vim.defer_fn(function()
  167. local clients = vim.lsp.get_clients({ bufnr = bufnr })
  168. for _, client in ipairs(clients) do
  169. vim.notify(client.name)
  170. if client.name == 'dprint' then
  171. goto continue
  172. end
  173. if client:supports_method('workspace/willRenameFiles') then
  174. vim.notify('lsp rename')
  175. local resp = client:request_sync('workspace/willRenameFiles', params, 5000, bufnr)
  176. if resp and resp.result ~= nil then
  177. vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding)
  178. end
  179. end
  180. ::continue::
  181. end
  182. for _, client in ipairs(clients) do
  183. if client:supports_method('workspace/didRenameFiles') then
  184. client:notify('workspace/didRenameFiles', params)
  185. end
  186. end
  187. end, 100)
  188. end,
  189. nested = true,
  190. })