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

Code before:
--- Either use |:au|, |nvim_create_autocmd()| or put the call in a
--- `ftplugin/<filetype_name>.lua` (See |ftplugin-name|)
---
--- @since 10
---
--- @param config vim.lsp.ClientConfig Configuration for the server.
--- @param opts vim.lsp.start.Opts? Optional keyword arguments.
--- @return integer? client_id
function lsp.start(config, opts)
  opts = opts or {}
  local reuse_client = opts.reuse_client or reuse_client_default
  local bufnr = vim._resolve_bufnr(opts.bufnr)

  if not config.root_dir and opts._root_markers then
    config = vim.deepcopy(config)

    if type(opts._root_markers) == 'table' then
      for _, marker in ipairs(opts._root_markers) do
        local root = vim.fs.root(bufnr, marker)
        if root ~= nil then
          config.root_dir = root
          break
        end
      end
    else
      config.root_dir = vim.fs.root(bufnr, opts._root_markers)
    end
  end

  if
    not config.root_dir
    and (not config.workspace_folders or #config.workspace_folders == 0)
    and config.workspace_required
  then
    log.info(
      ('skipping config "%s": workspace_required=true, no workspace found'):format(config.name)
    )
    return
  end

  for _, client in pairs(all_clients) do
    if reuse_client(client, config) then
      if opts.attach == false then
        return client.id
      end

      if lsp.buf_attach_client(bufnr, client.id) then
        return client.id
      end
      return
    end

Review comment (suggestion):
could eliminate this `else` by changing the above to:

```lua
local grouped = type(opts._root_markers[1] == 'string' and { opts._root_markers } or opts._root_markers
for _, markers in ipairs(grouped) do
  ...
```

Code after:
---
--- - `name` arbitrary name for the LSP client. Should be unique per language server.
--- - `cmd` command string[] or function.
--- - `root_dir` path to the project root. By default this is used to decide if an existing client
---   should be re-used. The example above uses |vim.fs.root()| to detect the root by traversing
---   the file system upwards starting from the current directory until either a `pyproject.toml`
---   or `setup.py` file is found.
--- - `workspace_folders` list of `{ uri:string, name: string }` tables specifying the project root
---   folders used by the language server. If `nil` the property is derived from `root_dir` for
---   convenience.
---
--- Language servers use this information to discover metadata like the
--- dependencies of your project and they tend to index the contents within the
--- project folder.
---
---
--- To ensure a language server is only started for languages it can handle,
--- make sure to call |vim.lsp.start()| within a |FileType| autocmd.
--- Either use |:au|, |nvim_create_autocmd()| or put the call in a
--- `ftplugin/<filetype_name>.lua` (See |ftplugin-name|)
---
--- @since 10
---
--- @param config vim.lsp.ClientConfig Configuration for the server.
--- @param opts vim.lsp.start.Opts? Optional keyword arguments.
--- @return integer? client_id
function lsp.start(config, opts)
  opts = opts or {}
  local reuse_client = opts.reuse_client or reuse_client_default
  local bufnr = vim._resolve_bufnr(opts.bufnr)

  if not config.root_dir and opts._root_markers then
    validate('root_markers', opts._root_markers, 'table')
    config = vim.deepcopy(config)

    for _, marker in ipairs(opts._root_markers) do
      local root = vim.fs.root(bufnr, marker)
      if root ~= nil then
        config.root_dir = root
        break
      end
    end
  end

  if
    not config.root_dir
    and (not config.workspace_folders or #config.workspace_folders == 0)
    and config.workspace_required
  then
    log.info(
      ('skipping config "%s": workspace_required=true, no workspace found'):format(config.name)