<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rneovim.git/test/functional/vimscript/fnamemodify_spec.lua, branch master</title>
<subtitle>Neovim fork with Rahm's personal hacks.</subtitle>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/'/>
<entry>
<title>refactor(path): pathcmp() #41035</title>
<updated>2026-08-07T23:54:29+00:00</updated>
<author>
<name>tao</name>
<email>2471314@gmail.com</email>
</author>
<published>2026-08-07T23:54:29+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=f0a01822850bf7324326a3424f6b9a6892e5a768'/>
<id>f0a01822850bf7324326a3424f6b9a6892e5a768</id>
<content type='text'>
Problem:
Redudant code

Solution:
Add `path_fold_char()` to normalize path sep.
Refactor `pathcmp()` and `path_fnamencmp()` into `path_cmp`.

| feature                  | pathcmp        | path_fnamencmp | path_cmp(now) |
| ------------------------ | -------------- | -------------- | ------------- |
| case folding             | `mb_toupper()` | `utf_fold()`   | `utf_fold()`  |
| consults fileignorecase  | ✅             | ✅             | `ic` param    |
| `maxlen`                 | ✅             | ✅             | ✅            |
| `/` == `\`               | ✅             | ✅             | ✅            |
| MSWIN drive letter       | ❌             | ✅             | ✅            |
| sep affects sorting      | ✅             | ❌             | ✅            |
| ignores a trailing slash | ✅             | ❌             | ✅            |

Refactor `path_fnamecmp` and `path_full_compare` into `path_equal`,
with flags controlling "no filesystem" comparison (i.e. `path_cmp`), env
variables expansion, absolute path resolution and filesystem access.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
Redudant code

Solution:
Add `path_fold_char()` to normalize path sep.
Refactor `pathcmp()` and `path_fnamencmp()` into `path_cmp`.

| feature                  | pathcmp        | path_fnamencmp | path_cmp(now) |
| ------------------------ | -------------- | -------------- | ------------- |
| case folding             | `mb_toupper()` | `utf_fold()`   | `utf_fold()`  |
| consults fileignorecase  | ✅             | ✅             | `ic` param    |
| `maxlen`                 | ✅             | ✅             | ✅            |
| `/` == `\`               | ✅             | ✅             | ✅            |
| MSWIN drive letter       | ❌             | ✅             | ✅            |
| sep affects sorting      | ✅             | ❌             | ✅            |
| ignores a trailing slash | ✅             | ❌             | ✅            |

Refactor `path_fnamecmp` and `path_full_compare` into `path_equal`,
with flags controlling "no filesystem" comparison (i.e. `path_cmp`), env
variables expansion, absolute path resolution and filesystem access.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(path): DOS device path check #40976</title>
<updated>2026-07-26T11:18:57+00:00</updated>
<author>
<name>Dominic Della Valle</name>
<email>ddvpublic@Gmail.com</email>
</author>
<published>2026-07-26T11:18:57+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=4a5062cda69fa6cb59b7dc0c488dfb05accf99de'/>
<id>4a5062cda69fa6cb59b7dc0c488dfb05accf99de</id>
<content type='text'>
Problem:
The current check is intended to match DOS device paths starting with
`\\?` or `\\.` but will match any path starting with `?` or `.`,
including relative paths such as `.\`.
This is because the leading slashes are removed before the comparison.

Solution:
Changes the check to include the path's prefix, assuring the path has
the correct amount of separators for a DOS device path.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
The current check is intended to match DOS device paths starting with
`\\?` or `\\.` but will match any path starting with `?` or `.`,
including relative paths such as `.\`.
This is because the leading slashes are removed before the comparison.

Solution:
Changes the check to include the path's prefix, assuring the path has
the correct amount of separators for a DOS device path.</pre>
</div>
</content>
</entry>
<entry>
<title>test(harness): migrate away from magic globals</title>
<updated>2026-07-21T11:22:39+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-20T15:16:51+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=6d8c8b18d551d0be0490640c00fabb816727ec10'/>
<id>6d8c8b18d551d0be0490640c00fabb816727ec10</id>
<content type='text'>
Problem:
The magic globals `it`, `describe`, etc., are more trouble than they are
worth.

- Hooking into `after_each` requires `getfenv()` hacks.
- They confuse luals/emmylua, because the top-level `.luarc.json` isn't
  merged with `test/.luarc.json` (apparently a luals limitation?)
- They totally defeat discoverability because the user just has to
  "know" about the various magic symbols.

So they harm DX, which means they serve no purpose at all.

Solution:
- Expose the test API from `testutil`, so tests can call `t.it()`,
  `t.describe()`, etc., in the conventional way.
- Drop `getfenv()` hacks.
- Drop the `setfenv()` injection in `load_chunk`.
- Drop `test/_meta.lua`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
The magic globals `it`, `describe`, etc., are more trouble than they are
worth.

- Hooking into `after_each` requires `getfenv()` hacks.
- They confuse luals/emmylua, because the top-level `.luarc.json` isn't
  merged with `test/.luarc.json` (apparently a luals limitation?)
- They totally defeat discoverability because the user just has to
  "know" about the various magic symbols.

So they harm DX, which means they serve no purpose at all.

Solution:
- Expose the test API from `testutil`, so tests can call `t.it()`,
  `t.describe()`, etc., in the conventional way.
- Drop `getfenv()` hacks.
- Drop the `setfenv()` injection in `load_chunk`.
- Drop `test/_meta.lua`.
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: misc, remove some old help tags #40214</title>
<updated>2026-07-18T08:29:51+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-18T08:29:51+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=446b9d8c5589f931a71904cd5bf384fec56ebf2b'/>
<id>446b9d8c5589f931a71904cd5bf384fec56ebf2b</id>
<content type='text'>
- Remove old help tags: they add noise to cmdline completion.

Co-authored-by: acehinnnqru &lt;acehinnnqru@gmail.com&gt;
Co-authored-by: KangaZero &lt;samuelyongw@gmail.com&gt;
Co-authored-by: Simone Ragusa &lt;hi@interrato.dev&gt;
Co-authored-by: Chinmay Dalal &lt;~chinmay/public-inbox@lists.sr.ht&gt;
Co-authored-by: coyaSONG &lt;66289470+coyaSONG@users.noreply.github.com&gt;
Co-authored-by: Olivia Kinnear &lt;git@superatomic.dev&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
- Remove old help tags: they add noise to cmdline completion.

Co-authored-by: acehinnnqru &lt;acehinnnqru@gmail.com&gt;
Co-authored-by: KangaZero &lt;samuelyongw@gmail.com&gt;
Co-authored-by: Simone Ragusa &lt;hi@interrato.dev&gt;
Co-authored-by: Chinmay Dalal &lt;~chinmay/public-inbox@lists.sr.ht&gt;
Co-authored-by: coyaSONG &lt;66289470+coyaSONG@users.noreply.github.com&gt;
Co-authored-by: Olivia Kinnear &lt;git@superatomic.dev&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>fix(path): avoid shell fallback for unknown users #40757</title>
<updated>2026-07-17T18:21:29+00:00</updated>
<author>
<name>MAAZIZ Adel Ayoub</name>
<email>adelayoub.maaziz@gmail.com</email>
</author>
<published>2026-07-17T18:21:29+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=9d3edf345f8e25f1a7976efff54818a426661802'/>
<id>9d3edf345f8e25f1a7976efff54818a426661802</id>
<content type='text'>
Problem:
Expanding an unknown ~user path falls back to the shell. In a fast event,
this re-enters the event loop and aborts Nvim.

Solution:
Leave unknown users unexpanded when the system account lookup fails.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
Expanding an unknown ~user path falls back to the shell. In a fast event,
this re-enters the event loop and aborts Nvim.

Solution:
Leave unknown users unexpanded when the system account lookup fails.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(coverity): RESOURCE_LEAK, USE_AFTER_FREE</title>
<updated>2026-07-13T03:48:05+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-13T03:46:46+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=e1c1bd3722d4fda27e7fba07445f917522327fb1'/>
<id>e1c1bd3722d4fda27e7fba07445f917522327fb1</id>
<content type='text'>
    /src/nvim/ex_docmd.c: 5033             in ex_restart()
    5027         // The address after --listen may be in use by the current server.
    5028         if (i &gt; 0 &amp;&amp; strequal(arg, "--listen")) {
    5029           const listitem_T *next_li = li-&gt;li_next;
    5030           if (next_li != NULL) {
    5031             const char *addr = tv_get_string(TV_LIST_ITEM_TV(next_li));
    5032             if (strstr(addr, ":") || strstr(addr, "/") || strstr(addr, "\\")) {
    &gt;&gt;&gt;     CID 649201:         Resource leaks  (RESOURCE_LEAK)
    &gt;&gt;&gt;     Overwriting "listen_arg" in "listen_arg = xstrdup(addr)" leaks the storage that "listen_arg" points to.
    5033               listen_arg = TO_SLASH_SAVE(addr);
    5034     #ifdef MSWIN
    5035               // On Windows, don't pass --listen to new server (named pipe can't be reused immediately).
    5036               // Instead pass the address via RPC; new server rebinds after startup.
    5037               li = next_li;
    5038               continue;

    *** CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    /src/nvim/eval/fs.c: 228             in modify_fname()
    222
    223       // ":h" - head, remove "/file_name", can be repeated
    224       // Don't remove the logical root, see `FileInfo`.
    225       while (src[*usedlen] == ':' &amp;&amp; src[*usedlen + 1] == 'h') {
    226         valid |= VALID_HEAD;
    227         *usedlen += 2;
    &gt;&gt;&gt;     CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    &gt;&gt;&gt;     Using freed pointer "s".
    228         while (tail &gt; s &amp;&amp; after_pathsep(s, tail)) {
    229           MB_PTR_BACK(*fnamep, tail);
    230         }
    231         *fnamelen = tail &lt;= s ? (size_t)(s - *fnamep) : (size_t)(tail - *fnamep);
    232         if (*fnamelen == 0) {
    233           // Result is empty.  Turn it into "." to make ":cd %:h" work.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
    /src/nvim/ex_docmd.c: 5033             in ex_restart()
    5027         // The address after --listen may be in use by the current server.
    5028         if (i &gt; 0 &amp;&amp; strequal(arg, "--listen")) {
    5029           const listitem_T *next_li = li-&gt;li_next;
    5030           if (next_li != NULL) {
    5031             const char *addr = tv_get_string(TV_LIST_ITEM_TV(next_li));
    5032             if (strstr(addr, ":") || strstr(addr, "/") || strstr(addr, "\\")) {
    &gt;&gt;&gt;     CID 649201:         Resource leaks  (RESOURCE_LEAK)
    &gt;&gt;&gt;     Overwriting "listen_arg" in "listen_arg = xstrdup(addr)" leaks the storage that "listen_arg" points to.
    5033               listen_arg = TO_SLASH_SAVE(addr);
    5034     #ifdef MSWIN
    5035               // On Windows, don't pass --listen to new server (named pipe can't be reused immediately).
    5036               // Instead pass the address via RPC; new server rebinds after startup.
    5037               li = next_li;
    5038               continue;

    *** CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    /src/nvim/eval/fs.c: 228             in modify_fname()
    222
    223       // ":h" - head, remove "/file_name", can be repeated
    224       // Don't remove the logical root, see `FileInfo`.
    225       while (src[*usedlen] == ':' &amp;&amp; src[*usedlen + 1] == 'h') {
    226         valid |= VALID_HEAD;
    227         *usedlen += 2;
    &gt;&gt;&gt;     CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    &gt;&gt;&gt;     Using freed pointer "s".
    228         while (tail &gt; s &amp;&amp; after_pathsep(s, tail)) {
    229           MB_PTR_BACK(*fnamep, tail);
    230         }
    231         *fnamelen = tail &lt;= s ? (size_t)(s - *fnamep) : (size_t)(tail - *fnamep);
    232         if (*fnamelen == 0) {
    233           // Result is empty.  Turn it into "." to make ":cd %:h" work.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(path): normalize separators (slashes) #39155</title>
<updated>2026-07-12T17:23:44+00:00</updated>
<author>
<name>tao</name>
<email>2471314@gmail.com</email>
</author>
<published>2026-07-12T17:23:44+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=4a0859631407bc9279a935f3219faabc0991a826'/>
<id>4a0859631407bc9279a935f3219faabc0991a826</id>
<content type='text'>
Problem:
Continue separators normalization, and try to keep it at the
nvim &lt;-&gt; external boundary, e.g., `fn.xxx`, `api.xxx`, `:xxx`

Solution:
some key changes
- normalize `$HOME-windows`
- normalize entry points of changing directory
  - `nvim_set_current_dir()`, `chdir()`
- normalize the named pipe
  - `--listen` arg, `--server` arg, `:restart`
  - `serverstart()`, `sockconnect()`, `serverstop()`
- make `expand()` respect 'shellslash' again
- clean up `did_set_shellslash`
- replace `forward_slash` with `TO_SLASH`
- remove obsolete `TMP_PATHSEPSTR`
- remove `slash_adjust` in `do_autocmd_dirchanged`?
- make `fnamemodify()` always return `/` (except when substituting
  separators via `:s`, `:gs` ?)

Note:
- these funcs still apply `slash_adjust` on return, as before:
  `:pwd`, `chdir()`, `exepath()`, `getcwd()`
- these funcs alwarys return `/`, unlike before the normalization PRs
  - `getcompletion()`, `finddir()`, `findfile()`

Also
- clean up code, comments, formatting and tests
- move `TO_SLASH` from `f_chdir` to `changedir_func`
- move `TO_SLASH` from `f_bufadd` to `buflist_new`

Co-authored-by: Justin M. Keyes &lt;justinkz@gmail.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
Continue separators normalization, and try to keep it at the
nvim &lt;-&gt; external boundary, e.g., `fn.xxx`, `api.xxx`, `:xxx`

Solution:
some key changes
- normalize `$HOME-windows`
- normalize entry points of changing directory
  - `nvim_set_current_dir()`, `chdir()`
- normalize the named pipe
  - `--listen` arg, `--server` arg, `:restart`
  - `serverstart()`, `sockconnect()`, `serverstop()`
- make `expand()` respect 'shellslash' again
- clean up `did_set_shellslash`
- replace `forward_slash` with `TO_SLASH`
- remove obsolete `TMP_PATHSEPSTR`
- remove `slash_adjust` in `do_autocmd_dirchanged`?
- make `fnamemodify()` always return `/` (except when substituting
  separators via `:s`, `:gs` ?)

Note:
- these funcs still apply `slash_adjust` on return, as before:
  `:pwd`, `chdir()`, `exepath()`, `getcwd()`
- these funcs alwarys return `/`, unlike before the normalization PRs
  - `getcompletion()`, `finddir()`, `findfile()`

Also
- clean up code, comments, formatting and tests
- move `TO_SLASH` from `f_chdir` to `changedir_func`
- move `TO_SLASH` from `f_bufadd` to `buflist_new`

Co-authored-by: Justin M. Keyes &lt;justinkz@gmail.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>feat(path): fnamemodify(':h') preserves logical root #40447</title>
<updated>2026-07-01T12:25:21+00:00</updated>
<author>
<name>tao</name>
<email>2471314@gmail.com</email>
</author>
<published>2026-07-01T12:25:21+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=fa9b3381bcf7d5cb91ba32aa83512e19b4965c3f'/>
<id>fa9b3381bcf7d5cb91ba32aa83512e19b4965c3f</id>
<content type='text'>
Problem:
On Windows, `fnamemodify('//foo/C$', ':h')` incorrectly removes `C$`
as a regular file name and returns `//foo`. However, this is a valid
UNC path, `foo` is a server name and `C$` is a share name.
The correct result should be `//foo/C$`.

Solution:
Extend `os_fileinfo2` and `FileInfo` with `prefix_off`, `rest_off` to
identify path types and logical root boundaries. ':h' can use this info
to prevent traversing past the logical root.

Examples:
  /foo               =&gt; /
  //foo              =&gt; // (POSIX)
  //foo/bar          =&gt; //foo (POSIX)
  //server/share/foo =&gt; //server/share/ (Windows)
  C:/foo             =&gt; C:/
  //?/C:/foo         =&gt; //?/C:/

Co-authored-by: Barrett Ruth &lt;br@barrettruth.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
On Windows, `fnamemodify('//foo/C$', ':h')` incorrectly removes `C$`
as a regular file name and returns `//foo`. However, this is a valid
UNC path, `foo` is a server name and `C$` is a share name.
The correct result should be `//foo/C$`.

Solution:
Extend `os_fileinfo2` and `FileInfo` with `prefix_off`, `rest_off` to
identify path types and logical root boundaries. ':h' can use this info
to prevent traversing past the logical root.

Examples:
  /foo               =&gt; /
  //foo              =&gt; // (POSIX)
  //foo/bar          =&gt; //foo (POSIX)
  //server/share/foo =&gt; //server/share/ (Windows)
  C:/foo             =&gt; C:/
  //?/C:/foo         =&gt; //?/C:/

Co-authored-by: Barrett Ruth &lt;br@barrettruth.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>fix(vimscript): normalize multi-slash heads in fnamemodify() #39805</title>
<updated>2026-05-17T14:54:59+00:00</updated>
<author>
<name>Barrett Ruth</name>
<email>62671086+barrettruth@users.noreply.github.com</email>
</author>
<published>2026-05-17T14:54:59+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=38c18ad3a8f231664abc0d12a9c57e73f93fafc6'/>
<id>38c18ad3a8f231664abc0d12a9c57e73f93fafc6</id>
<content type='text'>
Problem: `fnamemodify(..., ':h')` mishandles POSIX leading slash runs longer than `//`.

Solution: Collapse those slash runs to `/` before computing the head.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem: `fnamemodify(..., ':h')` mishandles POSIX leading slash runs longer than `//`.

Solution: Collapse those slash runs to `/` before computing the head.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(path): normalize path slashes on Windows #37729</title>
<updated>2026-04-24T17:20:25+00:00</updated>
<author>
<name>tao</name>
<email>2471314@gmail.com</email>
</author>
<published>2026-04-24T17:20:25+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=f130922744657b731c24a842a85fd8a9f8058073'/>
<id>f130922744657b731c24a842a85fd8a9f8058073</id>
<content type='text'>
Problem:
On Windows, path separators may become inconsistent for various reasons,
which makes normalization quite painful.

Solution:
Normalize paths to `/` at the entry boundaries and always use it
internally, converting back only in rare cases where `\` is really
needed (e.g. cmd.exe/bat scripts?).

This is the first commit in a series of incremental steps.

Note:
* some funcs won't respect shellslash. e.g. `expand/fnamemodify`
* some funcs still respect shellslash, but will be updated in a follow
  PR. e.g. `ex_pwd/f_chdir/f_getcwd`
* uv's built-in funcs always return `\`. e.g. `uv.cwd/uv.exepath`

Co-authored-by: Justin M. Keyes &lt;justinkz@gmail.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
On Windows, path separators may become inconsistent for various reasons,
which makes normalization quite painful.

Solution:
Normalize paths to `/` at the entry boundaries and always use it
internally, converting back only in rare cases where `\` is really
needed (e.g. cmd.exe/bat scripts?).

This is the first commit in a series of incremental steps.

Note:
* some funcs won't respect shellslash. e.g. `expand/fnamemodify`
* some funcs still respect shellslash, but will be updated in a follow
  PR. e.g. `ex_pwd/f_chdir/f_getcwd`
* uv's built-in funcs always return `\`. e.g. `uv.cwd/uv.exepath`

Co-authored-by: Justin M. Keyes &lt;justinkz@gmail.com&gt;</pre>
</div>
</content>
</entry>
</feed>
