Skip to content

bufnr()/bufwinid() lookups fail for filenames needing Ex-command escaping, breaking navigation to a second such file #57

Description

@vijayvaradan

Summary

Opening the diff for a second file whose name needs Ex-command-line escaping (contains spaces, single quotes, or braces, e.g. from a name like test_{{ foo }}.txt) throws an error, after the first such file opened without any problem.

Steps to reproduce

  1. Create two directories, each containing a file with the same name and differing content, where the filename needs escaping for Vim's Ex command line, e.g. test file.txt or test_{{ foo }}.txt. Include at least two such files (or one such file plus a second, normal file) so there is a "previous" file to navigate away from.
  2. :DirDiff dirA dirB
  3. Open the first differing entry (Enter, or :DirDiffNext).
  4. Navigate to the second differing entry and open it (Enter, or :DirDiffNext again).

Actual result

The first file opens fine. Opening the second one throws:

Error detected while processing function <SNR>NN_DirDiffOpen:
line   68:
line   73:
E94: No matching buffer for -1

(Line numbers are relative to the start of the function and vary by Vim/plugin version; the underlying error is always E94: No matching buffer for -1.)

Root cause

In DirDiffOpen(), s:FilenameA/s:FilenameB are set via EscapeFileName() (fnameescape()), which is correct for building :execute "edit " . name command strings. The same escaped value is then reused as previousFileA/previousFileB on the next invocation and passed into bufnr(previousFileA) and Drop(previousFileB) (which itself calls bufwinid(a:fname)).

bufnr()/bufwinid() match against the real (unescaped) buffer name, not an Ex-command-escaped string. Vim strips the command-line escaping when it resolves :edit <escaped> to the actual file path, so the buffer's stored name never contains the escaping backslashes. Passing the escaped string into bufnr()/bufwinid() therefore never matches, bufnr() returns -1, and the subsequent :bd -1/bufwinid() fallback throws E94.

This only surfaces on the second (or later) file opened in a session, since there is no "previous" file to look up on the first one, which matches the reported behavior above.

Fix

I have a minimal, tested fix ready (keep the raw filename alongside the escaped one, and use the raw form for bufnr()/bufwinid()/Drop() buffer lookups, escaping only at the point of building the :edit/:split/:diffsplit command strings). Verified under both Vim and Neovim, including repeated back-and-forth navigation and the manual keypress interaction path, with a plain-filename regression check. Will follow up with a PR referencing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions