diff --git a/src/nvim/eval/fs.c b/src/nvim/eval/fs.c index c3809b5faf..8bf7414d8e 100644 --- a/src/nvim/eval/fs.c +++ b/src/nvim/eval/fs.c @@ -203,6 +203,21 @@ repeat: } } +#ifndef MSWIN + if (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') { + char *fname = *fnamep; + // POSIX reserves exactly "//"; longer slash runs are ordinary absolute paths. + // "///foo/bar" => "/foo" + // "//foo/bar" => "//foo" + if (fname[0] == '/' && fname[1] == '/' && fname[2] == '/') { + while (fname[1] == '/') { + fname++; + } + *fnamep = fname; + } + } +#endif + char *tail = path_tail(*fnamep); *fnamelen = strlen(*fnamep); diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua index 7b581c225f..f3d160f9c5 100644 --- a/test/functional/vimscript/fnamemodify_spec.lua +++ b/test/functional/vimscript/fnamemodify_spec.lua @@ -109,6 +109,42 @@ describe('fnamemodify()', function() eq('.', fnamemodify('hello.txt', ':h')) eq_slashconvert('path/to', fnamemodify('path/to/hello.txt', ':h')) + + if is_os('win') then + -- Current Windows behavior for slash-style UNC paths, such as "//foo/C$/". + eq('/', fnamemodify('/', ':h')) + eq('/', fnamemodify('/foo', ':h')) + eq('//', fnamemodify('//', ':h')) + eq('//', fnamemodify('//foo', ':h')) + eq('//foo', fnamemodify('//foo/bar', ':h')) + eq('//foo', fnamemodify('//foo///bar', ':h')) + eq('//foo', fnamemodify('//foo/C$', ':h')) + eq('//foo/C$', fnamemodify('//foo/C$/', ':h')) + eq('//foo/C$', fnamemodify('//foo/C$/bar', ':h')) + eq('///', fnamemodify('///', ':h')) + eq('////', fnamemodify('////', ':h')) + eq('///', fnamemodify('///foo', ':h')) + eq('///foo', fnamemodify('///foo/bar', ':h')) + eq('///foo', fnamemodify('///foo////bar', ':h')) + else + -- POSIX roots. + eq('/', fnamemodify('/', ':h')) + eq('/', fnamemodify('/foo', ':h')) + + -- POSIX permits special handling for exactly two leading slashes. + eq('//', fnamemodify('//', ':h')) + eq('//', fnamemodify('//foo', ':h')) + eq('//foo', fnamemodify('//foo/bar', ':h')) + eq('//foo', fnamemodify('//foo///bar', ':h')) + + -- More than two leading slashes are ordinary absolute paths. + eq('/', fnamemodify('///', ':h')) + eq('/', fnamemodify('////', ':h')) + eq('/', fnamemodify('///foo', ':h')) + eq('/foo', fnamemodify('///foo/bar', ':h')) + eq('/foo', fnamemodify('///foo////bar', ':h')) + eq('/foo', fnamemodify('////foo/bar', ':h')) + end end) it('handles :t', function()