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

Code before:
    file = file:gsub(os_sep, '/') --[[@as string]]
    if file:match('^%w:/?$') then
      return ''
    end
  end
  return file:match('/$') and '' or (file:match('[^/]*$'))
end

--- Concatenates partial paths (one absolute or relative path followed by zero or more relative
--- paths). Slashes are normalized: redundant slashes are removed, and (on Windows) backslashes are
--- replaced with forward-slashes. Empty segments are removed. Paths are not expanded/resolved.
---
--- Examples:
--- - "foo/", "/bar" => "foo/bar"
--- - "", "after/plugin" => "after/plugin"
--- - Windows: "a\foo\", "\bar" => "a/foo/bar"
---
---@since 12
---@param ... string
---@return string
function M.joinpath(...)
  local segments = { ... }
  for i, segment in ipairs(segments) do
    if #segment == 0 then
      table.remove(segments, i)
    end
  end
  local path = table.concat(segments, '/')
  if iswin then
    path = path:gsub('\\', '/')
  end
  return (path:gsub('//+', '/'))
end

--- @class vim.fs.dir.Opts
--- @inlinedoc
---
--- How deep to traverse.
--- (default: `1`)
--- @field depth? integer
---
--- Predicate to control traversal.
--- Return false to stop searching the current directory.
--- Only useful when depth > 1
--- Return an iterator over the items located in {path}
--- @field skip? (fun(dir_name: string): boolean)
---
--- Follow symbolic links.
--- (default: `false`)
--- @field follow? boolean


Review comment (suggestion):
It seems that there is still a problem with this implementation if there is 2 or more adjacent empty segments.

```lua
print(joinpath('', '', 'foo', 'bar', '', '')) -- '/foo/bar/'
print(joinpath('', '', '', '')) -- '/'
```

Also, removing elements while iterating looks like a code smell. [`table.remove()`](https://neovim.io/doc/user/luaref/#table.remove()) mentions that it shifts the elements, so the `for` loop is probably not seeing the second `''` since it ended in the position of the previous one.

Code after:
    file = file:gsub(os_sep, '/') --[[@as string]]
    if file:match('^%w:/?$') then
      return ''
    end
  end
  return file:match('/$') and '' or (file:match('[^/]*$'))
end

--- Concatenates partial paths (one absolute or relative path followed by zero or more relative
--- paths). Slashes are normalized: redundant slashes are removed, and (on Windows) backslashes are
--- replaced with forward-slashes. Empty segments are removed. Paths are not expanded/resolved.
---
--- Examples:
--- - "foo/", "/bar" => "foo/bar"
--- - "", "after/plugin" => "after/plugin"
--- - Windows: "a\foo\", "\bar" => "a/foo/bar"
---
---@since 12
---@param ... string
---@return string
function M.joinpath(...)
  local n = select('#', ...)
  ---@type string[]
  local segments = {}
  for i = 1, n do
    local s = select(i, ...)
    if s and #s > 0 then
      segments[#segments + 1] = s
    end
  end

  local path = table.concat(segments, '/')

  return (path:gsub(iswin and '[/\\][/\\]*' or '//+', '/'))
end

--- @class vim.fs.dir.Opts
--- @inlinedoc
---
--- How deep to traverse.
--- (default: `1`)
--- @field depth? integer
---
--- Predicate to control traversal.
--- Return false to stop searching the current directory.
--- Only useful when depth > 1
--- Return an iterator over the items located in {path}
--- @field skip? (fun(dir_name: string): boolean)
---
--- Follow symbolic links.
--- (default: `false`)