Ignore parser treats literal exclamation marks as negation
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Does this issue occur when all extensions are disabled?: Reproduced in the core parser without loading extensions. Browser and Explorer UI verification has not been performed for this report.
- VS Code Version: source `main` at `fc0a9e94576224c89cc08d390b38ab760a261f1f` (`1.138.0` development version)
- OS Version: macOS 27.0 (26A5425a), arm64; Node 24.18.0
The shared `IgnoreFile` parser treats an exclamation mark anywhere in a `.gitignore` pattern as negation, then removes every exclamation mark. This can exclude the intended exception and include a different filename instead.
For example:
```gitignore
*.txt
!important!.txt
```
The first `!` negates the rule; the second belongs to the filename. The parser currently re-includes `important.txt` instead of `important!.txt`.
### Steps to reproduce in the core parser
1. Check out the source revision above and install the repository dependencies.
2. Run `npm run transpile-client`.
3. From the repository root, run:
```sh
node --input-type=module <<'JS'
import { IgnoreFile } from './out/vs/workbench/services/search/common/ignoreFile.js';
const ignore = new IgnoreFile('*.txt\n!important!.txt', '/');
for (const file of ['/important!.txt', '/important.txt']) {
console.log(file, ignore.isArbitraryPathIgnored(file, false));
}
JS
```
| File | Expected `isArbitraryPathIgnored` | Actual |
| --- | --- | --- |
| `/important!.txt` | `false` | `true` |
| `/important.txt` | `true` | `false` |
Other inputs exposing the same classification problem are `important!.txt` (a literal filename to exclude), `\!important.txt` (an escaped leading exclamation mark), and `[!a].txt` (a negated character class).
### Affected code paths
- Browser local-folder file and text search reads `.gitignore` and `.ignore` through this parser in `localFileSearch.ts`.
- Explorer filtering uses the same parser when `explorer.excludeGitIgnore` is enabled, including on desktop (`explorerViewer.ts`).
Native ripgrep search uses a separate implementation. The behavior above was reproduced directly in the shared parser, rather than inferred from a desktop search result.
The [Git pattern documentation](https://git-scm.com/docs/gitignore#_pattern_format) describes negation as a prefix and permits escaping a literal leading exclamation mark. Comparing 27 file, directory, and nested-path cases with `git check-ignore` found 17 mismatches before the proposed fix and none afterward.
Related: #156077 concerns re-including directories. This report reproduces with files at the root and literal exclamation marks, independently of that directory-traversal behavior.
Contributor guide
Assessment
This issue has not been assessed yet.