Repository: neovim/neovim
File: runtime/lua/vim/lsp.lua (Lua)

Code before:
      lsp.buf_detach_client(bufnr, client.id)
    end
  end

  -- Start any clients that apply to this buffer.
  for name in vim.spairs(lsp._enabled_configs) do
    local config = lsp.config[name]
    if config and can_start(bufnr, name, config) then
      -- Deepcopy config so changes done in the client
      -- do not propagate back to the enabled configs.
      config = vim.deepcopy(config)

      if type(config.root_dir) == 'function' then
        ---@param root_dir string
        config.root_dir(bufnr, function(root_dir)
          config.root_dir = root_dir
          vim.schedule(function()
            start_config(bufnr, config)
          end)
        end)
      else
        start_config(bufnr, config)
      end
    end
  end
end

--- Auto-starts LSP when a buffer is opened, based on the |lsp-config| `filetypes`, `root_markers`,
--- and `root_dir` fields.
---
--- Examples:
---
--- ```lua
--- vim.lsp.enable('clangd')
--- vim.lsp.enable({'luals', 'pyright'})
--- ```
---
--- Example: To _dynamically_ decide whether LSP is activated, define a |lsp-root_dir()| function
--- which calls `on_dir()` only when you want that config to activate:
---
--- ```lua
--- vim.lsp.config('lua_ls', {
---   root_dir = function(bufnr, on_dir)
---     if not vim.fn.bufname(bufnr):match('%.txt$') then
---       on_dir(vim.fn.getcwd())
---     end
---   end
--- })
--- ```
---
---@since 13

Review comment (suggestion):
I don't know how to justify this `_uninitialized = true` with a test, but I know it's necessary from manual testing with the scenario I described here: https://github.com/neovim/neovim/issues/33443#issuecomment-2800045448

Code after:
  if config.filetypes and not vim.tbl_contains(config.filetypes, vim.bo[bufnr].filetype) then
    return false
  end

  return true
end

--- @param bufnr integer
--- @param config vim.lsp.Config
local function start_config(bufnr, config)
  return vim.lsp.start(config, {
    bufnr = bufnr,
    reuse_client = config.reuse_client,
    _root_markers = config.root_markers,
  })
end

--- @param bufnr integer
local function lsp_enable_callback(bufnr)
  -- Only ever attach to buffers that represent an actual file.
  if vim.bo[bufnr].buftype ~= '' then
    return
  end

  -- Stop any clients that no longer apply to this buffer.
  local clients = lsp.get_clients({ bufnr = bufnr, _uninitialized = true })
  for _, client in ipairs(clients) do
    if not can_start(bufnr, client.name, lsp.config[client.name]) then
      lsp.buf_detach_client(bufnr, client.id)
    end
  end

  -- Start any clients that apply to this buffer.
  for name in vim.spairs(lsp._enabled_configs) do
    local config = lsp.config[name]
    if config and can_start(bufnr, name, config) then
      -- Deepcopy config so changes done in the client
      -- do not propagate back to the enabled configs.
      config = vim.deepcopy(config)

      if type(config.root_dir) == 'function' then
        ---@param root_dir string
        config.root_dir(bufnr, function(root_dir)
          config.root_dir = root_dir
          vim.schedule(function()
            start_config(bufnr, config)
          end)
        end)
      else
        start_config(bufnr, config)
      end