lsp.lua 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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('gopls')
  75. vim.lsp.config('ruby_lsp', {
  76. init_options = {
  77. enabledFeatures = {
  78. formatting = false,
  79. },
  80. }
  81. })
  82. vim.lsp.enable('ruby_lsp')
  83. vim.lsp.enable('pyright')
  84. vim.lsp.config('nil_ls', {
  85. on_init = function(client)
  86. -- disable formatting
  87. client.server_capabilities.documentFormattingProvider = false
  88. client.server_capabilities.documentRangeFormattingProvider = false
  89. end,
  90. })
  91. vim.lsp.enable('nil_ls')
  92. vim.lsp.config('jdtls', {
  93. handlers = {
  94. ['$/progress'] = function()
  95. -- this is quite noisy so just disable it
  96. end
  97. },
  98. })
  99. vim.lsp.enable('jdtls')
  100. vim.lsp.enable('lua_ls')
  101. -- custom LSP servers
  102. vim.lsp.config('elvish', {
  103. cmd = { 'elvish', '--lsp' },
  104. filetypes = { 'elvish' },
  105. settings = {},
  106. })
  107. vim.lsp.enable('elvish')
  108. -- diagnostics
  109. vim.keymap.set('n', '<space>e', function() vim.diagnostic.open_float() end)
  110. vim.keymap.set('n', '[d',
  111. function() vim.diagnostic.jump({ count = -1, float = true, severity = vim.diagnostic.severity.ERROR }) end)
  112. vim.keymap.set('n', ']d',
  113. function() vim.diagnostic.jump({ count = 1, float = true, severity = vim.diagnostic.severity.ERROR }) end)
  114. vim.keymap.set('n', '[D', function() vim.diagnostic.jump({ count = -1, float = true }) end)
  115. vim.keymap.set('n', ']D', function() vim.diagnostic.jump({ count = 1, float = true }) end)
  116. vim.keymap.set('n', '<space>qe', function() vim.diagnostic.setqflist({ severity = vim.diagnostic.severity.ERROR }) end)
  117. vim.keymap.set('n', '<space>qw',
  118. function() vim.diagnostic.setqflist({ severity = { min = vim.diagnostic.severity.WARN } }) end)
  119. vim.keymap.set('n', '<space>qd', function() vim.diagnostic.setqflist({}) end)
  120. vim.keymap.set('n', '<space>qc', '<cmd>cclose<CR>')
  121. -- LSP-specific
  122. vim.api.nvim_create_autocmd('LspAttach', {
  123. callback = function(args)
  124. local client = vim.lsp.get_client_by_id(args.data.client_id)
  125. if client.name == 'dprint' or client.name == 'eslint' then
  126. -- mappings should have been attached by typescript and re-attaching can
  127. -- overwrite the typescript specific overrides
  128. return
  129. end
  130. local opts = { buffer = args.buf }
  131. vim.keymap.set('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
  132. vim.keymap.set('n', 'gd', '<cmd>Telescope lsp_definitions<CR>', opts)
  133. vim.keymap.set('n', '<space>D', '<cmd>Telescope lsp_type_definitions<CR>', opts)
  134. -- as much as possible we try to use the default bindings, replacing them
  135. -- with Telescope if appropriate
  136. vim.keymap.set('n', 'gri', '<cmd>Telescope lsp_implementations<CR>', opts)
  137. vim.keymap.set('n', 'grr', '<cmd>Telescope lsp_references<CR>', opts)
  138. vim.keymap.set('n', 'gO', '<cmd>Telescope lsp_document_symbols<CR>', opts)
  139. if client.name == 'ts_ls' then
  140. -- exclude import statements from reference search (may have false positives)
  141. vim.keymap.set('n', 'grr', '<cmd>Telescope lsp_references default_text=!import\\ <CR>', opts)
  142. vim.keymap.set('n', 'grA', '<cmd>LspTypescriptSourceAction<CR>', opts)
  143. end
  144. end,
  145. })
  146. -- handle file renames
  147. vim.api.nvim_create_autocmd('User', {
  148. pattern = 'MiniFilesActionRename',
  149. callback = function(opts)
  150. local params = {
  151. files = { {
  152. oldUri = vim.uri_from_fname(opts.data.from),
  153. newUri = vim.uri_from_fname(opts.data.to),
  154. } }
  155. }
  156. local bufnr = vim.fn.bufadd(opts.data.to)
  157. -- delay a bit to allow LSP clients to attach
  158. vim.defer_fn(function()
  159. local clients = vim.lsp.get_clients({ bufnr = bufnr })
  160. for _, client in ipairs(clients) do
  161. vim.notify(client.name)
  162. if client.name == 'dprint' then
  163. goto continue
  164. end
  165. if client:supports_method('workspace/willRenameFiles') then
  166. vim.notify('lsp rename')
  167. local resp = client:request_sync('workspace/willRenameFiles', params, 5000, bufnr)
  168. if resp and resp.result ~= nil then
  169. vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding)
  170. end
  171. end
  172. ::continue::
  173. end
  174. for _, client in ipairs(clients) do
  175. if client:supports_method('workspace/didRenameFiles') then
  176. client:notify('workspace/didRenameFiles', params)
  177. end
  178. end
  179. end, 100)
  180. end,
  181. nested = true,
  182. })