lsp.lua 6.4 KB

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