Repository: LazyVim/LazyVim
File: lua/lazyvim/plugins/lsp/init.lua (Lua)

Code before:
        {},
        vim.lsp.protocol.make_client_capabilities(),
        has_cmp and cmp_nvim_lsp.default_capabilities() or {},
        has_blink and blink.get_lsp_capabilities() or {},
        opts.capabilities or {}
      )

      -- setup keymaps
      LazyVim.lsp.on_attach(function(client, buffer)
        require("lazyvim.plugins.lsp.keymaps").on_attach(client, buffer)
        local server = client.name
        local server_opts = vim.tbl_deep_extend("force", {
          capabilities = vim.deepcopy(capabilities),
        }, servers[server] or {})
        if server_opts.enabled == false then
          return
        end
        if opts.setup[server] then
          if opts.setup[server](server, server_opts) then
            return
          end
        elseif opts.setup["*"] then
          if opts.setup["*"](server, server_opts) then
            return
          end
        end
      end)

      LazyVim.lsp.setup()
      LazyVim.lsp.on_dynamic_capability(require("lazyvim.plugins.lsp.keymaps").on_attach)

      -- diagnostics signs
      if vim.fn.has("nvim-0.10.0") == 0 then
        if type(opts.diagnostics.signs) ~= "boolean" then
          for severity, icon in pairs(opts.diagnostics.signs.text) do
            local name = vim.diagnostic.severity[severity]:lower():gsub("^%l", string.upper)
            name = "DiagnosticSign" .. name
            vim.fn.sign_define(name, { text = icon, texthl = name, numhl = "" })
          end
        end
      end

      if vim.fn.has("nvim-0.10") == 1 then
        -- inlay hints
        if opts.inlay_hints.enabled then
          LazyVim.lsp.on_supports_method("textDocument/inlayHint", function(client, buffer)
            if
              vim.api.nvim_buf_is_valid(buffer)
              and vim.bo[buffer].buftype == ""
              and not vim.tbl_contains(opts.inlay_hints.exclude, vim.bo[buffer].filetype)
            then

Review comment (bug):
I've been going through manually updating my own config and I use LazyVim source code as a heavy inspiration. While upgrading to Neovim 0.11 and trying to apply the changes made in this PR I noticed that they seem to heavily alter the current `opts.setup` behavior.

Moving `opts.setup[server](server, server_opts)` moved inside `LazyVim.lsp.on_attach` call seems to break the current documented behavior of using it to

1. Fully disable a server and stop it from being configured [ts code example](https://github.com/LazyVim/LazyVim/blob/25abbf5/lua/lazyvim/plugins/extras/lang/typescript.lua#L125) | [ts docs](https://www.lazyvim.org/extras/lang/typescript#nvim-lspconfig)
```lua
setup = {
  tsserver = function()
    -- disable tsserver
    return true
  end,
  ts_ls = function()
    -- disable tsserver
    return true
  end,
```
or [java code example](https://github.com/LazyVim/LazyVim/blob/25abbf546d564dc484cf903804661ba12de45507/lua/lazyvim/plugins/extras/lang/java.lua#L75) | [java docs](https://www.lazyvim.org/extras/lang/java#nvim-lspconfig) uses it manually run [jdtls](https://www.lazyvim.org/extras/lang/java#nvim-jdtls)
```lua
-- make sure mason installs the server
servers = {
  jdtls = {},
},
setup = {
  jdtls = function()
    return true -- avoid duplicate servers
  end,
},
  ```
2. Modify the `server_opts` before they will be used in `vim.lsp.config(server, server_opts)` [code example](https://github.com/LazyVim/LazyVim/blob/25abbf5/lua/lazyvim/plugins/extras/lang/typescript.lua#L185) | [docs](https://www.lazyvim.org/extras/lang/typescript#nvim-lspconfig)
```lua
setup = {
  vtsls = function(_, opts)
    opts.settings.javascript =
      vim.tbl_deep_extend("force", {}, opts.settings.typescript, opts.settings.javascript or {})
```    
3. Add own `lsp.on_attach` callbacks [docs](https://www.lazyvim.org/configuration/recipes#add-eslint-and-use-it-for-formatting)
```lua
setup = {
  eslint = function()
    require("lazyvim.util").lsp.on_attach(function(client)
      if client.name == "eslint" then
        client.server_capabilities.documentFormattingProvider = true
      elseif client.name == "tsserver" then
        client.server_capabilities.documentFormattingProvider = false
      end
    end)
  end,
```

From what I understand

1. Won't work because calling `opts.setup[server](server, server_opts)` has been moved to `LazyVim.lsp.on_attach` which happens _after_ the server is configured. Its return value was used to [prevent calling `require("lspconfig")[server].setup(server_opts)`](https://github.com/LazyVim/LazyVim/blob/25abbf546d564dc484cf903804661ba12de45507/lua/lazyvim/plugins/lsp/init.lua#L200)
2. Since the `opts.setup[server](server, server_opts)` runs in `LazyVim.lsp.on_attach`, after a server is first configured and enabled, the options won't be altered _at least for the first `on_attach` event_. The server will be configured using original options, I'm not sure if the change will take effect for buffers opened later
3. If the `opts.setup[server](server, server_opts)` adds its own `require("lazyvim.util").lsp.on_attach` callback while it's already being run inside `LazyVim.lsp.on_attach` it won't run, _at least for that first `on_attach` event_

Sorry if I got anything wrong, I'm not too good with Lua. Let me know if I'm incorrect but from my testing, the stuff I've been using (based on the linked examples) doesn't seem to work properly

Code after:
        LazyVim.lsp.on_supports_method("textDocument/inlayHint", function(client, buffer)
          if
            vim.api.nvim_buf_is_valid(buffer)
            and vim.bo[buffer].buftype == ""
            and not vim.tbl_contains(opts.inlay_hints.exclude, vim.bo[buffer].filetype)
          then
            vim.lsp.inlay_hint.enable(true, { bufnr = buffer })
          end
        end)
      end

      -- code lens
      if opts.codelens.enabled and vim.lsp.codelens then
        LazyVim.lsp.on_supports_method("textDocument/codeLens", function(client, buffer)
          vim.lsp.codelens.refresh()
          vim.api.nvim_create_autocmd({ "BufEnter", "CursorHold", "InsertLeave" }, {
            buffer = buffer,
            callback = vim.lsp.codelens.refresh,
          })
        end)
      end

      if type(opts.diagnostics.virtual_text) == "table" and opts.diagnostics.virtual_text.prefix == "icons" then
        opts.diagnostics.virtual_text.prefix = function(diagnostic)
          local icons = LazyVim.config.icons.diagnostics
          for d, icon in pairs(icons) do
            if diagnostic.severity == vim.diagnostic.severity[d:upper()] then
              return icon
            end
          end
        end
      end

      vim.diagnostic.config(vim.deepcopy(opts.diagnostics))

      local servers = opts.servers
      local has_cmp, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp")
      local has_blink, blink = pcall(require, "blink.cmp")
      local capabilities = vim.tbl_deep_extend(
        "force",
        {},
        vim.lsp.protocol.make_client_capabilities(),
        has_cmp and cmp_nvim_lsp.default_capabilities() or {},
        has_blink and blink.get_lsp_capabilities() or {},
        opts.capabilities or {}
      )

      -- get all the servers that are available through mason-lspconfig
      local have_mason, mlsp = pcall(require, "mason-lspconfig")
      local all_mslp_servers = {}
      all_mslp_servers = vim.tbl_keys(require("mason-lspconfig.mappings").get_mason_map().lspconfig_to_package)