lsp.lua 6.1 KB

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